Is it possible to treat warnings as errors in a Makfile (and thus exit before Makefile proceeds)
Furthermore, is it possible to filter out which warning yields an error?
My use case: I want to use --warn-undefined-variables in combination with this so that Makefile will exit when a variable is undefined, which is a very common source of error. Obviously I don't want to manually check for each variable as this is error-prone/tedious. I couldn't find anything on this, but it's a pretty important/basic feature.
Note: I'm not looking for -Werror which is a gcc specific command not applicable to my use case.
If you're prepared to add a dependency to every target, you can make warnings into errors.
Here is a make file with an error in it ("SRCS" instead of "SRC"):
# Turn on the warning we want
MAKEFLAGS += --warn-undefined-variables
# Make sure MAKECMDGOALS is defined, so it doesn't cause an error itself
ifndef MAKECMDGOALS
MAKECMDGOALS = all
endif
SRC=hello.c
all: compile
# Fails if the Makefile contains any warnings.
# Run this Makefile with the same goals, but with the -n flag.
# Grep for warnings, and fail if any are found.
no-make-warnings:
! make -n $(MAKECMDGOALS) 2>&1 >/dev/null | grep warning
# Targets you want to check must depend on no-make-warnings
compile: no-make-warnings
gcc -o hello $(SRCS)
When I run it, I see this:
$ make
! make -n all 2>&1 >/dev/null | grep warning
Makefile:17: warning: undefined variable `SRCS'
make: *** [no-make-warnings] Error 1
You just need to make every target that you want to be checked depend on the target no-make-warnings.
If someone knows how to do that automatically, please chime in.
The standard version of make does not support what you are looking for. However, it should not be difficult to build your own version of make to fulfill your use case.
Looking at the source code of make 3.82, check out the macro warn_undefined in variable.h:
214 /* Warn that NAME is an undefined variable. */
215
216 #define warn_undefined(n,l) do{\
217 if (warn_undefined_variables_flag) \
218 error (reading_file, \
219 _("warning: undefined variable `%.*s'"), \
220 (int)(l), (n)); \
221 }while(0)
I have not tried this, but I think it should be sufficient to replace error with fatal.
Related
I’m trying to implement include guards in Gnu Make. In this Makefile, the first inclusion is OK, while the second one fails with an error.
ifndef INCLUDED
INCLUDED = 1
$(info Including)
define macro
ifneq ($(1),)
define inner_macro
macro content...
endef
else
define inner_macro
endef
endif
endef
endif
The same effect can be simulated by explicitly giving INCLUDED = 1 before the inclusion, e.g. on command line.
Gnu Make 4.1 under Gentoo says Makefile:14: *** missing separator. Stop., while Gnu Make 3.81 under Debian Wheezy says Makefile:14: *** extraneous `endef'. Stop.. On the first inclusion, they both say:
Including
make: *** No targets. Stop.
If I try $(eval $(call macro,whatever)) after the first inclusion, it defines inner_macro as expected.
I used make INCLUDED=1 and make commands respectively to get the described behavior.
The same happens when I clear the environment and disable built-in rules and variables: env -i make -rR INCLUDE=1. When I use -p to dump the database, without INCLUDED=1, the macro is defined as it should be, but with INCLUDED=1, empty inner_macro is defined. This is consistent across both the versions of Make. This hints me that when the condition is false, Make parses the Makefile differently and thinks the else inside macro’s definition belongs to the ifndef. Other condition types behave all the same.
If I remove both the definitions of inner_macro, the problem goes away.
I read the manual pages info make conditional\ syntax and info make multi-line (formerly defining), but I found no caveat there and I still think I am doing nothing wrong.
Am I correct with my conclusions?
Is this a bug in Make, or am I invoking undefined behavior?
How should I implement include guards in Gnu Make?
That's a bug. Report it on Savannah.
There's something wrong with the tracking of nested define/endef inside a not-taken ifdef/ifndef condition. If you don't use nested define/endef then it works; for example (obviously you may not be able to do this in your environment):
ifndef INCLUDED
INCLUDED = 1
$(info Including)
define macro
ifneq ($(1),)
inner_macro = macro content...
else
inner_macro =
endif
endef
endif
Ive got some large make files for a third party project that are not building due to linker issues.
From looking at the make files, I think it should be executing something like:
LIBS = -lm
CC = gcc
bin = bin
myapp: $(bin)/main.o $(bin)/other.o $(bin)/etc.o
$(CC) $(bin)/main.o $(bin)/other.o $(bin)/etc.o $(LIBS) -o myapp
gcc bin/main.o bin/other.o bin/etc.o -lm -o myapp
Instead from the error it seems to be failing on something like: It also didn't put any of the .o files in the expected bin/ location, but just left them in the source directory...
cc main.o -o myapp
But I cant locate anywhere that might come from. Is there some way to get some kind of stacktrace through the make files?
I am aware of -n and -d, but neither seems to tell me what target line and file yeilded that command, or which series of targets led there and the values of any $() expansions (The one im expecting is the only myapp: I can find in any of the makefiles...)
Check out the --debug option. From my manpage:
--debug[=FLAGS]
Print debugging information in addition to normal processing. If the
FLAGS are omitted, then the behavior is the same as if -d was specified.
FLAGS may be a for all debugging output (same as using -d), b for basic
debugging, v for more verbose basic debugging, i for showing implicit
rules, j for details on invocation of commands, and m for debugging
while remaking makefiles.
remake is a very good choice but in a pinch something like the following (saved as debug.mk) can be a good help too. It won't tell you as much as remake but it might tell you enough to start with.
# Use as: MAKEFILES=debug.mk make
OLD_SHELL := $(SHELL)
ifneq (undefined,$(origin X))
override X = -x
endif
SHELL = $(if $#,$(warning Running $#$(if $<, (from: $<))$(if $?, (newer: $?))))$(OLD_SHELL) $(X)
You can print out the other automatic variables there too if you wanted to see a bit more about what was going on.
I have two GNUmakefiles in my directory as follows,
GNUmakefile &
GNUmakefile2
Could someone please let me know the command I have to use, if I have to let the "make" command to process "GNUmakefile2" instead of "GNUmakefile".
I used the below command,
make -f GNUmakefile2
but in that case, I am getting the following errors,
This is gnustep-make 2.6.1. Type 'make print-gnustep-make-help' for help.
make[1]: ** No rule to make target `internal-master-tool-all'. Stop.*
make: ** [internal-all] Error 2*
I think it is considering GNUmakefile as makefile (when I use make with -f command), so it is checking for rules in GNUmakefile.
At present what I am doing is I am renaming the required file (which I want, make command to execute) to "GNUmakefile". And I am not getting any errors while executing "make" command, but I don't think this is the correct solution.
Please let me know which command I need to use for this scenario. Thanks for your help.
After checking Beta's solution (i.e.,but that makefile is invoking Make a second time, and the second Make process is probably reading GNUmakefile) what I have done is I renamed existing "GNUmakefile" to "GNUmakefile3".
So at present in my directory the following makefiles are present:- "GNUmakefile2" & "GNUmakefile3".
And then I executed the following command:- $ make -f GNUmakefile2
I recieved the below errors,
This is gnustep-make 2.6.1. Type 'make print-gnustep-make-help' for help.
make[1]: GNUmakefile: No such file or directory
make[1]: * No rule to make target `GNUmakefile'. Stop.
make: * [internal-all] Error 2
Please let me know what is the problem here
Your makefile includes two huge makefiles from the FSF. The second, library.make, contains this rule:
ifeq ($(GNUSTEP_MAKE_PARALLEL_BUILDING), no)
# Standard building
...
else
# Parallel building. ...
internal-library-all_:: $(GNUSTEP_OBJ_INSTANCE_DIR) $(OBJ_DIRS_TO_CREATE)
$(ECHO_NOTHING_RECURSIVE_MAKE)$(MAKE) -f $(MAKEFILE_NAME) ...
endif
and the first, common.make contains this assignment:
# The default name of the makefile to be used in recursive invocations of make
ifeq ($(MAKEFILE_NAME),)
MAKEFILE_NAME = GNUmakefile
endif
So try either make -f GNUmakefile2 GNUSTEP_MAKE_PARALLEL_BUILDING=no or make -f GNUmakefile2 MAKEFILE_NAME=GNUmakefile2, and see if that solves the problem.
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'
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.