defining a variable in makefile with special characters -- -MF"$(#:%.o=%.d)" - makefile

I want to run the next line in a makefile:
g++ -O2 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"$(#:%.o=%.d)" -o "$#" "$<"
I want to define a variable that will contain all the flags:
FLAGS := -O2 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"$(#:%.o=%.d)"
and then use this variable instead of the hardcoded line:
g++ $(FLAGS) -o "$#" "$<"
however the last part of the above line (the quoted part) creates problems.
my question is how can I assign this line to a variable? I tried all kind of escape characters combinations but nothing seems to work.
thanks.

The issue comes from the FLAGS :=. Indeed, using the := operator to set the FLAGS variable instructs make to evaluate the value of the variable only once and now. However, at the time of the definition of FLAGS, variable # is not defined. It will only be defined within the rule that has the g++ command. That's why it results in -MF"".
You should use FLAGS= (no column). Defined with the simple =, the FLAGS variable will only be evaluated when used, i.e. in the g++ command line. At that place, the $# variable will be defined and valid.

Related

how can I access makefile variable in xv6?

Now I am trying to access makefile variable in my user program in xv6.
In other linux system, it can be easily achieved by doing that
in makefile, define gcc -D MYVARIABLE=1 ...
in my linux user program, by defining #include <stdio.h>, I can access MYVARIABLE.
but in xv6, there is no <stdio.h>. so I can't access MYVARIABLE.
How can I do for access MYVARIABLE??
Guessing you use this repo: https://github.com/mit-pdos/xv6-public, you can define MYVARIABLE in CFLAGS declaration, near line 83.
CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
# Your macro here
CFLAGS += -DMYVARIABLE=1
In that makefile, there is no %.o: %.c rule: implicit rules are used:
n.o is made automatically from n.c with a command of the form $(CC) -c $(CPPFLAGS) $(CFLAGS)

Make refuses to expand my variables in the g++ compilation line

Here is my simple Makefile. I am trying to set the C macro "GIT_COMMIT" in my Makefile and pass it to the C program.
all: control
control: control.cpp serial_port.cpp
GIT_COMMIT=5
g++ -g -DGIT_COMMIT=$(GIT_COMMIT) -Wall $^ -o control -lpthread
Unfortunately, when I run make, I see this and make is completely ignoring my GIT_COMMIT variable. What am I doing wrong? Thanks.
GIT_COMMIT=5
g++ -g -DGIT_COMMIT= -Wall control.cpp serial_port.cpp -o control -lpthread
placing the setting of GIT_COMMIT as an action inside the 'control' rule will, as you discovered, not work to produce a macro. suggest:
all: control
GIT_COMMIT := 5
control: control.cpp serial_port.cpp
g++ -g -DGIT_COMMIT=$(GIT_COMMIT) -Wall $^ -o control -lpthread

CXXFLAGS changes not being honored?

I have the following in my GNU makefile:
# CXXFLAGS ?= -DNDEBUG -g2 -O3
CXXFLAGS ?=
# Add -DNDEBUG if nothing specified
ifeq ($(filter -DDEBUG -DNDEBUG,$(CXXFLAGS)),)
$(info Adding -DNDEBUG to CXXFLAGS)
CXXFLAGS += -DNDEBUG
endif
# Add a symolize if nothing specified
ifeq ($(filter -g -g1 -g2 -g3 -Oz,$(CXXFLAGS)),)
$(info Adding -g2 to CXXFLAGS)
CXXFLAGS += -g2
endif
# Add an optimize if nothing specified
$(info Adding -O3 to CXXFLAGS)
ifeq ($(filter -O -O0 -O1 -O2 -O3 -Og -Os -Oz -Ofast,$(CXXFLAGS)),)
CXXFLAGS += -O3
endif
When I run it:
$ make CXXFLAGS="-g3"
Adding -DNDEBUG to CXXFLAGS
Adding -O3 to CXXFLAGS
g++ -g3 -c foo.cpp
...
In fact, if I uncomment the CXXFLAGS ?= -DNDEBUG ..., then I can append again. But that's not very helpful since I'm trying to make arguments optional (but with sane defaults).
And if I type just make, then it works (-fPIC -march=native -Wall -Wextra -pipe is added later by the same makefile, and it has always worked):
$ make
Adding -DNDEBUG to CXXFLAGS
Adding -g2 to CXXFLAGS
Adding -O3 to CXXFLAGS
g++ -DNDEBUG -g2 -O3 -fPIC -march=native -Wall -Wextra -pipe -c serpent.cpp
...
According to the manual and 6.6 Appending More Text to Variables:
Often it is useful to add more text to the value of a variable already defined. You do this with a line containing ‘+=’, like this:
objects += another.o
Why is make not adding the values to the variable? How can I achieve the behavior I want?
By passing a variable via command-line, you're telling make that you are overriding any definitions in the file, which allows a user to compile as they intend rather than as you intend. Ignoring the restriction of user freedom, you can use the override directive:
To append more text to a variable defined on the command line, use:
override variable += more text
Variable assignments marked with the override flag have a higher priority
than all other assignments, except another override. Subsequent
assignments or appends to this variable which are not marked override
will be ignored.
I would discourage you from using override when possible because it's annoying to realize that -O0 was needed to disable the optimizations that you enabled when I don't want them enabled (after all, I specify my own flags for a reason). Of course, if no flags were specified at all, then defaults are perfectly reasonable. In fact, Automake projects seem to default to -g -O2 when no compilation flags are specified.
There are exceptions to this advice of course, such as adding a directory to search for includes/libs or preprocessor definitions for compiling a conditional section of code on a certain platform.

