A Makefile typically starts with some variable definitions which are then followed by a set of target entries for building specific targets (typically .o & executable files in C and C++, and .class files in Java) or executing a set of command associated with a target label.
The following is the generic target entry form:
# comment
# (note: the <tab> in the command line is necessary for make to work)
target: dependency1 dependency2 ...
<tab> command
# define the C object files #
# This uses Suffix Replacement within a macro:
# $(name:string1=string2)
# For each word in 'name' replace 'string1' with 'string2'
# Below we are replacing the suffix .c of all words in the macro SRCS
# with the .o suffix #
OBJS = $(SRCS:.c=.o)
--debug=basic
--debug=verbose
When you need to know how make analyzes your dependency graph, use the --debug option. This provides the most detailed information available other than by running a debugger. There are five debugging options and one modifier: basic, verbose, implicit, jobs, all, and makefile, respectively.
Example:
make --debug=basic -f Makefile.linux all
Example of --debug option
CC=gcc
CFLAGS=-I.
SRCS= hellomake.c \
hellofunc.c
DEPS=hellomake.h
OUT=hellomake
.c.o: $(DEPS)
$(CC) -c $< $(CFLAGS) -o $@
OBJS:=$(SRCS:.c=.o)
all:myar hellomake
myar: $(OBJS)
echo $(OUT)
ar rcsuv test.a $(OBJS)
hellomake::$(OBJS)
$(CC) -o $(OUT) $(OBJS) $(CFLAGS1)
clean:
rm -rf *.o
rm -rf $(OUT)
================
[root@ubuntu /personal/testcode/makefile_learning]# make --debug=basic all
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
Reading makefiles...
Updating goal targets....
File `myar' does not exist.
Must remake target `myar'.
echo hellomake
File `hellomake' does not exist.
Must remake target `hellomake'.
gcc -o hellomake hellomake.o hellofunc.o
hellomake
ar rcsuv test.a hellomake.o hellofunc.o
Prerequisite `myar' of target `all' does not exist.
Prerequisite `hellomake' is newer than target `all'.
[root@ubuntu /personal/testcode/makefile_learning]#
echo command can be used as recipe to check if the particular target is executed or not
Example for printing values
CC=gcc
CFLAGS=-I.
SRCS= hellomake.c \
hellofunc.c
DEPS=hellomake.h
OUT=hellomake
.c.o: $(DEPS)
$(CC) -c $< $(CFLAGS) -o $@
OBJS:=$(SRCS:.c=.o)
all:myar hellomake
myar: $(OBJS)
echo $(OUT)
ar rcsuv test.a $(OBJS)
hellomake::$(OBJS)
$(CC) -o $(OUT) $(OBJS) $(CFLAGS1)
clean:
rm -rf *.o
rm -rf $(OUT)
~
==========
Output
==========
[root@ubuntu /personal/testcode/makefile_learning]# make myar
echo hellomake
hellomake
ar rcsuv test.a hellomake.o hellofunc.o
By default, make does print every command before executing it. This printing can be suppressed by one of the following mechanisms:
on a case-by-case basis, by adding @ at the beginning of the command
globally, by adding the .SILENT built-in target.
somewhere along the make process, by invoking sub-make(s) with one of the flags -s, --silent or --quiet, as in $(MAKE) --silent -C someDir, for example. From that moment on, command echoing is suppressed in the sub-make.
To print command, -n option of make can be used. If your makefile does not print the commands, then it is probably using one of these three mechanisms, and you have to actually inspect the makefile(s) to figure out which.
As a workaround to avoid these echo-suppressing mechanisms, you could re-define the shell to be used to use a debug mode, for example like make SHELL="/bin/bash -x" target. Other shells have similar options. With that approach, it is not make printing the commands, but the shell itself.
-n option in make command causes make to print the recipes that are needed to make the targets up to date, but not actually execute them. Note that some recipes are still executed, even with this flag (see How the MAKE Variable Works). Also any recipes needed to update included makefiles are still executed (see How Makefiles Are Remade).
The include directive tells make to suspend reading the current makefile and read one or more other makefiles before continuing. The directive is a line in the makefile that looks like this:
include filenames…
filenames can contain shell file name patterns. If filenames is empty, nothing is included and no error is printed.
If you want make to simply ignore a makefile which does not exist or cannot be remade, with no error message, use the -include directive instead of include, like this:
-include filenames…
This acts like include in every way except that there is no error (not even a warning) if any of the filenames (or any prerequisites of any of the filenames) do not exist or cannot be remade.
Recursive use of Make
subsystem: cd subdir && $(MAKE)
is equivalent to
subsystem: $(MAKE) -C subdir
Example where make builds .o files automatically
CC=gcc CFLAGS=-I. hellomake: hellomake.o hellofunc.o $(CC) -o hellomake hellomake.o hellofunc.o -I.
------
[root@ubuntu /personal/testcode/makefile_learning]# make gcc -I. -c -o hellomake.o hellomake.c gcc -I. -c -o hellofunc.o hellofunc.c gcc -o hellomake hellomake.o hellofunc.o
In above makefile, by putting the object files--hellomake.o and hellofunc.o--in the dependency list and in the rule, make knows it must first compile the .c versions individually, and then build the executable hellomake.
Note that here make implicit variables CC and CFLAGS are used. This helps to get the include directory and compiler name in the highlighted text.
Example to create generic rule to build object file from source file
CC=gcc
CFLAGS=-I.
SRCS= hellomake.c hellofunc.c
DEPS=hellomake.h
OUT=hellomake
%.o: %.c $(DEPS)
$(CC) -c $< $(CFLAGS) -o $@
OBJS:=$(SRCS:.c=.o)
hellomake:$(OBJS)
$(CC) -o $(OUT) $(OBJS) $(CFLAGS1)
clean:
rm -rf *.o
rm -rf $(OUT)
---------------------
[root@ubuntu /personal/testcode/makefile_learning]# make
gcc -I. -c -o hellomake.o hellomake.c
gcc -I. -c -o hellofunc.o hellofunc.c
gcc -o hellomake hellomake.o hellofunc.o
---------------------
Above highlighted example first creates the macro DEPS, which is the set of .h files on which the .c files depend. Then we define a rule that applies to all files ending in the .o suffix. The rule says that the .o file depends upon the .c version of the file and the .h files included in the DEPS macro. The rule then says that to generate the .o file, make needs to compile the .c file using the compiler defined in the CC macro. The -c flag says to generate the object file, the -o $@ says to put the output of the compilation in the file named on the left side of the :, the $< is the first item in the dependencies list, and the CFLAGS macro is defined as above.
By default, make starts with the first target (not targets whose names start with ‘.’).
Handling recursive make invocations raises issues for parallel execution. If the ‘-j’ option is followed by an integer, this is the number of recipes to execute at once; this is called the number of job slots. If there is nothing looking like an integer after the ‘-j’ option, there is no limit on the number of job slots. The default number of job slots is one, which means serial execution (one thing at a time).
Example of dynamic creating object file
CC=gcc
CFLAGS=-I.
SRCS= hellomake.c \
hellofunc.c
DEPS=hellomake.h
OUT=hellomake
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,hellomake.o hellofunc.o)
$(OBJDIR)/%.o : %.c
$(CC) -c $(CFLAGS) $< -o $@
all: $(OBJS)
$(CC) -o $(OUT) $(OBJS) $(CFLAGS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
clean:
rm -rf *.o
rm -rf $(OBJS)
rm -rf $(OUT)
==================================
[root@ubuntu /personal/testcode/makefile_learning]# make all
mkdir objdir
gcc -c -I. hellomake.c -o objdir/hellomake.o
gcc -c -I. hellofunc.c -o objdir/hellofunc.o
gcc -o hellomake objdir/hellomake.o objdir/hellofunc.o -I.
[root@ubuntu /personal/testcode/makefile_learning]# make all
gcc -o hellomake objdir/hellomake.o objdir/hellofunc.o -I.
The value of the make directive namely vpath specifies a list of directories that make should search
Example of common make for files scattered in multiple folders
vpath %c ../hellomakedir
vpath %c ../hellofuncdir
SRCS = \
hellomake.c \
hellofunc.c
For this, we will use BASH feature which allows to pass variable name-value pair in the command.
Example to pass OS info
CC=gcc
CFLAGS=-I.
SRCS= hellomake.c \
hellofunc.c
DEPS=hellomake.h
OUT=hellomake
.PHONY: all
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,hellomake.o hellofunc.o)
$(OBJDIR)/%.o : %.c
$(CC) -c $(CFLAGS) $< -o $@
all: $(OBJS)
echo build os is $(BUILD_OS) -> BUILD_OS is a user-defined variable whose value will be passed in make command
$(CC) -o $(OUT) $(OBJS) $(CFLAGS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
FORCE:
clean:
rm -rf *.o
rm -rf $(OBJS)
rm -rf $(OUT)
----------------------------------------
[root@ubuntu /personal/testcode/makefile_learning]# BUILD_OS=linux make
echo build os is linux
build os is linux
gcc -o hellomake objdir/hellomake.o objdir/hellofunc.o -I.
------------------------
Note:
Here BUILD_OS variable name is user defined. In other words, it can be replaced by any other string.
Refer article https://sites.google.com/site/jbsakabffoi12449ujkn/home/software-programming/common-reasons-why-linux-make-always-build-target-although-not-needed
test.o: test1.c test2.c
$(CC) -c $< $(CFLAGS) -o $@
GEN_TESTLAYOUT= /test/testfolder/myfile.c .PHONY: $(GEN_TESTLAYOUT) $(GEN_TESTLAYOUT): $(MAKE) -C $(@D) $(@F)
Symbol
$D
$F
Value
target name first split (/test/testfolder/)
target name second split (myfile.c)
Shell command can be used for the same as shown in below example
Subtraction in Makefile
CORES=$(shell getconf _NPROCESSORS_ONLN 2>/dev/null)
JOPTION = $(shell echo $$(( $(CORES) - 1 )) )
Useful link: http://stackoverflow.com/questions/5776608/doing-simple-math-in-makefile
In below example, GEN_TESTLAYOUT_TARGET will contain myfile.c
GEN_TESTLAYOUT= /test/testfolder/myfile.c
GEN_TESTLAYOUT_TARGET= $(notdir $(GEN_TESTLAYOUT))
.PHONY: $(GEN_TESTLAYOUT) $(GEN_TESTLAYOUT): $(MAKE) -C $(@D) $(@F) $(GEN_TESTLAYOUT_TARGET)
useful link: https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html
Reference
https://www.cs.swarthmore.edu/~newhall/unixhelp/howto_makefiles.html
https://www.gnu.org/software/make/manual/html_node/Recursion.html#Recursion
https://www.gnu.org/software/make/manual/html_node/Include.html
http://www.oreilly.com/openbook/make3/book/ch12.pdf
http://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/
http://opensourceforu.com/2012/06/gnu-make-in-detail-for-beginners/
http://stackoverflow.com/questions/11004695/making-make-print-commands-before-executing-when-not-using-cmake