what makes make tick?
I don't understand something until I have done it myself. I
found make to be perpetually confusing until I had
made a small Makefile myself and tinkered with it.
This is what I propose to walk you through in this exercise. We are
not going to make a program which does anything interesting at all,
instead we are interested in the capabilities of the
make utility.
Make can be particularly confusing because it
already "knows" about a lot of things. First, it assumes that the
configuration file you want to use is called
[mM]akefile (that's Makefile or
makefile right?). So, if you just run
make on the command-line as you will often be asked to
do, in fact make is reading the file
[mM]akeile and processing the first target it finds in
that file. We will get to targets in the makefile
shortly but first I want to show you one of make's
built in knowledge base, which usually makes things which gets
people confused.
Copy the following bit of code into a file named
yello.c
#include <stdio.h>
int main () {
printf("I hate these dxxx hello programs\n");
printf("When will I really understand programming?\n");
exit(0);
}
It is a variation on the "hello world" program. You need to include the library headers for stdio.h (standard io (input-output) .h (header-file) in order to get the printf function, which knows how to print to the standard output. We know about stdout right? this is a unix class.
Now if you were to compile this tiny c program using
gcc the gnu c compiler. You would type the line
gcc -o yello yello.c which tells gcc to please compile
the source code file yello.c into an object code file
named yello. But with make you don't even
have to remember this much, try this : type make
yello. You are asking make to produce a target
called yello which you haven't defined anywhere. On my
system I get this result: (The dollar signs are stand-ins for my
shell prompt.)
$make yello cc yello.c -o yello $
make knows a lot about how to make c programs. In
this case I gave it a target and it went about finding ways in
which it could produce such a target. There is no
makefile with predefined targets, but in the current
working directory make found yello.c.
Given a target and a file of code with the same name,
make assumes that I want a binary with the same name
as the target I have requested. Given a filename.c,
make knows what to do. It invokes the c compiler. On
my system this shows up as cc, but if I ask
which cc then ls -l the cc which is being called, I
find that this is a symlink to gcc.
The GNU Make Manual which you can access by typing info make calls these "Implicit Rules" and explains it this way:
Using Implicit Rules
********************
Certain standard ways of remaking target files are used very often.
For example, one customary way to make an object file is from a C
source file using the C compiler, `cc'.
"Implicit rules" tell `make' how to use customary techniques so that
you do not have to specify them in detail when you want to use them.
For example, there is an implicit rule for C compilation. File names
determine which implicit rules are run. For example, C compilation
typically takes a `.c' file and makes a `.o' file. So `make' applies
the implicit rule for C compilation when it sees this combination of
file name endings.
Anyway,
make is knowledgeable about many programming languages
and can be made knowledgeable about any type of dependency structure
you may have, and this is what this example is going to try to
demonstrate. Now, the art of using make is in declaring your own
targets, or understanding those targets that the programmer of a
project you are interested in has prepared for you. There are some
targets which are commonly used, such as 'all' 'install' and
'clean' each of these runs completely different commands as defined
in the makefile.
- all
- is generally the first target in the
makefileand has the commands for all the successive targets and dependencies required to fulfill themake allcommand. - install
- is usually a bunch of shell commands and scripts which will copy the compiled binaries or libraries from their location in the source code at the end of compilation, into the system wide directories, such as /usr/bin , /usr/local/bin or /usr/lib where this binary or library could be in the paths which allow them to be called from anywhere in the system. 'install' tends to have 'all' as a dependency which makes sense because if the compilation did not succeed how could you install the perhaps non-existent binaries system-wide?
- clean
- performs a different job, it is usually a bunch of
rmcommands which remove the object files, and binaries which are left hanging around in the source code. You want tomake cleanto forcemaketo recompile every bit of a project.Another ofmake's intelligences is that because of the way in which it knows how to keep track of dependencies, if a dependency is already met, then it knows there is no more work to do. This is brilliant for the programmer who only changes one tiny piece of the source code and does not want the entire program to be recompiled, but just the little piece he is working on.
hold on!!
Ok, I feel you are getting confused. So far we have talked abouttargets and dependencies these are the
fundamentals of make. Make can take lists of
targets and their dependencies and you in
a makefile supply the rules which
make needs in order to create one of these
dependencies should it not exist.