Export makefile variable with dollar sign - makefile

I have two makefiles and I want to pass from Makefile1 a variable to Makefile2.
The problem is that this variable have a $ inside of it.
Here is the files:
# Makefile1
RPATH1 = 12\$$34
export RPATH1
all:
#echo RPATH1 "(Makefile1)" $(RPATH1)
#make -f Makefile2 RPATH2=$(RPATH1)
# Makefile2
all:
#echo RPATH1 "(Makefile2)" $(RPATH1)
#echo RPATH2 "(Makefile2)" $(RPATH2)
When I run it, I get:
$ make -f Makefile1
RPATH1 (Makefile1) 12$34
make[1]: Entering directory '/tmp/make'
RPATH1 (Makefile2) 124
RPATH2 (Makefile2) 124
make[1]: Leaving directory '/tmp/make'
I want to have a way to Makefile2 print 12$34 too.
What I may do?
Edit: I have discovered some way, but it's not very consistent. Usage in first Makefile is different than in second one.
# Makefile1
RPATH1 := '12$$$$34'
export RPATH1
all:
#echo RPATH1 "(Makefile1)" $(RPATH1)
#make -f Makefile2 RPATH2="$(RPATH1)"
#make -f Makefile2 RPATH2="'12\$$\$$34'"
# Makefile2
all:
#echo RPATH1a "(Makefile2)" $(value RPATH1)
#echo RPATH2a "(Makefile2)" $(RPATH2)
#echo RPATH2b "(Makefile2)" $(value RPATH2)
$ make -f Makefile1
RPATH1 (Makefile1) 12$$34
make[1]: Entering directory '/tmp/make'
RPATH1a (Makefile2) 12$$34
RPATH2a (Makefile2) 12151308134
RPATH2b (Makefile2) 12151308134
make[1]: Leaving directory '/tmp/make'
make[1]: Entering directory '/tmp/make'
RPATH1a (Makefile2) 12$$34
RPATH2a (Makefile2) 12$34
RPATH2b (Makefile2) 12$$34
make[1]: Leaving directory '/tmp/make'

Here's a solution for passing variables manually:
override quote = '$(subst ','"'"',$1)'
all:
#make -f Makefile2 RPATH2=$(call quote,$(value RPATH1))
Also, it's weird to see backslashes and quotes in Make variable definitions (in RPATH1).
Make itself ignores them, they're interpreted by the shell when printing the variable.
You might want to use $(info ) instead of echo, which doesn't escaping. Or use my $(call quote, ) when printing, to properly escape the contents.
Could you put a complete example?
Sure.
# Makefile1
RPATH1 = 12\$$34'
override quote = '$(subst ','"'"',$1)'
all:
$(info RPATH1 "(Makefile1)" $(RPATH1))
#make -f Makefile2 RPATH2=$(call quote,$(value RPATH1))
# Makefile2
all:
$(info RPATH2 "(Makefile2)" $(RPATH2))
#true
$ make -f Makefile1
RPATH1 "(Makefile1)" 12\$34'
make[1]: Entering directory '...'
RPATH2 "(Makefile2)" 12\$34'
make[1]: Leaving directory '...'

Related

Dollar in conditional variable assignment operator in Makefile

Is it possible to pass value with single dollar from shell to Makefile, or I it is only way to put double dollar in bash and then to call make?
Makefile is:
HASH ?= $$6$$salt$$val
.PHONY: tst
tst:
echo '$(HASH)'
Command to run:
> make HASH='$6$salt$val'
echo 'altal'
altal
If I use double quotes, all is fine:
> make HASH='$$6$$salt$$val'
echo '$6$salt$val'
$6$salt$val
But is it possible do not make substitution $ to $$ in bash?
How about writing the initialisation within the file identical to the one coming from the command line? The below script demonstrates how to rewrite a variable with the override directive:
quote-one-level = $(eval override $1=$(subst $,$$$$,$(value $1)))
var-info = $(info $1=$(value $1) flavour=$(flavor $1) origin=$(origin $1))
A ?= $abc
$(call var-info,A)
$(call quote-one-level,A)
$(call var-info,A)
$(call var-info,B)
$(call quote-one-level,B)
$(call var-info,B)
export A
export B
all:
#echo A = '$(A)'
#echo B = '$(B)'
ifeq ($(MAKELEVEL),0)
$(MAKE)
endif
Inflating one $ to $$$$ (and not just $$) is necessary because the eval command literally generates make code, thereby obviously reducing the quoting level by one. Resulting output:
$ make B='$abc'
A=$abc flavour=recursive origin=file
A=$$abc flavour=recursive origin=override
B=$abc flavour=recursive origin=command line
B=$$abc flavour=recursive origin=override
A = $abc
B = $abc
make
make[1]: Entering directory
A=$abc flavour=recursive origin=environment
A=$$abc flavour=recursive origin=override
B=$abc flavour=recursive origin=command line
B=$$abc flavour=recursive origin=override
A = $abc
B = $abc
make[1]: Leaving directory
Try this:
In console:
export HASH='$6$salt$val'; make
in Makefile:
.PHONY: tst
tst:
#echo "$$HASH"
Result:
$6$salt$val

