Turn Make Options into Tool Flags
Often times when developing programs there is a need to build the program in/for multiple configurations. Many times, autoconf and its resulting configure script do what you need. Other times you can just change a #define in your code. But sometimes, autoconf isn't an option and changing a define doesn't quite work (say you need to pass your defines/undefines to m4 or some other tool that can't handle include files). The solution is probably to change your makefile. The method presented here results in a fairly compact change to your makefile.
Let's start with the following simple makefile:
# Makefile
all: a.out
a.out: test.o
gcc test.o -o a.out
test.o: test.c
gcc -c test.c
Now let's suppose that we have 3 different configuration options that we would like to be able to enable at build time: OPTION_A, OPTION_B, and OPTION_C. So, we want to be able to configure the options by specifying the options on the make command line:
$ make OPTION_B=1 OPTION_C=1We also, want to be able to have some of these options on by default in the makefile and then disable them when we invoke make:
$ make OPTION_A=Inside the makefile we want to be able to use the option flags as variables:
ifdef OPTION_A ... endifWe also want to setup flags for our tool-chain for all the options:
$ make OPTION_A= OPTION_B=1 OPTION_C=1 # ... will result in: gcc -UOPTION_A -DOPTION_B -DOPTION_CThe modified makefile is:
# Makefile
CONFIG_OPTIONS=\
OPTION_A \
-OPTION_B \
-OPTION_C
SET_CONFIG_OPTIONS=$(filter-out -%,$(CONFIG_OPTIONS))
UNSET_CONFIG_OPTIONS=$(patsubst -%,%,$(filter -%,$(CONFIG_OPTIONS)))
ALL_CONFIG_OPTIONS=$(SET_CONFIG_OPTIONS) $(UNSET_CONFIG_OPTIONS)
#$(info Set: $(SET_CONFIG_OPTIONS))
#$(info Unset: $(UNSET_CONFIG_OPTIONS))
# Turn config options into make variables.
$(foreach cfg,$(SET_CONFIG_OPTIONS),$(eval $(cfg)=1))
$(foreach cfg,$(UNSET_CONFIG_OPTIONS),$(eval $(cfg)=))
# Make sure none of the options are set to anything except 1 or blank.
# Using "make OPTION=0" doesn't work, since "0" is set, you need "make OPTION=".
$(foreach cfg,$(ALL_CONFIG_OPTIONS), \
$(if $(patsubst %1,%,$(value $(cfg))), \
$(error Use "$(cfg)=1" OR "$(cfg)=" not "$(cfg)=$(value $(cfg))")))
# Turn them into tool flags (-D).
TOOL_DEFINES+=$(foreach cfg,$(ALL_CONFIG_OPTIONS),$(if $(value $(cfg)),-D$(cfg),-U$(cfg)))
#$(info $(TOOL_DEFINES))
# Configuration options are turned into make variables above.
ifdef OPTION_A
$(info Building with option-a)
endif
ifdef OPTION_B
$(info Building with option-b)
endif
ifdef OPTION_C
$(info Building with option-c)
endif
all: a.out
a.out: test.o
gcc $(TOOL_DEFINES) test.o -o a.out
test.o: test.c
gcc $(TOOL_DEFINES) -c test.c
The allowable configuration options are added to a make variable at the beginning of the makefile:
CONFIG_OPTIONS=\
OPTION_A \
-OPTION_B \
-OPTION_C
Option names that start with a minus sign are disabled by default,
option names without a minus sign are enabled by default.
After setting the config options we set three variables SET_CONFIG_OPTIONS, UNSET_CONFIG_OPTIONS, and ALL_CONFIG_OPTIONS which respectively contain the names of the set options, the unset options, and all the options (all without minus signs):
SET_CONFIG_OPTIONS=$(filter-out -%,$(CONFIG_OPTIONS)) UNSET_CONFIG_OPTIONS=$(patsubst -%,%,$(filter -%,$(CONFIG_OPTIONS))) ALL_CONFIG_OPTIONS=$(SET_CONFIG_OPTIONS) $(UNSET_CONFIG_OPTIONS)In the case of the set options we filter out all the words that start with a minus sign. In the case of unset options we filter "in" all the words that start with a minus sign and then remove the minus sign. All the options are simply resulting set and unset options combined.
Next we turn all the options into make variables:
$(foreach cfg,$(SET_CONFIG_OPTIONS),$(eval $(cfg)=1)) $(foreach cfg,$(UNSET_CONFIG_OPTIONS),$(eval $(cfg)=))This simply loops through each of the set/unset variable names and then sets the value to "1" (using eval) for set variables and blank for unset variables. Remember that any attempt to set a variable that was specified on the make command line is ignored by make, so the value on the command line will override the value in the makefile.
After that, the next way-too-complex make statement checks to make sure that all the configuration varialbes have a value of either "1" or blank:
$(foreach cfg,$(ALL_CONFIG_OPTIONS), \
$(if $(patsubst %1,%,$(value $(cfg))), \
$(error Use "$(cfg)=1" OR "$(cfg)=" not "$(cfg)=$(value $(cfg))")))
To do this we loop through all the configuation options,
the if test does a pttern substitution changing "%1" "%"
to remove a "1" from the value of the variable.
If there's anything left after the pattern substitution then the
configuration variable has an invalid value and we print out a error.
Finally, we turn all of our configuration options into tool flag defines and undefines:
TOOL_DEFINES+=$(foreach cfg,$(ALL_CONFIG_OPTIONS),$(if $(value $(cfg)),-D$(cfg),-U$(cfg)))and modify our tool invocations to include the flags:
a.out: test.o
gcc $(TOOL_DEFINES) test.o -o a.out
test.o: test.c
gcc $(TOOL_DEFINES) -c test.c
This sample program test.c is:
#include <stdio.h>
main()
{
#ifdef OPTION_A
printf("Hello option-a\n");
#endif
#ifdef OPTION_B
printf("Hello option-b\n");
#endif
#ifdef OPTION_C
printf("Hello option-c\n");
#endif
}
Some output from different builds follows:
# Default is OPTION_A on: $ rm -f a.out test.o; make; ./a.out Building with option-a gcc -DOPTION_A -UOPTION_B -UOPTION_C -c test.c gcc -DOPTION_A -UOPTION_B -UOPTION_C test.o -o a.out Hello option-a # Turn off OPTION_A and turn on OPTION_B: $ rm -f a.out test.o; make OPTION_A= OPTION_B=1; ./a.out Building with option-b gcc -UOPTION_A -DOPTION_B -UOPTION_C -c test.c gcc -UOPTION_A -DOPTION_B -UOPTION_C test.o -o a.out Hello option-b # Turn off OPTION_A and turn on OPTION_B and OPTION_C: $ rm -f a.out test.o; make OPTION_A= OPTION_B=1 OPTION_C=1; ./a.out Building with option-b Building with option-c gcc -UOPTION_A -DOPTION_B -DOPTION_C -c test.c gcc -UOPTION_A -DOPTION_B -DOPTION_C test.o -o a.out Hello option-b Hello option-c # Turn off OPTION_A and OPTION_B and turn on OPTION_C: $ rm -f a.out test.o; make OPTION_A= OPTION_B= OPTION_C=1; ./a.out Building with option-c gcc -UOPTION_A -UOPTION_B -DOPTION_C -c test.c gcc -UOPTION_A -UOPTION_B -DOPTION_C test.o -o a.out Hello option-c # Try to get tricky: $ rm -f a.out test.o; make OPTION_C=on Makefile.mak:20: *** Use "OPTION_C=1" OR "OPTION_C=" not "OPTION_C=on". Stop.
At first glance one might say that this is not really a particularly "compact" solution given the size of the resulting makefile compared to the original. However, the original makefile is fairly simple and isn't likely to be representative of anything you'd actually be using in a real world program. On top of that, if the original makefile included the ability to build with the different configuration options it would be much longer. Plus, if you take out the comments, line continuations, the info prints, and blank lines, the modification only results in 8 additional lines. You might want to take the lines after the CONFIG_OPTIONS=... line and put them in an include file that you could then reuse.
Mitch Frazier is an Associate Editor for Linux Journal.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- Linux Systems Administrator
- New Products
- Senior Perl Developer
- Technical Support Rep
- UX Designer
- Web & UI Developer (JavaScript & j Query)
- Designing Electronics with Linux
- Dynamic DNS—an Object Lesson in Problem Solving
- Using Salt Stack and Vagrant for Drupal Development
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?



3 hours 11 min ago
7 hours 43 min ago
7 hours 43 min ago
9 hours 44 min ago
18 hours 29 min ago
19 hours 3 min ago
20 hours 1 min ago
20 hours 52 min ago
1 day 54 min ago
1 day 4 hours ago