Possible bug in GNU make 4.3? - makefile

I have the following line in the Makefile of a software I'm working with:
VERSION = $(subst $(space),.,$(wordlist 1,2,$(subst ., ,$(patsubst v%,%,$(shell cat VERSION)))))
Where VERSION is a file containing the exact version of the software (f.e 3.12.3)
I'm not such an expert in Makefiles but this line should return the major version (without the v indicating TAG), in this case, 3.12. And it does, or, at least, it does it when you run it with GNU make <= 4.2
I've recently updated to make 4.3 (because I use a rolling release, Arch Linux) and then executing the same line in my makefile, I got 3 12. instead of 3.12
I've been reading Make changelog in order to check if there is any change in something related to the line in charge of retrieving the major version but I can't find where the problem is.
I've confirmed that the problem appears only with GNU make 4.3 (it works with make 4.2) and I'm wondering if there is a bug or I am missing something.
Maybe someone could help me.
Best regards

As G.M. mentioned, it all depends on how you've defined space, which you haven't shown us.
It worked for me using the "normal" way of defining space, with GNU make 4.3:
E =
space = $E $E
VERSION = $(subst $(space),.,$(wordlist 1,2,$(subst ., ,$(patsubst v%,%,$(shell cat VERSION)))))
$(info VERSION='$(VERSION)')
Then:
$ cat VERSION
v3.12.3
$ make --version
GNU Make 4.3
...
$ make
VERSION='3.12'

As MadScientist and G.M mentioned, the problem was in the definition of space. I dind't noticed it was defined as
space =
space +=
and, according to Makefile 4.3 change log:
* WARNING: Backward-incompatibility!
Previously appending using '+=' to an empty variable would result in a value
starting with a space. Now the initial space is only added if the variable
already contains some value. Similarly, appending an empty string does not
add a trailing space.
The expected behavior for += to an empty variable has changed... so here is the problem!
Thank you very much!

Related

How to make "%" wildcard match targets containing the equal sign?

The makefile wildcard system doesn't seem to match targets if they contain the equal sign. Is there a way to work around this deficiency? Some flag or setting or rule to escape the equal sign? I know I can just not use the equal sign but I'd prefer to fix this idiosyncrasy of make if possible.
Here's an example of what I mean
$ cat Makefile
all:
echo Dummy target
b_%:
echo $#
$ make b_c=1
echo Dummy Target
$ make b_c1
echo b_c1
The first make command does not match b_% even though it should. I also wasn't able to find documentation for exactly what is supposed to be matched by the % wildcard. Any pointers? My make version is
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This program built for i386-apple-darwin10.0
The problem here is not with the % syntax, but with the fact that any command-line argument with an equals sign in it is interpreted as a variable assignment.
You should find that if you add the dependency all: b_c=1, then make all will generate the file just fine.
There are restrictions on what file names you can use with make -- they can't contain spaces or newlines, and e.g. backslashes are problematic, too (though not completely impossible to accommodate for simple use cases).
If you absolutely have to have a file named like this, my suggested workaround would be to use a different name internally, and then symlink it to the external name as the last step of the make recipe.

Debugging Makefile

Some Makefile contains this -
ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
NO_LIBUNWIND := 1
and
whenever I run this make , I get the error message as
warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99
I want to debug this problem - I want to know the values of SOURCE_LIBUNWIND, FLAGS_UNWIND
which are causing this problem - how do I get these values printed on the stdout for debugging purpose ?
GNU make provides several functions that you can use to print the value of a variable: $(error ...), $(warning ...) and $(info ...). The manual mentions them in section 8.12 Functions That Control Make.
Additionally, you can use the command-line parameter -p or --print-data-base to have make print the values of all rules and variables. Redirecting the output to a file and analyzing that might give you a better understanding of why the values are what they are. See section 9.7 Summary of Options for some extra information.
to print value of macro X in the makefile - just add line. ( kind of printf )
$(warning X is $(X))
Reinier and Shraddha have the right answers for the question as asked but I'm not sure that's the right question to have asked.
It would seem to me (based on nothing more than the snippet of makefile posted) that those are more likely to be variables you can set than variables that are already set. That is they would be how you control the location used for locating libunwind.
So if the try-cc call is failing I'd assume that means you either don't have libunwind installed at all or that you have it installed in a non-standard system location and haven't set those variables to tell make about it.

