GNU Make - Set MAKEFILE variable from shell command output within a rule/target

Cloud

I'm trying to put together some complicated makefile rules to automate building a project against multiple compilers. I have one rule that creates some dynamically generated variables and assigns variables to them, then passes those variables along to a call to build a separate rule.

.PHONY: all
all:
    @echo "Detected CPULIST:${CPULIST_DETECTED}"
    @echo "CPULIST:${CPULIST}"
    @for cpu in $(CPULIST_DETECTED); do                   \
        echo "CPU:$${cpu}:";                                \
        eval VARIANTLIST_DETECTED=$(shell 2>&1 find ./.build/linux/$$cpu -mindepth 1 -maxdepth 1 | grep -v '\.svn' |  grep -v warning ); \
        eval echo "Detected Variant List:$${VARIANTLIST_DETECTED}"; \
        eval variant_$${cpu}=$${cpu};                      \
        eval echo "variant_\$${cpu}:\$${variant_$${cpu}}"; \
        $(MAKE) build CPULIST=$${cpu};                     \
    done

.PHONY: build
build: sanity_check $(TARGET)
    @true

I'm having two issues. The first is that, despite double-escaping cpu via $$cpu, it translates to null in the line:

eval VARIANTLIST_DETECTED=$(shell 2>&1 find ./.build/linux/$$cpu -mindepth 1 -maxdepth 1 | grep -v '\.svn' |  grep -v warning ); \

So, the find command searches against ./.build/linux/ for each iteration of the loop rather than looping through ./.build/linux/arm and ./.build/linux/x86 like I would expect. I've included a post where this is described in the references below. I suspect this might be causing a problem because I'm attempting this within a rule itself rather than in the global assignment portion of the makefile (before the rules).

The other problem is occurring at the exact same line. It seems that the shell command is evaluated, assigned to VARIANTLIST_DETECTED, but then VARIANTLIST_DETECTED is executed as if it were a command, since I get the following error during build:

Detected CPULIST:arm x86
CPULIST:
CPU:arm:
/bin/sh: 3: ./.build/linux/x86: Permission denied
Detected Variant List:
variant_arm:arm

It's attempting to run the first result in my query as if it were a command. That line should also be something like ./.build/linux/x86/so.

How do I go about resolving these two issues? They are the last two thorns impeding completion of my makefiles.

Thanks!

References

  1. Assign a makefile variable value to a bash command result?, Accessed 2014-06-19, <https://stackoverflow.com/questions/2373081/assign-a-makefile-variable-value-to-a-bash-command-result>
MadScientist

You need to step back a little bit and think about what's going on here: you seem to just be throwing things into your makefile and hoping the result is what you want, rather than really understanding what's happening and proceeding with a purpose to solve your problem.

The first thing to understand is how make invokes a recipe: first, make expands the recipe. Expanding means make looks through the text of the recipe and finds anything that begins with a $ and treats it like a make function or variable, and evaluates it. So, $$ is converted into a single $, $(CPU_LIST_DETECTED) is expanded to the value of that variable, and $(shell ....) is a make function which is run and the results are included in the recipe text. Maybe you can already see where your recipe is going wrong...

Then second, AFTER all of the recipe has been expanded, make takes the expanded text of the recipe and passes it to the shell. Make then waits for the shell to complete, and make looks at the exit code of the shell. If it's 0, then the recipe succeeds and make continues. If it's not 0, then the recipe fails and make exits with an error. There is NO INTERACTION between make and the shell except make starts it with a script to run, and gets back the exit code. If you couldn't before, maybe you can now see where your recipe is going wrong.

It's virtually always an error (or at least unnecessary) to use a $(shell ...) function inside a recipe... the recipe is already running in the shell! You don't need make to run another shell first, then give those results to a new shell.

Your shell invocation is trying to use a shell variable, $cpu. But that variable has no value here, when make runs the $(shell ...) function, because make runs that function before it starts your shell script. You can't have things in your make functions that refer to things that won't be defined until the recipe is running. This will run the shell script 2>&1 find ./.build/linux/$cpu -mindepth 1 -maxdepth 1 | grep -v '\.svn' | grep -v warning, but the shell variable cpu is not set so the find will recurse through everything under ./.build/linux/.

Second, you are misusing eval here. The shell function expands to a list of words, say foo bar baz. Then the eval will look like this:

