user654077
user654077

Reputation: 43

Make: Setting Target Specific Variables With Different Goals

I'm building a makefile that will be used to build a release or debug target library. I want to place the object and auto-generated dependancy files into either a debug or release directory structure, depending on the requested makefile goal. I don't want to specify a testable make command-line argument (i.e. DBG=1), but would prefer to run make -f Makefile, or make -f Makefiel dbg for release and debug target goals, respectively. Got that part down. I understand that I can't assign a target-specific variable containing the name of the object dir (either release or debug) that can be used as part of the Target specification in a rule, like I did in the example shown below. In this example, OBJDIR is the target-specific variable I would like to set depending on the build goal. For that reason, in this example, $(OBJDIR) is empty in the target rule $(OBJDIR)/%.o. Any recommendations on how to perform the suggested steps nicely? (The example shown is simply a copy/paste unverified example...syntax is not verified...in fact, I can't get the tabs to appear correctly...I'm hoping to get some implementation ideas). (Also, $(OBJDIR) is not set in the clean target as shown...since it is not in the dbg/all target dependancy heirarchy...thoughts?) Thanks in advance.

Makefile:

OBJS    := a.o b.o c.o  
SRCS    := $(OBJS:.o=.c)  

-- Set up the release and the debug directory paths and object filenames  
RELEASE_DIR := ./release  
RELEASE_OBJ := $(OBJS:%=$(RELEASE_DIR)/%)  
DEBUG_DIR   := ./debug  
DEBUG_OBJ   := $(OBJS:%=$(DEBUG_DIR)/%)  

.PHONY : all dbg 

all: CFLAGS = -O3  
all: OBJDIR := RELEASE_DIR  
all: df     := $(RELEASE_DIR)/$(*F)  
all: init_release lib1.so  

dbg: CFLAGS = -g -O0  
dbg: OBJDIR := DEBUG_DIR  
dbg: df     := $(DEBUG_DIR)/$(*F)  
dbg: init_debug lib1.so  

Lib1.so: $(OBJ)  

init_release:  
    -@mkdir -p $(RELEASE_DIR)  

init_debug:  
    -@mkdir -p $(DEBUG_DIR)  

lib1.so: $(OBJ)  
    @echo '--------------------------------------------------------------'
    @echo linking $@  
    @gcc -shared -o lib1.so $(OBJ)  

-Compile including advance dependancy generation alg, per Tom Tromey:
    # http://make.paulandlesley.org/autodep.html  
$(OBJDIR)/%.o: %.c  
    echo $@    
    echo $(OBJDIR)  
    echo compiling $@  
    $(COMPILE.c) -MD -o $@ $<  
    cp $(df).d $(df).P; \  
    sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \  
             -e '/^$$/ d' -e 's/$$/ :/' < $(df).d >> $(df).P; \  
    rm -f $(df)/$*.d  

# If the goal is "clean", don't include these to avoid trying to build them
ifneq($(MAKECMDGOALS),clean)  
-include $(SRCS:%.c=$(OBJDIR)/%.P)
endif  

clean:  
    -@rm -f    $(OBJDIR)/*.[Pdo] lib1.so  

Upvotes: 3

Views: 6079

Answers (2)

bobbogo
bobbogo

Reputation: 15483

Target specific variables can be tricky. Use indirection instead. Make has lots of syntax to cut-down on boilerplate text. .SECONDEXPANSION is often good. A sketch:

.SECONDEXPANSION:
${DEBUG_OBJ} ${RELEASE_OBJ}: $$(patsubst %.o,%.c,$${@F})
    gcc ${copts-${@D}} -c $< -o $@

Here we tell make that ./release/a.o depends on a.c. When make decides to build ./release/a.o it expands the shell line. As it does so, ${@D} is naturally release, so make carries on and expands ${copts-release} which you will have defined usefully.

Similarly, when producing ./debug/a.o make expands ${copts-debug}.

Copious use of $(warning [blah]), $(error [blah blah]) and the mandatory --warn-undefined-variables will help you get this right.

Upvotes: 5

Didier Trosset
Didier Trosset

Reputation: 37427

The Makefile you wrote is not valid, and it will not generate your targets as you expect. For instance, you cannot set the CFLAGS variable in the targets definitions all and dbg.

The only solution I can think of is to call make with the same Makefile defining the DBG variable as you wish. E.g.:

ifdef DBG
CFLAGS = -O0 -ggdb
OBJDIR = dbgdir
else
CFLAGS = -O2
OBJDIR = reldir
endif

all: $(OBJDIR)/target
    #Your commands here

dbg:
    $(MAKE) DBG=1

With this, if you call make, you have the release build. If you call make dbg you have the release build.

Upvotes: 1

Related Questions