我正在研究下面描述的问题。在研究它时,GNU Make 手册第 6.11 节说:
make中的变量值通常是全局的;也就是说,它们是相同的 无论在哪里评估它们...一个例外是 自动变量(请参阅自动变量(。
另一个例外是特定于目标的变量值。此功能 允许您根据 Make的目标目前正在构建中。与自动一样 变量,这些值仅在 目标的配方(以及其他特定于目标的分配(。
设置特定于目标的变量值,如下所示:
target … : variable-assignment
多个目标值创建特定于目标的变量值 目标列表中的每个成员单独列出。
。
目标特定变量还有一个特殊功能:当 定义一个特定于目标的变量,该变量值也在 对本目标的所有先决条件及其所有先决条件的影响 先决条件等(除非这些先决条件覆盖了该变量 具有自己的特定于目标的变量值(。因此,例如,一个 像这样的声明:
prog : CFLAGS = -g prog : prog.o foo.o bar.o
。
在上面的 GNU Make 示例的上下文中,我需要这样的东西:
采用 SSE4.2 的英特尔机器 :
crc-simd.o: CRC_FLAG = -msse4.2
crc-simd.o:
$(CXX) $(CXXFLAGS) $(CRC_FLAG) -c $<
带CRC32的ARMv8a机器:
crc-simd.o: CRC_FLAG = -march=armv8-a+crc
crc-simd.o:
$(CXX) $(CXXFLAGS) $(CRC_FLAG) -c $<
我认为在规则执行时定义 make 变量可能是相关的,但细节对我来说仍然模糊不清。我不确定它是基石还是另一种选择。
特定于目标的变量是否是有条件地设置CRC_FLAG
变量的正确工具?如果是,那么我们如何使用它来有条件地设置变量?
如果没有,那么有没有办法仅在需要构建crc-simd.o
时才为CRC_FLAG
赋值?如果有,那我们该怎么做?
以下是我们的 GNUmakefile 包含的内容。虽然显示了 ARMv8a,但 x86/x32/x64 是相似的。我们对SSE4.2,NEON,AES,SHA,CLMUL,AVX和BMI也做了类似的工作。
测试编译完成后,CRC_FLAG
在MIPS上为空,在SSE4.2可用时取-msse4.2
,在ARMv8a上-march=armv8-a+crc
。问题是,它使像make clean
这样的食谱需要太多时间来运行。即使构建一个脏目标文件也会引起所有编译的全部愤怒。滞后是显而易见的。
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) $<
如果你只需要像crc-simd.o
这样的单个 .o 文件这个标志,那么为什么要在CRC_FLAG
的分配中使用:=
? 如果您改用=
则在使用之前不会扩展它,如果您只使用它一次,则只会扩展一次。
像这样:
ifeq ($(IS_ARMV8),1)
CRC_FLAG = $(shell $(CXX) $(CXXFLAGS) -march=armv8-a+crc -o $(TEMPDIR)/t.o -c crc-simd.cpp 2>/dev/null && printf %s -march=armv8-a+crc)
endif
# SSE4.2 or ARMv8a available
crc-simd.o : crc-simd.cpp
$(CXX) $(strip $(CXXFLAGS) $(CRC_FLAG) -c) $<
这仍然编译文件两次;似乎应该有一种更快的方法来确定是否支持该标志,但无论如何。