eval VARIANTLIST_DETECTED=foo bar baz

which is the same as writing just this:

VARIANTLIST_DETECTED=foo bar baz

which is the same as running the command bar with an argument baz, after setting the variable VARIANTLIST_DETECTED to the value foo. Which is why it seems to be "running your directory".

You probably wanted this:

VARIANTLIST_DETECTED="foo bar baz"

(note quotes). However, getting quotes through an eval is tricky" you have to escape them. Luckily you don't need eval at all here anyway, because you're not trying to assign a dynamically named variable. You can just write the assignment directly.

So, losing the shell function and the eval, that line should be written:

VARIANTLIST_DETECTED=`2>&1 find ./.build/linux/$$cpu -mindepth 1 -maxdepth 1 | grep -v '\.svn' |  grep -v warning`; \

Ditto for the echo: you don't need the eval there.

However, I really don't see the point of setting this variable or the variant_$cpu variable either. You never do anything with them.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

how to set an expect variable with output of shell command

From Dev

Set output of a command to a variable

From Dev

Set command output as variable

From Dev

Set output of a command to a variable

From Dev

make output is different from Makefile

From Dev

Put command result in variable within makefile target

From Dev

make command execution from the Makefile

From Dev

GNU make - How to concatenate to variable depending on shell command result (GCC version)?

From Dev

Use the output of a shell command as a variable

From Dev

Assign output of a shell command to a variable

From Dev

How to output a shell command into a variable?

From Dev

Use make variable in builtin shell function in a Makefile

From Dev

Makefile: set the environment variables output by a command

From Dev

GNU Make - how to add timestamp output (with minimal makefile modification)

From Dev

How can I stop the Z shell from conspiring to tamper with the output of GNU Make?

From Dev

How to set proper values for -L and -l in make from a command output

From Dev

Run a command in GNU and BSD Makefile and store the result into a variable

From Dev

Run a command in GNU and BSD Makefile and store the result into a variable

From Dev

imitate "make -j" from within the Makefile

From Dev

How to set a variable equal to the output from a command in GRUB2?

From Dev

makefile.am variable to set some libs after object files in make command

From Dev

makefile.am variable to set some libs after object files in make command

From Dev

How to use echo in shell command from Makefile?

From Dev

Set an environment variable within a shell alias

From Dev

storing error message of command output into a shell variable

From Dev

Grunt-shell save command output as variable

From Dev

How to assign a variable the output of a shell command in Tupfile?

From Dev

storing the output of ls command in a shell variable

From Dev

Set a variable from within a rule

Related Related

  1. 1

    how to set an expect variable with output of shell command

  2. 2

    Set output of a command to a variable

  3. 3

    Set command output as variable

  4. 4

    Set output of a command to a variable

  5. 5

    make output is different from Makefile

  6. 6

    Put command result in variable within makefile target

  7. 7

    make command execution from the Makefile

  8. 8

    GNU make - How to concatenate to variable depending on shell command result (GCC version)?

  9. 9

    Use the output of a shell command as a variable

  10. 10

    Assign output of a shell command to a variable

  11. 11

    How to output a shell command into a variable?

  12. 12

    Use make variable in builtin shell function in a Makefile

  13. 13

    Makefile: set the environment variables output by a command

  14. 14

    GNU Make - how to add timestamp output (with minimal makefile modification)

  15. 15

    How can I stop the Z shell from conspiring to tamper with the output of GNU Make?

  16. 16

    How to set proper values for -L and -l in make from a command output

  17. 17

    Run a command in GNU and BSD Makefile and store the result into a variable

  18. 18

    Run a command in GNU and BSD Makefile and store the result into a variable

  19. 19

    imitate "make -j" from within the Makefile

  20. 20

    How to set a variable equal to the output from a command in GRUB2?

  21. 21

    makefile.am variable to set some libs after object files in make command

  22. 22

    makefile.am variable to set some libs after object files in make command

  23. 23

    How to use echo in shell command from Makefile?

  24. 24

    Set an environment variable within a shell alias

  25. 25

    storing error message of command output into a shell variable

  26. 26

    Grunt-shell save command output as variable

  27. 27

    How to assign a variable the output of a shell command in Tupfile?

  28. 28

    storing the output of ls command in a shell variable

  29. 29

    Set a variable from within a rule

HotTag

Archive