The way in which we design a software system is that we first write code, then the compiler compiles it and creates executable files. These executable files are the ones that carry out the actual task. “Make” is a tool that controls the generation of executables and other non-source files of a program from the program’s source files.
The make tool needs to know how to build your program. It gets its knowledge of how to build your program from a file called the “Makefile”. This makefile lists each of the non-source files and how to compute it from other files. When you write a program, you should write a makefile for it, so that it is possible to use “Make” to build and install the program. Simple stuff! If you didn’t understand it, go back and read the paragraph again because it’s important for the next part.
when your try to uninstall, it becomes complicated if you installed with make install. This is where checkinstall comes in handy
https://thoughtbot.com/blog/the-magic-behind-configure-make-make-install
Make
./configure # scans system and generates a Makefile from Makefile.in template
make # uses Makefile to build the program
make install # uses Makefile to install the program. may require sudo
make clean # optionalThere are three distinct steps in this process:
-
Configure the software
The
configurescript is responsible for getting ready to build the software on your specific system. It makes sure all of the dependencies for the rest of the build and install process are available, and finds out whatever it needs to know to use those dependencies.Unix programs are often written in C, so we’ll usually need a C compiler to build them. In these cases the
configurescript will establish that your system does indeed have a C compiler, and find out what it’s called and where to find it. -
Build the software
Once
configurehas done its job, we can invokemaketo build the software. This runs a series of tasks defined in aMakefileto build the finished program from its source code.The tarball you download usually doesn’t include a finished
Makefile. Instead it comes with a template calledMakefile.inand theconfigurescript produces a customisedMakefilespecific to your system. -
Install the software
Now that the software is built and ready to run, the files can be copied to their final destinations. The
make installcommand will copy the built program, and its libraries and documentation, to the correct locations.This usually means that the program’s binary will be copied to a directory on your
PATH, the program’s manual page will be copied to a directory on yourMANPATH, and any other files it depends on will be safely stored in the appropriate place.Since the install step is also defined in the
Makefile, where the software is installed can change based on options passed to theconfigurescript, or things theconfigurescript discovered about your system.Depending on where the software is being installed, you might need escalated permissions for this step so you can copy files to system directories. Using
sudowill often do the trick.
Where do these scripts come from
All of this works because a configure script examines your system, and uses the information it finds to convert a Makefile.in template into a Makefile, but where do the configure script and the Makefile.in template come from?
If you’ve ever opened up a configure script, or associated Makefile.in, you will have seen that they are thousands of lines of dense shell script. Sometimes these supporting scripts are longer than the source code of the program they install.
Even starting from an existing configure script, it would be very daunting to manually construct one. Don’t worry, though: these scripts aren’t built by hand.
Programs that are built in this way have usually been packaged using a suite of programs collectively referred to as autotools. This suite includes autoconf, automake, and many other programs, all of which work together to make the life of a software maintainer significantly easier. The end user doesn’t see these tools, but they take the pain out of setting up an install process that will run consistently on many different flavours of Unix.
Hello world
Let’s take a simple “Hello world” C program, and see what it would take to package it with autotools.
Here’s the source of the program, in a file called main.c:
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("Hello world\n");
return 0;
}Creating the configure script
Instead of writing the configure script by hand, we need to create a configure.ac file written in m4sh—a combination of m4 macros and POSIX shell script—to describe what the configure script needs to do.
The first m4 macro we need to call is AC_INIT, which will initialise autoconf and set up some basic information about the program we’re packaging. The program is called helloworld, the version is 0.1, and the maintainer is george@thoughtbot.com:
AC_INIT([helloworld], [0.1], [george@thoughtbot.com])We’re going to use automake for this project, so we need to initialise that with the AM_INIT_AUTOMAKE macro:
AM_INIT_AUTOMAKE
Next, we need to tell autoconf about the dependencies our configure script needs to look for. In this case, the configure script only needs to look for a C compiler. We can set this up using the AC_PROG_CC macro:
AC_PROG_CCIf there were other dependencies, then we’d use other m4 macros here to discover them; for example the AC_PATH_PROG macro looks for a given program on the user’s PATH.
Now that we’ve listed our dependencies, we can use them. We saw earlier that a typical configure script will use the information it has about the user’s system to build a Makefile from a Makefile.in template.
The next line used the AC_CONFIG_FILES macro to tell autoconf that the configure script should do just that: it should find a file called Makefile.in, substitute placeholders like @PACKAGE_VERSION@ with values like 0.1, and write the results to Makefile.
AC_CONFIG_FILES([Makefile])
Finally, having told autoconf everything our configure script needs to do, we can call the AC_OUTPUT macro to output the script:
AC_OUTPUT
Here’s the whole thing. Not bad, compared to the 4,737 line configure script it’s going to produce!
AC_INIT([helloworld], [0.1], [george@thoughtbot.com])
AM_INIT_AUTOMAKE
AC_PROG_CC
AC_CONFIG_FILES([Makefile])
AC_OUTPUTWe’re almost ready to package up and distribute our program, but we’re still missing something. Our configure script will expect a Makefile.in file that it can substitute all of those system-specific variables into, but so far, we’ve not created that file.
Creating the Makefile
As with the configure script, the Makefile.in template is very long and complex. So instead of writing it by hand, we write a shorter Makefile.am file, which automake will use to generated the Makefile.in for us.
First, we need to set some options to tell automake about the layout of the project. Since we’re not following the standard layout of a GNU project, we warn automake that this is a foreign project:
AUTOMAKE_OPTIONS = foreign
Next, we tell automake that we want the Makefile to build a program called helloworld:
bin_PROGRAMS = helloworld
There’s a lot of information packed into this line, thanks to automake’s uniform naming scheme.
The PROGRAMS suffix is called a primary. It tells automake what properties the helloworld file has. For example, PROGRAMS need to be built, whereas SCRIPTS and DATA files don’t need to be built.
The bin prefix tells automake that the file listed here should be installed to the directory defined by the variable bindir. There are various directories defined for us by autotools—including bindir, libdir, and pkglibdir—but we can also define our own.
If we wanted to install some Ruby scripts as part of our program, we could define a rubydir variable and tell automake to install our Ruby files there:
rubydir = $(datadir)/ruby
ruby_DATA = my_script.rb my_other_script.rbAdditional prefixes can be added before the install directory to further nuance automake’s behaviour.
Since we’ve defined a PROGRAM, we need to tell automake where to find its source files. In this case, the prefix is the name of the program these source files build, rather than the place where they will be installed:
helloworld_SOURCES = main.c
Here’s the whole Makefile.am file for our helloworld program. As with the configure.ac and the configure script, it’s a lot shorter than the Makefile.in that it generates:
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = helloworld
helloworld_SOURCES = main.cPutting it all together
Now we’ve written our config files, we can run autotools and generate the finished configure script and Makefile.in template.
First, we need to generate an m4 environment for autotools to use:
aclocal
Now we can run autoconf to turn our configure.ac into a configure script, and automake to turn our Makefile.am into a Makefile.in:
autoconf
automake --add-missingDistributing the program
The end user doesn’t need to see our autotools setup, so we can distribute the configure script and Makefile.in without all of the files we used to generate them.
Fortunately, autotools will help us with distribution too. The Makefile contains all kinds of interesting targets, including one to build a tarball of the project containing all of the files we need to distribute:
./configure
make distYou can even test that the distribution tarball can be installed under a variety of conditions:
make distcheckOverview
Now we know where this incantation comes from and how it works!
On the maintainer’s system:
aclocal # Set up an m4 environment
autoconf # Generate configure from configure.ac
automake --add-missing # Generate Makefile.in from Makefile.am
./configure # Generate Makefile from Makefile.in
make distcheck # Use Makefile to build and test a tarball to distributeOn the end-user’s system:
./configure # Generate Makefile from Makefile.in
make # Use Makefile to build the program
make install # Use Makefile to install the program