特定于目标的变量是否是有条件地设置变量的正确工具?



我正在研究下面描述的问题。在研究它时,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) $<

这仍然编译文件两次;似乎应该有一种更快的方法来确定是否支持该标志,但无论如何。

最新更新