using an ifdef conditional to set a Make flag

I have a simple gnu makefile:
ifdef $(DEBUGGING)
CFLAGS = -g -O0 -Wall
else
CFLAGS = -O3 -Wall
endif
test:
#echo DEBUGGING is $(DEBUGGING)
#echo $(CFLAGS)
When I invoke it like this, I see that DEBUGGING is set to true, but ifdef $DEBUGGING appears to be false:
$ DEBUGGING=true make test
DEBUGGING is true
-O3 -Wall
I would expect that CFLAGS would be set to "-g -O0 -Wall". What am I missing?
You use the NAME of the variable in the ifdef:
ifdef DEBUGGING
The value given to ifdef is expanded first, and the result is considered a variable name.

How to hide print information of Makefile?

when Makefile execute some tasks, il will print many information in console, can we choose to hide them? when I have many .o to generate, these information will be too many to see and they are just meaningless if we don't read them.
The following code
$(obj)environment.o: $(src)environment.c
$(CC) $(AFLAGS) -Wa, --no-warn \
-DENV_CRC=$(shell $(obj)../tools/envcrc) \
-c -o $# $(src)environment.c
will print heavy information like
arm-linux-gcc -g -Os -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float
-D__KERNEL__ -DTEXT_BASE=0x01000000
-I/home/mingzhao/Documents/bootloader/u-boot-1.2.0/include
-fno-builtin -ffreestanding -nostdinc -isystem
/home/mingzhao/Documents/bootloader/arm/4.3.2/bin/../lib/
gcc/arm-none-linux-gnueabi/4.3.2/include -pipe -DCONFIG_ARM
-D__ARM__ -march=armv4 -mabi=apcs-gnu -Wall -Wstrict-prototypes
-c -o environment.o environment.c
The "right" way to handle this (IMO) is to add this to your makefile:
$(VERBOSE).SILENT:
Then in your rules where you don't ever want the command printed (for example, an echo statement as in Beta's answer below) you prefix it with #. For all other commands, you don't prefix it with #.
What this does is enable "silent" mode by default (because the variable VERBOSE is not set and so this resolves to the .SILENT pseudo-target).
Then if you want to see everything, you add a VERBOSE=1 (actually you can set it to any non-empty value, so VERBOSE=true if you prefer). When you do that it turns off "silent" mode because the above line expands to 1.SILENT: (or true.SILENT: or whatever) which is meaningless to make.
You can use the option make --silent which will suppress output for all targets. If you want to suppress output for some commands, you can prefix them by #
I like something like this:
$(obj)environment.o: $(src)environment.c
#echo building $#
#$(CC) $(AFLAGS) -Wa, --no-warn \
-DENV_CRC=$(shell $(obj)../tools/envcrc) \
-c -o $# $(src)environment.c
The #echo ... gives a minimal status message, the '#' in front of the $(CC) suppresses standard output (but still allows error messages).
You can use this syntax : #$(CC) $(AFLAGS) -Wa, --no-warn \...

Resources