How to make gcc uses march=native as default?

Is there a way to change the specs file so that it will pass -march=native if nothing is specified in command line?
Related things in the default specs file is:
*cc1:
%(cc1_cpu)
*cc1_cpu:
%{march=native:%>march=native %:local_cpu_detect(arch) %{!mtune=*:%>mtune=native %:local_cpu_detect(tune)}} %{mtune=native:%>mtune=native %:local_cpu_detect(tune)}
I am not sure how specs works. Simply specifying -march=native before or after %(cc1_cpu) doesn't work. However, this line does take effect because GCC will report error if I put -something_wierd instead of -march=native.
Another thing I noticed is if I put %{march=i386:-something_wierd} before %(cc1_cpu), gcc reports error so looks like -march=i386 is always passed in if nothing is specified, so is there a way to distinguish between nothing specified and -march=i386 in specs file?
BTW, what does %> do? Seems like it is not specified in the documentation.
I am using MinGW's gcc-4.6.2.
Referring to your last question: The gcc 4.6.1 sources (gcc/gcc.c) contain the following comment on %>:
%>S Similar to "%<S", but keep it in the GCC command line.
For the sake of completeness following the comment for %< form the same file:
%<S remove all occurrences of -S from the command line.
Note - this command is position dependent. % commands in the
spec string before this one will see -S, % commands in the
spec string after this one will not.
To answer the first question in short: yes, but ....
... the only generic solution I found has the significant drawback that the -march option will be ignored, so every build is done as if -march=native had been specified. Anyhow there is a workaround to that.
1 The solution (without workaround)
Create a specs-file called let's say specs.nativealways containing:
*cc1_cpu:
%<march=* -march=native %>march=native %:local_cpu_detect(arch) %{!mtune=*:%>mtune=native %:local_cpu_detect(tune)} %{mtune=native:%>mtune=native %:local_cpu_detect(tune)}
When using the specs-file (for example by invoking gcc with the option -specs=specs.nativealways) the build will be done as if -march=native was specified (with the mentioned drawback that any occurrence of option -march=<arch> would have simply been ignored).
2 The workaround
To still by able to override the newly configured default behavior one can use a modified version of the specs-file described above, introducing a new option called -myarch using the same syntax as -march (except for -myarch=native, which won't work, which does not metter as native now is the default).
The modfied specs-file looks like this:
*cc1_cpu:
%<march=* %{myarch=*:%<myarch* -march=%* ; :-march=native %>march=native %:local_cpu_detect(arch) %{!mtune=*:%>mtune=native %:local_cpu_detect(tune)}} %{mtune=native:%>mtune=native %:local_cpu_detect(tune)}
PS: This has been tested with with gcc 4.6.2 on Linux, but should work on MinGW.
While not a direct answer to your question, you can reach a very similar effect by defining CFLAGS and CXXFLAGS in your shell's initialization file. 99% of the Makefiles are sufficiently standard to pick up the environment values and pass the flags to gcc.
*cc1_cpu:
+ %{!march*:-march=native}

No rule to make target `/Makefile', needed by `Makefile'

I'm trying to 'make' using a pretty simple makefile. My makefile is named 'Makefile' so I'm simply using the command 'make'.
I get this strange error:
make: *** No rule to make target `/Makefile', needed by `Makefile'. Stop.
If, however, I use
make -f "full-path-to-makefile" it actually does run (with odd consequences...). I should say that I'm running all this from the directory where the Makefile lies, of course.
I'm working on Mac OSX, using tcsh.
Edit:
I'm working in the LLVM framework, trying to compile a pass function and this is the associated makefile:
LEVEL = ../../../
LIBRARYNAME = FunctionName
LOADABLE_MODULE = 1
include $(LEVEL)/Makefile.common
Any ideas will be appreciated :)
I had the same problem trying to write a new pass for LLVM i followed these instructions trying to make a HelloB (as Hello already exsited) http://llvm.org/docs/WritingAnLLVMPass.html#quickstart
What i has to do was do a ./configure again then make from the base directory.
I'll go out on a limb: you have an extra slash. Try omitting the final slash in $(LEVEL).
I found the answer, sort of:
The problem was with the installation process of LLVM. It seems that if you do the installation in one order instead of another it can lead to this error. It doesn't make any sense to me, but after I installed it properly everything compiles great (same code, same Makefile, same make program).
I don't really know why this happened, but I know how to fix it :)
What you want to do is ./configure again then make from the base directory (contrary to what is stated in the instructions on the web-site). That worked for me.
BTW - I got the same results running on Ubuntu (with the same fix).
Just to add some information here (since this is the first hit that comes up on Google when looking for the error) - I had the same problem which suddenly popped up on a (previously working) LLVM setup on OSX, and traced it back to the behavior of the realpath command in make.
Specifically, what was happening was that I had a directory called "LLVM/llvm-2.9-build", but for some reason the attempt to resolve PROJECT_OBJ_ROOT at the top of Makefile.config would decide that this directory was in fact called "llvm/llvm-2.9-build". Since OSX is case-insensitive by default, this doesn't cause an immediate problem, except that subsequently LLVM_SRC_ROOT would be set to "LLVM/llvm-2.9-build". This then meant that the creation of PROJ_SRC_DIR using patsubst to replace the object directory would result in a non-existent path (as the unmatched case means that no pattern replace occurs), which in turn would get resolved to / by realpath.
With PROJ_SRC_DIR set to /, this results in the makefile copy rule in Makefile.rules deciding that the source makefile is at $(PROJ_SRC_DIR)/Makefile (ie /Makefile), and the error message described.
It seems that it is only the built-in implementation of realpath in Make (GNU Make 3.81 in my case) that has this behaviour, as forcibly using the macro version of realpath from the top of Makefile.config fixes the problem. However, this isn't a good long-term fix, as you'd have to manually patch every one of the LLVM makefiles.
In the end, I couldn't see where realpath would be getting the lower-case "llvm" from, but figured it was probably an artifact somehow of some caching of the name from a point in time when I'd referenced the directory using its lower-case name. Hence I tried going to that directory and mv-ing it to a completely different name, and then back to "LLVM" before going in and building again, and that seems to have solved the problem.
I hope that's of some use to anyone else who comes across this particular weirdness!
It's not a complete answer, but what you are seeing is gmake not finding the Makefile it is told to include, and thus it is trying to remake it and failing because it can't find a recipe for it either.
However, the Makefile snippet you posted does not produce the error message you are seeing, so I think the problem is inside the Makefile.common file. Look for include statements which reference a $(some variable expansion)/Makefile and work backwards from there. You can also try to run gmake with the -d option and follow the processing based on the output.
Since your include line reads:
include $(LEVEL)/Makefile.common
it is puzzling that you are not getting an error about /Makefile.common. If you were, then I'd suggest that maybe you have a trailing blank after the definition of LEVEL.
Could there be a line in Makefile.common that itself includes $(SOMEMACRO)/Makefile and you have not set the value of SOMEMACRO?
here's my fixes for this issue: (https://github.com/rust-lang/rust/issues/24887#issuecomment-99391849)
update src/llvm/Makefile.config.in before running ./configure
or update x86_64-apple-darwin/llvm/Makefile.config before make
line 59:
PROJ_SRC_DIR := $(LLVM_SRC_ROOT)$(patsubst $(PROJ_OBJ_ROOT)%,%,$(PROJ_OBJ_DIR))
update to
PROJ_SRC_DIR := $(patsubst $(PROJ_OBJ_ROOT)%,$(LLVM_SRC_ROOT)%,$(PROJ_OBJ_DIR))
line 86:
PROJ_SRC_DIR := $(call realpath, $(PROJ_SRC_ROOT)/$(patsubst $(PROJ_OBJ_ROOT)%,%,$(PROJ_OBJ_DIR)))
update to
PROJ_SRC_DIR := $(call realpath, $(patsubst $(PROJ_OBJ_ROOT)%,$(PROJ_SRC_ROOT)%,$(PROJ_OBJ_DIR)))

