Two assignments on same line in GNU makefile - makefile

A certain makefile (namely, the otherlibs/num/Makefile in the OCaml 4.2 distribution) has the following line :
EXTRACFLAGS=-DBNG_ARCH_$(BNG_ARCH) -DBNG_ASM_LEVEL=$(BNG_ASM_LEVEL)
I am surprised to see two assignments on the same line here. What does it mean ? Is it the same as
EXTRACFLAGS=-DBNG_ARCH_$(BNG_ARCH)
-DBNG_ASM_LEVEL=$(BNG_ASM_LEVEL)
I did not find anything about that in the GNU make manual, maybe I am unaware of the right keyword to search this.

There are not two assignments here. The line assigns the definition:
-DBNG_ARCH_$(BNG_ARCH) -DBNG_ASM_LEVEL=$(BNG_ASM_LEVEL)
to the make variable EXTRACFLAGS. The value appears to consist
of flags that are to be passed to some invocation of the C preprocessor to
define macros BNG_ARCH_$(BNG_ARCH) and BNG_ASM_LEVEL. E.g. as
in a make recipe:
$(CPP) $(EXTRACFLAGS) ...
Which, supposing the make assignments:
BNG_ARCH = foo
BNG_ASM_LEVEL = bar
would expand to:
cpp -DBNG_ARCH_foo -DBNG_ASM_LEVEL=bar ...
OP comments:
So you might say that = is "left-associative", the leftmost = sign is the one that really gets executed. Is this documented somewhere in the manual?
From my frequent, but far from exhaustive resorts to manual I can't say it is documented. Somebody
may know better. There is no formal grammar there, but it is everywhere illustrated that the definition of a variable extends from the
start of the non-whitespace text following =, := or ?= to the end of the (possibly \-extended)
logical line. You may satisfied on the point by running the makefile:
.PHONY: all
x = X y = Y
all:
#echo [$(x)]
#echo [$(y)]
which prints:
[X y = Y]
[]
Assignment signs within a make-definition are not assignments, they're just characters in the definition.

Related

What is the meaning of $(Q)#: in Makefile

I've read in linux Makefile:
$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
$(Q)#:
What is the meaning of $(Q)#:?
I'm trying to google it, but google always crappy if the search using some weird character. So in the end i can't found any Manual about it.
After looking in the code. Q is defined somewhere after those line. Since makefile have peculiar concept of variable (which is expandable), it can be implement in anywhere. Q is used to whether show message or not (Q maybe for Quiet).
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = #
endif
And for the last #: this means do-nothing-output-nothing.
So the conclusion $(Q)#: simply do-nothing-output-nothing.
To reinforce and expand on what nafsaka found:
Sometimes Makefiles are written like this:
target:
rm -rf $(DIRECTORY)
$(Q)$(MAKE) all
And Q will be defined as # or nothing for example:
V ?= 0
ifeq ($(V), 0)
Q = #
else
Q =
endif
If a target action is preceded by # then make won't display it when run. Here's the GNU make documentation on that subject: Recipe Echoing
In this case you need to define V=1 before running make to see commands as they're run (This is very common).
Another wrinkle: Look for "include file.mk" statements in your Makefile, which is where V and Q were defined in my case. Here's the GNU make documentation on include: Including Other Makefiles
From the Make manual:
5.2 Recipe Echoing
Normally make prints each line of the recipe before it is executed. We call this echoing because it gives the appearance that you are typing the lines yourself.
When a line starts with ‘#’, the echoing of that line is suppressed. The ‘#’ is discarded before the line is passed to the shell. Typically you would use this for a command whose only effect is to print something, such as an echo command to indicate progress through the makefile:
#echo About to make distribution files
When make is given the flag ‘-n’ or ‘--just-print’ it only echoes most recipes, without executing them. See Summary of Options. In this case even the recipe lines starting with ‘#’ are printed. This flag is useful for finding out which recipes make thinks are necessary without actually doing them.
The ‘-s’ or ‘--silent’ flag to make prevents all echoing, as if all recipes started with ‘#’. A rule in the makefile for the special target .SILENT without prerequisites has the same effect (see Special Built-in Target Names).

How to override a target-specific variable from the command-line?

