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
GNU Make Documentation

Tutorials

 * Tutorial - Makefile

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/
 * http://filepi.com/i/v5Ta6Dc

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)
 * 1) GNUmakefile
 * 2) makefile
 * 3) 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." 

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: sample: main.o example.o	cc -o sample main.o example.o	echo sample: make complete
 * 1) Linking object files

main.o: main.c main.h	cc -c main.c
 * 1) Compiling source files

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
all: echo %@ # "all"
 * 1) make all

%:	echo %@ # "test"
 * 1) make test

%.txt: echo %@ # "test"
 * 1) make test.txt

.PHONY: all first second TARGETS=first second
 * 1) make all
 * 2) output: "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 '#':
 * 1) 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:
 * 1) Internal (default) definitions of 'make'
 * 2) Current shell environment variables (including those preceding 'make' command)
 * 3) Description file macro definitions
 * 4) 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: ANOTHER_MYVAR=$(MYVAR) four
 * 1) Using variable with another variable

all: echo $(MYVAR) echo ${MYVAR}
 * 1) Using variable from target

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)
 * 1) sets 'bar' to 'a.c b.c c.c'

Make variable example: CC=g++ CFLAGS=-c -Wall
 * 1) I am a variable

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: /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/

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:

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

Source: http://stackoverflow.com/questions/1077676/how-to-conditional-set-up-a-makefile-variable-by-testing-if-a-file-exists

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
See Linux/make/Examples

Postfix main.cf Makefile:
 * 1) 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):

Reference

 * Introduction to Make | O'Reilly Media
 * Makefile Howto - Waikato Linux Users Group
 * Makefile Tutorial by Example
 * Creating Makefiles: A Mini Tutorial LG #83