Allowing users to override CFLAGS, CXXFLAGS and friends
Clash Royale CLAN TAG#URR8PPP
Allowing users to override CFLAGS, CXXFLAGS and friends
Typical makefiles often use the built-in variables CFLAGS
, CXXFLAGS
, CPPFLAGS
and so on1 to set the flags passed to the C, C++ or other compilers/tools. In principle, this sometimes even lets you avoid writing a compilation recipe entirely since the various built-in rules use these flags.
CFLAGS
CXXFLAGS
CPPFLAGS
In general, a makefile might add things to the FLAGS
variables that are required for the code to compile, such as include directories, arguments indicating which language standard to use and so on. The variables might also include "optional" or "default" arguments, such as optimization level, warning level and other settings that might validly be altered or removed.
FLAGS
Since CFLAGS
and fields are "well known" variables, they are also apparently a configuration point for end users. For example, if a project compiles without debug information by default, it is expected that CFLAGS=-g
on the make
command line causes -g
to be added to the $(CC) compiler command line and hence cause debug info to be produced. Similarly for other options the end user might want to control, such as the optimization level, the -march
setting on gcc, and so on.
CFLAGS
CFLAGS=-g
make
-g
-march
However, these two uses seem incompatible to me. If the user overrides $(CFLAGS)
they will obliterate any internal "required" flags as described above, and the project either may not compile or may compile incorrectly.
$(CFLAGS)
Is there a best practice for handling this? The same problem doesn't really arise for "single value" variables like $(CC)
since they generally have exactly one value: in this example, the C compiler to use. If the user overrides it, you use their value. Things like $(CFLAGS)
are in principle a list of values, some of which are internal and shouldn't be overridden, an others which a user may want to override.
$(CC)
$(CFLAGS)
Intuitively, a solution seems to be to leave $(CFLAGS)
and friends empty and unused in your makefile, preferring say CFLAGS_INTERNAL
for in-makefile arguments, and then put both on the command line. I'm curious, however, if there is a best practice around this or if I'm missing something obvious.
$(CFLAGS)
CFLAGS_INTERNAL
1 For the rest of this question I will often simply refer to $(CFLAGS)
with the understanding that this is simply a convenient representative of the whole family of well known compiler flag variables such as $(CPPFLAGS)
, $(CXXFLAGS)
and so on.
$(CFLAGS)
$(CPPFLAGS)
$(CXXFLAGS)
CFLAGS
@Vroomfondel - what do you mean by dependency hierachy?
– BeeOnRope
Jul 31 at 15:48
Generally, people create two different variables: one containing all the "required" flags and the other set to something like
-O2 -g
that users can override with what they want. This is, for example, how automake makefiles work. This does mean you need to create your own implicit rules, you can't use the built-in rules. Others do things the opposite way and ask users to use a non-standard variable to override things on the command line.– MadScientist
Jul 31 at 16:05
-O2 -g
Does something like a command line belong to the input data set, i.e. are C files dependent on the compiler switches the same way they are on header files, or do you prefer to see this as a separate information space, which lives outside of the dependency hierarchy of
make
? If the former, the most logical thing to do is lay them down in a file which effects recompilation if changed, if the latter, you have to live with make clean
as the patch which hides this logical inconsistency.– Vroomfondel
Jul 31 at 20:33
make
make clean
@Vroomfondel - well the first one yeah a bit, I mean some files might need some switches to compile (e.g.,
-std=c++11
or similar), but some are optional. Rebuilding when the flags change is interesting, but not really my question here (in fact I do usually set up my Makefiles to regenerate everything when they change by using a dummy file touched by the Makefile:
target). The latter, I'm still not really understanding.– BeeOnRope
Jul 31 at 23:15
-std=c++11
Makefile:
3 Answers
3
I am faced with the same problem. For the time being my solution is to provide "non-standard" flags such as OPTIMS
, WARNINGS
, MODENV
which will be appended to the "standard" CXXFLAGS
internally.
OPTIMS
WARNINGS
MODENV
CXXFLAGS
If the user defines CXXFLAGS
from the command-line it is assumed that he wants to override it, and if that's what he wants, that's what he should get: an override. Ironically this means I'm not using override CXXFLAGS += ...
in the Makefile.
CXXFLAGS
override CXXFLAGS += ...
I don't want advanced users to pull their hairs out because I insist on appending/prepending my stuff to their flags, so in my opinion the final situation is like this:
The override directive may be what you are looking for:
$ cat Makefile
override CFLAGS += -foobar
all:
$(info CFLAGS = $(CFLAGS))
$ make
CFLAGS = -foobar
make: 'all' is up to date.
$ make CFLAGS=-g
CFLAGS = -g -foobar
make: 'all' is up to date.
Note that you can also use:
$ make CFLAGS+=-g
on the command line but it behaves just like:
$ make CFLAGS=-g
I've used
override
but it doesn't seem to work well here. For example, if the user specifies CFLAGS=-O2
and you have override CFLAGS += -O1
in your makefile, the -O1
will take priority. In general, override
seems awkward for the variables that should be overriden if specified by the user.– BeeOnRope
Jul 31 at 7:29
override
CFLAGS=-O2
override CFLAGS += -O1
-O1
override
Absolutely, override does not help in situations where the command line flags are not compatible with the Makefile. This is the reason why I prefer having two different variables, as you suggested yourself,
cflags
defined in the Makefile and CFLAGS
that can be overridden on the command line.– Renaud Pacalet
Jul 31 at 7:37
cflags
CFLAGS
The approach I prefer is to provide sensible default values to these common variables, but let users provide their own - overriding the default values.
include $(wildcard makefile.in Makefile.in)
BUILD ?= build
CFLAGS ?= -O2 -fPIC -pedantic -Wall -Wextra -Wconversion
This can be done by either environment variables, command line parameters like make CFLAGS=-g
or persistently in a makefile.in
.
make CFLAGS=-g
makefile.in
I am aware that this doesn't exactly pick up the issue you described in the questions, but I found use cases in which users want to compile a project with non-default flags should be able to
If someone wants to build with some special flags and is incapable of these steps, there will be some more serious problems anyhow.
This approach will not scale well when the build becomes more involved and the defaults are set across a larger makefile and dependent on other conditions.
Often it is not so simple to replicate the entire
CFLAGS
or whatever since it may be composed of several variables, conditional makefile directives and so on. I would expect a user to carefully trace through the makefile to rebuild the default CFLAGS
in order to modify it (at least based on many examples I've seen where people casually modify CLFLAGS
). In the example you should though it would work fine: my concern is with clobbering flags that will make the code not compile, e.g, a bunch of -I
directives, etc.– BeeOnRope
Jul 31 at 7:41
CFLAGS
CFLAGS
CLFLAGS
-I
@BeeOnRope Ok, that's a good point. I was thinking of rather smallish projects, where the defaults can simply be set in one or two lines. I'll add this restricition to the answer.
– lubgr
Jul 31 at 7:46
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
And then there's the big Question if
CFLAGS
and cousins belong to the dependency hierarchy. How do you want it?– Vroomfondel
Jul 31 at 12:02