Makefile: what is "#-"? - makefile

In a makefile I use there is #-, that is not mentioned in any makefile tutorial I could find.. Could you please explain what #- is for?
For example:
#- $(RM) *.o

The at-sign # tells Make to not print the command line before executing it.
(Manual: Recipe echoing)
The minus sign - tells Make to ignore the result of the command and not fail the target if it was unsuccessful.
(Manual: Errors in recipes)
In your case it's just both of them being used, because somebody did not want to pollute the output with the erase command, and did not want to fail the build if anything goes wrong with the deletion either.

Related

Makefile passing additional arguments to targets command from make command

I have a Makefile that defines docker-compose project.
It essentially assembles me a command:
COMMAND := docker-compose --project-name=$(PREFIX) --file=$(FILE_PATH)
up:
$(COMMAND) up -d
I would like to add a target named dc to which I would be able to pass any arguments I want.
I know there is one solution:
target:
$(COMMAND) $(ARGS)
And then call it with make target ARGS="--help" for example.
But isn't there an easier way like in bash $# ? I would like to skip the ARGS=... part and send everything to the command after target name.
Not really. The make program interprets all arguments (that don't contain =) as target names to be built and there's no way you can override that. So even though you can obtain the list of arguments given on the command line (via the GNU make-specific $(MAKECMDGOALS) variable) you can't prevent those arguments from being considered targets.
You could do something like this, which is incredibly hacky:
KNOWN_TARGETS = target
ARGS := $(filter-out $(KNOWN_TARGETS),$(MAKECMDGOALS))
.DEFAULT: ;: do nothing
.SUFFIXES:
target:
$(COMMAND) $(ARGS)
(untested). The problem here is you have to keep KNOWN_TARGETS up to date with all the "real" targets so you can remove them from the list of targets given on the command line. Then add the .DEFAULT target which will be run for any target make doesn't know how to build, which does nothing. Reset the .SUFFIXES meta-target to remove built-in rules.
I suspect this still will have weird edge-cases where it doesn't work.
Also note you can't just add options like --help to the make command line, because make will interpret them itself. You'll have to prefix them with -- to force make to ignore them:
make target -- --help
Another option would be to add a target like this:
target%:
$(COMMAND) $*
Then you can run this:
make "target --help"
But you have to include the quotes.
In general I just recommend you reconsider what you want to do.
You could write a bash wrapper script to do what you'd like:
#/bin/bash
make target ARGS=\"$#\"
The reason you don't want to do it in make, is that make parses the command line parameters before it parse the makefile itself, so by the time you read the makefile, the targets, variables, etc have already been set. This means that make will have already interpreted the extra parameters as new targets, variables etc.
A target that re-run make containerized
.PHONY: all containerized
ifeq ($(filter containerized,$(MAKECMDGOALS)),containerized)
.NOTPARALLEL: containerized
MAKEOVERRIDES ?=
containerized: ## Build inside a container
#docker run image_with_make make $(MAKEOVERRIDES) $(filter-out containerized,$(MAKECMDGOALS))
else
# other targets here
all: xxxx
endif
Executing
make containerized all runs make all in container
The first answer is correct, no passthru of args. However, here is a plausible path for experimentation, use of branch by include selection:
# Makefile:
COMMAND := $(PYTHON) this_shit_got_real.py
LOCAL_MK ?= local.mk
# '-' important, absence of LOCAL_MK is not cause for error, just run with no overrides
- include $(LOCAL_MK)
target:
$(COMMAND) $(ARGS)
Now see how you add branching with env:
echo "ARGS=--help">>local.mk
# make target
And the other cli controlled branch
echo "ARGS=--doit">>runner.mk
# LOCAL_MK=runner.mk make target

GNU Makefile first target not getting invoked

I am following the solution in GNU Makefile treating each recipe line as sub-shell command without continuation character
target_compile: PROJECT_SIM_OPTS += -LDFLAGS -L${CURRENT_DIR},-lm -load
target_compile: copy_shared_object actual_compile_with_sim_opts
#echo PROJECT_SIM_OPTS=${PROJECT_SIM_OPTS} ...
When I make the Makefile, I am able to see the second target_compile fire off but not the first target_compile which has no dependencies and recipe except a variable. I tried adding override before PROJECT_SIM_OPTS and ; at the end of the line but still it is not working.
There is no Error message reported which makes it even harder to detect. In nutshell, I have to embed this piece of code in another Makefile and if the first target would work, I will see a file generated with -LDFLAGS -L${CURRENT_DIR},-lm -load in it. Since this file is being generated without these flags, I am confident to say that first target is not firing.
How can the two target_compile work together?
It turned out to be an ordering issue. In my case
target_compile: copy_shared_object actual_compile_with_sim_opts
#echo PROJECT_SIM_OPTS=${PROJECT_SIM_OPTS} ...
actual_compile_with_sim_opts was running before copy_shared_object
Once I put the dependency like this,
actual_compile_with_sim_opts: copy_shared_object
I was able to get both targets to work with proper flags
Thanks #Beta for all the help.

Suppressing First Part of Output in Makefile

DEPRECATED_CHECK := $(shell grep "test454" tex/*.tex)
ifneq ($(DEPRECATED_CHECK), )
$(warning \test454 is deprecated. Use \test2 instead)
endif
When I run this I get:
../common/Makefile.include:133: \test454 is deprecated. Use \test2 instead
That's fine, but I'd quite like to have only:
\test454 is deprecated. Use \test2 instead
Is this possible? Some sort of awk function? I think I need something with:
#echo \text454 is deprecated ...
But I don't know how to get this working with the basic purpose of my MWE, as it keeps complaining about missing separators.
Many thanks
You could use $(info ...) instead of $(warning ...). info doesn't prepend the file and line number.
just an aside -- I usually try to do those sort of checks as part of a sanity rule, and make everything depend on that rule instead of doing it at the top level. It gives you more flexibility that way. For example, if you didn't want to run the check when building clean, it becomes simple, or if you wanted to fail the build if a check failed, it becomes simple as well.
EDIT (adding more detail on aside)
Instead of doing an ifneq at the top level of make, you could add a target as so:
sanity_check:
# ! grep -q "test454" tex/*.txt || echo "test454 is depricated"
.PHONY: sanity check
The add dependencies of your main targets to sanity check:
all maintarg1 maintarg2: sanity_check
This way the sanity check will be run before any of your main targets, and will output as desired. This is in my opinion, a cleaner way of doing the test. This way the test is only run if you are building any of your targets, and will not be run, if for example you are making clean, or if your makefile was included by a parent makefile, or in a bunch of other corner cases that might pop up in the future.
Just a quick note on the recipe syntax: the # is a make directive that tells make not to echo the command as it's run. The ! is bash syntax to inverse the return of grep (so ! grep returns false if the text is found, thereby causing the || part of the statement to be evaluated.). The .PHONY: sanity_check tells make to run the rule, even if a file called sanity_check already exists

Passing Variable to make from the command line?

All,
I'm trying to pass variables to make from the command line. My command is below
make ARCH=arm CROSS_COMPILE=/my_dir/bin/arm-openwrt-linux-g++
The error I received is
g++: error: arm: No such file or directory
But the file 'arm-openwrt-linux-g++' does exist.
I think the problem is I need to pass varibale to sub-make files. Can some help with an example of how to pass varialbes to sub-makefile from the command-line. I have tried using the -e and export options for make, but can't seen to get anything to work.
Thanks
Content of makefile:
# GNU Make solution makefile autogenerated by Premake
# Type "make help" for usage help
ifndef config
config=debug
endif
export config
PROJECTS := json openjaus
.PHONY: all clean help $(PROJECTS)
all: $(PROJECTS)
json:
#echo "==== Building json ($(config)) ===="
#${MAKE} --no-print-directory -C .build -f json.make
openjaus: json
#echo "==== Building openjaus ($(config)) ===="
#${MAKE} --no-print-directory -C .build -f openjaus.make
So, your problem is not related to sending variables over the command line.
Your problem is that in one of the makefiles in your sub-directories, which you haven't shown us, you're using the variable $(ARCH) in an incorrect way such that the expansion of the command line is not a legal g++ command line.
Based on the error message, most likely you're adding a space somewhere where it shouldn't be, so instead of something like -fmarch=arm you're getting -fmarch= arm. Obviously this is just an example because you didn't provide nearly enough information.
One other note: we can't know how your makefiles work but typically makefiles that support a variable like CROSS_COMPILE expect it to be set to just the prefix of the cross-compilation command; in your case it would be CROSS_COMPILE=/my_dir/bin/arm-openwrt-linux-. But, your makefiles might be different.
When asking questions, it's best to if you don't immediately jump to a guess about what the answer is. First describe the problem, and that includes showing the error line as well as a few lines before it. For example in this case you're getting an error from g++ so the command line that make printed out showing you how it invoked g++ would have helped greatly.
Once you've given the underlying detail, then if you think you have an idea about what the problem is go ahead and suggest it, and/or ask about it.
If you provide the rule that invokes g++ and/or the output from make showing the g++ command line, then we can help more.
Cheers!
Here's what I think needs to happen:
You need to make sure that your sub-makefiles actually respect the $(ARCH) and $(CROSS_COMPILE) variables. Are they also generated by Premake? If so, is that how it handles cross-compilation? Check the docs.
In my test (below), I found that variables set on the command line are propagated to sub-makes, which makes me think that your sub-makefiles aren't respecting $(ARCH):
Makefile:
a:
$(MAKE) -C z
z/Makefile:
a:
#echo "MAKE=$(MAKE)"
#echo "ARCH=$(ARCH)"
Running make with no arguments:
$ make
make -C z
make[1]: Entering directory `/home/foo/test/z'
MAKE=make
ARCH=
make[1]: Leaving directory `/home/foo/test/z'
Running make ARCH=bar:
$ make ARCH=bar
make -C z
make[1]: Entering directory `/home/foo/z/z'
MAKE=make
ARCH=bar
make[1]: Leaving directory `/home/foo/z/z'

Error when running: make clean

I am trying to build some simulation software using makefile provided by them after I have made some changes to the libraries. But when I run make clean, it stops midway and I get the following error
rm: invalid option -- 'l'
Try `rm --help' for more information.
make: *** [neat] Error 1
I checked the man page for rm and there is no -l option, but I don't know why this command is being executed with -l option. Is there anyway to ignore this, or find out which specific file is causing the problem?
EDIT:
I have figured out the source of the error, but dont know how to edit it to make it work properly. Below is a snippet from an included Makefile with the faulty line:
UDP_INTERFACE_SRCS = \
$(UDP_INTERFACE_DIR)/interfaceudp_app.cpp \
$(UDP_INTERFACE_DIR)/interfaceudp.cpp \
$(UDP_INTERFACE_DIR)/external_interface_udp.cpp \
$(UDP_INTERFACE_DIR)/packet_send.cpp \
$(UDP_INTERFACE_DIR)/addr.cpp \
$(UDP_INTERFACE_DIR)/packet_capture.cpp -lpcap \
$(UDP_INTERFACE_DIR)/queue.cpp
In particular, the line: $(UDP_INTERFACE_DIR)/packet_capture.cpp -lpcap \
is causing the error. What does the "-lpcap" added after "packet_capture.cpp" do? Now if I try to remove it, "make" gives an error saying:
./interfaces/extinterface/src/packet_capture.o: In function pcap_sniff_packets(void*)': /home/qualnet/4.5/main/../interfaces/extinterface/src/packet_capture.cpp:63: undefined reference to pcap_setdirection' make: *** [../bin/qualnet] Error 1
I checked the line number 63 in packet_capture.cpp in an effort to understand what -lpcap means. But I have no idea what that code does.
(This is clearly an iterative process, and the comments are getting long, so I'd better start an answer.)
You say: "When I put echo SIM_JOBS: $(SIM_OBJS) in the rule, i get the following when i run make clean: rm -f ../bin/qualnet ../bin/radio_range"
This doesn't make sense. You should get something like
SIM_JOBS: ../bin/qualnet ../bin/radio_range
rm -f ../bin/qualnet ../bin/radio_range
or
SIM_JOBS: something/else
rm -f ../bin/qualnet ../bin/radio_range
or at least
SIM_JOBS:
rm -f ../bin/qualnet ../bin/radio_range
This suggests that you are looking at the wrong rule: the rule which produces rm -f ../bin/qualnet ../bin/radio_range is not the rule in which you put the echo ... command. If it is the rule and you were just being imprecise in the report, put this right above the clean rule:
SIM_JOBS=../bin/qualnet ../bin/radio_range
and tell us what happens.
EDIT:
Sorry, I wrote `SIM_JOBS` when I meant `SIM_OBJS`.
The `echo` command was outside the rule, where it cannot work.
It looks as if the problem. Could you edit your question to show the line you mentioned to #thiton, and a few previous lines? It looks as if the flag "-lpcap" is getting into a variable, where it doesn't belong.
EDIT:
The "-lpcap" is a kludge. My guess is that it's an option intended for the linker. Suppose you want to link a bunch of object files into an executable, and you want to search a certain library called "pcap":
gcc foo.o -lpcap bar.o baz.o
The order is very important; when the linker is searching for something, you want it to search foo.o first, then pcap, then bar, then baz. It's a question of precedence. But you want to store those filenames in a nice tidy variable, and how will you insert the lpcap at the right place? You could do it a good way, or use a lazy hack like this:
OBJECTS = foo.o -lpcap bar.o baz.o
gcc $(OBJECTS)
And if you're deducing the OBJECTS from the SOURCES, you have to put the hack in earlier:
SOURCES = foo.cc -lpcap bar.cc baz.cc
OBJECTS = $(SOURCES:.cc=.o)
Whoever wrote these makefiles saved half an hour with this kludge, and it's taking you days to fix it. If you can confirm that this is what's happening, the easiest way is probably to split the list in two:
SOURCES_LEFT = foo.cc
SOURCES_RIGHT = bar.cc baz.cc
OBJECTS_LEFT = $(SOURCES_LEFT:.cc=.o)
OBJECTS_RIGHT = $(SOURCES_RIGHT:.cc=.o)
gcc $(OBJECTS_LEFT) -lcap $(OBJECTS_RIGHT)
Like #AndrejPanjkov noted in the comments, the standard tool to find out what exactly is going on in Makefiles is the -n (--dry-run) switch of make. It prints all commands as they would be run by the shell, even those normally silenced (e.g. via #).
Have a long, hard look in this output for any pattern like ' -l' (piping the output to less and using / helps). If that doesn't help, try running all commands output by -n by hand in make's shell (normally /bin/sh) or try removing all the silencers (# characters at a rule's start) from the Makefile and running make clean, checking the last line of output.

Resources