Do I need to pass CFLAGS explicitly to gcc? - gcc

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

Related

Makefile dependency file error when including it

I am finding problem when I try to include a C source file in my Makefile. This C source file contains a function which is called by the C++ code (list.cpp) through external C linkage option. I would like to know which is the right place in the Makefile to include this C source code whose function is invoked inside C++ code. If I try adding this C file in the Makefile's SOURCES variable in order to built it, then the C++ code fails to correctly resolve the function call of C and I am getting linker error: undefined reference
Following is my Makefile content:
CFLAGS =-c -g -Wall -std=c++11
SOURCES = list.cpp
OBJECTS = $(SOURCES:.cpp=.o)
EXEC = a.out
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS)
#$(CXX) $(OBJECTS) -o $# && $(EXEC)
.cpp.o:
#$(CXX) $(CFLAGS) $< -o $#
Let's assume the C source file that you need in the build is bar.c,
and that it has an associated header file bar.h that you are
#include-ing in list.cpp, and that you have correctly coded the extern C
boilerplate in bar.h.
Then the following makefile will do what you need:
Makefile
CXX_SOURCES := list.cpp
C_SOURCES := bar.c
OBJECTS = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
CXXFLAGS := -g -Wall -std=c++11
CFLAGS := -g -Wall
CPPFLAGS :=
LDFLAGS :=
LDLIBS :=
EXEC := a.out
.PHONY: all clean test
all: $(EXEC)
test: $(EXEC)
./$<
$(EXEC): $(OBJECTS)
$(CXX) $(LDFLAGS) $^ -o $# $(LDLIBS)
list.o: bar.h
clean:
rm -f $(EXEC) *.o
There are a lot of learning-points here:
1. Use immediate evaluation (:=) rather than recursive evaluation (=) of
make variables unless you particularly want recursive evaluation. See
6.2 The Two Flavors of Variables
2. If a target is merely a name for a task and not the name of a file that
the task will create, then it's a phony target
and you should tell make that it is a phony target, like:
.PHONY: all clean test
3. It is not normal for the make-recipe that builds a program to run the program as
well, like your:
#$(CXX) $(OBJECTS) -o $# && $(EXEC)
You don't always want to run a program just because you've built it, and
if the program is a long-running or interactive one then this approach
will make it impractial to build the program at all.
Probably, you want to run the program to test that it has been built correctly.
But building is one task, testing is another (that may take much longer and
involve additional resources); so you should provide a separate phony target
for testing. I've called it test in this makefile: often it is called check.
To build the program without testing it, just run make. To test it,
run make test - and this will also (re)build the program if it needs to be (re)built.
4. You don't need to write a rule to make name.o from a name.cpp, or
a rule to make name.o from a name.c. GNU make has builtin rules for doing
this correctly, as long as you have correctly set the make-variables that
make uses in those builtin rules:
CC: The command that invokes C compilation or linkage, e.g. gcc
CXX: The command that invokes C++ compilation or linkage, e.g. g++
CFLAGS: Options for C compilation
CXXFLAGS: Options for C++ compilation
CPPFLAGS: Options for the C/C++ preprocessor
5. Two more important make-variables that have conventional meanings are:
LDFLAGS: Options for linkage, excluding library (-l) options
LDLIBS: Library options (-l) for linkage.
In the simple makefile above, CPPFLAGS, LDFLAGS and LDLIBS are not
needed and could be ommitted. Instead, I've assigned them empty values
just to illustrate their use.
6. A makefile should have a phony target clean that deletes any files
that the makefile might have created, so that make clean gets you
ready to build anything or everything from scratch.
7.. If name.o is compiled from name.c or name.cpp, then of
course name.o depends on name.c|name.cpp, but it also depends
on every header file that is included by name.c|name.cpp, and the
makefile needs to express all those dependencies to work reliably. So
in this case you need (at least) the rule:
list.o: bar.h
so that if you change bar.h then make will see that foo.o is out of
date and will carry out its recipe for re-making foo.o. When you
start building complex programs it will become impractical for you
to figure out all these header-file dependencies yourself: then you'll need
to find out about auto dependency generation.
Here is the GNU Make manual

Why does Make use ASFLAGS for both gcc and as when their flags aren't compatible?

I want to assemble and link some code for a 32-bit target from a 64-bit host, and I'm trying to use make's implicit rules as much as possible.
If I put -m32 in ASFLAGS it works fine for linking and assembling in one step, as make will use gcc for this. But if one of my executables needs separate linking, everything breaks, because make will then use as for assembling, and as doesn't understand -m32. To solve this I can use --32 instead, but this will of course not work with gcc.
$ cat Makefile
ASFLAGS = -m32
all: prog1 prog2
prog2: prog2.o
$ make
cc -m32 prog1.s -o prog1
as -m32 -o prog2.o prog2.s
as: unrecognized option '-m32'
<builtin>: recipe for target 'prog2.o' failed
make: *** [prog2.o] Error 1
Why does make use ASFLAGS for both gcc and as when their flags aren't compatible? Am I not supposed to specify the architecture this way? Do I really have to hack my way around this (i.e. actually write something in my Makefile), or is there something I've missed?
Since ASFLAGS is used by both LINK.s (gcc) and COMPILE.s (as) as you mentioned, one possible solution is to add following in the Makefile for compiling %.s with $(AS),
EXTRA_ASFLAGS = --32
%.o : %.s
$(AS) $(ASFLAGS) $(EXTRA_ASFLAGS) $(TARGET_MACH) -o $# $<
, or
COMPILE.s += --32
Well, you lied to make and as. If you put in ASFLAGS something that is not an assembler option, you're doing something out of spec.
make cannot know what options the compiler and assembler understand. To deal with this, make provides a way to specify the options for each tool separately: use CFLAGS for the compiler, ASFLAGS for the assembler, LDFLAGS for the link step.
I suggest using make CFLAGS=-m32 ASFLAGS=--32.

