gnu-make how to: Private or unique variable names on included makefiles - gnu-make

Our current main Makefile imports lots of sub makes. Along with auto dependency, the general format of each of these looks like this:
OBJS += \
$(OBJS_DIR)/<filename>.o \
...
C_DEPS += \
$(OBJS_DIR)/<filename>.d \
$(OBJS_DIR)/%.o: $(MODULES_PATH)/%.c $(OBJS_DIR)/%.d
$(GCC) ...
Where OBJS and C_DEPS are defined in the main makefile and accumulated across all included makefiles. BTW we are using -j in the call to make for parallel execution.
The first thing I tried was to change the fact that in each makefile each entry is listed twice, once in the OBJS and once again in the C_DEPS. The change I had in mind is the following:
OBJ := \
$(OBJS_DIR)/<filename>.o \
...
OBJS += $(OBJ)
C_DEPS += $(OBJ:.o=.d)
kind of making a local variable once and using it to add to the objects and dependency lists. But this doesn't work, there are at least two issues:
The first one is that each make include will overwrite the previous definition. The fact that the make files are included and not called results in all my attempts to use keywords like unexport and private prove useless and the variable OBJ is overwritten in each makefile.
I am concerned about make concurrency (make -j is used) - should I be?
I was thinking of making the variable name dynamic but that also looks ugly and there is no guarantee that there won't be two makefiles with the same name from different paths included.
Is there any way around this?

Thanks to #Vroomfondel for the observations that lead to the simple answer.
Saving the contents of the varibale in between include calls is actually what is performed by the concatination into OBJS and C_DEPS, the problem was that the variable was not expanded at the time it was read and after the accumelation was done it only held the value from the last makefile that set the value of OBJ.
As it turns out it didnt realy matter what falver variable OBJ was, the problem lay in the fact that I had both OBJS and C_DEPS set as recursivly expanded variable. Once I set them to simply expanded varibles the issue was resolved, OBJ was expanded into them at reading time.
That is from
OBJS =
C_DEPS =
To
OBJS :=
C_DEPS :=

Related

Augment makefile compilation switches for specific files

CFLAGS environment variable can be used to pass compilation switches to Makefile from the outside world without modifying the file itself. Is there a way to pass switches only for one specific source file?
In my case I'd like to suppress gcc warning for several files but not for all and the Makefile is automatically generated by IDE so I cannot edit it.
We can't answer this question given the lack of details.
However you can add NEW makefiles to be parsed along with the old makefiles, without changing the old makefiles. For example, you can run this:
make -f Makefile -f ExtraMakefile
and create your own ExtraMakefile that contains any extra makefile text you want and make will read them both, in that order.
Please find below way which will help you to pass extra compiler flags and assign value into it based on your conditions.
You can pass switches by creating a new variable , Ex: CCFLAGS_EXTRASWITCH and use this flag in CCFLAGS variable.
# Append CC_FLAGS with variable CCFLAGS_EXTRASWITCH which will be used to
# pass extra switches. Value of CCFLAGS_EXTRASWITCH you can assign
# to empty or some switches based on conditions/files that you have
CC_FLAGS = $(CCFLAGS_EXTRASWITCH) \
... \ # Other default compiler flags that already exists. Keep as it is

GNU make pattern rules with different file base names

I have a data processing job that I would like to automate with Make. Hundreds of files need to be processed, in several steps.
Unfortunately, the base name will change for at least one of the steps, but it would be easy to write these dependencies into a separate file that then is included.
However, I'd like to avoid also writing the build instructions (which are quite complicated) for all these files separately.
I envisage something along these lines:
# automatically generated rules, included into make file
dir1/test.bb: dir2/test_other_name.aa
# (many more rules like the above, linking xxx.bb to yyy.aa)
# pattern rule
%.bb: %.aa
# build step using $# $>
What I would like is the pattern rule to provide the rules, and the explicit rule defining the dependencies. Can something like this be achieved?
When make's noddy patterns don't cut the mustard,
just write out the rules explicitly.
(This has the happy side effect of not using pattern rules.)
Let's say you have a function src-to-target which will generate the target filename (i.e., $(call src-to-target,dir2/test_other_name.aa) expands to dir1/test.bb.
Also, you have a list of sources in ${srcs}, and ${recipe} is a list of shell commands using $#, $< etc.
define src-to-target = ... # $1:source
define recipe =
echo Building $# from $<
⋮
endef
define generate-rule = # $1:source
target := $(call src-to-taget,$1)
targets += $${target}
$${target}: $1 ; $${recipe}
endef
$(foreach _,${srcs},$(eval $(call generate-rule,$_)))
.PHONY: all
all: ${targets} ; : $# Success
The $(foreach ...) does all the work here.
So, looking at that in painful detail,
First expand ${srcs}
Set $_ to the first in the list (dir2/test_other_name.aa say)
Expand $(call generate-rule,$_)
Expand $(call generate-rule,dir2/test_other_name.aa)
$1 is set to dir2/test_other_name.aa, and the expansion of $(generate-rule) follows, leading to this block of text
target := dir1/test.bb
targets += ${target}
${target}: dir2/test_other_name.aa ; ${recipe}
As a side effect, $(eval) swallows the above text. The expansion of the $(eval) though is empty.
$_ is set to the next source file.
Wash, lather, rinse, repeat
Once the $(foreach) is complete,
${targets} contains the complete list of targets.
Parallel safe too.
What's not to like?

