Reputation: 1963
I have to define a target that contains a version number, which in turn is extracted from some file (the prerequisite of this target) retrieved from git.
What I first tried was to set a variable with eval
and use this in the name, like this.
version_file:
@checkout
version: version_file
@eval version := get version from version_file
file_$(version):
@echo file_$(version)
final_target: file_$(version)
@echo $@
This cannot work: make
reads the makefile in the first pass and does not find the variable dynamic_prerequisite
, so the target created is simply named file_
.
But when I try to create the rule dynamically, after the variable has been set, like this
...
define rule_file_version
file_$(version):
@echo version: $@
endef
version: version_file
@eval version := get version from version_file
$(eval $(rule_file_version))
... this gives me the error message:
makefile:12: *** prerequisites cannot be defined in recipes.
Of course I cannot move the eval
for the target outside of the recipe, as I then encounter the same problem as before.
Is there a way to achieve what I want with gnu make
?
Upvotes: 1
Views: 2713
Reputation: 46
Another option is to use a build tool more suited to dynamic targets. For example, I've written a Gnu Make-like tool incorporating some of the concepts from DJB's ReDo, called GoodMake. Your equivalent makefile would just be:
#? version_file
checkout
#? final_target
$0 version_file # Static dependency
version=$(get version from version_file)
$0 file_$version # Dynamic dependency
Simpler, huh? If you try out GoodMake, I'd love to hear what you think!
Upvotes: 0
Reputation: 1963
I found the problem can be solved by using constructed include files.
For the construction of the files itself I created a simple shell script, that takes the dynamically set variable as an argument:
#!/bin/bash
read -r -d '' MAKE <<EOF
file_$1:
@echo version: $1
final_target: file_$1
@echo final_target: $1
EOF
echo "$MAKE" > rules.mk
This is used in the makefile
to create an included makefile rules.mk
, like this:
version_file:
@checkout
version: version_file
@eval version := get version from version_file
rules.mk: version
$(shell ./create_rules_mk.sh $(version))
-include rules.mk
When I run make final_target
it creates the rules.mk
as wished.
The bottom line for me is, that target names, that themselves depend on other targets have to use dynamic creation of makefiles.
Upvotes: 1
Reputation: 99154
Here is a much simpler approach:
blackbox.sh:
#!/bin/bash
echo 1.0
Makefile:
dynamic_prerequisite := $(shell ./blackbox.sh)
file_$(dynamic_prerequisite):
@echo target is $@
Upvotes: 0