nlu
nlu

Reputation: 1963

Define a makefile target from variables set with eval

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

Answers (3)

user5484700
user5484700

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

nlu
nlu

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

Beta
Beta

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

Related Questions