Suppress make warning from not-yet-built include without suppressing error

If I have a makefile
include foo
foo: Makefile
#echo 'bar::' > foo
#echo "\t#echo 'bar'" >> foo
bar::
#echo 'baz'
then when I run make bar, I get
Makefile:1: foo: No such file or directory
bar
baz
I want to suppress this warning. If I have a makefile
-include foo
foo: Makefile
#echo 'bar::' > foo
#echo "\t#echo 'bar'" >> foo
bar::
#echo 'baz'
then I get, as expected,
bar
baz
However, if I have a makefile
-include foo
bar::
#echo 'baz'
and I run make bar, then I get
baz
while I would instead like to get something like
Makefile:1: foo: No such file or directory
make: *** No rule to make target 'foo'. Stop.
or at least
make: *** No rule to make target 'foo'. Stop.
How do I suppress the warning without suppressing the error, so that I get a failure if the file cannot be created / if the target does not exist, but no spew when it is successfully created?
This is a hackish solution: You could split your makefile into two like so:
# Makefile
foo.mak:
#echo running $#
#echo 'bar::' > foo.mak
#echo -e "\t#echo 'bar'" >> foo.mak
bar bar2 bar3: foo.mak
#$(MAKE) --file Makefile.2 $#
and then
#Makefile.2:
include foo.mak
bar::
#echo baz
The problem with this is that it has to invoke a new copy of make for each top-level target. I seem to remember using a match-anything rule instead of a list of explicit targets, but I just tried it, and it seems to be giving me problems, so I listed the targets explicitly.
I have discovered an extremely hacky solution, that involves emitting the error message manually:
-include foo
ifeq (,$(filter-out foo,$(MAKECMDGOALS)))
ifeq (,$(wildcard foo))
$(shell $(MAKE) foo)
ifeq (,$(wildcard foo))
$(error No rule to make target 'foo')
endif
endif
endif
foo: Makefile
#echo 'bar::' > foo
#echo "\t#echo 'bar'" >> foo
bar::
#echo 'baz'
Perhaps an ever-so-slightly-less-hacky solution would be:
ifeq (,$(filter-out foo,$(MAKECMDGOALS)))
ifeq (,$(wildcard foo))
$(shell $(MAKE) foo)
endif
include foo
else
-include foo
endif
foo: Makefile
#echo 'bar::' > foo
#echo "\t#echo 'bar'" >> foo
bar::
#echo 'baz'

Dynamically generating a list of targets

