I try to implement a non-recursive make build system in my current project. What I struggle with is variables scopes. Target specific variables don't fit my needs as often variables define targets and not prerequisites.
What I need is:
Makefile1:
SOMEVAR := original_value
include Makefile2
$(warning $(SOMEVAR))
Makefile2:
#some magic here to do what I want and make me happy
SOMEVAR := included_value
#and maybe here
And the output I want is 'original_value'.
Are there any strategies to make it real?
EDIT: The only solution I came for the moment is to force and organize myself to place all inlcudes in the end of each particular Makefile and use immediate variable assignment :=
One strategy is the old-fashioned solution to variable name collisions when all you have is global variables: add a prefix to your variable names in a form of poor-man's namespaces.
Makefile1:
Makefile1_SOMEVAR := original_value
include Makefile2
$(warning $(Makefile1_SOMEVAR))
Makefile2:
# no magic needed
Makefile2_SOMEVAR := included_value
# rest of Makefile2 uses $(Makefile2_SOMEVAR) of course
Hey presto, with a convention like this it's as if each makefile has its own local variables (or, at least, its own variables in a namespace that doesn't collide with any other makefiles).
Related
I am trying to build a framework which is supposed to apply similar operations to different designs/projects. Therefore, I have a general Makefile which defines general targets used for most of the operations. The idea is then that each design has its own main Makefile. This main Makefile includes the general Makefile for the general functionality, defines some variables for some basic configuration of the general Makefile, but can also extend or override variables from the general Makefile or define new targets or override targets when they are not applicable.
So the simplified directory structure looks something like this:
<Root Dir>
| -- targets.mk
| -- design1
| -- Makefile
| -- design2
| -- Makefile
The simplified general Makefile targets.mk looks something like this
${FF_LIST}: ${SRC_FILES}
#echo "Extract FF List for ${DESIGN_NAME}"
.PHONY: get_ff_list
get_ff_list: ${FF_LIST}
#echo "Get FF list for ${DESIGN_NAME} from ${FF_LIST}"
And the simplified design specific Makefile looks something like this:
include ../targets.mk
DESIGN_NAME = design1
FF_LIST = ./misc/ff_list.csv
With this implementation, I have the problem now, when calling the target get_ff_list within the design1 directory, that the recipe for the get_ff_list target is executed but the prerequisites are not, although the echo prints the right file.
user:/tmp/make_test/design1$ make get_ff_list
Get FF list for design1 from ./misc/ff_list.csv
It seems like that the target ${FF_LIST} is not expanded correctly. I can understand that during the time I am including the targets.mk Makefile this variable does not exist. However, my understanding of Makefile's recursive variable declaration with = should expand the variable every time the variable is used (as it is done and seems to work within the recipe itself).
I could include the targets.mk Makefile at the end after the configuration/setting the variables, like:
DESIGN_NAME = design1
FF_LIST = ./misc/ff_list.csv
include ../targets.mk
This seems to work and solve this particular issue. However, when I also want to extend or override variables/targets from the general Makefile, then it becomes a bit less obvious where to include it. Especially, if I am not the only one using the framework and other users create there own new designs.
Maybe this is even not a good way to use Makefiles to begin with. I would also be happy to get suggestions of better ways to implement this.
However, my understanding of Makefile's recursive variable declaration with = should expand the variable every time the variable is used (as it is done and seems to work within the recipe itself).
No. Read the section of the manual on How make Reads a Makefile to understand when variables are expanded immediately, and when the expansion is deferred.
The simplest way to do what you want is for the include targets.mk to come at the end of the Makefile, not at the beginning. If that's not feasible then you'll have to split the main makefile into two parts, one that sets variables and is included first, and the other that defines rules and is included last.
I am designing a simple makefile that defines one target which takes an argument, and I would like to define a second target that invokes the first target in a loop, once per every variable defined in an array variable at the top of the Makefile.
my_loop_var = var1 var2
my_thing:
echo $MY_VAR
all:
invoke my_thing once for each value of my_loop_var
What is the right way to solve this?
Note: $MY_VAR will probably expand as Y_VAR because make will try to expand variable M, which is probably undefined, and concatenate Y_VAR to the result. Use $(VARNAME) to expand make variable VARNAME. It is only with single-character variable names that you can expand with $X.
There is not really a "right way". There are many ways. The most straightforward from your specifications (but the less natural) would be something like:
my_loop_var := var1 var2
my_thing:
echo "$(MY_VAR)"
.PHONY: all my_thing
all:
for v in $(my_loop_var); do $(MAKE) my_thing MY_VAR="$$v"; done
The recipe of all is a shell loop that re-invokes make with the my_thing goal and with each value in my_loop_var passed as the value of make variable MY_VAR.
Note the $$v to escape the first expansion that make always performs before passing the recipe to the shell. With just $v make would expand the recipe as ... MY_VAR="" ... and the result would not be what you expect.
Note also the use of the MAKE make variable instead of directly calling make (have a look at the documentation if you want to understand why it is better like this).
all and my_thing are declared as phony because they are not real file names that their recipes create, and make needs to know this kind of things.
But a much more make-ish way would be something like:
my_loop_var := var1 var2
my_thing_targets := $(addprefix my_thing_,$(my_loop_var))
.PHONY: all $(my_thing_targets)
all: $(my_thing_targets)
$(my_thing_targets): my_thing_%:
echo "$*"
Here we define as many my_thing_something targets as there are something values in my_loop_var. And explain make how to build such targets with a static pattern rule. In the recipe of a pattern rule the $* automatic variable expands as the part that matched the % pattern. So, this static pattern rule says that if we need to build my_thing_something, the recipe is echo "something".
We declare all these my_thing_something targets as prerequisites of all such that if you type make or make all, make will build all the my_thing_something targets.
This second solution is better for at least two reasons. First, make is invoked only once, which is better, at least for performance. Second, make can parallelize the build of the my_thing_something if you use the -j N option (to allow make to run up to N jobs in parallel). This also is better for performance.
But it is also a matter of style. Very frequently if you use shell loops in your recipes, especially to invoke make again, it is the sign that you did not really understand what make is intended for and how it works. The make language is not a scripting language (even if the recipes are written in shell language, which is a scripting language); make is designed to "loop" over all targets to build, without the need for explicit loops.
I want to set a Global variable through a recipe then reference that variable in another independent recipe
The below code is an example code that sets the variable within the recipe but the variable stays with the initial value if referenced outside the recipe
ACTIVE = a
switch:
ifeq ($(ACTIVE),b)
ACTIVE=$(shell echo 'a')
else
ACTIVE=$(shell echo 'b')
endif
print:
$(info acitve = $(ACTIVE))
I know there are ways to broadcast the value of a target-specific variable to dependent targets, but that's not what I want.
You can use $(eval ...) for this, although it's almost always a bad idea. I have to assume that your real situation is much more complicated because there are many better ways to accomplish what you've actually provided in the sample makefile.
switch:
$(eval ACTIVE=$(if $(filter-out a,$(ACTIVE)),a,b))
My idea is to use computed names to emulate namespaces, for example:
GetVar = $(or $($2#$1),$($2))
fubar#namespace = foo bar
frob = baz
$(info $(call GetVar,namespace,fubar))
$(info $(call GetVar,namespace,frob))
furthermore this could be used in rules to have target local variables
cmd#target = echo hello
target:
$(call GetVar,$#,cmd)
This seem to work on GNU-make, but it raises a few questions:
First of all this will result in using non-normal characters in variable names. Of course one may use another separator than #, but in using the target name as the namespace name you would inevitably run into cases where dots and slashes end up in the variable name. How bad is this? The GNU-make manual tells me to avoid this and mentions the ability to share this via environment to submakes, but this is in a non-recursive makefile setup.
Is this exploiting a non-portable feature of GNU-make? Need I be concerned with feature versions of make breaking this feature?
Is there any example of this idiom actually being used? Not being able to find any cases makes me wonder if there's anything I've missed that makes this a bad idea.
If it's not that bad idea, are there any particular namespace separator that would be more suitable than other?
As far as I can see you're mostly recreating target-specific variables. Is there some reason you don't want to use them?
target: cmd = echo hello
target:
$(cmd)
I have several environment variables set in my makefile that all have a common prefix, and others that do not share the prefix. How can I grab all of the variables that do have that prefix, and prepend a -D to the front of it, and set those all to a new variable? See below:
ENVIRONMENT VARIABLES
=====================
FOOD_VEGETABLE
FOOD_FRUIT
FOOD_DESSERT
HEAT
GAS
So I want a new variable FOOD_FEATURES to grab all of the FOOD_* variables, and prepend a -D prefix. If I printed FOOD_FEATURES I would get this:
$(warning $(FOOD_FEATURES))
gives
-DFOOD_VEGETABLE -DFOOD_FRUIT -DFOOD_DESSERT
If you have a sufficiently new version of GNU make, you can use the .VARIABLES special variable for this sort of introspection:
FOOD_FEATURES := $(patsubst %,-D%,$(filter FOO_%,$(.VARIABLES)))
I should point out that this will match all make variables containing the prefix FOO_, not just environment variables. If you really want only environment variables that's doable, but much more complex; something like:
FOOD_FEATURES := $(patsubst %,-D%,$(foreach V,$(filter FOO_%,$(.VARIABLES)),$(if $(filter environment,$(origin $V)),$V)))