java
html
css
c
database
linux
xcode
regex
mysql
objective-c
visual-studio
multithreading
flash
algorithm
facebook
cocoa
delphi
mvc
php5
api
If you are using GNU make, you have two options (in addition to the recursive make invocation, which has the problems outlined above).
The first option is to use target-specific variables. You are using them in your original example:
debug: CPPFLAGS=$(CPPFLAGS_DEBUG) debug: CFLAGS=$(CFLAGS_DEBUG) optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL) optimal: CFLAGS=$(CFLAGS_OPTIMAL)
The thing you're missing is that target-specific variables are inherited by their prerequisites. So you need to declare prerequisites of "debug" and "optimal" (they don't have to have recipes themselves; in fact, they can be declared .PHONY). So for example:
debug: CPPFLAGS=$(CPPFLAGS_DEBUG) debug: CFLAGS=$(CFLAGS_DEBUG) debug: appfs appmount optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL) optimal: CFLAGS=$(CFLAGS_OPTIMAL) optimal: appfs appmount
Now if you run "make debug" it will build both appfs and appmount with the debug settings for CPPFLAGS and CFLAGS; if you run "make optimal" it will use the optimal settings.
However this has the same downside as the recursive invocation of make; if you run "make appfs" directly then NEITHER of the settings will be used; target-specific variables are inherited from the parent(s) that led to the target being built in this invocation of make. If neither of those targets are in the parent target list then their target-specific variables won't be used.
The second option, which gives you pretty much exactly the interface you were looking for, is to use the MAKECMDGOALS variable to decide whether the user asked for optimal or debug builds. For example something like this:
CPPFLAGS_debug = <debug CPPFLAGS> CFLAGS_debug = <debug CFLAGS> CPPFLAGS_optimal = <optimal CPPFLAGS> CFLAGS_optimal = <optimal CFLAGS> STYLE := $(firstword $(filter debug optimal,$(MAKECMDGOALS))) $(if $(STYLE),,$(error No style "debug" or "optimal" set)) CPPFLAGS = $(CPPFLAGS_$(STYLE)) CFLAGS = $(CFLAGS_$(STYLE)) debug optimal: .PHONY: debug optimal
Or if you prefer you can choose a default behavior if one isn't given, instead of throwing an error; this chooses "debug" by default for example:
STYLE := $(firstword $(filter optimal,$(MAKECMDGOALS)) debug)
However, it's important to note that the reason this seems tricky to do is that what you're asking for is inherently flawed. Suggesting that a single derived file in a directory should be built in one of two different ways based on a build-time parameter is asking for trouble. How do you know which variation was used last? Suppose you run make with optimization, then you modify some files, then you run make again this time with debug... now some of your files are optimized and some are debug.
The right way to handle different build variations of code is to ensure that the derived files are unique. This means that the debug targets are written to one directory, and the optimized targets are written to a different directory. Once you make this distinction the rest of it falls out easily: you simply use the debug flags when you write the rules for the debug targets and the optimal flags when you write the rules for the optimized targets.
One ghastly but moderately effective technique is:
# Optimization settings. debug: +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" optimal: +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)"
This means that make debug reinvokes make with the debug flags set on the command line, and make optimal reinvokes make with the optimal flags set on the command line.
make debug
make
make optimal
This is far from perfect; it means the default rule will be run when make is reinvoked.
You could vary this with:
# Optimization settings. debug: +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" debug_build optimal: +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)" optimal_build
This now runs two different build targets for the debug build and the optimal build. Other rules, such as clean or depend don't get the special treatment.
clean
depend
The + notation on the command lines is POSIX's way of saying 'run this rule even under make -n', which is probably what you want. The $(MAKE) notation may also achieve the same effect. If your make does not like the + signs, try removing them.
+
make -n
$(MAKE)
This doesn't let me do 'make debug appmount' to build the appmount target in debug mode though does it? It only allows for 'make debug' which builds all the targets in debug.
make debug appmount
You're correct; that's the sort of reason why it is not perfect. If you're lucky, someone else will come up with a better solution. There is a slightly devious way to more or less achieve what you want:
BUILD_TARGET = all # Optimization settings. debug: +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" $(BUILD_TARGET) optimal: +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)" $(BUILD_TARGET)
Now when you run make debug, it will rerun and build the all target by default with the debug options. But, you can change that with:
all
make optimal BUILD_TARGET="appmount totherprog"
This will build the two named targets with the optimal flags. The initial command line is not dreadfully elegant, but it would get you to your destination - just about. Careful choice of defaults and the ability to override them should get you where you need to go.