Linux/make
make
The principal domain, of 'make', is C programming. Many sites also use 'make' for software installation, document formatting, and cleaning out temporary files.
Make file uses backward-chaining to process a Makefile (description file).
GNU Make Documentation
Tutorials
Books
Managing Projects with GNU Make, 3rd Edition - O'Reilly Media - http://oreilly.com/catalog/make3/book/index.csp
PDF - http://it-ebooks.info/book/383/
usage
make [target(s)]
make -f mymakefile [target(s)]
validation
Check the tabs in description file:
cat -v -t -e makefile
file name
To specify make description file name: make -f filename.
When GNU Make is run, with no arguments, it will look for one of the following configuration files, in the current working directory: (in priority order, is also directory sort order)
- GNUmakefile
- makefile
- Makefile
"If no -f option is present, make will look for the makefiles GNUmakefile, makefile, and Makefile, in that order." (make man page)
-
"This file is normally named makefile or Makefile. As a convention, GNU programs named their makefile, Makefile, because it is easy to see (if you do "ls" then this file is usually always on the top of the list). If you give it another name, just make sure you include option -f to make command in order to let it know that you use it." [1]
Layout
Makefile layout:
- dependency line / rule line (targets:dependencies)
- command lines (tab command)
- comments (# comment)
Lines can be wrapped using the '\' character at the end of a line.
A Makefile is composed of rules. The rules are composed of targets, dependencies (prerequisites) and system commands. The first target in the Makefile is the default target.
A Makefile rule is composed of:
target(s) : dependencies [tab] system commands
Examples:
# Linking object files sample: main.o example.o cc -o sample main.o example.o echo sample: make complete
# Compiling source files main.o: main.c main.h cc -c main.c
example.o: example.c defs.h cc -c example.c
new_Spec new_impt : menus hash store date >> $@ ls $? >> $@
targets
target : dependency
target target2 : dependency dependency2
Able to reuse target with multiple colons:
target :: dependency1 target :: dependency2
Logic
A target is considered "up to date" if an identically named file exists and is newer than its dependencies.
Make works backwards, starting with the target of the first rule in the file. In our example, that's sample. Make checks the dependencies for sample -- main.o and example.o -- to see if they have rules. If they do, it recursively checks their rules.
Make walks down the recursion chain until it finds a target that has no dependencies, or whose dependencies have no rules. Once it hits one of those, it walks back up its recursion chain and runs commands as necessary. It creates a recursion chain for every prerequisite it encounters that has a rule.
Make can run the dependencies in any order. The important part of this sequence is that it runs recursively backwards from the first target (or the target named in the command parameters), and tests only the rules that it encounters in the dependencies chain.
Make aborts compilation if it receives an error. This is usually useful behavior -- it lets you correct compiler-detected problems during a compile-and-test cycle. The option -i tells Make to ignore errors.
make will check the last modification date of target against the last modification date of all the dependencies files that follow it. If none of these things have changed, then it won't recompile the target.
Default Target
The default target is the first target found.
Phony Target
A phony target is a fake filename. It is just a name for commands that will be executed when you give an explicit request. There are two reasons for using phony target : to avoid conflicts with a file with the same name, and to enhance the makefile performance.
If you write a rule whose command will not create a target file, those commands will be executed every time the target is remade. For example:
clean: rm *.o temp
Because the command rm will not create a file named clean, that file will never exist. Command rm will always be executed every time you called make clean, because make assume that the clean file is always new.
The above target will stop working if a file named clean exists in the current directory. Because it does not require dependencies, file clean will be considered up-to-date, and the command 'rm *.o temp' will not be executed. To resolve this problem, you can explicitly declare a target as phony, using special target command .PHONY. For example :
.PHONY : clean
In the makefile above, if we give instruction make clean from the command-line, the command 'rm *.o temp' will always be run, whether or not a file named clean exists in the current directory.
Example:
.PHONY : all test1 test2 all: test1 test2 test1: cd test1 ; tar -cf ../test1.tar * test2: cd test2 ; tar -cf ../test2.tar *
Target name. To reference from within a command use '$@'
test1: cd $@ ; tar -cf ../$@.tar *
Source: Creating Makefiles: A Mini Tutorial LG #83
Wildcard Target
# make all all: echo %@ # "all"
# make test %: echo %@ # "test"
# make test.txt %.txt: echo %@ # "test"
# make all # output: "first" "second" .PHONY: all first second TARGETS=first second all: $(TARGETS) $(TARGETS): @echo $@
Ignore Error
Start a line with '-' to continue even on error:
-command_that_fails
Comments
Comments are start with a '#':
# This is a comment
End of line comment:
some makefile statement # a comment
Comments and Continued Makefile Lines:
line_one \ line_two # more_line_two \ line_three
is the same as:
line_one line_two line_three
Source: http://www.opussoftware.com/tutorial/TutMakefile.htm
Hide Command
The '@' character will hide the command name, but show command output.
usage: @echo "This is the usage"
macros
macro definitions:
name = string name=string name = some strings name = # set to null string, not "undefied" name = "some strings" # " will be included in output
macro usage:
$(name) ${name} $A # optional only with single character macros (or special character macros)
Define from command line:
make DIR=/path export DIR=path ; make # shell environment form DIR=path make # shell environment form
Macro assignment priority order:
- Internal (default) definitions of 'make'
- Current shell environment variables (including those preceding 'make' command)
- Description file macro definitions
- Macros specified on 'make' command line
Can swap priority 2 and 3 with make -e
Tips:
- Macro names, by convention, are in uppercase.
- If macro referred to without defining, will be null string. Never will get an undefined error.
- Order of macros is unimportant, will be evaluated when used
- Macros cannot be redefined, once defined (unless doing a recursive make)
- Can display all predefined macros with make -p (and there are a lot)
- Shell/environment variables are available as macros
-
String substitution: (limitation: end of macro only - like extensions)
ls ${SRCS:.c=.o} # src.c to src.o
-
Internal macros:
$@ - current target (command line only) $? - prerequisites that are newer than target (command line only) $$@ - current target (dependency line only)
Example:
new_Spec new_impt : menus hash store date >> $@ ls $? >> $@
docmk : $$@.c # evaluates to: docmk : docmk.c
C_OBJS = main.o iodat.o dorun.o ${C_OBJS} : $${@:.o=.c} ${CC} -c $?
Variables or Macros
Certain versions of Make call variables "macros".
Make variables are different from shell variables.
Make's variables are defined and set in the header portion before targets are defined.
Set a Make variable:
MYVAR = one two three # recursively expanded variable MYVAR := one two three # simply expanded variables
Use a Make variable:
# Using variable with another variable ANOTHER_MYVAR=$(MYVAR) four
# Using variable from target all: echo $(MYVAR) echo ${MYVAR}
Setting make variables from environment variables:
DESTDIR ?= /usr/local
An environment variable can also be passed to the Makefile by not defining the variable in the Makefile. If it is not set in the environment, the variable will default to empty.
Passing environment variable to pass to Makefile:
$ DESTDIR="/bin" make $ export DESTDIR="/bin" ; make
DESTDIR="/bin" make
Append variable (will also append to the environment variables)
CFLAGS += -g -Wall
Substitution:
foo := a.o b.o c.o bar := $(foo:.o=.c) # sets 'bar' to 'a.c b.c c.c'
Make variable example:
# I am a variable CC=g++ CFLAGS=-c -Wall main.o: main.cpp $(CC) $(CFLAGS) main.cpp
Redefining Macros from the command line:
make CFLAGS=–ms make "CFLAGS=-ms -z -p"
Macro Shell Assignment
$(shell) is a special function in gmake that runs an external command and captures the output for use in the makefile. For example, you could get the current working directory like this:
CWD:=$(shell pwd) all: @echo This makefile lives in $(CWD).
Note, make sure to use ":=" or it will be reevaluated in each new section, unless that is what you want
DATE=$(warning Invoking shell)$(shell date) all: first @echo ${DATE} first: @echo ${DATE} sleep 3
References:
- Development Cloud Solutions | Electric Cloud - http://www.electric-cloud.com/blog/2009/03/23/makefile-performance-shell/
Macro Functions
$(dir names...) # Extracts the directory-part of each file name in names. $(basename names...) # Extracts all but the suffix of each file name in names. $(addprefix prefix,names...) # The argument names is regarded as a series of names, separated by whitespace; prefix is used as a unit.
File Name Functions - GNU `make' - https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html
Warn on Undefined
Warn on undefined variables:
--warn-undefined-variables
Warning
Display warning macro:
$(warning This is a warning)
Shell Variables
Shell variables in Makefiles
There may come a time you need to use shell scripting complicated enough to require shell vars in a Makefile but make has issues since $ is the prefix for Make vars too, to escape the $, just use $$, so this:
for e in * ; do echo $e ; done
becomes:
for e in * ; do echo $$e ; done
Another method is to embed within a bash command: [2]
/bin/sh -c 'i="test" ; echo $$i'
Multiple Combined Commands
Each line runs in it's own shell. If you would like to chain several commands together (usually to get to shell variables):
line_one \ line_two # more_line_two \ line_three
%.pem: umask 77 ; \ PEM1=`/bin/mktemp /tmp/openssl.XXXXXX` ; \ PEM2=`/bin/mktemp /tmp/openssl.XXXXXX` ; \ /usr/bin/openssl req $(UTF8) -newkey rsa:1024 -keyout $$PEM1 -nodes -x509 -days 365 -out $$PEM2 -set_serial $(SERIAL) ; \ cat $$PEM1 > $@ ; \ echo "" >> $@ ; \ cat $$PEM2 >> $@ ; \ $(RM) $$PEM1 $$PEM2
change directory
How do you change directories in a makefile, run a command and then change back? First off, all the commands that you want to run for that situation must be on the same line, because make executes each line with a new shell
foo: cd /bin; stat ls; cd -
Source: http://crawlicious.com/wp/2009/06/11/make-change-dir/
Include Other Makefiles
include filenames...
ref: https://www.gnu.org/software/make/manual/html_node/Include.html
Info and Error Output
Info message:
$(info [message])
Error message:
$(error [message])
Example:
HELLO=hello world all: $(info hi $(HELLO)) $(error this is a test)
Conditionals
USERID=$(shell id -u) all: $(info User Id is $(USERID)) ifeq ($(USERID),0) $(info Running as root... OK) else $(error You must be root to execute this command) endif
Source: [3]
If file1 does not exist then $(wildcard file1) will evaluate to an empty string:
ifeq ($(wildcard file1),) CLEAN_SRC = else CLEAN_SRC = *.h file3 endif
References:
- http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html
- http://www.gnu.org/software/autoconf/manual/make/Conditional-Syntax.html
Suffixes
Define new default behavior for targets
.SUFFIXES : .txt .rst .txt.rst : cat $< > $@ # cat test.txt > test.rst # or cat $@ > $*.rst manual : test.rst
- $< evaluates to prerequisite that triggered the rule (test.txt)
- $* evaluates to target minus suffix
- $@ evaluates to target
Example Make Files
Postfix main.cf Makefile:
# Kenneth .PHONY : aliases .PHONY : clean MAIN-FILES = main.cf.original main.cf.kenneth all: main.cf aliases clean: # CLEANING FILES # rm -f main.cf # main.cf: $(MAIN-FILES) # REBUILDING MAIN.CF... # cat main.cf.original main.cf.kenneth > main.cf # aliases: # REBUILDING ALIASES... # newaliases # $(MAIN-FILES):
Examples
Reference
- Introduction to Make | O'Reilly Media
- Makefile Howto - Waikato Linux Users Group
- Makefile Tutorial by Example
- Creating Makefiles: A Mini Tutorial LG #83