Reputation: 1480
I have been using a makefile that was fairly straightforward. I defined OBJS with a list of .cc files. I set up dependencies and include flags and appended all of those to $CXXFLAGS. It looks something like this:
SRCS = file1.cc file2.cc file3.cc
OBJS = $(SRCS:.cc=.o)
CXXFLAGS=some flags
CXXFLAGS+=some include dirs
$(mylib.so): $OBJS
$CXX -shared -o $@ $^
mylib.so uses the CXXFLAGS (implicitly) and everything builds just fine.
I have recently had the need to have mylib_1.so and mylib_2.so, in addition to mylib.so. Each .so depend on all the same .cc files, but the compiler flags are all different (including include directories).
How do I get it so I can set the compiler flags based on the target .so? The problem that I have is that if I set CXXFLAGS more than once it gets overwritten. It's almost like I need an if/else situation.
I tried doing something like setting three different flags, $CXXFLAGS1, $CXXFLAGS2, $CXXFLAGS3, and using those in the line
$(mylib1.so): $OBJS
$CXX $(CXXFLAGS1) -shared -o $@ $^
but that does not work.
How do I accomplish what I am trying to do? Is it better to have 3 separate makefiles? I did find a way to get it to work. I can stop using $OBJS and spell out the flags explicitly for each source file but this seems like a horrible idea in terms of scaling to size.
Upvotes: 1
Views: 3437
Reputation: 5711
Your CXXFLAGS1 in your example is only used at the stage of creating the .so file, not for compilation of the actual C++ sources (which is what you are trying to do, I assume).
To achieve the above, consider making the Makefile invoke itself 3 times for 3 different targets and pass CXXFLAGS (with different values) as part of MAKEFLAGS or in the command line.
Update: here's an example
all: build-lib1 build-lib2 build-lib3 build-lib1: $(MAKE) $(MAKEFLAGS) CXXFLAGS="$(CXXFLAGS1)" lib1.so build-lib2: $(MAKE) $(MAKEFLAGS) CXXFLAGS="$(CXXFLAGS2)" lib2.so build-lib3: $(MAKE) $(MAKEFLAGS) CXXFLAGS="$(CXXFLAGS3)" lib3.so $(lib1.so): $OBJS $(CXX) -shared -o $@ $^ etc...
Upvotes: 3
Reputation: 213338
I would do this with a recursive call to make. I would use two makefiles:
In Makefile
:
all: mylib1.so mylib2.so SRCS := file1.cc file2.cc file3.cc mylib1.so: $(SRCS) test -d mylib1 || mkdir mylib1 $(MAKE) -f ../lib.mak -C mylib1 TARGET=mylib1.so CXXFLAGS=-DMYLIB=1 cp mylib1/mylib1.so mylib1.so mylib2.so: $(SRCS) test -d mylib2 || mkdir mylib2 $(MAKE) -f ../lib.mak -C mylib2 TARGET=mylib2.so CXXFLAGS=-DMYLIB=2 cp mylib2/mylib2.so mylib2.so
In lib.mak
, in the same directory:
VPATH = .. SRCS := file1.cc file2.cc file3.cc OBJS := $(SRCS:.cc=.o) $(TARGET): $(OBJS) $(CXX) -shared -o $@ $^
The second makefile actually builds the library, but only uses one set of CXXFLAGS
. The primary makefile calls the first makefile for each version with separate CXXFLAGS
and in a separate directory. The VPATH
makes it easier to compile source files that aren't in the same directory.
I tested this setup with a dry run,
test -d mylib1 || mkdir mylib1 make -f ../lib.mak -C mylib1 TARGET=mylib1.so CXXFLAGS=-DMYLIB=1 make[1]: Entering directory `/home/depp/Maketest2/mylib1' g++ -DMYLIB=1 -c -o file1.o ../file1.cc g++ -DMYLIB=1 -c -o file2.o ../file2.cc g++ -DMYLIB=1 -c -o file3.o ../file3.cc g++ -shared -o mylib1.so file1.o file2.o file3.o make[1]: Leaving directory `/home/depp/Maketest2/mylib1' cp mylib1/mylib1.so mylib1.so test -d mylib2 || mkdir mylib2 make -f ../lib.mak -C mylib2 TARGET=mylib2.so CXXFLAGS=-DMYLIB=2 make[1]: Entering directory `/home/depp/Maketest2/mylib2' g++ -DMYLIB=2 -c -o file1.o ../file1.cc g++ -DMYLIB=2 -c -o file2.o ../file2.cc g++ -DMYLIB=2 -c -o file3.o ../file3.cc g++ -shared -o mylib2.so file1.o file2.o file3.o make[1]: Leaving directory `/home/depp/Maketest2/mylib2' cp mylib2/mylib2.so mylib2.so
Upvotes: 2
Reputation: 361605
Makefiles can have target-specific variable values. Something like:
$(mylib1.so): CXXFLAGS += -lib1flags
$(mylib2.so): CXXFLAGS += -lib2flags
$(mylib3.so): CXXFLAGS += -lib3flags
According to the documentation, the flags will propagate to prerequisite targets.
There is one more special feature of target-specific variables: when you define a target-specific variable that variable value is also in effect for all prerequisites of this target, and all their prerequisites, etc. (unless those prerequisites override that variable with their own target-specific variable value). So, for example, a statement like this:
prog : CFLAGS = -g prog : prog.o foo.o bar.o
will set CFLAGS to ‘-g’ in the recipe for prog, but it will also set CFLAGS to ‘-g’ in the recipes that create prog.o, foo.o, and bar.o, and any recipes which create their prerequisites.
Upvotes: 2