3

I have a makefile from which i am trying to invoke an executable, the executable needs 5 arguments, how do i pass these arguments from makefile

doing this does not works

run-exe:
  arg1 = "somevalue"
  arg2 = "somevalue"
  arg3 = "somevalue"
  arg4 = "somevalue"
  arg5 = "somevalue"
  $(ExeFolderPath)/Task $(arg1) $(arg2) $(arg3) $(arg4) $(arg5)

the arguments are getting ignored.

Pharaoh
  • 712
  • 1
  • 9
  • 33
  • Possible duplicate of [Passing additional variables from command line to make](https://stackoverflow.com/questions/2826029/passing-additional-variables-from-command-line-to-make) – Andrew Diamond Feb 07 '18 at 12:18
  • 1
    No, I think it's not a duplicate of that question. This is about how to set variables in a recipe that can be used later in the recipe, not how to pass in arguments from outside the makefile. (I'm sure it's a duplicate of _another_ question, as this has definitely been asked before). – Jonathan Wakely Feb 07 '18 at 12:31

2 Answers2

3

The commands in a makefile recipe are executed by the shell, not by Make, and each line is executed in a new shell subprocess, so variables defined on previous lines are no longer defined after that line (unless you use .ONESHELL as shown in this answer).

So you cannot set Make variables there, and then use them like $(arg1) later. You need to set shell variables (with no space around the =) and refer to them using shell variable syntax, i.e. $arg1 or ${arg1}, but you need to escape the $ signs so that Make doesn't try to interpret them itself, i.e. use $$arg1 or $${arg1}.

With your attempt you are trying to refer to Make variables called $(arg1) and $(arg2) but those were never defined in the Makefile, so they expand to nothing, and no arguments are passed.

Furthermore, each line of the make recipe is executed in a separate shell process, so the way you wrote it, make creates a new shell subprocess, sets arg1="somevalue" and then that shell process exits (so the variable definition is lost). Then it starts a new shell, sets another variable, then exits that shell etc.

Setting the variables and using them needs to happen in a single shell process, which can be done using .ONESHELL if you are using GNU Make version 3.82 or later. For other versions of Make, another way to ensure that the variable definitions and the uses are all in the same shell process is to put them all on one line:

run-exe:
  arg1="somevalue" ; arg2="somevalue" ; arg3="somevalue" ; arg4="somevalue" ; arg5="somevalue" ; $(ExeFolderPath)/Task $$arg1 $$arg2 $$arg3 $$arg4 $$arg5

But this is hard to read, so you can keep them on separate lines but use backslashes so that make still treats them as a single line and runs them in the same shell process:

run-exe:
  arg1="somevalue" ; \
  arg2="somevalue" ; \
  arg3="somevalue" ; \
  arg4="somevalue" ; \
  arg5="somevalue" ; \
  $(ExeFolderPath)/Task $$arg1 $$arg2 $$arg3 $$arg4 $$arg5
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
2

Each line in the recipe of the run-exe rule runs in a different shell instance. So, if you set a variable in one line, that assignment won't have any effect for the next line, because that next line runs in a new shell instance.

You can however keep your approach by defining the .ONESHELL-target in order to get all the lines (commands) of a recipe executed in a single shell:

.ONESHELL:
run-exe:
  arg1="somevalue"
  arg2="somevalue"
  arg3="somevalue"
  arg4="somevalue"
  arg5="somevalue"
  $(ExeFolderPath)/Task $$arg1 $$arg2 $$arg3 $$arg4 $$arg5

Note that there shouldn't be spaces around the =, since those variable assignment are run by the shell, not make.

Also note that the $ should be escaped for the shell variables (i.e.: $$ instead of $).


You are going to need GNU Make 3.82 (or newer) in order to use .ONESHELL.

JFMR
  • 23,265
  • 4
  • 52
  • 76