Makefile Syntax - makefile

I am learning about makefiles and am a bit confused about some of the syntax and how SUFFIXES work.
CPP = g++
OFLAG = -o
.SUFFIXES : .o .cpp .c
.cpp.o :
$(CPP) $(CPPFLAGS) -c $<
.c.o :
$(CPP) $(CPPFLAGS) -c $<
all: \
Return \
Declare \
Ifthen \
Guess \
Guess2 \
Return: Return.o
$(CPP) $(OFLAG)Return Return.o
Deckare: Declare.o
$(CPP) $(OFLAG)Declare Declare.o
# follow same format for other executables
Return.o: Return.cpp
Declare.o: Declare.cpp
# follow same format for other executables
What does the line ".SUFFIXES : .o .cpp .c" actually do?
I do not quite understand what $< means.
Where does CPPFLAGS come from? (is it a special syntax just for make?).

.SUFFIXES defines the set of suffixes that make will understand for suffix rules. So with this example, you can define suffix rules involving the suffixes .o .cpp and .c. If you were to define a rule .x.o, since .x isn't in the .SUFFIXES list, it would not be a suffix rule -- it would instead be a rule to build the file .x.o
$< is short for $(<) and expands to the first dependency of the target in the current rule.
$(CPPFLAGS) is a make variable reference. Since you don't set it in this makefile, it will expand to an empty string. There's nothing particularly special about the name CPPFLAGS other than convention -- its generally the set of C pre-processor flags you want to pass to invokations of the c or c++ compiler, which is exactly how it is used here.

Related

Forcing the order of implicit rule/pattern rule evaluation in GNU Make

