I'm working on the issue described below. When researching it, the GNU Make manual, Section 6.11, says:
Variable values in make are usually global; that is, they are the same regardless of where they are evaluated ... One exception to that is automatic variables (see Automatic Variables).
The other exception is target-specific variable values. This feature allows you to define different values for the same variable, based on the target that make is currently building. As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).
Set a target-specific variable value like this:
target … : variable-assignment
Multiple target values create a target-specific variable value for each member of the target list individually.
...
There is one more special feature of target-specific variables: when you define a target-specific variable that variable value is also in effect for all prerequisites of this target, and all their prerequisites, etc. (unless those prerequisites override that variable with their own target-specific variable value). So, for example, a statement like this:
prog : CFLAGS = -g prog : prog.o foo.o bar.o
...
In the context of the GNU Make example above, I need something like:
Intel machine with SSE4.2:
crc-simd.o: CRC_FLAG = -msse4.2
crc-simd.o:
$(CXX) $(CXXFLAGS) $(CRC_FLAG) -c $<
ARMv8a machine with CRC32:
crc-simd.o: CRC_FLAG = -march=armv8-a+crc
crc-simd.o:
$(CXX) $(CXXFLAGS) $(CRC_FLAG) -c $<
I think Define make variable at rule execution time may be related, but the details are still foggy for me. I'm not sure if it is the keystone or just another alternative.
Is a target-specific variable the proper tool to conditionally set the CRC_FLAG
variable? If it is, then how do we use it to conditionally set a variable?
If not, then is there a way to assign a value to CRC_FLAG
only when crc-simd.o
needs to be built? If there is, then how do we do it?
Here's what our GNUmakefile contains. Though ARMv8a is shown, x86/x32/x64 is similar. And we do similar for SSE4.2, NEON, AES, SHA, CLMUL, AVX and BMI.
After the test compile, CRC_FLAG
will be empty on MIPS, take -msse4.2
when SSE4.2 is available, and -march=armv8-a+crc
on ARMv8a. The problem is, it makes recipes like make clean
take too much time to run. Even building one dirty object file incurs the full wrath of all the compiles. The lag is noticeable.
TEMPDIR ?= /tmp
EGREP ?= egrep
IS_ARMV8 ?= $(shell uname -m | $(EGREP) -i -c 'aarch32|aarch64')
...
ifeq ($(IS_ARMV8),1)
HAS_CRC := $(shell $(CXX) $(CXXFLAGS) -march=armv8-a+crc -o $(TEMPDIR)/t.o -c crc-simd.cpp; echo $$?)
ifeq ($(HAS_CRC),0)
CRC_FLAG := -march=armv8-a+crc
endif
endif
...
# SSE4.2 or ARMv8a available
crc-simd.o : crc-simd.cpp
$(CXX) $(strip $(CXXFLAGS) $(CRC_FLAG) -c) $<