How to include makefiles dynamically?

Is it possible to include Makefiles dynamically? For example depending on some environment variable? I have the following Makefiles:
makefile
app1.1.mak
app1.2.mak
And there is an environment variable APP_VER which could be set to 1.1.0.1, 1.1.0.2, 1.2.0.1, 1.2.0.2.
But there will be only two different makefiles for 1.1 and 1.2 lines.
I have tried to write the following Makefile:
MAK_VER=$$(echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$$/\1/')
include makefile$(MAK_VER).mak
all: PROD
echo MAK_VER=$(MAK_VER)
But it does not work:
$ make all
"makefile$(echo", line 0: make: Cannot open makefile$(echo
make: Fatal errors encountered -- cannot continue.
UPDATE:
As far as I understand make includes files before it calculates macros.
That's why it tries to execute the following statement
include makefile.mak
instead of
include makefile1.1.mak
You have two problems: your method of obtaining the version is too complicated, and your include line has a flaw. Try this:
include app$(APP_VER).mak
If APP_VER is an environmental variable, then this will work. If you also want to include the makefile called makefile (that is, if makefile is not the one we're writing), then try this:
include makefile app$(APP_VER).mak
Please note that this is considered a bad idea. If the makefile depends on environmental variables, it will work for some users and not others, which is considered bad behavior.
EDIT:
This should do it:
MAK_VER := $(subst ., ,$(APP_VER))
MAK_VER := $(word 1, $(MAK_VER)).$(word 2, $(MAK_VER))
include makefile app$(MAK_VER).mak
Try this:
MAK_VER=$(shell echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$$/\1/')
MAK_FILE=makefile$(MAK_VER).mak
include $(MAK_FILE)
all:
echo $(MAK_VER)
echo $(MAK_FILE)
Modifying the outline solution
Have four makefiles:
makefile
app1.1.mak
app1.2.mak
appdummy.mak
The app.dummy.mak makefile can be empty - a symlink to /dev/null if you like. Both app.1.1.mak and app.1.2.mak are unchanged from their current content.
The main makefile changes a little:
MAK_VER = dummy
include makefile$(MAK_VER).mak
dummy:
${MAKE} MAK_VER=$$(echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$$/\1/') all
all: PROD
...as now...
If you type make, it will read the (empty) dummy makefile, and then try to build the dummy target because it appears first. To build the dummy target, it will run make again, with APP_VER=1.1 or APP_VER=1.2 on the command line:
make APP_VER=1.1 all
Macros set on the command line cannot be changed within the makefile, so this overrides the line in the makefile. The second invocation of make, therefore, will read the correct version-specific makefile, and then build all.
This technique has limitations, most noticeably that it is fiddly to arrange for each and every target to be treated like this. There are ways around it, but usually not worth it.
Project organization
More seriously, I think you need to review what you're doing altogether. You are, presumably, using a version control system (VCS) to manage the source code. Also, presumably, there are some (significant) differences between the version 1.1 and 1.2 source code. So, to be able to do a build for version 1.1, you have to switch from the version 1.1 maintenance branch to the version 1.2 development branch, or something along those lines. So, why isn't the makefile just versioned for 1.1 or 1.2? If you switch between versions, you need to clean out all the derived files (object files, libraries, executables, etc) that may have been built with the wrong source. You have to change the source code over. So why not change the makefile too?
A build script to invoke make
I also observe that since you have the environment variable APP_VER driving your process, that you can finesse the problem by requiring a standardized 'make invoker' that sorts out the APP_VER value and invokes make correctly. Imagine that the script is called build:
#!/bin/sh
: ${APP_VER:=1.2.0.1} # Latest version is default
case $APP_VER in
[0-9].[0-9].*)
MAK_VER=`echo $APP_VER | sed -e 's/^\(...\).*/\1/'`
;;
*) echo "`basename $0 .sh`: APP_VER ($APP_VER) should start with two digits followed by dots" 1>&2;
exit 1;;
esac
exec make MAK_VER=$MAK_VER "$#"
This script validates that APP_VER is set, giving an appropriate default if it is not. It then processes that value to derive the MAK_VER (or errors out if it is incorrect). You'd need to modify that test after you reach version 10, of course, since you are planning to be so successful that you will reach double-digit version numbers in due course.
Given the correct version information, you can now invoke your makefile with any command line arguments.
The makefile can be quite simple:
MAK_VER = dummy
include app$(MAK_VER).mak
all: PROD
...as now...
The appdummy.mak file now contains a rule:
error:
echo "You must invoke this makefile via the build script" 1>&2
exit 1
It simply points out the correct way to do the build.
Note that you can avoid the APP_VER environment variable if you keep the product version number under the VCS in a file, and the script then reads the version number from the file. And there could be all sorts of other work done by the script, ensuring that correct tools are installed, other environment variables are set, and so on.

Resources