开发者

Makefile ifeq logical or

开发者 https://www.devze.com 2023-04-10 12:59 出处:网络
How do you perform a logical OR using make\'s ifeq operator? e.g., I have (simplified): ifeq ($(GCC_MINOR), 4)

How do you perform a logical OR using make's ifeq operator?

e.g., I have (simplified):

ifeq ($(GCC_MINOR), 4)
    CFLAGS += -fno-strict-overflow
endif
ifeq ($(GCC_MINOR), 5)
    CFLAGS += -fno-strict-overflow
endif

but would like to consolidate these lines.

(yes, yes, autotools, configure, etc etc; too heavy-handed for the current situation, would like to keep everything within the Makefile here)

[logical opposite of this question: How to Use of Multiple co开发者_StackOverflow中文版ndition in 'ifeq' statement ]


As found on the mailing list archive,

  • http://osdir.com/ml/gnu.make.windows/2004-03/msg00063.html
  • http://osdir.com/ml/gnu.make.general/2005-10/msg00064.html

one can use the filter function.

For example

ifeq ($(GCC_MINOR),$(filter $(GCC_MINOR),4 5))

filter X, A B will return those of A,B that are equal to X. Note, while this is not relevant in the above example, this is a XOR operation. I.e. if you instead have something like:

ifeq (4, $(filter 4, $(VAR1) $(VAR2)))

And then do e.g. make VAR1=4 VAR2=4, the filter will return 4 4, which is not equal to 4.

A variation that performs an OR operation instead is:

ifneq (,$(filter $(GCC_MINOR),4 5))

where a negative comparison against an empty string is used instead (filter will return en empty string if GCC_MINOR doesn't match the arguments). Using the VAR1/VAR2 example it would look like this:

ifneq (, $(filter 4, $(VAR1) $(VAR2)))

The downside to those methods is that you have to be sure that these arguments will always be single words. For example, if VAR1 is 4 foo, the filter result is still 4, and the ifneq expression is still true. If VAR1 is 4 5, the filter result is 4 5 and the ifneq expression is true.

One easy alternative is to just put the same operation in both the ifeq and else ifeq branch, e.g. like this:

ifeq ($(GCC_MINOR),4)
    @echo Supported version
else ifeq ($(GCC_MINOR),5)
    @echo Supported version
else
    @echo Unsupported version
endif


You can introduce another variable. It doesnt consolidate both checks, but it at least avoids having to put the body in twice:

do_it = 
ifeq ($(GCC_MINOR), 4)
    do_it = yes
endif
ifeq ($(GCC_MINOR), 5)
    do_it = yes
endif
ifdef do_it
    CFLAGS += -fno-strict-overflow
endif


I don't think there's a concise, sensible way to do that, but there are verbose, sensible ways (such as Foo Bah's) and concise, pathological ways, such as

ifneq (,$(findstring $(GCC_MINOR),4-5))
    CFLAGS += -fno-strict-overflow
endif

(which will execute the command provided that the string $(GCC_MINOR) appears inside the string 4-5).


Here more flexible variant: it uses external shell, but allows to check for arbitrary conditions:

ifeq ($(shell test ".$(GCC_MINOR)" = .4  -o  \
                   ".$(GCC_MINOR)" = .5  -o  \
                   ".$(TODAY)"     = .Friday  &&  printf "true"), true)
    CFLAGS += -fno-strict-overflow
endif


Note that ifeq ($(GCC_MINOR),$(filter $(GCC_MINOR),4 5)) will catch the case where GCC_MINOR is not defined at all.

If you want to catch GCC_MINOR==4 or GCC_MINOR==5 this will do trick:

ifneq ($(filter $(GCC_MINOR),4 5),)
    echo "def"
endif


ifeq ($(GCC_MINOR), 4)
    CFLAGS += -fno-strict-overflow
endif
ifeq ($(GCC_MINOR), 5)
    CFLAGS += -fno-strict-overflow
endif

Another you can consider using in this case is:

GCC42_OR_LATER = $(shell $(CXX) -v 2>&1 | $(EGREP) -c "^gcc version (4.[2-9]|[5-9])")

# -Wstrict-overflow: http://www.airs.com/blog/archives/120
ifeq ($(GCC42_OR_LATER),1)
  CFLAGS += -Wstrict-overflow
endif

I actually use the same in my code because I don't want to maintain a separate config or Configure.

But you have to use a portable, non-anemic make, like GNU make (gmake), and not Posix's make.

And it does not address the issue of logical AND and OR.


In the case that you are looking to logically "or" several boolean flags together, one practical hack can be to simply let strings concatenate: if the end result is an empty string, then none of the options were true, else non-empty then at least one of them was enabled:

# Use `docker build --pull` in case either `PULL=whatever` is set OR if the `CI` environment variable is present.
ifneq ($(PULL)$(CI),)
PULL_OR_NOT := --pull
endif

build:
    docker build $(PULL_OR_NOT)

0

精彩评论

暂无评论...
验证码 换一张
取 消