Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to conditionally assign value to a variable in a Makefile (BSD + GNU)?

I have a (from my point of view) rather complicated Makefile.

That is mostly because I wanted colors there and other unnecessary things.

Anyway, might I jump right into my question:

Apart from Linux I newly support *BSD, thus I need to check for the platform in use on several places. Is conditional variable assignment possible in a Makefile? Something like:


platform := [ $$(uname) = Linux ] && echo Linux || echo BSD or other

Of course this does not work, but hopefully, you get my point.


I need a solution, that works both with the BSD make, and the GNU make.

like image 209
LinuxSecurityFreak Avatar asked Oct 21 '18 04:10

LinuxSecurityFreak


2 Answers

The != shell assignment operator is apparently supported on both BSD and GNU make:

platform_id != uname -s

platform != if [ $(platform_id) = Linux ] || \
    [ $(platform_id) = FreeBSD ] || \
    [ $(platform_id) = OpenBSD ] || \
    [ $(platform_id) = NetBSD ]; then \
        echo $(platform_id); \
    else \
        echo Unrecognized; \
    fi

Note that the assignments are really evaluated by the shell: it is the result of this evaluation that gets assigned to the make variables, not the shell commands.

Solution that requires GNU make. It works with GNU make on BSD, but not with BSD make.

One possibility is to use the if GNU make function:

platform := $(if $(patsubst Linux,,$(shell uname -s)),BSD or other,Linux)

Another one is to rely only on the shell conditionals:

platform := $(shell [ $$(uname) = Linux ] && echo Linux || echo BSD or other)

The GNU make conditionals can also be used:

ifeq ($(shell uname -s),Linux)
    platform := Linux
else
    platform := BSD or other
endif
like image 98
Renaud Pacalet Avatar answered Sep 22 '22 04:09

Renaud Pacalet


Beware before using this solution

A compliment of Renaud Pacalet: What you are assigning to your make variables are shell commands, not the result of their execution by the shell. It will seriously limit the use you can make of them (basically to recipes). You will not be able to use them as targets, prerequisites, other variables definitions, conditions of make conditionals.

Expanding on MadScientist's comment

I quote:

Note != was added to GNU make in version 4.0. It won't work in older versions.

And also simplifying the bunch of unnecessary ifs, we could get a working version on possibly all versions of both GNU and BSD make like the below approach.

An alternative approach through the shell

platform_id = $$( uname -s )

platform = $$( \
    case $(platform_id) in \
        ( Linux | FreeBSD | OpenBSD | NetBSD ) echo $(platform_id) ;; \
        ( * ) echo Unrecognized ;; \
    esac )

Important notes:

  • You need to use the standard = lazy assignments here. With immediate assignment operator :=, it does not work in BSD make.

  • You need to use ( ... ) in the case statement. Otherwise, it would not work on OpenBSD


Successfully tested on:

  • Linux Mint 19.0 Cinnamon (based on Ubuntu 18.04)

  • FreeBSD 11.2

  • OpenBSD 6.4

I am still working on making NetBSD 8.0 work in VirtualBox, so I cannot yet confirm this one.


Further testing on older versions of these systems necessary, so if you have one of them significantly older, please do test it, thank you.

like image 29
LinuxSecurityFreak Avatar answered Sep 21 '22 04:09

LinuxSecurityFreak