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)
精彩评论