Compile program using a Makefile with gcc instead of clang

I am writing a program to spell-check a given text. On my pc I used this Makefile to compile the program:
# compiler to use
CC = clang
# flags to pass compiler
CFLAGS = -ggdb3 -O0 Qunused-arguments -std=c99 -Wall -Werror
# name for executable
EXE = speller
# space-separated list of header files
HDRS = dictionary.h
# space-separated list of source files
SRCS = speller.c dictionary.c
# automatically generated list of object files
OBJS = $(SRCS:.c=.o)
# default target
$(EXE): $(OBJS) $(HDRS) Makefile
$(CC) $(CFLAGS) -o $# $(OBJS) $(LIBS)
# dependencies
$(OBJS): $(HDRS) Makefile
I would like to continue programming on my Raspberry Pi but I only have gcc installed. Is it possible to make this Makefile work for gcc? I tried to change the compiler with:
CC = gcc
but It doesn't work. I get the error message "unrecognised option -Qunused-arguments".
The problem is that the -Q option which Clang accepts isn't an option which GCC recognises.
GCC and Clang are completely separate compilers, and so one shouldn't really expect one of them to understand the other's options. In fact, Clang does make some efforts to be modestly compatible with GCC, in large part to make it possible to use it as a drop-in replacement for GCC. However that compatibility isn't, and probably shouldn't be, complete.
So your solution is simply to change the CFLAGS definition at the same time as you change the CC definition.

make is calling g++ is always re-compiles even when I do not change the source code

I am using make which calls g++ always re-compiles the code, even when I do not change the source code. That happens for all my projects, even for simple ones such as:
[code]
all: main.cpp
g++ -std=c++11 -c main.cpp
[/code]
I believe it should compare the date/time on source and object code. Could some help me with this, I am running using GNU toolchain on Ubuntu 12.04
THX
Edit: sorry guys, I do use Makefile, I edited my question accordingly.
Simplest Makefile
It was already pointed out that your Makefile is probably wrong. The 'all' target is indeed always built (although it may result in a no-op if it has no commands and all dependencies are already satisfied). All you need in your makefile is this:
all: main
Object files
If you expect to have more source file in your build, you should consider creating intermediate object files:
all: main
main: main.o
Tweak the build
Make will automatically find the main.ccp file and turn it into main which is required per the directive above. You can use special make variables to further tweak the compilation, e.g. for debug information inclusion and for warning configuration:
CXXFLAGS = -g -Wall -Werror
all: main
main: main.o
Nitpicking
If you insist on building up the compile rule yourself, you can do it like this:
%.o: %.hpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
CXX: C++ compiler
CPPFLAGS: C preprocessor flags
CXXFLAGS: C++ compiler flags
$#: Target
$<: First dependency
If you don't want to use the standard variables nor pattern matching, you can build up the whole makefile explicitly:
all: main
main: main.o
gcc -o $# $^
main.o: main.c
gcc -g -Wall -Werror -o $# -c $<
$^: Use that one if you want to include all dependencies, for example if you have multiple *.o files to build one binary.
Note: It is a bad idea to write the file names directly into the command as you might forget to update them later.
all: main.cpp
g++ -std=c++11 -c main.cpp
This seems wrong. Why does the rule for all has main.cpp as its target? Shouldn't it be something.exe or something.o? Say
all: main.exe
main.exe: main.cpp
g++ -std=c++11 main.cpp -o main.exe
clean:
del main.exe
Targets are output files and cpp files are source code which should be input to the make system.
g++ would have to "recompile" in general (what happens if you change the header but not main.cpp?)
If you are concerned about long build times, you should use something like Make (which is designed specifically to avoid recompiling when the source hasn't changed)
The compiler will always compile the code. If you want to do conditional compilation (based on file times etc) you will need to use a make system such as Make, CMake, Ant, etc. For the simplest you can set up a small "Makefile" in the directory and use the command "make" to build.
Simple Makefile for compiling "myapp.exe" from "main.cpp", "file1.cpp" and "file2.cpp"
myapp.exe: main.o file1.o file2.o
g++ -o myapp.exe main.o file1.o file2.o
(make knows to use .cpp files to build .o files)
But if you also have header files, then you will need to build dependency chains, for which you may want to look into something more sophisticated like automake, cmake, ant, etc.
---- EDIT ----
Based on your updated post, the problem is that you aren't specifying a target, so Make has to assume it needs to recompile. See my example in the above answer.

Makefile for using make as gcc

Is it possible to write universal Makefile which would get any target and act like a wrapper to gcc, but with parameters? For example, this means that
make 01.c
will have the same result as
g++ -o 01.out 01.c
make already has several "implicit rules" to do what you're trying.
For example, even with no makefile,
make 01.o
Will run:
c++ -c -o 01.o 01.cpp
If it finds a file called 01.cpp in your current directory. You can set the CXXFLAGS environment variable if you want to pass more flags. If you're really set on using g++ rather than the system compiler, you can set CXX=g++, too.
Yes - You using implicit rules.
Summat like (if memory serves me right)
.cpp.o:
$(CCC) $(CFLAGS) $< -o $#
Maybe in the set of default implicit rules
You can use a wildcard - %.
However, the thing specified on the commandline is the target, not the source - what you want, not what you have.
It looks like what you want is approximately:
%.out: %.c
g++ -o $# $<
This means: to make (something).out, first make sure you have (something).c, then run g++ -o (something).out (something).c
$# is always the target file, and $< is the first prerequisite.
You will need to run make 01.out, not make 01.c

Resources