I came across to this line in one of the makefiles I examine. I am afraid that my guess might be completely wrong since I don't know what the double quotes are for in the assignment.
PROJECT_CONF_H=\"project-conf.h\"
What is the purpose of the double quotes In the assignment? Can't I just type
PROJECT_CONF_H=\project-conf.h\
?
I wasn't able to find the answer into the GNUmake manual so I decided to ask you for help. Please explain.
Sorry but the English is not my native language.
AFTER EDITION:
DEFINES += PROJECT_CONF_H=\"project-conf.h\"
CFLAGS += ${addprefix -D,${subst $(COMMA), ,$(DEFINES)}}
Where CFLAGS are the compiler option flags.
The option -D has the same effect as a #define statement at the top of the source file.
It is a Variable assignment.
The backslashes escape the ", so the " are part of Variable content.
Related
I'm trying to build some c programs with gnu make (4.1) through a shell script. I want to use different CFLAGS parameters, which I read from a file. The file contains lines like:
"-O1 -freorder-functions"
I am trying to do something like
while read line
do
opts="$line"
make CFLAGS="$opts"
done < $1
but all my attempts end up in the following error:
cc1: error: argument to ‘-O’ should be a non-negative integer, ‘g’, ‘s’ or ‘fast’
So I tried to change the file's contents to only the parameters after -O1 (-freorder-functions), and add the -O1 in the shell script:
opts=$(printf "\"-O%d %s\"", 1, "$line")
(and a lot of other things that seem less sensible) but I still get the same error message.
Hard-coding the parameter to make in the shell script works fine:
make CFLAGS="-O1 -freorder-functions"
Sorry if this is a stupid question, but I can't seem to find any examples of how something like this is done, and I'm new to shell scripting, so I don't really understand how it's treating the variables here. An echo of what I'm attempting to pass to CFLAGS looks okay to me.
With double quotes around the flags in the file and you dutifully quoting your shell variables properly, your make call ends up being
make CFLAGS="\"-O1 -freorder-functions\""
That is to say, with double quotes in the flags. This is passed all the way down to the compiler call, which means that the compiler call is something like
cc "-O1 -freorder-functions" -c foo.c
...which asks the compiler to use optimization level 1 -freorder-functions, and it complains that that is not valid.
To solve this, I would remove the quotes from the file. You could also use opts=$line with $line unquoted, but that is not exactly safe.
My main Makefile call config.mk
include $(TOPDIR)/config.mk
then config.mk include some sentences like this:
ifdef CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk
endif
ifdef SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk
endif
I have prepared these two tree and necessary config.mks. But for "SOC", whose value is "versatile", there is a problem. If I put "versatile" directly here, it could find the file and everything is fine; but when I use $(SOC), il will meet an error, and say
/../../../cpu/arm926ejs/versatile: is a folder, stop
Anyone know what the problem is ??
Are you sure you gave the exact error message? What version of make are you using? That error doesn't look like anything GNU make would print.
Anyway, I'll bet the problem is that your assignment of the SOC variable has trailing whitespace. According to the POSIX definition of make, leading whitespace before a variable value is removed, but trailing whitespace is preserved. That means, for example, if you write your makefile like this:
SOC = versatile # this is the versatile SOC
then make will remove the comment, but keep the space, so the value will be 'versatile' (space at the end). This means when the value is expanded in the sinclude line you get:
sinclude $(TOPDIR)/cpu/$(CPU)/versatile /config.mk
which make interprets as trying to include two different values, the first of which is a directory.
Even if you don't have a comment there, any trailing whitespace will be preserved. When editing makefiles you should try to put your editor into a mode where it flags trailing whitespace, or even better removes it automatically. GNU Emacs, for example, can do this.
I maintain a project which provides makefile for Arduino
There is a master (common) makefile and the users create a small makefile where they set certain environmental variables and then include the master makefile.
A typical makefile looks likes this
# Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile
BOARD_TAG = atmega328
ARDUINO_PORT = /dev/ttyACM*
include $(ARDMK_DIR)/arduino-mk/Arduino.mk
Recently, I was debugging a bug and then found out that if there is an additional space at the end of BOARD_TAG environmental variable, then it results in an error, which is not very intuitive for someone to fix.
My initial thought was to fix it by trimming the environmental variable inside the makefile. But on second thought I was not sure whether that is the correct way to fix this issue.
So my question is what is the recommended way to fix these kind of user input issues in makefile? Should I try to trim it or is there an alternate way to fix this?
To trim the variable "in place", just treat it as a simply expanded variable:
BOARD_TAG = atmega328
BOARD_TAG := $(strip $(BOARD_TAG))
If you use "=", it's a recursive expanded variable, so any expression on the right (e.g. $(strip ...)) will not be expanded until the variable itself is evaluated; if you try to put the variable itself on the right, Make warns you that that expression can't be evaluated because it goes into an infinite loop.
If you use ":=", it becomes a simply expanded variable; Make expands the right-hand side then and there, assigns the result to the variable and that's that.
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 )##
I am trying to figure out what the following two lines in a .mk file mean
include $(ROOTDIRECT)/target/$(MYSUBDIR)/defs.mk
include $(ROOTDIRECT)/target/$(dir $(patsubst %/,%,$(MYSUBDIR)))/defs.mk
For clarity let ROOTDIRECT be "/home/me" and MYSUBDIR be "platform"
The first line I guess is straight forward and includes "/home/me/target/platform/defs.mk"
The second line I dont understand and my guess from my environment is that it includes "/home/me/target/defs.mk"
Am I right/wrong and could could someone help me to understand the second line
$(patsubst %/,%,$(MYSUBDIR)) will substitute anything matching the pattern %/ by %, where % can be anything.
In other words, it will remove the trailing / of $(MYSUBDIR).
See GNU Make Manual 8.2 Functions for String Substitution and Analysis