Hacker News new | ask | show | jobs
by 0x09 3222 days ago
The problem comes in as soon as you need conditionals, which is likely when attempting to build something portably. There may be some gymnastics that can be done to write around the lack of their presence in standard make, but otherwise your options are:

- Supply multiple makefiles targeting different implementations

- Bring in autotools in all its glory (at this point you are depending on an external GNU package anyway)

- Or explicitly target GNU Make, which is the default make on Linux and macOS, is very commonly used on *BSD, and is almost certainly portable to every platform your software is going to be tested and run on. The downside being that BSD users need a heads up before typing "make" to build your software. But speaking as a former FreeBSD user, this is pretty easy to figure out after your first time seeing the flood of syntax errors.

5 comments

> But speaking as a former FreeBSD user, this is pretty easy to figure out after your first time seeing the flood of syntax errors.

I seem to be about the only person that makes use of the following feature, but FreeBSD and GNU make will in addition to looking for a file named Makefile, also look for BSDmakefile or GNUmakefile respectively.

So when I write a makefile with GNU make specific contents, I name it GNUmakefile, and when I write one that is specific to FreeBSD make, I name it BSDmakefile.

The user has to do absolutely nothing different; they simply write

    make
and if their make is GNU make and my makefile is a GNUmakefile then it builds. Likewise with FreeBSD make and a file named BSDmakefile.

The big win is when someone then has the wrong make. Instead of beginning to build and then failing at some point kicking and screaming, they will simply be told

    make: no target to make.

    make: stopped in (path)
by FreeBSD make, or

    make: *** No targets specified and no makefile found.  Stop.
by GNU make.

And at that point they will consult the README I have written for the project in question and they will learn that they need the other make than what they are using if they want to build this software.

Nowadays I write a GNUmakefile, then add a Makefile with a message telling people to use gmake. Same idea.
i have this in a (hand-written) configure script:

    case "$(uname -s)" in
    Darvin|Linux)
      MAKE=make
      GMAKE=$MAKE
    ;;
    DragonFly|*BSD)
      MAKE=make
      GMAKE=gmake
    ;;
    *)
      MAKE=gmake
      GMAKE=$MAKE
    ;;
    esac

    ...

    if test "$MAKE" != "$GMAKE"; then
      case "$(uname -s)" in
      DragonFly|*BSD)
        populate $rootdir/Makefile.in Makefile
      ;;
      esac
    fi

    cat <<EOF

    to build the programs from their sources:

      $MAKE

    to test their correctness:

      $MAKE check

    EOF
$rootdir/Makefile.in contains

    all .DEFAULT:
      @@GMAKE@ --no-print-directory "$@"
POSIX Make supports conditionals, thanks to recursive macro expansion. And while POSIX doesn't yet support a macro construct to invoke and capture shell utilities, you can use both the GNU $(shell COMMAND) and Sun $(COMMAND:sh) syntax. All the BSDs and Solaris support the latter, and GNU Make the former. Both constructs are ignored with an empty string expansion where they're not supported, and no implementation supports both.

To see what I'm talking about, see my proof of concept library that I've put together.

https://github.com/wahern/autoguess/blob/config-guess/config...

Another possibility is conditional compilation at the C level. thefile.c #includes thefile_unix.c or thefile_windows.c as appropriate.
That doesn't really help situations like "iconv is in libiconv on some systems, and is in libc on others" though.
Or just use CMake -- it's not perfect, but it explicitly solves this.
> it's not perfect

I used to be so hopeful for cmake, but just grew to be sort of annoyed by it. Build systems are, however, perennial like the grass, so we'll see more.

I just wish it would work with relative paths. It shouldn't break your build to move a folder around.
AFAIK cmake works perfectly fine with relative paths; what breaks?
The author of that blog post wants something fundamentally different from what CMake is. The project files generated by it are just temporary build intermediates, and it makes no more sense to distribute them than it would the .d files generated by gcc -MD. Perhaps he is expecting it to be like autotools, where the generated Makefiles can be bundled in your tarballs so that people do not need autotools installed to build your project, but no meta-build-system other than autotools that I have encountered even tries to support that.

The author's claim that "a CMake-generated project cannot possibly be the final say" is so incorrect that I am not surprising that he found CMake frustrating. It is quite the opposite; if you ever find yourself manually editing the generated project files for any reason other than debugging build-system issues you're doing it wrong and are going to have a very bad time. You must always find a way to express the thing you need within the CMakeFiles.txt, which sometimes unfortunately requires awful hacks.

Amusingly the SO question he links to as evidence that editing the generated project file is required now has an answer saying how to do it properly...

I thought you meant giving it relative paths in your CMakeLists.txt -- which does work as expected.

> This makes CMake-generated projects almost useless: you cannot source control them or share them in any other way.

Yes, and this is a good thing. I'm surprised anyone would want to do this on a visual studio solution of all things -- managing solution and project file merges in source control is incredibly tedious.

A lot of things about CMake irritate me, but its treatment of out of source build files as purely intermediate is a major plus to me, not a negative.

I could see how this would mess up your use case; but you have to admit your use case is very narrow -- I guess you want to be able to just rename the build folder; if you moved it more than that even the relative path to the source dir would be off -- and the justification for the limitation seems sensible.

Whenever I start to write a moderately complex makefile I realize yet again that the makefile programming language sucks and that if I want to stay sane the only way to do it is to go meta (use a separate program to generate a makefile using the bare-minimum features)
Putting the logic into a more flexible configure script that generates definitions for your Makefile and imitates the autotools build process without actually using autotools is a good/obvious compromise. Even some large projects like FFmpeg and mplayer/mpv do this.