BigBrownBear00
BigBrownBear00

Reputation: 1480

Extending a simple makefile to support different implicit compiler flags

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

Answers (3)

Alexander L. Belikoff
Alexander L. Belikoff

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

Dietrich Epp
Dietrich Epp

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

John Kugelman
John Kugelman

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

Related Questions