Can we use NMAKE.EXE as a substitute for GNU Make? - windows

I was curious to see if I can compile this repo, with the Microsoft Program Maintenance Utility (NMAKE.EXE) (location) where I got the U1001 error:
makefile(4) : fatal error U1001: syntax error : illegal character '.' in macro
Stop.
so I am wondering if nmake.exe is by any means a substitute for GNU Make?
my questions are:
Can we have cross-compatible Makefiles by using a subset of shared syntax between the two?
Can we use some sort of NMake or GNU Make macros to have compatible MakeFiles?
What are the major syntax differences between NMake and GNU Make?
P.S. It seems that this discussion is very relevant to my question, if not a duplicate.

No, you cannot use nmake as a replacement for GNU make.
If your GNU make makefile is written strictly to POSIX specification and doesn't use any GNU-specific enhancements, then you could use any POSIX-conforming instance of make with that makefile.
However, (a) it's unlikely the makefile is really POSIX-conforming, and (b) nmake (as far as I'm aware) isn't a POSIX-conforming implementation of make anyway.

Related

The make on FreeBSD doesn't support "ifdef" directives

My FreeBSD is 11.0, and find the make can't process the ifdef directives. For example:
ifdef VERBOSE
Q :=
else
Q := #
endif
The make will complain:
make: "/root/Project/powermon/Makefile" line 13: Need an operator
make: "/root/Project/powermon/Makefile" line 15: Need an operator
make: "/root/Project/powermon/Makefile" line 17: Need an operator
My current solution is using gmake instead. So does any make port on FreeBSD support processing ifdef?
BSD make uses different syntax and has different features than GNU make. The snippet you show should look like the following for BSD make:
.ifdef VERBOSE
Q :=
.else
Q := #
.endif
You have basically three options:
If your software targets specifically BSD, write your Makefile in BSD make syntax. man make(1) has the complete manual for FreeBSD's make.
Write a portable Makefile. This would only use the most basic features of make that every known make tool implements (e.g. don't use any pattern rules etc). This can be tedious and there are other tools helping to manage this by generating the Makefile like cmake or the GNU autotools.
write a GNU make Makefile (might be a good idea to name it GNUmakefile, so it is never interpreted by any other make than GNU make) and rely on the fact that GNU make is available nearly everywhere. For FreeBSD, this would mean installing the appropriate port.
If you go with the third option, you can add a "wrapper" Makefile like e.g. this:
GNUMAKE?= gmake
all:
${GNUMAKE} $#
.DEFAULT:
${GNUMAKE} $#
.PHONY: all
Typing make on BSD will cause the BSD make to read this file and accordingly call gmake. On a GNU system (where make is GNU make), this file will be ignored when there is a GNUmakefile -- GNU make prefers this over just Makefile.
A more portable way to write something like that is:
Q$(VERBOSE) := #

Detect when only preprocessing, i.e. gcc -E

I currently invoke clang or gcc as
cc -E -DPREPROCESSING ...
when debugging macros.
It has occurred to me that the define is redundant. Is there an expression I could write in the source to detect when the compiler will stop after preprocessing, and so drop this definition from my build scripts?
#if magic
#define PREPROCESSING
#ending
A look at the docs suggests not, but with luck I'm missing something.
Whatever solution you come up with is going to be compiler-specific, since the C standard does not have anything to say about separate preprocessing.
In gcc, you could implement the magic by adding a custom spec file:
%rename cpp old_cpp
*cpp:
%{E:-DPREPROCESSING} %(old_cpp)
You would need to tell gcc to use this spec file (-specs=/path/to/specfile), unless you compiled your own gcc with the above definition added to the built-in cpp spec. If you are using a Makefile, you could add the -specs option above to your CFLAGS.
(I should add that I don't think this is a particularly good idea. But it is possible.)

How do I work around gnu linker command line pickiness?

This question and its answer explains the importance of linking command line order.
However, I deal with a lot of makefiles containing lines like
$(CC) $(LDFLAGS) $^ -o $#
Aparently, commands like these just work on some systems, but not on mine. Is there a way to work around this behaviour other than finding and patching all Makefiles like these?
I am using gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
EDIT for clarification:
I do a lot of patching and integration as part of my job(Usually buildroot or LTIB) , and I come across multiple makefiles written like this. Also some example compiling commands on the web follow the same pattern.
So, the problem is that some idiot has created a makefile that puts all the library options before the .o file. Presumably there is some broken toolchain out there that doesn't care, but that doesn't help you.
There's only two options here:
Fix the makefile.
Create a compiler wrapper that reorders the options. Such a wrapper would be broken in general, but could make it work for the exact pattern used by your makefiles.
I did wonder if --start-group would help you here, but a quick experiment suggests not.

Detecting (non-)GNU Make when someone runs `make`

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".

Separating objects and source with a makefile

I have been having troubles getting my makefiles to work the way I want. First off, I would like to say this is POSIX make, as in http://www.opengroup.org/onlinepubs/009695399/utilities/make.html I am needing my build system to work with both BSDs and GNUs(Linux).
What I am wanting is a zero maintenance makefile. I want it to just compile all .c and .asm files in src/ and place the object files in objs/ and then to link everything in objs/ to a binary file.
I can do a lot, but I can't get it to separate the source and obj files.
I am ok if this requires a little built-in shell scripting (using POSIX defined /bin/sh), but I can just not get the dependencies to work right. I want it to only build the object file if the source file is newer.
My closest is this:
${C_OBJS}: ${HDRS} ${*:objs/%=src/%}.c
${CC} ${CFLAGS} -c ${*:objs/%=src/%}.c -o $*.o
This has the problem that I must still specify C_OBJS=objs/foo.o and such and also it is just barely not POSIX and therefore, compiles with BSD make but not GNU make.
The POSIX version of make does not explicitly support file names with slashes in them, nor does it make provision for separating source files in a different directory from the object files. And, as noted by #caskey, it does not support any notation using '%' characters, though it notes that such rules exist and recommends that they be reserved for use as metacharacters.
Consequently, you probably cannot do what you want with standard POSIX make.
In practice, you can often do what you seek with specific implementations of make, but the resulting makefile has limited portability.
Consider using a makefile generation systems of some sort - cmake or the auto-tools (autoconf, libtool, automake, etc). Or one of the many reworkings of the basic concepts of make:
scons
ant
cake
cook
bras
...and a dozen I've forgotten or not heard of...
POSIX make doesn't support constructs like?
objs/%.o : src/%.c
${CC} ${CFLAGS} -c $< -o $#
Forgot the question mark at the end, hope that makes my comment more clear.

Resources