If a file exists, I want to add a target to build. If the file does not exist, I want the target to be skipped.
an example:
FILENAME = f
TARGETS := normal
ifneq($(shell stat test_$(FILENAME).c), "")
TARGETS += test
endif
all: $(TARGETS)
normal:
#echo normal
test:
#echo test
I'm not sure the $(shell stat ...) part even works, but the bigger problem is that make with any file test_f.c in the current folder gives:
Makefile:4: *** multiple target patterns. Stop.
Removing the ifneq ... endif block makes the target normal. How can I only run the target test if test_f.c exists?
What you can do is generate a string variable (let's call it OPTIONAL) such that when 'test_f.c' exists, OPTIONAL=test; otherwise, OPTIONAL=_nothing_. And then add OPTIONAL as a prerequisite of all. e.g.:
FILENAME = f
TARGETS = normal
OPTIONAL = $(if $(wildcard test_f.c), test, )
all: $(TARGETS) $(OPTIONAL)
normal:
#echo normal
test:
#echo test
You can also iterate over targets with for loop
.PHONY: all
RECIPES = one
all: RECIPES += $(if $(wildcard test_f.c), two, )
all:
for RECIPE in ${RECIPES} ; do \
$(MAKE) $${RECIPE} ; \
done
one:
$(warning "One")
two:
$(warning "Two")
> make
for RECIPE in one ; do \
/Applications/Xcode.app/Contents/Developer/usr/bin/make ${RECIPE} ; \
done
makefile:11: "One"
make[1]: `one' is up to date.
> touch test_f.c
> make
for RECIPE in one two ; do \
/Applications/Xcode.app/Contents/Developer/usr/bin/make ${RECIPE} ; \
done
makefile:11: "One"
make[1]: `one' is up to date.
makefile:14: "Two"
make[1]: `two' is up to date.

Gnu Make target out of expanded list of files

I am grouping some type of files like:
https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html
about 100 sub directories...
CC_FILES_TO_BUILD += $(wildcard $(SRC_DIR)/01-Application/*.c)
ASM_FILES_TO_BUILD += $(wildcard $(PROJECT_ROOT)/01-Sources/07-Target/01-MC9S12G/04-STARTUP/01-CPL_LIB/*.s)
When I dump for example CC_FILES_TO_BUILD per rule, I get nice lists of files names:
E:\1983_1\02-Safety>make dump-CC_FILES_TO_BUILD
make[1]: Entering directory `E:/1983_1/02-Safety/01-Application'
E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/01-INIT/app_init.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Applicat
ion/02-MAIN/app.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/03-FM/fm.c E:\1983_1\02-Safety\01-Application/01-Sources//01
-Application/05-SMCM/SMCM.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/06-LIM/LIM.c E:\1983_1\02-Safety\01-Application/0
1-Sources//02-Services/01-CanM/can_user.c E:\1983_1\02-Safety\01-Application/01-Sources//02-Services/01-CanM/v_par.c E:\1983_1\02-Safety\01-
Application/01-Sources//02-Services/01-CanM/vstdlib.c E:\1983_1\02-Safety\01-Application/01-Sources//02-Services/01-CanM/sip_vers.c ...
......make[1]: Leaving directory `E:/1983_1/02-Safety/01-Application'
I then build new lists out these by normal subst to get the corresponding lists of depend and obj files, like:
CC_TO_MAK_BUILD_LIST = $(call unique, $(foreach src,$(CC_FILES_TO_BUILD ),
$(DEP_PATH)\$(basename $(notdir$(subst,\,/,$(SRC)))).$(MAK_FILE_SUFFIX)))
I then want to use these depend and obj lists as targets in rules like:
$(filter-out $(GCC_IGNORE_LIST), $(CC_TO_MAK_BUILD_LIST)) :$(DEP_OUTPUT_PATH)\\%.$(MAK_FILE_SUFFIX):$(DEPEND_FORCE) | $(DEPEND_CPP_OPTIONS_FILE) $(DIRECTORIES_TO_CREATE)
$(SEPARATOR) [depend] $(notdir $#)
$(CPP) #$(DEPEND_CPP_OPTIONS_FILE) -undef -MM -MF "$#" -MT "$(call depend_get_target,$#)" -MT "$#" "$(getSourceFile)"
Then the target depend:
depend: $(LIB_TO_MAK_BUILD_LIST) $(CC_TO_MAK_BUILD_LIST) | $(DEPEND_CPP_OPTIONS_FILE) $(DIRECTORIES_TO_CREATE)
and the output:
E:\1983_1\02-Safety\01-Application>make depend
* [build] depend.cpp_options
E:\1983_1\02-Safety\01-Application>
apparently nothing to be done although the dependcies files(*.mak) are not there. No force or phony could solve it for me.

make: Error in ifneq: word unexpected (expecting ")")

I would like to create a makefile for LaTeX documents (in this minimal
example). When there is no file "makeindexstyle.ist", it should be created (by
running make makeindexstyle.ist) and used for formatting the index. The rule for
%.pdf reflects this. However, it is not working yet, I receive the error
ifneq (, ) {
/bin/sh: 1: Syntax error: word unexpected (expecting ")")
make: *** [master.pdf] Error 2
What's wrong?
Parts from Makefile:
MASTER = master
TEX = slave
TEXI = texi2dvi -p
all: $(MASTER:=.pdf)
%.pdf: %.tex $(TEX:=.tex)
ifneq ($(wildcard makeindexstyle.ist), ) { # if makeindexstyle.ist exists, compile and build index
$(TEXI) $<
make makeindexstyle.ist
makeindex -c -s makeindexstyle.ist $(MASTER:=.idx)
}
endif
$(TEXI) $<
makeindexstyle.ist:
#(echo "...") > makeindexstyle.ist
UPDATE:
I tried to make it as simple as possible to see where the error comes from. Among other things (like quoting), I tried this:
%.pdf: %.tex $(TEX:=.tex)
exist := $(wildcard "absolute-path-to-makeindexstyle.ist")
ifneq ($strip $(exist)),)
echo "foo"
endif
$(TEXI) $<
but the result is
exists :=
make: exists: Command not found
make: *** [book.pdf] Error 127
In the meanwhile, I could solve it on the shell side:
IDX = "makeindexstyle.ist"
%.pdf: %.tex $(TEX:=.tex)
#if test -f $(IDX); then \
echo "foo"; \
fi
$(TEXI) $<
This sounds like a duplicate of How do I check if file exists in Makefile? or How to conditional set up a Makefile variable by testing if a file exists.
Try
ifneq ($(wildcard makeindexstyle.ist),)
without the space. Alternatively, throw "" around the arguments?

Resources