Given a makefile, with a target-specific defintion:
# A target-specific definition for both: 'all' and 'x'.
all : foo += target
x : foo += target
all : x ;
x ::
#echo '$(foo)'
Running, I get:
# override Makefile-level variables, with a command-line definition.
$ make foo=cmd
cmd
Now, the same makefile, as above, but with a pattern-specific defintion:
# A pattern-specific definition that matches both targets: 'all' and 'x'.
% : foo += target
all : x ;
x ::
#echo '$(foo)'
Running, I get:
# override Makefile-level variables, with a command-line definition.
$ make foo=cmd
cmd cmd cmd
Now, both makefiles are almost identical, except that:
For version 1 of Makefile: (With target-specific definition), we had:
all : foo += target
x : foo += target
For version 2 of Makefile (With pattern-specific definition), we had:
% : foo += target
In both cases, we had basically the same configuration:
A pattern/target definition that appends to a previous value.
The pattern/target definition applies both to all and x targets.
We had a command-line definition that is suppose to override the makefile-level definition.
Now, interpreting or implementing that override, Make uses a very different methodology, for version 1 (target definition) than version 2 (pattern definition).
Let's see:
For target definition, Make completely ignores ANY value defined in the makefile. Hence, the final value is: cmd.
For pattern definition, however, Make comes up with "conciliatory" approach, trying to satisfy both, the makefile-level definition and the command-line defintion, so it:
Accepts that the final value is cmd, per the command-line that overrides the makefile definition.
But, because the makefile implies that the "patterns" are supposed to "append" additional values - never mind that those same values had been overridden - Make will still "obey" those appends, but it will done with different values (i.e. the "winning" command-line value), thereby reaching a "compromise" where nor does the makefile, or the command-line have sole control over the final value of the variable.
Well, these different approaches that Make takes to implement a command-line override, (per pattern vs target specific variables), is even more obvious when we expect the very different final results we get for them, respectively:
cmd (for target-specific).
cmd cmd cmd (for pattern-specific).
Is this justified? And how so?
This appears to be a minimal complete example:
%: foo += targ
x:
#echo $(foo)
Invoked as make foo=cmd (using GNUMake v3.81), this produces
cmd cmd
This looks like a bug to me. According to the manual:
Variables provided on the command line (and in the environment if the
‘-e’ option is in force) will take precedence [over target-specific variables].
So the += statement should have no effect. But apparently if the assignment is in a pattern rule, the command-line value overrules the value which the rule tries to append, but not the act of appending it, so that Make appends $(foo) to itself.

Trailing comments after variable assignment subvert comparison

