特定于目标的变量是有条件地设置变量的合适工具吗?

Posted

技术标签:

【中文标题】特定于目标的变量是有条件地设置变量的合适工具吗?【英文标题】:Is a target-specific variable the proper tool to conditionally set a variable? 【发布时间】:2017-07-29 20:02:07 【问题描述】:

我正在处理下述问题。在研究它时,GNU Make manual,第 6.11 节说:

make 中的变量值通常是全局的;也就是说,它们是相同的 无论它们在哪里被评估......其中一个例外是 自动变量(请参阅自动变量)。

另一个例外是特定于目标的变量值。此功能 允许您为同一变量定义不同的值,基于 make 当前正在构建的目标。和自动一样 变量,这些值仅在 a 的上下文中可用 目标的配方(以及其他特定于目标的任务)。

像这样设置一个特定于目标的变量值:

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 $<

我认为Define make variable at rule execution time 可能是相关的,但细节对我来说仍然是模糊的。我不确定它是基石还是只是另一种选择。

特定于目标的变量是有条件地设置CRC_FLAG 变量的合适工具吗?如果是,那我们如何使用它来有条件地设置一个变量呢?

如果没有,那么有没有办法只在需要构建 crc-simd.o 时才为 CRC_FLAG 赋值?如果有,那我们怎么做呢?


这是我们的 GNUmakefile 包含的内容。虽然显示的是 ARMv8a,但 x86/x32/x64 是相似的。我们对 SSE4.2、NEON、AES、SHA、CLMUL、AVX 和 BMI 也做了类似的工作。

测试编译后,MIPS 上CRC_FLAG 为空,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) $<

【问题讨论】:

你似乎已经回答了你原来的问题,现在听起来你的问题应该是“我如何阻止make clean重建一切”,但你还没有提供一个完整的例子。跨度> 感谢@user657267。 “我如何阻止 make clean 重新构建所有内容” - 实际上还有更多规则需要避免构建所有内容。因此,我试图对填充CRC_FLAG 进行外科手术的原因。很抱歉造成混乱。 我不知道你的意思是什么招致所有编译的全部愤怒。所有什么编译?你的意思是,HAS_CRC := $(shell $(CXX) ...) 编译?我不明白为什么所有人都会跑。不仅会为 IS_... 的这个特定值编译吗? @MadScientist - 如果我需要构建foo.obar.o,它们将导致HAS_CRC 齿轮运行,因为我不知道怎么说,“只评估HAS_CRC 并且仅在构建 crc-simd.o 时设置 CRC_FLAG 变量的值“ 好的,但是每次调用 make 它只运行一次,并且只有一个运行,对吗?所以,基本上每次调用 make 都会额外编译一次,对吧?我知道这可能很烦人,但我试图了解您的 cmets 关于招致所有编译的全部愤怒 【参考方案1】:

如果您只需要此标志用于像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) $<

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

【讨论】:

" 似乎应该有一种更快的方法来确定是否支持该标志,但无论如何......" - 大声笑,是的,我知道你的意思。问题主要是 ARM 目标。在原生构建方面,GCC 和 Clang 非常适合。它们的行为就像是 Aarch64 上的 ARMv6,除了它们为 Aarch64 生成代码。否则,GCC 不会做任何广告。例如,请参阅Why is __ARM_FEATURE_CRC32 not being defined by the compiler? 那么,gcc -march=armv8-a --target-help 的输出在可用时不显示 crc 扩展名,而在不可用时不显示? 感谢@MadScientist。我没有看到任何有趣的东西。没有像 crc、aes、sha、pmull、asimd 这样的命中。这是 Pastebin,如果有兴趣:gcc -march=armv8-a --target-help. 相信你已经回答了这个问题:"如果没有,那么有没有办法只在需要构建 crc-simd.o 的时候给 CRC_FLAG 赋值?如果有,那么我们该怎么做?” 对吗(你回答了)? 这就是我要回答的问题,是的。如果您使用递归变量赋值,则在定义变量时不会扩展该值;相反,当使用变量时它会被扩展。如果该变量仅在 crc-simd.o 目标的配方中使用一次,则仅在构建该目标时才会扩展它。

以上是关于特定于目标的变量是有条件地设置变量的合适工具吗?的主要内容,如果未能解决你的问题,请参考以下文章

具有特定于案例值的 YAML 可重用变量

Makefile 在目标中设置变量

通过回发但特定于页面用户的变量的持久性

如何使用特定于应用程序的值覆盖共享库中的 sass 变量

使用 GitHub Actions 在 .net 应用程序中填充特定于环境的变量

我可以创建一个“全局”对象来存储多个对象的变量吗?