Solved GNU and BSD Makefile Directives and Conditions Compatibility

NOTE: I am not interested in dealing with autotools/autogen yet. I want to focus on learning about make/gmake.

I have seen this subject posted on the web, but have not found a solution for myself yet.

I want users to be able to compile from my Makefile on Linux, BSD, and Windows systems. The Makefile tests if the target platform is Win32 using conditional directives. I much prefer BSD as the GNU syntax is confusing to me:
Code:
...
EXESUFFIX=
ICON=myabcs.xpm
.if defined(WIN32) || defined(__WIN32__)
  EXESUFFIX=.exe
  ICON=myabcs.ico
.endif
...

However this is not compatible with GNU make:
Code:
$ gmake
Makefile:20: *** missing separator.  Stop.

For GNU make it needs to be something like this:
Code:
...
EXESUFFIX=
ICON=myabcs.xpm
ifdef WIN32 # don't know how to use logical "or" (||) here
  EXESUFFIX=.exe
  ICON=myabcs.ico
endif
ifdef __WIN32__
  EXESUFFIX=.exe
  ICON=myabcs.ico
endif
...

or I think I can use something like this (though this example doesn't work as intented):
Code:
...
EXESUFFIX=
ICON=myabcs.xpm
ifeq (,$(filter "",$(WIN32) $(__WIN32__)))
  EXESUFFIX=.exe
  ICON=myabcs.ico
endif
...

Neither of which are compatible with BSD make.

My base question is how to make my Makefile both GNU and BSD compatible. Is it possible to do within a single file or do I need to separate them? Can I have a base Makefile that imports another of either GNU or BSD standards? Or, do I just need to make two completely separate files?

NOTE: I have also posted this to the Unix.com forums.
 
I think I've just decided to make separate Makefiles. I don't know that I even want to go into GNU autotools.
 
To reduce confusion about which make to use, you could name the files GNUmakefile and BSDmakefile (No capital M!); GNU make and make on FreeBSD will pick up on this and use the correct file. I didn't verify if the make flavours on {Net,Open}BSD do the same!
 
Thank you Carpetsmoker! That is very helpful.

Edit: I created a couple of generic Makefiles with variables and rules. Anything requiring platform dependent directives was placed in separate files.
 
Assume that only basic make constructs are compatible: defining, modifying and referencing variables and specifying targets with sources. Also some attributes like @ and .SILENT. Conditions, functions, default variables, variable modifiers are not compatible.

Something limited to this works with both BSD and GNU make:
Code:
FOO=  bar
FOO+= baz
BAR?= quiz

target: source1 source2
    echo ${FOO} ${BAR}

But from my experience, if you need anything beyond this, you should anyway consider using a proper build system. A Makefile with complex logic is hard to read and maintain (and usually a pain to use for a user with a system different from the software authors), and it's even worse if there are two Makefiles. Tools like autotools (or, much better, CMake) let you describe your project in higher level terms, so build code is much cleaner and shorter, and take care of much more target platform differences than you can consider in a Makefile written by hand. Both autotools and CMake generate Makefiles compatible with both GNU and BSD syntax, by the way.
 
Perhaps I'll take a closer look at CMake. As an end-user I like autotools, but as a developer, I hate trying to set it up.
 
I wonder why people use autotools. I have used it once and needed hours to figure out why something does not work. Then, after some time I realized that I needed to swap some rules, because one does not work after another. This seemed purely random to me and made no sense at all. It feels like software from the '80s: badly designed crap with random traps that I need to know workarounds for and no one feels that these are actually bugs.

I prefer to write Makefiles, too. And if it gets complex and needs to be portable devel/cmake was acceptable after my first steps.
 
Back
Top