I have a project whose makefile uses features exclusive to GNU Make. Sadly, there are platforms we must support where GNU make is still not the default when running make
.
One of my colleagues was bitten by this, when a non-GNU make implementation silently failed to build our code correctly (it expanded an automatic variable to an empty string). I want to prevent that from happening again, by generating an explicit error message instead.
What can I write in a Makefile
to distinguish GNU make from non-GNU make, print a clear error, and exit?
I've already figured out a workaround in renaming my real makefile to GNUmakefile
, and putting a small stub in Makefile
, but I'd rather something more direct.
The answers by Beta and Dan Moulding look really nice and simple, but on AIX 6.1, the make implementation can't handle either of them:
$ cat testmake
foo:
touch foo
ifeq ($(shell $(MAKE) -v | grep GNU),)
$(error this is not GNU Make)
endif
ifeq "${MAKE_VERSION}" ""
$(info GNU Make not detected)
$(error ${MIN_MAKE_VER_MSG})
endif
$ /usr/bin/make -f testmake
"testmake", line 5: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 6: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 7: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 8: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 11: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 12: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 13: make: 1254-055 Dependency line needs colon or double colon operator.
make: 1254-058 Fatal errors encountered -- cannot continue.
I run into similar issues on both archaic and modern versions (Solaris 8 & 10) of Sun's make. That one's less critical, but would be nice to manage.
As noted, GNU make
checks for GNUmakefile
before makefile
or Makefile
, I've used a trivial fix such as you described, a default (decoy) Makefile
that causes an error/warning:
default:
@echo "This requires GNU make, run gmake instead"
exit 70
The GNU make documentation recommends using the GNUmakefile
name when the Makefile
is GNU make specific, so that's my preferred solution.
On platforms where the native make
prefers a different Makefile name, you can do a variation on this, e.g. on FreeBSD I have the above decoy in the BSDmakefile
which is used in preference to Makefile
(thus preventing the system make
from mangling my build). AFAICT the AIX or Solaris make
do not have an alternate name you could use in this way.
One problem with a wrapper Makefile
which tries to call GNU make
is passing all the arguments.
A seemingly portable test (so far, I've found it to work on a mix of ancient OSF1, BSD and Solaris systems) you can use SOMETHING=$(shell ...)
to detect if GNU make
is running, non GNU versions will not set SOMETHING
. Because of deferred evaluation of variables, you cannot use this as easily as might be expected though. This relies on the implementation silently handling macro names with spaces when expanded with $()
(i.e. treats $(shell foo)
as a variable/macro name rather than a function, even though an assignment to such a name in that implementation would cause an error).
The only portable way you can print a clear error is to have a dummy target that is always run, using the above trick:
GNUMAKE=$(shell echo GNUMAKE)
default: gnumake all
gnumake:
@[ "$(GNUMAKE)" = "GNUMAKE" ] || { echo GNU make required ; exit 70; }
This assumes you have a POSIX sh
shell.
(I have seen tests which inspect $(MAKE) -v
fail when both system and GNU make are called "make
", the system make
conspires against you and invokes GNU make
... You'd need some carefully checking of environment variables PATH
, MAKE
and possibly SHELL
to handle every case.)
I don't know of any internal feature that is definitely unique to GNUMake, but here's a kludge: call "make -v" and parse the output for "GNU" (since it seems unlikely that a non-GNU Make would have MAKE
set to a GNU Make):
ifeq ($(shell $(MAKE) -v | grep GNU),)
$(error this is not GNU Make)
endif
EDIT:
Like Dan Moulding, I am starting to see the real size of this problem. As written, it requires a Makefile that is syntactically correct in all versions of Make. I don't have access to Sun Make (and I can't find manuals for it) so I don't know whether that's even possible, or how to write it if it is, or how to test it if I did.
But I can suggest an approach that might work. Maybe something like this can be made universal:
default:
./runGNUMake.pl
That's it, that's the whole makefile. Then write the runGNUMake
script in Perl (or bash, or whatever you like) that will do something like my "make -v" kludge and then either print the error message or run "make -f realMakefile".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With