Hacking in additional variables to qmake's Makefile

In qmake's Makefile, there's a series of variables that are defined. I'd like to add one more, defined by the .pro file. This section in the Makefile looks like the following:
DEL_DIR = rmdir
MOVE = mv -f
CHK_DIR_EXISTS= test -d
MKDIR = mkdir -p
I'd like to add:
TESTARGS = -xunitxml -o xunitresults.xml
A little background as to why: When qmake makes a Makefile using "testcase," it also makes a "check" target that looks like so:
check: first
$(TESTRUNNER) ./$(QMAKE_TARGET) $(TESTARGS)
Fully documented here.
This is really powerful for automated unit testing! Yet, I'd like to set "TESTARGS" elsewhere in the make file. How can I do this?
I discovered that there's a way to add variables, but not the way I expected. I cannot define "TESTARGS" with the following way. What I can do is this, in the .pro file:
QMAKE_EXTRA_VARIABLES = FOO
FOO=BAR
... But what that renders in the Makefile is this (not quite what I was looking for, but perhaps someone is looking for it):
####### Custom Variables
EXPORT_FOO = BAR

Makefiles: Alternate between two different prerequisites in the same implicit goal

I'm writing my very first makefile and I'm stuck on a problem.
I have a bunch of prerequisites, of which the first one is a template that needs to be in a special position. I get to do this like so:
target : req1 req2 req3
command $(filter-out $<,$^) $# --template=$<
The thing is, sometimes I need to switch that template for another one while leaving the other prerequisites alone, so that
# Changing just the first prerequisite
target : req1b req2 req3
command $(filter-out $<,$^) $# --template=$<
I'm searching for a way to achieve this using the goal I have right now, without writing an ad-hoc explicit goal, maybe calling make with an argument or something similar, but I know too little about makefiles to get it done.
The general idea is you will want to use a variable, how you set that variable is up to you. One way is to pass a variable via the command line. Your Makefile would look like:
target : $(REQ_ONE) req2 req3
command $(filter-out $<,$^) $# --template=$<
and then do make target REQ_ONE=reg1 or make target REQ_ONE=reg1b
If you have a preferred default that you wish to use (say req1) and you want to use the alternative in rarer circumstances you could use the modified forms of the previous example.
# only set if the variable doesn't exist
REQ_ONE ?= req1
target : $(REQ_ONE) req2 req3
command $(filter-out $<,$^) $# --template=$<
Finally, a variant on this approach is to have your Makefile call make with a variable assignment:
# only set if the variable doesn't exist
REQ_ONE ?= req1
target2:
$(MAKE) target REQ_ONE=req1b
target : $(REQ_ONE) req2 req3
command $(filter-out $<,$^) $# --template=$<
Another solution is to use secondary expansion as demonstrated in this SO post on target specific variables as a prerequisites.

subset functionality in the code below what actually it is doing

bj_dir = $(addprefix $(OBJDIR),$(subst $(ROOTDIR),,$(CURDIR)))/
target = $(obj_dir)libnovds_delivery.a
sources = \
novds_my_delivery_service_timer.c \
novds_my_delivery.c \
novds_dcmd.c \
novds_my_delivery_reply_service.c \
novds_my_delivery_reply.c \
novds_serial.c
objects = $(addprefix $(obj_dir),$(patsubst %.c,%.o,$(sources)))
deps = $(addprefix $(obj_dir),$(patsubst %.c,%.d,$(sources)))
i know the functionality of subst in makefile but in this piece code after ROOTDIR two commas are used i don't know what it will do.
Just to be clear, subst is not short for subset, it's short for substitute.
$(subst $(ROOTDIR),,$(CURDIR))) replaces every occurrence of whatever value $(ROOTDIR) expands to, with nothing (no text), in the value that $(CURDIR) expands to. The commas separate arguments so the first comma separates $(ROOTDIR) from the next argument and the second comma separates the second argument (which is empty) from $(CURDIR).
This is kind of a bad use of subst, though, because it will replace $(ROOTDIR) every time it appears (even multiple times) anywhere in the value (even in the middle or the end).
For things like this, where you want to remove a prefix only, it's best to use patsubst, as in $(patsubst $(ROOTDIR)%,%,$(CURDIR)).

Resources