Makefile : assigning function variable in target command line - makefile

I need the xpi_hash variable to be assigned only when update target's command is decided to execute. Then I'm using this variable as environment, exporting, etc..
If I put it outside of rule, it will be expanded firstly, before $(xpi) target is called, hence will not find that file.
substitute := perl -p -e 's/#([^#]+)#/$$ENV{$$1} bla bla...
export xpi_hash
.PHONY: dirs substitute update
update: $(xpi) $(target_update_rdf)
xpi_hash := $(shell sha1sum $(xpi) | grep -Eow '^[^ ]+')
#echo "Updating..."
$(target_update_rdf): $(update_rdf)
$(substitute) $< > $#
and above of course is not correct, because for command part the shell is represented. So maybe another way to put this question is - how to bring variable as command output?

I'm not sure exactly what you're looking for here, how are you planning to use xpi_hash? If you want to get the current hash every time you use the variable use = to assign the variable instead of :=, e.g.
xpi_hash=$(shell sha1sum $(xpi) | grep -Eow '^[^ ]+')
update:$(xpi) $(target_update_rdf)
#echo $(xpi_hash)
will print the hash of xpi after it has been updated.
For variables in make, see section 6.2 of the manual. Briefly ':=' will expand variables on the right hand side, '=' will leave them to be expanded later.
The altered command in my comment (substitute = xpi_hash="$(xpi_hash)" perl -p -e 's/#([^#]+)#/$$ENV{$$1}...') will expand to be equivalent to
$(substitute)
xpi_hash="$(xpi_hash)" perl -p -e 's/#([^#]+)#/$$ENV{$$1}...'
xpi_hash="`sha1sum $(xpi) | grep -Eow '^[^ ]+'`" perl -p -e 's/#([^#]+)#/$$ENV{$$1}...'
xpi_hash="`sha1sum xpi_expansion | grep -Eow '^[^ ]+'`" perl -p -e 's/#([^#]+)#/$$ENV{$$1}...'
The xpi_hash="..." syntax is defining a variable in the bash subshell, rather than using the variable in make.

If only substitute must use xpi_hash, make xpi_hash a target-specific variable:
$(target_update_rdf): xpi_hash = $(shell ...)
$(target_update_rdf): $(update_rdf)
$(substitute) $< > $#
If other Perl scripts will need xpi_hash, and you want to export it, you have a problem, because the variables assigned in the subshells of a rule cannot (easily) be communicated to Make. But you can store it in a file and include it:
xpi_hash_file: $(xpi)
rm -f $#
echo xpi_hash = $(shell...) > $#
-include xpi_hash_file

Related

Rewrite rule printout in make file

I am currently using a makefile for cocotb, similar to this.
That consists of a bunch of variable definitions followed by and
include $(shell cocotb-config --makefiles)/Makefile.sim
Where the final commands will be executed.
I run it in Visual studio code, the simulator output message format is (%file,%line|%column). I want them to be shown as (%file:%line:%col). I can easily do it piping the output to sed.
make MODULE=x TESTCASE=y | sed -e 's/,\([0-9]\+\)|\([0-9]\+\)):/:\1:\2):/g'
I was expecting to be able to change the make file so that the output will be edited before shown
Something like
...
.DEFAULT:
make -C $PWD -f $(shell cocotb-config --makefiles)/Makefile.sim \
(all variables/environment) (rule) \
| sed -e 's/,\([0-9]\+\)|\([0-9]\+\)):/:\1:\2):/g
Where "magic rule" would apply the specified rule and pipe its output to sed.
How can I achieve this?
Thank you.
Given your example, it seems like the .DEFAULT target would do what you want:
.DEFAULT:
$(MAKE) -f $$(cocotb-config --makefiles)/Makefile.sim $# \
| sed -e 's/,\([0-9]\+\)|\([0-9]\+\)):/:\1:\2):/g
Edit (from the OP)
The default works when the rule is given, e.g. if I invoke make sim instead of make. For this I can create a default-delegate rule.
More importantly, I have to pass all the variables to the sub make, that can be achieved by using export by itself.
Then, replacing the include command but the following snippets, works for the more common cases.
export
default-delegate: sim
.DEFAULT:
$(MAKE) -f $$(cocotb-config --makefiles)/Makefile.sim $# \
| sed -e 's/,\([0-9]\+\)|\([0-9]\+\)):/:\1:\2):/g'

how to avoid variable expansion for a bash for loop in define makefile

