0

I am trying to create a file and set the contents of a file to a variable but the variable is always seen as empty.

An example:

define FILE_VAR
    cat /output/1.txt >> /output/2.txt
    $(eval s := $(shell cat /output/2.txt)) 
    $(eval FILENAME_BIN=$(word 1, $(s)).$(word 2, $(s)).$(word 3, $(s)).bin) 
    $(eval FILENAME_JFFS2=$(word 1, $(s)).$(word 2, $(s)).$(word 3, $(s)).jffs2)        
endef

If 2.txt exists before running this the variables will be set to the data prior to running make (not the new redirected data), if 2.txt doesn't exist then the variables are not set. It looks like it is evaluating what the file is like when make is first run, which is not what I want...

Paul
  • 5,756
  • 6
  • 48
  • 78
  • Isn't this mostly a duplicate of [your earlier post](http://stackoverflow.com/questions/41570930/using-eval-in-make-file)? Several comments made on that post apply to this one. Posting a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) is highly recommended indeed. – Come Raczy Jan 12 '17 at 18:35

1 Answers1

2

You are unclear as to what is done by GNU make, and when, and what is done by the shell, and when, to execute a recipe.

Anything anywhere in a makefile of the form $(...) is evaluated by make unless it escaped as $$(...) in a shell command.

A shell command, unless in the context of the make-function $(shell ...) or back-ticks can only be a command within a recipe:

target: [prerequisite...]
    command
    ...

The commands composing a recipe are executed in sequence, each in a distinct shell, to execute the recipe.

Nothing of the unescaped form $(...) is a command in the command-sequence of a recipe unless it is the expansion of a variable or macro you have defined that expands to a command.

A line in the scope of a target need not be a command or expand to a command. It may also consist of an $(...) expression that expands to nothing, and simply instructs make to do something, e.g.

$(info ...)

expands to nothing and tells make to print ... on the standard output.

$(eval ...)

expands to nothing and tells make to evaluate ...

This recipe has just two commands, not four:

target: prereq...
    $(eval TARGET=$@)
    command1
    $(info $(TARGET))
    command2

Any make-expressions, $(...) in the scope of a recipe are evaluated in sequence when make decides to run the recipe and the command-sequence is what is left after they have all been evaluated. Then the command-sequence is run. For example:

Makefile

target:
    echo Hello > hello.txt
    $(info Begin {)
    $(eval s := $(shell cat hello.txt)) 
    $(eval WORD=$(word 1, $(s)))
    $(info [$(WORD)])
    $(info } End)

Run that:

$ make
Begin {
cat: hello.txt: No such file or directory
[]
} End
echo Hello > hello.txt

Observe that all of the make-expressions are evaluated before the commands of the target are run.

Your FILE_VAR macro is evidently intended to be expanded in recipe scope, since the first line is a shell command. The remaining lines must therefore achieve their purposes by shell commands if they depend upon the the effects of running the first line. None of them does so. The remaining 3 lines are evaluated before 2.txt exists, if it doesn't already exist at make-time.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
  • Thanks Mike, great answer. Never used make before so it was very informative. What I mainly take from ti to solve my problem is that the Make evaluates the expressions before I desire them to, so should do everything via shell. This is also why if my file does exist at make-time and is changed, I am reading the old values in the file. – Paul Jan 13 '17 at 08:55
  • Yes. It is nearly always right to make a recipe of lines that are shell commands or expand to shell commands after expansion of the ordinary, global make-variables and macros. Cases in which [`$(eval ...)`](https://www.gnu.org/software/make/manual/html_node/Eval-Function.html) is serviceable within a recipe are unusual. See [How make Reads a Makefile](https://www.gnu.org/software/make/manual/html_node/Reading-Makefiles.html) and in general consult the [manual](https://www.gnu.org/software/make/manual/make.html) for guidance. – Mike Kinghan Jan 13 '17 at 09:10