I am attempting to convert my entire project to a single Makefile at the behest if this paper that I see littering all of my search results whenever I have a recursive makefile question. However, I have run into quite a fundamental problem that I'm not sure how to address. I would like to define a couple common but not identical variables for every Makefile module. To do this, I have created a Makefile.var
file first:
# ============================================================================
# Common aliases for local dirs
# ============================================================================
# Every make module must define WORKING_DIR :=
BIN = $(WORKING_DIR)/bin
OBJ = $(WORKING_DIR)/obj
SRC = $(WORKING_DIR)/src
DEP = $(WORKING_DIR)/obj
INC = $(WORKING_DIR)/include
INCLUDES = -I$(INC)
ALL_SRCS = $(wildcard $(SRC)/*.C)
ALL_INCS = $(wildcard $(INC)/*.h)
ALL_OBJS = $(subst $(SRC),$(OBJ),$(ALL_SRCS:%.C=%.o))
ALL_DEPS = $(subst $(SRC),$(DEP),$(ALL_SRCS:%.C=%.d))
This is in a Makefile.var
file that is included first in the master file. After this, subsequent makefile modules are included. Here is my master Makefile
:
include MakeModules/Makefile.var
include MakeModules/Makefile.tools
clean: $(CLEAN_LIST)
all: $(MAKE_LIST)
Finally, here is what a module would look like. For ease, I'll just copy and paste the same module twice, and tweak the name for the second instantion. This is Makefile.tools
:
# ============================================================================
# queuing (QUE)
# ============================================================================
WORKING_DIR := $(TOP)/tools/queuing
QUE_TARGET := libqueue.so
-include $(DEP)/*.d
$(QUE_TARGET): $(ALL_OBJS)
$(CPP) $(CFLAGS) -shared -o $@ $(ALL_OBJS)
que-clean:
-rm -f $(OBJ)/*.o $(DEP)/*.d
CLEAN_LIST += que-clean
MAKE_LIST += $(QUE_TARGET)
# ============================================================================
# queuing2 (QUE2)
# ============================================================================
WORKING_DIR := $(TOP)/tools/queuing2
QUE2_TARGET := libqueue2.so
-include $(DEP)/*.d
$(QUE2_TARGET): $(ALL_OBJS)
$(CPP) $(CFLAGS) -shared -o $@ $(ALL_OBJS)
que2-clean:
-rm -f $(OBJ)/*.o $(DEP)/*.d
CLEAN_LIST += que2-clean
MAKE_LIST += $(QUE2_TARGET)
As you can see, Makefile.tools
uses the derived variables from Makefile.var
based on the value of WORKING_DIR
. Well, this doesn't actually work because of the 2-phase reading that make
does. The WORKING_DIR
variable will only take on the last known assignment, and ALL_OBJS
will be the same value for all rules regardless of where they are located. This means only the last defined module actually has the correct rules.
Is there a way to give access to the common BIN, OBJ, SRC, ...
variables to each module without just c/ping over and over again with new prefixes? That is, can I scope a variable definition to a Makefile section and then change it later while retaining the old rules? I have an itching feeling that this isn't possible, but it would be really nice if I'm missing some nice trick that will wrap this up nicely. Otherwise, this global Makefile thing isn't really feasible (there are TONS of common variables used that derive values from the WORKING_DIR
, which was scoped by recursive make previously).
When a variable is evaluated its value at that time is used. Most make variables are recursively expanded and are thus deferred in their evaluation until used in a "final" location.
Where that final location is (and when it occurs in the processing) differs depending on the purpose of the variable.
Variables (like CFLAGS
) used in rule bodies are not evaluated until the rule body runs and as such are going to see the last value assigned during the parsing phase.
Variables used in make context itself are simpler to handle. All you need to do is create simply expanded (and thus immediately evaluated) variables that reference the common variables and use those in your specific makefiles. (Additionally, you may have just realized, this is a solution to the rule body variable problem as well... at least for rules you are writing yourself and not generic pattern rules.)
Solving this for generic pattern rules is also possible and requires target-specific simply expanded variables to shadow the global variables.
I've only got a minute so I can't explain in detail but here's an example makefile that shows some of the issues and one of the fixes I mentioned (the pattern rules/target-specific variables one). See if this makes sense. Ask any questions about things that don't make sense and I'll try to explain/answer when I get time.
all: $(addsuffix -tgt,main second third)
W_D := main
ALLOBJS = $(addprefix main-,one two three)
OBJ = main-obj
DEP = main-dep
M_TGT := main-tgt
$(M_TGT): OBJ := $(OBJ)
$(M_TGT): DEP := $(DEP)
$(M_TGT): $(ALLOBJS)
W_D := second
ALLOBJS = $(addprefix second-,one two three)
OBJ = second-obj
DEP = second-dep
S_TGT := second-tgt
$(S_TGT): $(ALLOBJS)
W_D := third
ALLOBJS = $(addprefix third-,one two three)
OBJ = third-obj
DEP = third-dep
T_TGT := third-tgt
$(R_TGT): $(ALLOBJS)
%:
@echo Making '$@' $(if $^,from '$^')
@echo 'OBJ=$(OBJ)'
@echo 'DEP=$(DEP)'
Repeated include:
$ more inc.mk Makefile | cat
::::::::::::::
inc.mk
::::::::::::::
FOO:=$(PREFIX)_bar
$(PREFIX)_OBJS=wildcard $(PREFIX)/*
::::::::::::::
Makefile
::::::::::::::
PREFIX=one
include inc.mk
$(info FOO:$(FOO))
$(info $$(PREFIX)_OBJS:$($(PREFIX)_OBJS))
rule_one: PREFIX:=$(PREFIX)
PREFIX=two
include inc.mk
$(info FOO:$(FOO))
$(info $$(PREFIX)_OBJS:$($(PREFIX)_OBJS))
rule_two: PREFIX:=$(PREFIX)
PREFIX=three
include inc.mk
$(info FOO:$(FOO))
$(info $$(PREFIX)_OBJS:$($(PREFIX)_OBJS))
rule_three: PREFIX:=$(PREFIX)
all: rule_one rule_two rule_three
%:
@echo '# Making $@'
@echo FOO:$(FOO)
@echo PREFIX_OBJS:$($(PREFIX)_OBJS)
$ make
FOO:one_bar
$(PREFIX)_OBJS:wildcard one/*
FOO:two_bar
$(PREFIX)_OBJS:wildcard two/*
FOO:three_bar
$(PREFIX)_OBJS:wildcard three/*
# Making rule_one
FOO:three_bar
PREFIX_OBJS:wildcard one/*
# Making rule_two
FOO:three_bar
PREFIX_OBJS:wildcard two/*
# Making rule_three
FOO:three_bar
PREFIX_OBJS:wildcard three/*
# Making all
FOO:three_bar
PREFIX_OBJS:wildcard three/*
You could even get more clever and define a canned recipe in the included file which takes a target name and creates the per-target variable assignments to avoid needing to do that part manually if you wanted to.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments