I am using GNU make to compile my C++ code, and i would like to understand how to make my compilations customizable.
I read in different places that CFLAGS, CCFLAGS and CXXFLAGS are used for this purpose. So how should i use them? If i have additional command-line arguments to the compiler, should i append them to CFLAGS or prepend them? Is there a common practice?
Why the three different variables? I suppose the C compiler should get CFLAGS and CCFLAGS, while the C++ compiler should get CFLAGS and CXXFLAGS - did i get it right?
Is the human user supposed to set these variables at all? Do any automatic tools (automake, autoconf, etc) set them? The linux system that i am supposed to use doesn't define any of these variables - is this typical?
Currently my Makefile looks like this, and i feel it's a bit dirty:
ifdef code_coverage
GCOV_FLAG := -fprofile-arcs -ftest-coverage
else
GCOV_FLAG :=
endif
WFLAGS := -Wall
INC_FLAGS := -Istuff -Imore_stuff -Ietc
CCFLAGSINT := -O3 $(WFLAGS) $(INC_FLAGS) $(CCFLAGS)
... (somewhere in the makefile, the command-line for compilation looks like this)
$(CC) $(CCFLAGSINT) -c $< -o $#
... (somewhere in the makefile, the command-line for linking looks like this)
$(CC) $(GCOV_FLAG) $(CCFLAGSINT) $(OBJLIST) $(LDFLAGS) -o $#
I am pretty sure there are no bugs here; the Makefile works very well. But is there anything that goes against conventions (like CCFLAGSINT - should i just overwrite CCFLAGS instead? Or CXXFLAGS? FUD!)
Sorry for so many questions; you will obviously not answer them all but i hope the answers will help me understand the general idea behind these settings.
As you noticed, these are Makefile {macros or variables}, not compiler options. They implement a set of conventions. (Macros is an old name for them, still used by some. GNU make doc calls them variables.)
The only reason that the names matter is the default make rules, visible via make -p, which use some of them.
If you write all your own rules, you get to pick all your own macro names.
In a vanilla gnu make, there's no such thing as CCFLAGS. There are CFLAGS, CPPFLAGS, and CXXFLAGS. CFLAGS for the C compiler, CXXFLAGS for C++, and CPPFLAGS for both.
Why is CPPFLAGS in both? Conventionally, it's the home of preprocessor flags (-D, -U) and both c and c++ use them. Now, the assumption that everyone wants the same define environment for c and c++ is perhaps questionable, but traditional.
P.S. As noted by James Moore, some projects use CPPFLAGS for flags to the C++ compiler, not flags to the C preprocessor. The Android NDK, for one huge example.
According to the GNU make manual:
CFLAGS: Extra flags to give to the C compiler.
CXXFLAGS: Extra flags to give to the C++ compiler.
CPPFLAGS: Extra flags to give to the C preprocessor and programs that use it (the C and Fortran compilers).
src: https://www.gnu.org/software/make/manual/make.html#index-CFLAGS
note: PP stands for PreProcessor (and not Plus Plus), i.e.
CPP: Program for running the C preprocessor, with results to standard output; default ‘$(CC) -E’.
These variables are used by the implicit rules of make
Compiling C programs
n.o is made automatically from n.c with a recipe of the form
‘$(CC) $(CPPFLAGS) $(CFLAGS) -c’.
Compiling C++ programs
n.o is made automatically from n.cc, n.cpp, or n.C with a recipe of the form
‘$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c’.
We encourage you to use the suffix ‘.cc’ for C++ source files instead of ‘.C’.
src: https://www.gnu.org/software/make/manual/make.html#Catalogue-of-Rules
Minimal example
And just to make what Mizux said as a minimal example:
main_c.c
#include <stdio.h>
int main(void) {
puts("hello");
}
main_cpp.cpp
#include <iostream>
int main(void) {
std::cout << "hello" << std::endl;
}
Then, without any Makefile:
make CFLAGS='-g -O3' \
CXXFLAGS='-ggdb3 -O0' \
CPPFLAGS='-DX=1 -DY=2' \
CCFLAGS='--asdf' \
main_c \
main_cpp
runs:
cc -g -O3 -DX=1 -DY=2 main_c.c -o main_c
g++ -ggdb3 -O0 -DX=1 -DY=2 main_cpp.cpp -o main_cpp
So we understand that:
make had implicit rules to make main_c and main_cpp from main_c.c and main_cpp.cpp
CFLAGS and CPPFLAGS were used as part of the implicit rule for .c compilation
CXXFLAGS and CPPFLAGS were used as part of the implicit rule for .cpp compilation
CCFLAGS is not used.
BTW, the SCons build system for example uses CCFLAGS for flags that are common to C and C++, which is a convention I sometimes follow on my custom make rules.
Those variables are only used in make's implicit rules automatically: if compilation had used our own explicit rules, then we would have to explicitly use those variables as in:
main_c: main_c.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $# $<
main_cpp: main_c.c
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $# $<
to achieve a similar affect to the implicit rules.
We could also name those variables however we want: but since Make already treats them magically in the implicit rules, those make good name choices.
Tested in Ubuntu 16.04, GNU Make 4.1.
Related: CFLAGS vs CPPFLAGS
This is an addition to all the existing answers, which mostly describe how these make variables affect the compilation process. In this answer, I describe a suggested way to use these variables, and any surrounding considerations. It is partly inspired by an answer to a similar question.
How should I use them? Should I append or prepend?
Compilation flags are of two types:
Those which are required to make the compilation work (example: -I, which tells the compiler where to find h-files).
Those which customize the compilation (example: -O, optimization level).
Only type 2 (customization) should go into CCFLAGS, and if the user specifies them, they should override whatever is defined in the Makefile. Use ?= syntax for that in your Makefile:
CCFLAGS ?= -O3
Type 1 settings should go into a new made-up variable, which should aggregate them all, and also include the standard variables, like CCFLAGS:
INC_FLAGS := -Istuff -Imore_stuff -Ietc
CCFLAGS_INTERNAL := $(INC_FLAGS) $(CCFLAGS)
Is there a common practice?
No, it doesn't seem so. Stuff I described above is one option, which looks good, but it's not standard.
Is the human user supposed to set these variables at all? The linux system that I use doesn't define any of these variables - is this typical?
Yes, these are for specifying options using the command line. The environment variables usually don't exist.
Is there anything that goes against conventions? (like CCFLAGSINT - should I just overwrite CCFLAGS instead? Or CXXFLAGS? FUD!)
No, the idea of this Makefile is correct: append CCFLAGS and other flags to the compiler's command-line; don't update CCFLAGS.
Related
My directory structure looks like this:
root
|____SG
| |
| |____Makefile
| |____simple_client_main.cpp
|
|___EEE
|___my_utils.h
SG is essentially my base of operations for building "simple_client", and I'm running make from here. In simple_client_main.cpp I have the following #includes:
#include <iostream>
#include <string>
#include "my_utils.h"
So I need my makefile to know where my_utils.h is. With this in mind, I want to add the root/EEE directory as an include directory. (From where I am, that would be ../EEE.)
Following the advice suggested here, my makefile looks like this:
DIR1 = ../EEE
CXXFLAGS = $(FLAG)
OBJS = simple_client_main.o
SRCS = simple_client_main.cpp
all: simple_client
simple_client: $(OBJS)
g++ -o simple_client -I$(DIR1) $(OBJS) -lz
# [...]
depend:
makedepend -- $(CFLAGS) -- $(SRCS)
But it doesn't work:
simple_client_main.cpp:6:25: fatal error: my_utils.h: No such file or directory
compilation terminated.
Note that if I manually set the #include directive in the cpp as follows:
#include "../EEE/my_utils.h"
...everything works as expected.
What am I likely to be doing wrong here?
You need to add -I$(DIR1) to either CFLAGS or CXXFLAGS (or perhaps both), so that when the object file is compiled, the option is present in the compiler command line.
You want make to execute something similar to:
g++ -c -I../EEE simple_client_main.cpp
It should do that if you add -I../EEE to $(CXXFLAGS) or $(CFLAGS). You need to know the rules used by the make program you're using — they can vary.
When linking object files, it is too late for the -I option to be of relevance (but you should still include $(CFLAGS) or $(CXXFLAGS) in the linker command line as other options, notably -g, are of relevance when linking as well as when compiling to object code).
Here is some simple modifications to the outline makefile shown in the question.
DIR1 = ../EEE
IFLAGS = -I$(DIR1)
CXXFLAGS = $(FLAG) $(IFLAGS)
CFLAGS = $(IFLAGS)
LDFLAGS =
LDLIBS = -lz
CXX = g++
OBJS = simple_client_main.o
SRCS = simple_client_main.cpp
all: simple_client
simple_client: $(OBJS)
$(CXX) -o $# $(CXXFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS)
A makefile like this stands a modest chance of working correctly. It is not clear what you might put in the FLAG macro, so I've left it. (I use UFLAGS and UXXFLAGS for 'user-defined C (or C++) flags'; they can be set on the command line and are never set by the makefile and are included in the CFLAGS or CXXFLAGS — you may be after something similar.)
Note how the linking line is almost all macros. This is normal and desirable; macros can be changed when running make without editing the makefile, but constant text cannot be changed without editing the makefile. The -c and -o options to the C and C++ compilers are about all that should ever appear as plain text.
If there are still problems, look at the built-in rule for compiling C++ source code to an object file, and tweak definitions accordingly. (You can use make -p to print the rules — you may need that to find out what is going on, but I hope not for your sake because they tend to be complex. Using make -f /dev/null -p shows the built-in rules only; that can be useful, too.)
Note that the make depend rule may need some surgery. It uses $(CFLAGS). If $(CXXFLAGS) contains extra options that are needed by the makedepend command, then you may need that instead, or even as well. If you have only C++ source, you probably only need the $(CXXFLAGS) macro in the command line.
Is the error coming from the compile stage, or the makedepend stage?
Because what I see above is that makedepend uses $(CFLAGS), and you haven't put -I$(DIR1) into CFLAGS.
I seem to be having an issue getting my makefile to build my C++ file correctly. My makefile code is below; the file I am trying to compile is named "avl.cc" (which is working and compiles properly).
CC=g++
CFLAGS=-g -O2
PROGS=avl
all: $(PROGS)
$#:
$(CC) $(CFLAGS) $# $#.cc
.PHONY: clean
clean:
rm $(PROGS)
However, when I enter the command make or make all, I get
c++ avl.cc -o avl
And the debugging symbols I want from the -g flag don't come up. A similar makefile (only changing the PROGS variable) worked for a similar project, so I am not sure what I'm doing wrong. Does anyone have any tips? Thanks!
From Makefile documentation about automatic variables:
It’s very important that you recognize the limited scope in which
automatic variable values are available: they only have values within
the recipe. In particular, you cannot use them anywhere within the
target list of a rule; they have no value there and will expand to the
empty string.
This means you cannot use $# as a rule, which means the default c++ compilation rule of Makefile is used, and since you did not use the correct variable names for c++ compilation, they are also ignored.
You can replace CC by CXX and CFLAGS by CXXFLAGS to work with c++.
You don't have a target for 'avl', so make uses a default rule.
Try changing the makefile to this:
CC=g++
CFLAGS=-g -O2
PROGS=avl
all: $(PROGS)
$(PROGS):
$(CC) $(CFLAGS) -o $# $#.cc
.PHONY: clean
clean:
rm $(PROGS)
I had the exact same question but a much different source of the problem. There were typos or misnamed files in my makefile. Make found no rules for such files but tried to compile targets with the c++ compiler. This made the process seem like it was ignoring my rules and imposing its own, switching compilers since I needed g++. Finally I tried using the -r option, and then the resulting different error messages allowed me to figure out what was really wrong. Below is the entry from the make man page for option -r.
-r, --no-builtin-rules
Eliminate use of the built-in implicit rules. Also clear out the default
list of suffixes for suffix rules.
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
Can I use COMPILER instead of CC, or OBJ instead of OBJECTS? Will the make tool recognize them — is it just pure convention on my side?
The built-in rules use names such as ${CC} (or $(CC) — the notations are equivalent). If you choose to use different macro names, you'll have to override/rewrite the rules to use your names:
%: %.c
${COMPILER} -o $# ${OBJ} ...
If you're explicit, there won't be a problem:
hello: ${OBJS}
${COMPILER} -o $# ${OBJS}
Note, though, that using the alternative names may make it harder for people to understand your makefile. Makefiles can grow to be complex; one way of reducing their complexity is to follow the normal conventions. I don't particularly recommend doing what you're suggesting, but it can be done.
CC and CFLAGS are used by implicit rules but not OBJECT : (see http://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html#Implicit-Rules)
OBJECT can be changed as it is not belonging to any explicit rule.
If you want to use other names for variables used in explicit rules, I think you have to define your own rules by adding something like that to your Makefile :
.cpp.o:
$(COMPILER) $(COMPILATIONFLAGS) $< -o $#
The commands in default rules and names of variables used in them are standardized by POSIX. GNU make to a certain extent obeys these. You're free to completely ignore anything built-in and use your own explicit rules and variables, though.
I have a makefile in my src directory.
The makefile should build the data structures, which are in DataStructures/, and then iterate over all cpp files in calculations/ and create a corresponding .so file in ../bin/calculations
I tried the following syntax:
DAST = DataStructures/
COMPS = computations/
BIN = ../bin/
OBJECTS = ${DAST}Atom.o ${DAST}Molecule.o
COMPILE = g++ -Wall -g -c -std=c++0x -I/usr/local/include/openbabel-2.0 LINK = g++ -Wall -g -std=c++0x ${OBJECTS} -lopenbabel -I/usr/local/include/openbabel-2.0
all: ${BIN}main ${DAST}Molecule.o ${DAST}Atom.o ${BIN}${COMPS}%.so
${BIN}main: ${OBJECTS} main.cpp
${LINK} main.cpp -o ${BIN}main
${DAST}Molecule.o: ${DAST}Molecule.h ${DAST}Molecule.cpp
${COMPILE} ${DAST}Molecule.cpp -o ${DAST}Molecule.o
${DAST}Atom.o: ${DAST}Atom.h ${DAST}Atom.cpp
${COMPILE} ${DAST}Atom.cpp -o ${DAST}Atom.o
${BIN}${COMPS}%.o: ${COMPS}%.cpp
gcc -Wall -fPIC -c -lopenbabel $< -I/usr/local/include/openbabel-2.0 -std=c++0x
${BIN}${COMPS}%.so: ${COMPS}%.o
gcc -shared -Wl,-soname,libcsmtest.so.1 -o libcsmtest.so $#
clean:
rm -rf ${OBJECTS}
.PHONY: all clean
But it obviously doesn't work, as I get the following output:
shai#ubuntu:~/csm/csm2/src$ make all
make: *** No rule to make target `../bin/computations/%.so', needed by 'all'. Stop.
thanks
You need to specify in the all: target, the prerequisites explicitly.
In Makefile parlance, % is a wildcard that can be used in automatic rules. However, the all: target is a simple target with no such wildcard, thus ${BIN}${COMPS}%.so is wrong in that context.
Please note that when I say 'wildcard' in this context, this wildcard matches the target against the prerequisites, not against the filesystem like * do in glob expressions.
Also, while your hart is in the right place, as a matter of style, your Makefile can be better:
Intermediary objects, should not be prerequisites of the all target, but only the final targets you wish to ship.
There is a mix of automatic and simple rules to specify the creation of objects.
Typically one doesn't write an automatic rule for %.so, because a library is often constructed from more than one object.
The dependencies between an object and header files is a complex issue. In short you need to specify that the resulting object depends on the *.cpp (or .c) as well as all the headers included (directly and indirectly) by the *.cpp file.
By convention, that is well supported by GNU make, instead of using ${COMPILE} as you do, one should use $(CXX) for your C++ compiler, and $(CXXFLAGS) for the standard flags you wish to pass to that compiler.
You need something like
SOBJECTS = ...
all: ${BIN}main ${SOBJECTS}
...
You need a way to gather all the *.so names in the variable SOBJECTS. You can do this manually, or use some of make's internal functions to scan the source directory.
Also notice that I removed the two *.o files as dependencies from the all target. They are not final goals of the build (I assume), so you don't need to mention them there.
Besides this there are other stylistic points which I would do differently, but at the moment they are not causing immediate problems, so I won't digress, but I advise you to have a look at some tutorials to see how things are done generally.
For starters, look at Paul's Rules of Makefiles, and How Not to Use VPATH.
Makefile
default:
(!) g++ -Werror -Wunused-variable -Wunused-value -Wunused-function -Wfloat-equal -Wall -ansi -o main -pedantic-errors main.cpp
'/home/HomeName/Desktop/main'
I have been using this code to compile a C++ file. Is this a good way of using this code in the makefile? Moreover, I wonder if the line marked with (!) has the compiler options in the correct order.
So, your makefile itself does not contain the '(!)' marking, I believe.
What you have 'works'. It compiles the program with a stringent set of options and then runs it by absolute pathname.
However, it is not very flexible:
it will only build main if you run make
it will always build main even if you built it a moment ago
if you run make main, it will use a different set of commands to build the program, and it won't run the program.
It would be better - it would allow you to move the code more easily - if the line to run the program used the current directory.
And it would be better if you used some of the built-in features of make.
The C++ and C compilers are very tolerant of various orders for their options; what you have is OK.
Inside make, the C++ compiler is known by the macro CXX; it takes a set of flags defined by CXXFLAGS. You could, therefore, use:
CXX = g++
CXXFLAGS_W = -Werror -Wunused-variable -Wunused-value -Wunused-function \
-Wfloat-equal -Wall
CXXFLAGS_M = -ansi -pedantic-errors
CXXFLAGS = ${CXXFLAGS_M} ${CXFLAGS_W}
all: main
./main
This allows you to run make, make all and make main and get the program main built. If you use either of the first two, the program will also be run. It will only recompile the program if the source has changed since it was last compiled. If you have other programs in the directory, say 'exercise2.cpp' and 'exercise3.cpp', then you'd be able to say make exercise2 exercise3 and those would now be compiled in much the same way that main is.
If you really wanted to run the program after building it (probably not something you'd do in the long-term), then you'd probably rewrite the compilation rule (assuming GNU Make):
% : %.cpp
${CXX} ${CXXFLAGS} -o $# $*.cpp
./$#
If you have a classic or POSIX variant of make, you'd write:
.cpp:
${CXX} ${CXXFLAGS} -o $# $*.cpp
./$#
The notation using '%' is more flexible when it is available.