Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"ifeq" conditional syntax in makefile

As the conditional-directive ifeq is frequently used to compare word(s) expanded from variables, which often contains white-space, we may want and, in fact need, for Make to strip any leading or trailing white-space.

In fact, you may have an opposite view, i.e. Make should keep verbatim all of the arguments to an ifeq conditional, because the user may have had those whitespace as part of the "test", with the intention for those whitespace to play a deciding factor, when evaluating this ifeq directive, as true or false.

I can not decide, which of them is more correct.

In fact, I'm not alone!

Make itself cannot decide, which of them is correct. So, it may or may not strip leading or trailing whitespace.

In fact, sometimes it will strip only leading whitespace.

Not disappointing, Make will sometimes strip only trailing whitespace.

Of course, there are too many cases to check, so I will "do" only a few of them.



A makefile (VERSION 1), is:

ifeq ( a, a)
all::
    echo 'true'
else
all::
    echo 'false'
endif



Executing, I get:

$ make -r
echo 'false'
false



A makefile (VERSION 2), is:

ifeq (a ,a )
all::
    echo 'true'
else
all::
    echo 'false'
endif



Executing, I get:

$ make -r
echo 'false'
false



A makefile (VERSION 3), is:

ifeq ( a , a )
all::
    echo 'true'
else
all::
    echo 'false'
endif



Executing, I get:

$ make -r
echo 'false'
false



A makefile (VERSION 4), is:

ifeq (a , a)
all::
    echo 'true'
else
all::
    echo 'false'
endif



Executing, I get:

$ make -r
echo 'true'
true



A makefile (VERSION 5), is:

ifeq (a, a)
all::
    echo 'true'
else
all::
    echo 'false'
endif



Executing, I get:

$ make -r
echo 'true'
true



Summing up, just a few of the cases, we have:

# Both, have only leading whitespace.
ifeq( a, a)    as: false.

# Both, have only trailing whitespace.
ifeq(a ,a )    as: false.

# Both, have trailing AND trailing whitespace.
ifeq( a , a )  as: false.

# Left-hand-size has only trailing, and right-hand-size has only leading whitepsace.
ifeq(a , a)    as: true.

# Left-hand-size has NO whitespace at-all, and right-hand-size has only leading whitepsace.
ifeq(a, a)     as: true.

So, this methodology, that Make uses to evaluate the truthfulness of an ifeq conditional directive, is definitely turning it into:

  • Less consistent.
  • Less maintainable.
  • Harder to debug.
  • Prone to error.
  • Finally, a lot of "fun"!

Do we agree?

like image 315
Ji Cha Avatar asked Aug 24 '15 07:08

Ji Cha


People also ask

How do I add a condition in makefile?

Syntax of Conditionals Directives The text-if-true may be any lines of text, to be considered as part of the makefile if the condition is true. If the condition is false, no text is used instead. If the condition is true, text-if-true is used; otherwise, text-if-false is used.

What is := in makefile?

Expanded assignment = defines a recursively-expanded variable. := defines a simply-expanded variable.

How do you check if a variable is defined in makefile?

Check if variable is defined in a Makefilecheck_defined = \ $(strip $(foreach 1,$1, \ $(call __check_defined,$1,$(strip $(value 2))))) __check_defined = \ $(if $(value $1),, \ $(error Undefined $1$(if $2, ($2)))) install: $(call check_defined, var1) $(call check_defined, var2) # do stuff here..


1 Answers

You should read this:

Commas and unmatched parentheses or braces cannot appear in the text of an argument as written; leading spaces cannot appear in the text of the first argument as written. These characters can be put into the argument value by variable substitution. First define variables comma and space whose values are isolated comma and space characters, then substitute these variables where such characters are wanted, like this:

comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
# bar is now ‘a,b,c’.

You should also use the strip function when in doubt.


Here an example Makefile:

empty:=
space:= $(empty) $(empty)

x := $(space)a$(space)
y := $(space)a$(space)

ifeq ($(x),$(y))
all::
        @echo 'regular: true'
else
all::
        @echo 'regular: false'
endif

ifeq ($(strip $(x)),$(strip $(y)))
all::
        @echo 'strip:   true'
else
all::
        @echo 'strip:   false'
endif

And the result:

1:

x = $(space)a
y = $(space)a
regular: true
strip:   true

2:

x = a$(space)
y = a$(space)
regular: true
strip:   true

3:

x = $(space)a$(space)
y = $(space)a$(space)
regular: true
strip:   true

4:

x = a$(space)
y = $(space)a
regular: false
strip:   true

4:

x = a
y = $(space)a
regular: false
strip:   true
like image 104
jmlemetayer Avatar answered Sep 18 '22 04:09

jmlemetayer