Usually, I use foreach call in a makefile. Notwithstanding, I wanted to try different approaches.
For that, I have created the code bellow.
I am using GNU Make 3.81
I have replaced the eval by info to understand what is happening.
I cannot avoid both the call and the eval expansion to keep the $file
I mean, when I open the file I am getting:
"for file in *.v; do echo ; echo ; done; > trial.sh;"
define create_area
$(1): $(2)
mkdir -p $$(#D); \
cp -nLr -v $(2)/* $$(#D); \
cd $$(#D); \
for file in *.v; do echo $$(file); \
done; \
" > trial.sh;
$(foreach a,$(A1) $(A2),\
$(foreach b,$(B1),\
$(eval $(call create_area,$(a),$(b)))))
Thank you in advance,
You're almost there.
If you run the loop in a shell, you must precede the variable name with '$' so that it will be expanded.
If you put that command in a makefile recipe, to prevent Make from expanding the variable name too soon (when the variable has not yet been given a value) you must precede ("escape") that '$' with another '$'.
If you put that recipe in a definition which you will expand with call, you must double each of them:
for file in *.v; do echo $$$$file; done

makefile use variable defined in target [duplicate]

This question already has answers here:
Define make variable at rule execution time
(4 answers)
Closed 4 years ago.
How can one use the variable defined inside a make target
.PHONY: foo
VAR_GLOBAL=$(shell cat /tmp/global)
foo:
echo "local" > /tmp/local
VAR_LOCAL=$(shell cat /tmp/local)
echo ${VAR_GLOBAL}
echo ${VAR_LOCAL}
here is the execution output:
$ echo global > /tmp/global
$ make foo
echo "local" > /tmp/local
VAR_LOCAL=local
echo global
global
echo
As #KelvinSherlock pointed out this is a duplicate of another question
here is the specific solution for my question:
.PHONY: foo
VAR_GLOBAL=$(shell cat /tmp/global)
foo:
echo "local" > /tmp/local
$(eval VAR_LOCAL := $(shell cat /tmp/local))
echo ${VAR_GLOBAL}
echo ${VAR_LOCAL}
You probably want to use the override directive in a target-specific variable assignment, so try:
foo: override LS_LOCAL=$(shell ls /var | tail -1)
echo ${LS_GLOBAL}
echo ${LS_LOCAL}
If LS_LOCAL is never defined (even by builtin-rules) you might not need the override keyword.
BTW, you might avoid $(shell ls /var | tail -1) by using the wildcard function combined with the lastword function (perhaps combined with notdir function), so you might code $(lastword $(wildcard /var/*)) or $(notdir $(lastword $(wildcard /var/*))) instead . However, beware of the order of expansion, and of filenames with spaces. At last the shell function probably uses your $PATH variable (so strange things could happen if some weird ls program appears there before /bin/ls). Perhaps using $(shell /bin/ls /var | /usr/bin/tail -1) might be better.
Look also into Guile-extended make; consider perhaps some other build-automation tool like ninja and/or generating your Makefile (or other build configuration) with something like a configure script generated via autoconf or cmake.
Notice also that a command in recipe can be made of several physical backslashed lines (hence executed in the same shell). Maybe you might consider something like
export MY_VAR=$$(ls /var | tail); \
dosomething; \
use $$MY_VAR
inside some recipe.

How do I concat a system call in a Makefile?

I want to concatenate a string inline with a system call. I cannot use an intermediate variable to hold the result because this makefile is autogenerated by qmake (which removes all user variables).
test:
cp foo.exe $(system echo -n "foo`echo you`.exe")
Later I will replace echo you with a more complicated command, but this doesnt work as is.
I'm not sure where system comes from; that's not a valid function in GNU make.
Maybe you mean shell?
test:
cp foo.exe $(shell echo -n "foo`echo you`.exe")

How can I pass all command line arguments to a program in a Makefile?

I can do:
all:
$(CC) -DFOO=$(FOO) -DBAR=$(BAR) main.c
And call it with:
make FOO=foo BAR=bar
But I want a more generic solution in a way that I don't have to write ALL possible variables in the compiler call line. I know, for example, that MAKECMDGOALS variable has all targets from the command line. There is any MAKECMDVARS-like variable that contains all variables from command line? So I could do something like this:
CONFIGS = $(addprefix -D, $(MAKECMDVARS))
all:
$(CC) $(CONFIGS) main.c
In my opinion this is a bad idea. It will break everyone's understanding of how make works, and it will mean you can't use variable overrides for their intended purpose. What if you want to change CC for just a single build using make? Or CFLAGS? Or some other variable?
However, if you really want to do it you can: all variables assigned on the command line are put into the -*-command-variables-*- variable:
$ echo 'all: ; #echo variables: $(-*-command-variables-*-)' | make -f-
variables:
$ echo 'all: ; #echo variables: $(-*-command-variables-*-)' | make -f- FOO=foo BAR=bar
variables: BAR=bar FOO=foo

Resources