Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<p><tt>make</tt> is a phenomenally handy tool for organising the build process of your program. It makes it trivially easy to recompile parts of your program after changing it. It is especially handy if your program consists of many source files, or some of the code is generated automatically (e.g. by <tt>lex</tt>).</p>
<p><tt>make</tt> is used by writing a file which tells it how to do whatever it is you want it to do (such as compiling a program). This file is called a <em>makefile</em>, and is usually called <tt>Makefile</tt> (this is the name make will look for if you don't tell it otherwise).</p>
<h2>What can make do?</h2>
<ul>
<li><tt>make</tt> enables the end user to build and install your package without knowing the details of how that is done — because these details are recorded in the makefile that you supply.</li>
<li><tt>make</tt> figures out automatically which files it needs to update, based on which source files have changed. It also automatically determines the proper order for updating files, in case one non-source file depends on another non-source file. As a result, if you change a few source files and then run <tt>make</tt>, it does not need to recompile all of your program. It updates only those non-source files that depend directly or indirectly on the source files that you changed.</li>
<li><tt>make</tt> is not limited to any particular language. For each non-source file in the program, the makefile specifies the shell commands to compute it. These shell commands can run a compiler to produce an object file, the linker to produce an executable, ar to update a library, or T<sub>E</sub>X or Makeinfo to format documentation.</li>
<li><tt>make</tt> is not limited to building a package. You can also use <tt>make</tt> to control installing or deinstalling a package, generate tags tables for it, or anything else you want to do often enough to make it worth while writing down how to do it.</li>
</ul>
<p>(This list is taken from the home page of the <a href="http://www.gnu.org/">GNU</a> version of <a href="http://www.gnu.org/software/make/"><tt>make</tt></a>.)</p>
<h2>What's in a makefile?</h2>
<br />
<p>In general, a makefile contains two things:</p>
<ol>
<li>Constant definitions, such as the name of the compiler, what flags to pass it, etc</li>
<li>Rules for making files</li>
</ol>
<h3>Rules for making files</h3>
<p>A rule consists of:</p>
<ol>
<li>a target name</li>
<li>a list of prerequisites</li>
<li>a list of actions</li>
</ol>
<p>These are written like so:</p>
<pre>target: prereq1 prereq2
action1
action2</pre>
<p>When <tt>make</tt> follows one of these rules and executes the actions, we say that <tt>make</tt> <em>updates</em> the target.</p>
<p>When you run make, you give it the name of zero or more targets to update, and it <em>brings up for renewal</em> those targets and all the ones they depend on (but each target only gets updated once each time). If you don't give it any targets, it assumes you want to update the first target listed in the makefile.</p>
<p>The target name is usually the name of a file, though it does not have to be. Now, suppose a particular target comes up for renewal. If the following are all true, then make decides the target is already up to date and does not bother updating it.</p>
<ul>
<li>A file with that name exists (relative to the current directory)</li>
<li>All of its (direct or indirect) prerequisites are also the names of existing files</li>
<li>If any of those prerequisites are also targets, those targets are all up to date</li>
<li>The timestamp on the file named by the target is newer than the timestamps on all of its (direct or indirect) prerequisites</li>
</ul>
<p>On large projects especially, this can save a huge amount of time waiting for compilation of parts of the program that haven't changed.</p>
<p>A target with a name that is not the name of an existing file is called a phony target. These get updated regardless whenever you tell make to update them, e.g. on the command line or as a prerequisite. This is based partly on the assumption that the target names a file which it creates (which is quite commonly the case). So if a target has phony prerequisites, <tt>make</tt> will never think it is up to date.</p>
<h3>Constants</h3>
<p>Constants are not strictly necessary, but using them makes it easier to make major changes to the way your program is built.</p>
<p>For example, suppose you are writing a C program, and you want all of your files to be compiled with <tt>gcc</tt> using the flags <tt>-Wall -pedantic -O2</tt> (turning on lots of warnings and simple optimisations). Then you can specify:</p>
<pre>CC = gcc
CFLAGS = -Wall -pedantic -O # this comment does not get included</pre>
<p>Then, to compile a file, you would create a target for it, such as this:</p>
<pre>foo.o: foo.c foo.h
$(CC) $(CFLAGS) -c foo.c -o foo.o</pre>
<p>Notice that to refer to the constant's value you write <tt>$(CFLAGS)</tt>. That string gets replaced with whatever you put on the right hand side of the <tt>=</tt> sign (up until a <tt>#</tt> if there is one, which indicates a comment).</p>
<p>In this example we have specified the C compiler to use in the variable <tt>CC</tt>. This is good practice if you are trying to produce portable code, as it makes it easy to compile your program with a different compiler - all you need is to change the definition of <tt>CC</tt>, and all the actions referring to <tt>$(CC)</tt> will use the new definition automatically.</p>
<h2>Using <tt>make</tt></h2>
<p>To get the best out of <tt>make</tt>, you should specify a rule for each of your source files so that they get compiled separately, with the final stage being a simple linkage operation.</p>
<h3>An example makefile</h3>
<p>Here is a fairly typical example. Suppose you are writing a program called <tt>fred</tt>, and the source code for this program is in three source files, called <tt>foo.c</tt>, <tt>bar.c</tt>, and <tt>baz.l</tt>. You also have header files called <tt>fred.h</tt>, <tt>bar.h</tt> and <tt>lexer.h</tt>. <tt>baz.l</tt> is a <tt>lex</tt> file, which <tt>lex</tt> uses to generate a lexical analyser, also written in C, in the file <tt>lexer.c</tt>. You also use readline and the standard maths functions. A good makefile would look something like this:</p>
<pre>CC = gcc
LEX = flex
CFLAGS = -Wall -pedantic -O
LDFLAGS = -ltermcap -lreadline -lm -lfl
.PHONY: proper clean
fred: foo.o bar.o lexer.o
$(CC) $(CFLAGS) foo.o bar.o lexer.o $(LDFLAGS) -o fred
foo.o: fred.h bar.h foo.c
$(CC) $(CFLAGS) -c foo.c -o foo.o
bar.o: fred.h bar.h bar.c
$(CC) $(CFLAGS) -c bar.c -o bar.o
lexer.o: fred.h lexer.h lexer.c
$(CC) $(CFLAGS) -c lexer.c -o lexer.o
lexer.c: baz.l
$(LEX) -olexer.c baz.l
proper:
rm -vf *.o lexer.c
clean: proper
rm -vf fred</pre>
<p>To make the whole project, given just those source files, just type</p>
<pre>make</pre>
<p>This tells <tt>make</tt> to update the first target listed in the makefile. make notices that none of <tt>foo.o</tt>, <tt>bar.o</tt> and <tt>lexer.o</tt> actually exist yet, so it goes and updates those targets.</p>
<p>In the case of <tt>lexer.o</tt>, the file <tt>lexer.c</tt> also does not exist, because first it must be generated by lex. So before updating <tt>lexer.o</tt>, make first updates the target <tt>lexer.c</tt>, which runs <tt>lex</tt> on <tt>baz.l</tt>. Now <tt>make</tt> compiles <tt>lexer.c</tt> into <tt>lexer.o</tt>, using the <tt>-c</tt> switch to tell <tt>gcc</tt> not to do any linking yet. Once all the other prerequisites are updated, make looks at <tt>fred</tt> again and runs its action, which is linking together of the three object files along with some libraries.</p>
<p>Now suppose that, having compiled the whole program once, you change one of the source files, say, <tt>bar.h</tt>. <tt>foo.o</tt> and <tt>bar.o</tt> both depend on this file, so when you compile the program again, make will see that those object files have older timestamps than the header file they are dependent on, and so they need to be updated. However, <tt>lexer.o</tt> does not depend on bar.h, so it is still newer than all of its prerequisites. So <tt>make</tt> decides it is up to date and does not rebuild it.</p>
<p>If you want to compile only part of a program - for example, you're ironing out all the syntax errors from the lexer - you give make the name of the target(s) you want it to update, viz.:</p>
<pre>make lexer.o</pre>
<h3>Cleaning up after yourself</h3>
<p>You won't want to distribute your program, when it is finally ready, with all of the .o and executable files, and all the other intermediate files such as <tt>lexer.c</tt>. These are created during the build process, from the other source files. It's useful to have a convenient way to get rid of these before packaging. The usual way, when using <tt>make</tt>, is to have one or more phony targets which delete these files. The target which removes all files created in the build process is usually called "clean", as above. Another common target is "proper", which removes only the intermediate files, and not the final executable. Obviously one can be implemented using the other as a prerequisite. As before, to tell make to update these targets, type:</p>
<pre>make clean</pre>
<p>or</p>
<pre>make proper</pre>
<p>The .PHONY target at the top tells <tt>make</tt> which targets are always phony. If any files with those names ever actually appear in the directory, <tt>make</tt> pretends they don't exist and always updates those targets when they come up for renewal.</p>