In GNU make, trailing comments appended to variable assignments prevent subsequent comparison (via ifeq) from working correctly.
Here's the Makefile...
A = a
B = b ## trailing comment
C = c
RESULT :=
ifeq "$(A)" "a"
RESULT += a
endif
ifeq "$(B)" "b"
RESULT += b
endif
ifeq "$(C)" "c"
RESULT += c
endif
rule:
#echo RESULT=\"$(RESULT)\"
#echo A=\"$(A)\"
#echo B=\"$(B)\"
#echo C=\"$(C)\"
Here's the output...
$ make
RESULT=" a c"
A="a"
B="b "
C="c"
As you can see from the displayed value of RESULT, the ifeq was affected by the presence of the comment in the assignment of B. Echoing the variable B, shows that the problem is not the comment, but the intervening space.
The obvious solution is to explicitly strip the whitespace prior to comparison like so...
ifeq "$(strip $(B))" "b"
RESULT += b
endif
However this seems error prone. Since the strip operation is not needed unless/until a comment is used, you can leave out the strip and everything will initially work just fine -- so chances are you won't always remember to add the strip. Later, if someone adds a comment when setting the variable, the Makefile no longer works as expected.
Note: There is a closely related issue, as demonstrated in this question, that trailing whitespace can break string compares even if there is no comment.
Question: Is there a more fool-proof way to deal with this issue?
This is not something particular to GNU Make; rather, make is defined by POSIX to work this way:
string1 = [string2]
The macro named string1 is defined as having the value of string2, where string2 is defined as all characters, if any, after the <equals-sign>, up to a comment character (#) or an unescaped <newline>. Any <blank> characters immediately before or after the <equals-sign> shall be ignored.
This can be construed as a feature allowing you to clearly create variables with trailing whitespace:
FOO = stuff # this macro has two trailing spaces
BAR = something else# and this one has none
though probably usually it would be clearer to reorganise the places you use $(FOO) rather than depend on it having obscure whitespace.
Probably the best way to deal with this is just to avoid it: have a convention that you do not put comments on variable definition lines (except very occasionally to make intentional whitespace explicit). Instead of writing this:
A = a # list of apples
B = b # list of bananas
C = c # list of carrots
write this:
# list of apples
A = a
# list of bananas
B = b
# list of carrots
C = c
This tends to be the style in GNU projects (see for example the bottom of this page), though I don't recall whether this is documented anywhere.
Incidentally, when examining whitespace you probably want to quote your variables in your echo command more:
rule:
#echo 'RESULT="$(RESULT)"'
In your echo RESULT=\"$(RESULT)\" version, $(RESULT) is not quoted from the shell, so tabs and multiple spaces are being misleadingly displayed as single spaces.
Here are some raw ideas that I have:
Make it a policy to always use strip with ifeq
Not using strip would be a rare exception and would require an explanation in the comments.
Don't manually set configuration variables inside of a Makefile
Find or create some other tool to do that.
maybe the POSIX shell will suffice (although I think the nuances of shell variables may be worse than those of make).
I suspect that the GNU build system (Autoconf/Automake/etc.) addresses this, but my feeling is that this is overkill for most purposes.
Use some kind of "lint" tool to find these kind of problems
I'm not aware of the existence of any such tool.
Modify GNU make to fix this problem.
Preferably minimizing the impact on existing Makefiles.
Modify the make language so that by default the trailing-spaces are stripped
Use a more modern build tool instead of GNU make
Ugly, but perhaps more foolproof. Anyone who edits this in the future might at least notice that you, perhaps, made it ugly on purpose.
A = $(strip a )##
B = $(strip b )## trailing comment
C = $(strip c )##

Order of processing components in makefile

In a makefile, the dependency line is of the form -
abc: x y z
All three of the components (x,y,z) are themselves targets in dependency lines further down in the makefile.
If make abc is invoked, in what order will the three targets x,y,z be executed?
By default, the order of execution is the same as specified in the prerequisites list, unless there are any dependencies defined between these prerequisites.
abc: x y z
The order is x y z.
abc: x y z
y : z
The order would be x z y.
But ideally, you should design your Makefiles so that it wouldn't rely on the order in which prerequisites are specified. That is, if y should be executed after z, there must be a y : z dependence.
And keep in mind that GNU Make can execute some recipes in parallel, see Mat's answer.
You really shouldn't depend on the order in which they are executed - all else being equal, all three recipes for those prerequisites could run in parallel.
The only hard rule is that all prerequisites must be met before the target recipe is run.
If there are no dependencies between x, y and z, and no parallel execution, GNU make appears to run them in the order you specified them, but this is not guaranteed in the docs.
The POSIX description of make includes a rationale which says:
The make utilities in most historical implementations process the prerequisites of a target in left-to-right order, and the makefile format requires this. It supports the standard idiom used in many makefiles that produce yacc programs; for example:
foo: y.tab.o lex.o main.o
$(CC) $(CFLAGS) -o $# t.tab.o lex.o main.o
In this example, if make chose any arbitrary order, the lex.o might not be made with the correct y.tab.h. Although there may be better ways to express this relationship, it is widely used historically. Implementations that desire to update prerequisites in parallel should require an explicit extension to make or the makefile format to accomplish it, as described previously.
(I believe the t.tab.o in the $(CC) line is a typo for y.tab.o, but that is what the rationale actually says.)
Thus, the observed behaviour that pre-requisites are processed from left to right has validation here, though it is only in the Rationale section, not in the main description. The Rationale also mentions issues with parallel make etc.
From https://stackoverflow.com/a/22638294/636849, you can add the pipe symbol:
abc: | x y z
From make manual:
Order-only prerequisites can be specified by placing a pipe symbol (|) in the prerequisites list: any prerequisites to the left of the pipe symbol are normal; any prerequisites to the right are order-only:
targets : normal-prerequisites | order-only-prerequisites

Generating list of generated sources (a la foreach) in automake

I am currently working on a project using templates quite extensively, and running into memory constraints during instantiation. I have split up the instantiation into a number of very simple files, which are all three-liners consisting of includes only.
I let these be generated by a rule in Makefile.am. Now I have a quite long list of files that should be generated in my Makefile, and would like to refactor this list with a foreach-like expression. In more specific terms: I have a line like
libfoo_la_SOURCES = a_0.cpp a_1.cpp ... b_0.cpp b_1.cpp ... c_0.cpp c_1.cpp ...
which could be more concisely expressed as
libfoo_la_SOURCES = $(foreach i,a b ...,$(foreach j,0 1 ...,$i_$j.cpp))
However, the second construct is not only warned against by automake, but also does not work: The files given in this manner are neither compiled nor cleaned.
My current workaround is generating this file list by a shell script.
Any ideas how to implement this iteration?
I would forget about making loops: the GNU extension is not standard, and not understood by Automake. One standard (and portable) make construction you can use here is the macro expansion with substitution: $(var:subst1=subst2) will expand to the value of $(var) after replacing any suffix subst1 of a word by subst2. Automake understands this.
If subst1 is empty, as in $(var:=subst2), you are appending subst2 to all files in $(var). You can use this to construct your list of files as follows:
f = a b c d e f
g = $(f:=_0) $(f:=_1) $(f:=_2) $(f:=_3)
all_files = $(g:=.cpp)
echo:
#echo $(all_files)
Running make echo with the above Makefile will display all files from a_0.cpp to f_3.cpp.
Like you, I discovered that the GNU make foreach function will not work like this because
the sources need to be there at the time the Makefile is generated. So, I use GNU Autogen (also here) to generate a makefile fragment which is subsequently included in Makefile.am. So it's probably not that different than your shell script approach.

Resources