2013-06-02 00:00:00 -0700
A good plan violently executed now is better than a perfect plan executed next week.
George S. Patton
expressing learned knowledge and skills in a manner understandable to others is an essential part of moving past understanding and towards groking. Or at least that’s what I’m claiming. If you want something more highbrow, http://www.gnu.org/software/make/manual/make.html.
Its a tool for writing build systems. Based on configuration data from a ‘makefile’, the make utility determines which sections of a program need to be recompiled and issues the appropriate commands.
to invoke make in a shell:
$ make
make will first look for ‘makefile’, or ‘Makefile’ in that order. If neither is found, make will say:
make: *** No targets specified and no makefile found. Stop.
to invoke make with an arbitrarily named makefile, use the -f option
$ make -f foomaketo invoke make with makefile named ‘foomake’
a makefile is a set of rules describing how to compile and link a program, as well as the execution of various utility commands
/<target/> : /<prerequisites/>
/<recipe/>
...
...
/<target/> is the output file
/</prerequisites/> are the files that /<target/> depends on as input
/</recipe/> is the action or actions taken to generate /<target/>
A recipe, therefore explains not only how to build a target, but when to rebuild it as well. If a /
It is possible to write rules with no prerequisites. This enables rules like ‘clean’ to be written which support development, but don’t build anything directly. Make it can be used as a convenient way of grouping related functionality together. Generally speaking, however, makefiles can offer a convenient method of scripting any time-stamp based maintenance scripts. Some cool applications include building books and more general purpose scripting (covered below)
single source file project
#include <stdio.h> int main() { printf("hello world\n"); return 0; }
one rule makefile
foo: helloworld.c gcc helloworld.c -o foo
running
$ makewill rebuild the program to an executable ‘foo’ every time the source ‘helloworld.c’ changes
for a project with the following simple dependency graph
a simple makefile would look like
all: amodule.o bmodule.o helloworld.o gcc amodule.o bmodule.o helloworld.o -o foo amodule.o: amodule.c gcc -c amodule.c -o amodule.o bmodule.o: bmodule.c gcc -c bmodule.c -o bmodule.o helloworld.o: helloworld.c gcc -c helloworld.c -o helloworld.o clean: rm *.o echo clean done
the first definition is interpreted as the default goal when make is run with no arguments. For that reason, we place the rule handling the executable first. The clean target removes intermediate compilation artifacts.
because make allows
or dumber, if abused
there is a heavy amount of data duplication in the example above, which just gets worse as the makefile grows: the list of dependencies in the /
OBJECT_FILES = obj-1.o obj-2.o obj-3.o ...
our rules can reference variables like
out : $(OBJECT_FILES) gcc -o out $(OBJECT_FILES)
make can deduce that a ‘.o’ file depends on a corresponding ‘.c’ file provided they share the same name. These will be compiled with ‘cc -c’
this will attempt to build an arbitrary, multifile c program. This does not attempt to keep track of module dependencies, instead it uses the implicite rule to compile each .c file into a .o file.
CFLAGS=-g -Wall $(OPTFLAGS) LIBS=-ldl $(OPTLIBS) PREFIX?=/usr/local SOURCES=$(wildcard ./**/*.c ./*.c) OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) TARGET=build/helloworld # The Target Build all: $(TARGET) $(TARGET): CFLAGS += -fPIC $(TARGET): build $(OBJECTS) $(CC) -o $@ $(OBJECTS) build: @mkdir -p build clean: rm -rf build $(OBJECTS)
never put anything but the primary compilation target at the top of the file. When run without argumenst, make will take the first rule as the default.
-c “compile only” directive should be placed for each compile target except for the final executable
specifying dependencies incorrectly is a common way a build system written in make fails. This is a big reason why a higher level build system like scons or cmake are recommended over raw make. By incorrectly specifying dependencies, the build system may rebuild or fail to build targets, resulting in frequent use of ‘$ make clean’, which defeats one of the main advantages of a build system.