when I run make, how can i add some extra flags?
seems like:
make CXXFLAGS="-pg" # will substitute original flags
and:
make CXXFLAGS+="-pg" # does not work either
You are right, in a basic Makefile when you are using environment or command line variables they will substitute the original variable.
To only add some extra flags you can use the override directive. In your Makefile:
CFLAGS ?= -Wall -Wextra -Werror
override CFLAGS += -I include/
This way, you could run make with other flags:
make CFLAGS=-MyOtherFlag
And you will have:
CFLAGS = -MyOtherFlag -I include/
Related
I am trying to a create a makefile architecture so I have one global makefile at the top which call another in a subdirectory.
Global makefile :
CC = gcc
CFLAGS = -W -Wall -pedantic
LDFLAGS =
PROJECT = proj
SOURCES =
PATH = $(PROJECT)
include $(PATH)/Makefile
all : $(PROJECT).exe
$(PROJECT).exe :
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) $(INCLUDES) $(SOURCES) -o $#
clean :
rm -rf *.exe
Subdirectory makefile :
CC = gcc
CFLAGS = -W -Wall -pedantic
LDFLAGS =
SOURCES += $(PATH)/main.c
When I "make" in the top directory I have the following error :
gcc -W -Wall -pedantic proj/main.c -o proj.exe
make: gcc: Command not found
make: *** [Makefile:17: FK16_jake.exe] Error 127
But when i type exactly the same command (gcc -W -Wall -pedantic proj/main.c -o proj.exe) in my terminal, it's building.
And if I remove the makefile include, he recognize gcc but don't build because no sources (normal behavior).
You are overriding PATH, which is used to determine where to look for executables. Change this variable and it should work.
In the UNIX shell, the environment variable PATH specifies the set of directories to search for executables when you run a command.
The GNU Make manual says:
When make runs a recipe, variables defined in the makefile are
placed into the environment of each shell. This allows you to pass
values to sub-make invocations (see Recursive Use of make). By default, only variables that came from the environment
or the command line are passed to recursive invocations.
Because PATH is a shell variable and is defined in the environment of make, it is "came from the environment". That means when you modify the value with PATH = $(PROJECT) the updated value will be set in the environment of the shell that runs the recipe for $(PROJECT).exe. That means the shell runs with a bad value for the PATH and so cannot find gcc.
To avoid this confusion, do not use PATH as a makefile variable. Use another name which is not the same as an environment variable that the shell depends on. You could call it PROJECT_PATH instead, or just use $(PROJECT) instead of $(PATH).
I have the following in my GNU makefile:
# CXXFLAGS ?= -DNDEBUG -g2 -O3
CXXFLAGS ?=
# Add -DNDEBUG if nothing specified
ifeq ($(filter -DDEBUG -DNDEBUG,$(CXXFLAGS)),)
$(info Adding -DNDEBUG to CXXFLAGS)
CXXFLAGS += -DNDEBUG
endif
# Add a symolize if nothing specified
ifeq ($(filter -g -g1 -g2 -g3 -Oz,$(CXXFLAGS)),)
$(info Adding -g2 to CXXFLAGS)
CXXFLAGS += -g2
endif
# Add an optimize if nothing specified
$(info Adding -O3 to CXXFLAGS)
ifeq ($(filter -O -O0 -O1 -O2 -O3 -Og -Os -Oz -Ofast,$(CXXFLAGS)),)
CXXFLAGS += -O3
endif
When I run it:
$ make CXXFLAGS="-g3"
Adding -DNDEBUG to CXXFLAGS
Adding -O3 to CXXFLAGS
g++ -g3 -c foo.cpp
...
In fact, if I uncomment the CXXFLAGS ?= -DNDEBUG ..., then I can append again. But that's not very helpful since I'm trying to make arguments optional (but with sane defaults).
And if I type just make, then it works (-fPIC -march=native -Wall -Wextra -pipe is added later by the same makefile, and it has always worked):
$ make
Adding -DNDEBUG to CXXFLAGS
Adding -g2 to CXXFLAGS
Adding -O3 to CXXFLAGS
g++ -DNDEBUG -g2 -O3 -fPIC -march=native -Wall -Wextra -pipe -c serpent.cpp
...
According to the manual and 6.6 Appending More Text to Variables:
Often it is useful to add more text to the value of a variable already defined. You do this with a line containing ‘+=’, like this:
objects += another.o
Why is make not adding the values to the variable? How can I achieve the behavior I want?
By passing a variable via command-line, you're telling make that you are overriding any definitions in the file, which allows a user to compile as they intend rather than as you intend. Ignoring the restriction of user freedom, you can use the override directive:
To append more text to a variable defined on the command line, use:
override variable += more text
Variable assignments marked with the override flag have a higher priority
than all other assignments, except another override. Subsequent
assignments or appends to this variable which are not marked override
will be ignored.
I would discourage you from using override when possible because it's annoying to realize that -O0 was needed to disable the optimizations that you enabled when I don't want them enabled (after all, I specify my own flags for a reason). Of course, if no flags were specified at all, then defaults are perfectly reasonable. In fact, Automake projects seem to default to -g -O2 when no compilation flags are specified.
There are exceptions to this advice of course, such as adding a directory to search for includes/libs or preprocessor definitions for compiling a conditional section of code on a certain platform.
I read a lot of tutorials about CFLAGS and also looked in the official docs. Everywhere they say CFLAGS is implicit but still pass it explicitly in their example makefile to the compiler:
CFLAGS=-O2
gcc $(CFLAGS) -c foo.c -o foo.o
So, what does the term "implicit" mean in this context? If I declare CFLAGS=-O2 in my makefile and later just say gcc -c foo.c -o foo.o, will -O2 be active or not (so, is it really implicit)? If so, why do all tutorials (including official docs) still pass it explicitly in their examples?
Everywhere they say CFLAGS is implicit but still pass it explicitly in their example makefile to the compiler.
gcc does not use CFLAGS environment variable. See Environment Variables Affecting GCC.
CFLAGS is a conventional name for a Makefile variable with C-compiler flags and it is used by implicit make rules. See Variables Used by Implicit Rules for more details.
If you use your own make rules instead of the built-in ones, you do not need to use CFLAGS at all. Although it is a useful convention to do so because people are familiar with the conventional make variable names.
I believe CFLAGS is implicitly passed to the compiler command line by the makefile via the default compilation rule... Yet the CFLAGS can be overridden with custom flags so that each compilation command will take it and use.
You can test it easily:
$ cat cflags.mak
CFLAGS = -wrong
foo.o: foo.c
$ make -f cflags.mak
cc -wrong -c -o foo.o foo.c
cc: unrecognized option '-wrong'
So you can see it used the value of CFLAGS even though it was not explicitly specified in a rule; thus it is implicit.
But if you do specify your own rule for compiling .c files, you have to include it if you want it used:
$ cat cflags.mak
CFLAGS = -wrong
foo.o: foo.c
gcc -c $<
$ make -f cflags.mak
gcc -c foo.c
Here I provided my own rule for .c files which did not include CFLAGS, so CFLAGS was not used.
So the bottom line is if you rely on the built-in make rule for compiling .c files, CFLAGS will be included implicitly. But if you override that rule, you have to include it explicitly if you still want it to be used.
It means that there are implicit make rules, that use the CFLAGS, you can use.
So you can write a one line makefile with:
CFLAGS=-O2
if you later do:
make filename
(omitting extension) it will use an implicit rule that references the CFLAGS to convert you source file .c in an executable, so you don't need to write an explicit build statement for simple builds.
E.g. if you prepared a source name file.c it will build it with an implicit rule like:
$GCC $CFLAGS file.c -o file $LDFLAGS
see: GNU make documentation
I'm following Zed Shaw's tutorial "Learn C the Hard Way" and trying to teach myself c programming language.
On my ubuntu desktop, I encountered the linking problem he mentioned in the note of this post.
That is, when linking a static library with gcc, using a command like this:
gcc -Wall -g -DNDEBUG -lmylib ex29.c -o ex29
The linker fails to find the functions in the lib. To link correctly, I have to change the order of source file and lib to this:
gcc -Wall -g -DNDEBUG ex29.c -lmylib -o ex29
And I'm trying to use the makefile offered by Zed to automate unit test. The makefile looks like this:
TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))
TARGET=build/libYOUR_LIBRARY.a
tests: CFLAGS += $(TARGET)
tests: $(TESTS)
sh ./tests/runtests.sh
The rest part of the makefile that isn't listed here can build the $(TARGET) lib flawlessly.
The problem is Zed append the lib to the $(CFLAGS) and use the implicit rule to compile the test files which leads to a command like this:
gcc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG tests/hashmap_tests.c build/mylib.a -o tests/list_tests
The command fails because of the link problem mentioned before as expected.
The solution I came up with was to write the compilation command explicitly like this so I can change the order:
$(TESTS): $(TARGET)
$(CC) $(CFLAGS) $^ $(TARGET) -o $#
This works fine if there is only one main source file. Unfortunately, I have several out there under the ./tests directory, and a command like this is a total disaster.
My question is, how should I change my makefile to make it work or is there any other way I can do the same work as elegant as expected?
CFLAGS holds compiler flags, like -g -O2. You should not add linker flags to it. CPPFLAGS holds preprocessor flags like -Isrc -DNDEBUG. LDFLAGS holds linker flags, which would include things like -L (capital L) if you need it to find libraries, and -rdynamic. And the LDLIBS variable holds libraries, so you should do this:
CPPFLAGS = -Isrc -DNDEBUG
CFLAGS = -g -O2 -Wall -Wextra
LDFLAGS = -rdynamic
LDLIBS = -lmylib
Now you can use the built-in rules for GNU make to build your program. You can see a list of the build-in rules by running make -p -f/dev/null.
Of course the above are just the default variables make defines and uses with its default rules. You don't have to use them, but in general it's better to follow conventions rather than flaunt them.
The project that I am trying to build has default flags
CFLAGS = -Wall -g -O2
CXXFLAGS = -g -O2
I need to append a flag -w to both these variables (to remove: 'consider all warnings as errors')
I have a method to work it out, give
make 'CFLAGS=-Wall -g -O2 -w'; 'CXXFLAGS=-g -O2 -w'
OR
Run ./configure and statically modify Makefile
But I want to append my options with the existing options while running configure or make
The post
Where to add a CFLAG, such as -std=gnu99, into an autotools project
conveniently uses a macro to achieve this.
You almost have it right; why did you add the semicolon?
To do it on the configure line:
./configure CFLAGS='-g -O2 -w' CXXFLAGS='-g -O2 -w'
To do it on the make line:
make CFLAGS='-g -O2 -w' CXXFLAGS='-g -O2 -w'
However, that doesn't really remove consider all warnings as errors; that removes all warnings. So specifying both -Wall and -w doesn't make sense. If you want to keep the warnings but not have them considered errors, use the -Wall -Wno-error flags.
Alternatively, most configure scripts which enable -Werror by default also have a flag such as --disable-werror or similar. Run ./configure --help and see if there's something like that.