I have a domain specific language compiler (homemade) which takes a file x.inflow and generates two files: x.c and x.h. The C file is compiled in the conventional manner and the generated header file has to be included into any file that calls the functions defined within it.
The header files therefore have to be generated before any C files that use them are compiled. My current Makefile, below, works fine except for the first build from clean where it can try and compile main.c before the header file that it includes has been created.
NAME = simplest
OBJ = $(patsubst %.c,%.o,$(wildcard *.c)) \
$(patsubst %.inflow,%.o,$(wildcard *.inflow))
CC = gcc
CFLAGS = -g -Wall
$(NAME): $(OBJ)
$(CC) $(CFLAGS) -o $# $^ $(CLIBS)
# Dependencies for existing .o files.
-include $(OBJ:.o=.d)
# Compile an inflow file into both a .c and .h file.
# Note that this rule has two targets.
%.c %.h: %.inflow
inflow $<
# Compile object files and generate dependency information.
%.o: %.c
$(CC) -MD -MP -c $(CFLAGS) -o $# $<
Obviously, I can fix this for specific cases by adding, for example (where simplest.h is a generated header):
main.o: simplest.h
But is there a general way to force one type of pattern rule (%.c %.h: %.inflow) to be run before any invokations of another (%.o: %.c)?
Well, you can force any target to be run before any other target with order-only prerequisites. So for example, you can write:
%.o : %.c | simplest.h
$(CC) -MD -MP -c $(CFLAGS) -o $# $<
which will ensure that no target that uses this pattern rule to build will be invoked before the target simplest.h is created. However, I don't think you can put patterns in an order-only prerequisite. To be honest, I've never tried it so it's possible that it works, I'm not sure.
If not, you could just list all the order-only prerequisites in the %.o pattern rule; this would ensure that all the inflow files are generated before any of the object files are built. That's probably OK.
It seems the problem is twofold:
Make doesn't know that it needs to generate simplest.h before compiling main.c.
You don't want to have to explicitly tell Make about the dependency (and remember to update it when it changes).
Rather than force Make to evaluate rules in a set order, you can solve your problem by letting Make create the dependencies for you. Check out this section of the Gnu Make manual: http://www.gnu.org/software/make/manual/make.html#Automatic-Prerequisites
When you run Make, it will scan your source files and gather their dependencies for you (and you won't have to explicitly list that main.o depends on simplest.h).

Understanding a makefile

I am talking about this question where the person has updated his final solution with a makefile for the task. I am having a hard time understanding how it's done.
There is a rule:
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
#$(CC) $(CFLAGS) -c $< -o $#
which I am unable to understand, but by intuition I know what it will be doing. Almost everything else is pretty much clear. Thanks!
This is a static pattern rule. The first field is a list of targets, the second is a target pattern which Make uses to isolate a target's "stem", the third is the prerequisite pattern which Make uses to construct the list of prerequisites.
Suppose you have
SRCDIR = src
OBJDIR = obj
OBJECTS = obj/foo.o obj/bar.o obj/baz.o
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
#$(CC) $(CFLAGS) -c $< -o $#
If you make obj/foo.o, Make first identifies this rule as the one to use (since obj/foo.o is in the target list $(OBJECTS)), matches it against the target pattern obj/%.o and finds that the stem (the part matched by the wildcard %) is foo, then plugs that into the prereq pattern src/%.c and finds that the prerequisite is src/foo.c.
If you've also defined the variables
CC = gcc
CFLAGS = -thisflag -thatflag=something
Then the command in the rule becomes
#gcc -thisflag -thatflag=something -c src/foo.c -o obj/foo.o
(Note that $< is the first prerequisite and $# is the target name.)
In answer to your other question: Yes, a makefile can handle a dependency on a header file (x.h) so that if the header has been modified, Make will rebuild the target. No, this makefile doesn't do that. You can modify the makefile by hand, adding rules like
a.o: x.h
assuming you know what the inclusions actually are, or you can have the makefile do it automatically, which is an advanced technique you probably shouldn't attempt yet.
This line is explaining how to obtain the object files (.o) from the source (.c), it avoids having to repeat the line for each .c file.
The objects will be in OBJDIR and the sources in SRCDIR
$(CC) will contain the compiler, CFLAGS will contain the options for the compiler and -c tells gcc to compile the source into objects.
For example:
CC = gcc
CFLAGS = -g -Wall
can be converted into
gcc -g -Wall -c test.c -o test.o

makfile variable expansion

I have a few libs that use each other. Whenever I build any of them I need to define preprocessor define to make sure that proper visibility modifiers are used (e.g. dllimport/dllexport in windows speak).
All the libs use the same makefile, that is, they share rules, CFLAGS etc. All these libs only differ by list of input files, the rest of makefiles are shared by the libs.
The shared makefile has a variable that contains list of all the libs, like this:
MODULE_LIBS = liba123 libb456 libc999
Then, I need these preprocessor defines to be enabled for each of these libs:
For liba123: -Da123_EXPORTS
For libb456: -Db456_EXPORTS
For libc999: -Dc999_EXPORTS
Each of these libs live in their respective subfolders that are names like the libs themselves (e.g. liba123, libb456 etc).
So, I wrote this makefile trick to enabled these EXPORTS defines based on the path of the file being compiled:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -D$(filter $(MODULE_LIBS),$(subst lib, ,$(subst /, ,$#)))_EXPORTS -c -o $# $<
I have to add that thing ('-D$(filter $(MODULE_LIBS),$(subst lib, ,$(subst /, ,$#)))_EXPORTS') all over the place, because I have many similar rules. There is nothing can be done with all these different rules, but there is one thing that they have in common: the $(CPPFLAGS).
Here comes the question. Can I add that "-D$(filter $(MODULE_LIBS),$(subst lib, ,$(subst /, ,$#)))_EXPORTS" to CPPFLAGS in such a way that all these makefile variables would only expand in place where it's used?
I think I'd do it this way:
liba123/%.o : EXPORTS=a123_EXPORTS
libb456/%.o : EXPORTS=b456_EXPORTS
libc999/%.o : EXPORTS=c999_EXPORTS
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -D$(EXPORTS) -c -o $# $<
But you can put them in CPPFLAGS if you prefer:
liba123/%.o : CPPFLAGS+=-Da123_EXPORTS
libb456/%.o : CPPFLAGS+=-Db456_EXPORTS
libc999/%.o : CPPFLAGS+=-Dc999_EXPORTS

How to write a simpler makefile for a lot of single-c-file programmes?

I want to write a lot of tiny example programmes for one same library, each needs gcc $(OtherOpt) -o xxx -lthelibname xxx.c.
How to write a Makefile without dozens of tagret lines ?
Pattern rules are your friend for these situations. As long as your targets all match a predictable pattern -- and they do in this case, as they are all of the form "create foo from foo.c" -- you can write a single pattern rule that will be used for all of the targets:
OtherOpt=-Wall -g
all: $(patsubst %.c,%,$(wildcard *.c))
%: %.c
gcc $(OtherOpt) -o $# -lthelibname $<
Now you can either run simply make to build all your apps, or make appname to build a specific app. Here I've created a single pattern rule that will be used anytime you want to create something from something.c. I used the $# automatic variable, which will expand to the name of the output, and the $< variable, which will expand to the name of the first prerequisite, so that the command-line is correct regardless of the specific app being built. Technically you don't need the all line, but I figured you probably didn't want to always have to type in the name(s) of the apps you want to build.
Also, technically you can probably get away without having any of this makefile, because GNU make already has a built-in pattern rule for the %: %.c relationship! I mention this option only for completeness; personally, I prefer doing things the way I've shown here because it's a little bit more explicit what's going on.
%.o: %.c
gcc $(OtherOpt) -c -o $# -lthelibname $<
That compiles all .c files to their .o files (object code) of the same base name. Then in your actual target(s), you would include all necessary .o files as dependencies and use gcc $(OtherOpt) -o $# $^ -lthelibname, assuming I'm not misunderstanding how your build is set up.
Some versions of make also support the suffix rule .c.o to be ALMOST the same thing as %.o: %.c, but the suffix rules can't have any dependencies. Writing .c.o: foo.h tells make to compile "foo.h" to "foo.c.o" rather than requiring "foo.h" as a dependency of any file with a .c suffix as %.o: %.c foo.h would correctly do.
I learnd from http://sourceforge.net/projects/gcmakefile/
LDLIB = -lpthread
LDFLAGS = -Wl,-O1 -Wl,--sort-common -Wl,--enable-new-dtags -Wl,--hash-style=both $(LDLIB)
SRCDIRS =
SRCEXTS = .c .C .cc .cpp .CPP .c++ .cxx .cp
CFLAGS = -pipe -march=core2 -mtune=generic -Wfloat-equal \
#-Wall -pedantic
ifeq ($(SRCDIRS),)
SRCDIRS = .
endif
SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
TARGET = $(addprefix bin/,$(basename $(SOURCES)))
all: $(TARGET)
ls -l $(TARGET)
bin/%: %.c dir
gcc $(CFLAGS) $(LDFLAGS) -o $# $<
dir:
#-mkdir bin
.PHONY : clean
clean:
-rm $(TARGET)
-rmdir bin

What do the makefile symbols $# and $< mean?

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
What do the $# and $< do exactly?
$# is the name of the target being generated, and $< the first prerequisite (usually a source file). You can find a list of all these special variables in the GNU Make manual.
For example, consider the following declaration:
all: library.cpp main.cpp
In this case:
$# evaluates to all
$< evaluates to library.cpp
$^ evaluates to library.cpp main.cpp
From Managing Projects with GNU Make, 3rd Edition, p. 16 (it's under GNU Free Documentation License):
Automatic variables are set by make after a rule is matched. They
provide access to elements from the target and prerequisite lists so
you don’t have to explicitly specify any filenames. They are very
useful for avoiding code duplication, but are critical when defining
more general pattern rules.
There are seven “core” automatic variables:
$#: The filename representing the target.
$%: The filename element of an archive member specification.
$<: The filename of the first prerequisite.
$?: The names of all prerequisites that are newer than the target,
separated by spaces.
$^: The filenames of all the prerequisites, separated by spaces. This
list has duplicate filenames removed since for most uses, such as
compiling, copying, etc., duplicates are not wanted.
$+: Similar to $^, this is the names of all the prerequisites separated
by spaces, except that $+ includes duplicates. This variable was
created for specific situations such as arguments to linkers where
duplicate values have meaning.
$*: The stem of the target filename. A stem is typically a filename
without its suffix. Its use outside of pattern rules is
discouraged.
In addition, each of the above variables has two variants for
compatibility with other makes. One variant returns only the directory
portion of the value. This is indicated by appending a “D” to the
symbol, $(#D), $(<D), etc. The other variant returns only the file
portion of the value. This is indicated by appending an “F” to the
symbol, $(#F), $(<F), etc. Note that these variant names are more than
one character long and so must be enclosed in parentheses. GNU make
provides a more readable alternative with the dir and notdir
functions.
The $# and $< are called automatic variables. The variable $# represents the name of the target and $< represents the first prerequisite required to create the output file.
For example:
hello.o: hello.c hello.h
gcc -c $< -o $#
Here, hello.o is the output file. This is what $# expands to. The first dependency is hello.c. That's what $< expands to.
The -c flag generates the .o file; see man gcc for a more detailed explanation. The -o specifies the output file to create.
For further details, you can read this article on linoxide about Linux Makefiles.
Also, you can check the GNU make manuals. It will make it easier to make Makefiles and to debug them.
If you run this command, it will output the makefile database:
make -p
The $# and $< are special macros.
Where:
$# is the file name of the target.
$< is the name of the first dependency.
The Makefile builds the hello executable if any one of main.cpp, hello.cpp, factorial.cpp changed. The smallest possible Makefile to achieve that specification could have been:
hello: main.cpp hello.cpp factorial.cpp
g++ -o hello main.cpp hello.cpp factorial.cpp
pro: very easy to read
con: maintenance nightmare, duplication of the C++ dependencies
con: efficiency problem, we recompile all C++ even if only one was changed
To improve on the above, we only compile those C++ files that were edited. Then, we just link the resultant object files together.
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
main.o: main.cpp
g++ -c main.cpp
hello.o: hello.cpp
g++ -c hello.cpp
factorial.o: factorial.cpp
g++ -c factorial.cpp
pro: fixes efficiency issue
con: new maintenance nightmare, potential typo on object files rules
To improve on this, we can replace all object file rules with a single .cpp.o rule:
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
.cpp.o:
g++ -c $< -o $#
pro: back to having a short makefile, somewhat easy to read
Here the .cpp.o rule defines how to build anyfile.o from anyfile.cpp.
$< matches to first dependency, in this case, anyfile.cpp
$# matches the target, in this case, anyfile.o.
The other changes present in the Makefile are:
Making it easier to changes compilers from g++ to any C++ compiler.
Making it easier to change the compiler options.
Making it easier to change the linker options.
Making it easier to change the C++ source files and output.
Added a default rule 'all' which acts as a quick check to ensure all your source files are present before an attempt to build your application is made.
in exemple if you want to compile sources but have objects in an different directory :
You need to do :
gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...
but with most of macros the result will be all objects followed by all sources, like :
gcc -c -o <all OBJ path> <all SRC path>
so this will not compile anything ^^ and you will not be able to put your objects files in a different dir :(
the solution is to use these special macros
$# $<
this will generate a .o file (obj/file.o) for each .c file in SRC (src/file.c)
$(OBJ):$(SRC)
gcc -c -o $# $< $(HEADERS) $(FLAGS)
it means :
$# = $(OBJ)
$< = $(SRC)
but lines by lines INSTEAD of all lines of OBJ followed by all lines of SRC

Resources