如何在xcconfig变量中添加值?

50

我正在使用Xcode和.xcconfig文件。我想要在预处理器定义中添加一些值,但我无法使其起作用。

我尝试了以下方法(以及许多变化),但目前还没有成功:

GCC_PREPROCESSOR_DEFINITIONS = '$(GCC_PREPROCESSOR_DEFINITIONS) NEW_VALUE'

符号NEW_VALUE从未被添加到预处理器定义中。

是否有人成功地将新值追加到xcconfig文件中的变量中?

8个回答

36

由于其他答案中提到的原因,您不能轻松地继承值。

我建议采用级联定义设置。假设APP是您的项目前缀,让我们简单地定义一些CFLAGS:

platform.xcconfig:

APP_PLATFORM_CFLAGS = -DMAS=1

project.xcconfig:

#include "platform.xcconfig"
APP_PROJECT_CFLAGS = -DBETA=1

target-one.xcconfig:

#include "project.xcconfig"
APP_TARGET_CFLAGS = -DSUPER_COOL=1
#include "merge.xcconfig"

目标-two.xcconfig:

#include "project.xcconfig"
APP_TARGET_CFLAGS = -DULTRA_COOL=1
#include "merge.xcconfig"

合并.xcconfig:

OTHER_CFLAGS = $(inherited) $(APP_PLATFORM_CFLAGS) $(APP_PROJECT_CFLAGS) $(APP_TARGET_CFLAGS)
然后,你将基于 target-xxx.xcconfig 为每个目标构建配置创建。一个真实的项目将使用更复杂的设置,使用一个项目配置文件和一个不同的目标配置文件,但是这个想法很清楚了。
另外,请记住 $(inherited) 是指在层次结构中 更高级别的,而不是 更早的。例如,在目标层面它从项目层面继承。不确定这是否也适用于 Xcode 4。
这是对 GTM 的简化,去那里了解更多。

22

如其他答案所述,在 Xcode 10 之前,xcconfig 文件不能简单地继承和扩展彼此的值。但是,

自从 Xcode 10 起,xcconfig 现在可以按照人们的期望工作:$(inherited) 实际上会扩展为变量的先前定义值。

当一个 .xcconfig 文件包含同一构建设置的多个赋值时,使用 $(inherited)$(<setting_name>) 进行的后续赋值将继承 .xcconfig 中较早的赋值。传统的构建系统导致每个使用 $(inherited)$(<setting_name>) 的情况都跳过 .xcconfig 中定义的任何其他值。要检测您的 .xcconfig 是否受到此改进的影响,请在终端中运行 defaults write com.apple.dt.XCBuild EnableCompatibilityWarningsForXCBuildTransition -bool YES,这将导致 Xcode 生成有关此情况的警告。

(Xcode 10 beta 1 发布说明)

例如,给定两个简单的 .xcconfig 文件:

// Generic.xcconfig
OTHER_SWIFT_FLAGS = $(inherited) -DMY_GENERIC_FLAG
// Debug.xcconfig
#include "Generic.xcconfig"
OTHER_SWIFT_FLAGS = $(inherited) -DMY_DEBUG_FLAG

假设您的项目在Debug配置中使用Debug.xcconfig,您将会在OTHER_SWIFT_FLAGS中得到预期的值-DMY_GENERIC_FLAG -DMY_DEBUG_FLAG,而不是在Xcode 9及之前的版本中仅得到-DMY_DEBUG_FLAG


新行为非常简单:如果有的话,$(inherited)将被先前定义的变量值替换。

因此,在上面的示例中,如果我们展开#include语句,我们将得到以下xcconfig文件:

// Merged xcconfig files after resolving #include
OTHER_SWIFT_FLAGS = -DMY_GENERIC_FLAG
OTHER_SWIFT_FLAGS = $(inherited) -DMY_DEBUG_FLAG
  • 第一行的OTHER_SWIFT_FLAGS值为-DMY_GENERIC_FLAG ($(inherited)不会被展开,因为这是我们遇到的第一个OTHER_SWIFT_FLAGS的定义1)。
  • 在第二行,OTHER_SWIFT_FLAGS被覆盖,并且它的值现在为-DMY_GENERIC_FLAG -DMY_DEBUG_FLAG (它之前的值加上新添加的标志)。

在更复杂的xcconfig设置中,情况可能如下所示:

// First.xcconfig
OTHER_SWIFT_FLAGS = $(inherited) -DMY_FIRST_FLAG
// Second.xcconfig
OTHER_SWIFT_FLAGS = $(inherited) -DMY_SECOND_FLAG
// Last.xcconfig
#include "Generic.xcconfig"
OTHER_SWIFT_FLAGS = $(inherited) -DMY_LAST_FLAG
// Merge.xcconfig
#include "First.xcconfig"
#include "Second.xcconfig"
OTHER_SWIFT_FLAGS = $(inherited) -DMY_INTERMEDIATE_FLAG
#include "Last.xcconfig"

我们假设这一次我们在配置中使用Merge.xcconfig。

OTHER_SWIFT_FLAGS的解析值将是-DMY_FIRST_FLAG -DMY_SECOND_FLAG -DMY_INTERMEDIATE_FLAG -DMY_GENERIC_FLAG -DMY_LAST_FLAG

起初可能会感到惊讶,但实际上这是有道理的:一旦#include被解析,我们最终得到了这个xcconfig:

OTHER_SWIFT_FLAGS = $(inherited) -DMY_FIRST_FLAG
OTHER_SWIFT_FLAGS = $(inherited) -DMY_SECOND_FLAG
OTHER_SWIFT_FLAGS = $(inherited) -DMY_INTERMEDIATE_FLAG
OTHER_SWIFT_FLAGS = $(inherited) -DMY_GENERIC_FLAG
OTHER_SWIFT_FLAGS = $(inherited) -DMY_LAST_FLAG

最终解析的值是最后一行定义的值,即 -DMY_LAST_FLAG 加上它从上一行继承的值 -DDMY_GENERIC_FLAG(这个值来自于 Generic.xcconfig,包含在 Last.xcconfig 中)等等。

请注意,如果您在其中一个定义中忘记了 $(inherited),则会破坏继承链,只会获得从底部定义开始的值,直到没有 $(inherited) 的定义。


1 人们可能期望 xcconfig 文件继承在项目级别定义的先前值,但似乎并不是这种情况。


截至 Xcode 10 beta 1,构建设置编辑器 GUI 似乎无法正确解析在 xcconfig 文件中定义的变量的正确值,并显示值,就像使用旧的 Xcode 10 之前的行为解析的值一样。我在此方面提交了 rdar://40873121 的问题报告 (https://openradar.appspot.com/radar?id=4925869923500032)。


这个答案中描述的行为似乎在Xcode 12.5(我测试过的唯一版本)中不再是这样了。其他人也是这种情况吗? - Roger Oba
2
@RogerOba 我刚刚验证了一下,Xcode 12.5 没有任何变化。 - Guillaume Algis
1
顺便说一下,我通过将项目的配置xcconfig文件更改为generic.xcconfig并使其所有子目标使用debug.xcconfig(其中我删除了generic.xcconfig的#include)来解决了我的问题 - 这样$(inherited)就可以工作了。 以前,我将debug.xcconfig分配给父级和所有子级目标,并进行#include。也许值得在回答中澄清您正在使用的配置设置@GuillaumeAlgis? 我的这个解决方法适用于单层继承,但不适用于多层继承(例如您的“第1个,第2个中间和最后”示例)。 - Roger Oba
1
@RogerOba 在 PRODUCT_NAME 中使用 $(inherited) 确实存在问题。我认为这与我在答案末尾提到的错误有关。在某些地方,Xcode可以理解新的继承系统(我有一个使用完整继承名称创建的 .app),而在其他一些地方则不行,这会导致问题。我在一个示例项目中重现了这个问题: https://github.com/guillaumealgis/SO-1393987-ProductNameInheritanceXcconfig - Guillaume Algis
@RogerOba,你从项目的xcconfig继承变量的方式很有趣,我通常只使用每个{目标;构建配置}组合最多一个xcconfig文件,所以我从未尝试过这种方法。不过它似乎将继承链限制为仅两个成员(一个父级+一个子级)。 - Guillaume Algis
显示剩余4条评论

10
根据Xcode Build System Guide:
当一个配置单元包含多个特定构建设置的定义时,Xcode会使用该单元中的最后一个定义。请记住,配置文件无法访问其所包含的配置文件中进行的构建设置定义。也就是说,您无法修改包含的配置文件中所做的定义;您只能替换它。
因此,我想这意味着不可能向给定变量追加值。

9

这个有效:

xcodebuild GCC_PREPROCESSOR_DEFINITIONS='$(value) NEW_VALUE'

2
谢谢,我只是使用 GCC_PREPROCESSOR_DEFINITIONS=$(value) NEW_VALUE(不带引号)。 - mkeiser

4

我认为在尝试将Cocoapods的xcconfig文件集成到我的项目中时,我意外发现了一个更好的方法。我喜欢在我的项目中设置以下内容:

GCC_PREPROCESSOR_DEFINITIONS = CONFIGURATION_$(CONFIGURATION)

不幸的是,这与Pods.xcconfig附带的定义发生了冲突。正如其他地方所述,$(inherited)不能按预期工作。下面的内容可以正常工作:

GCC_PREPROCESSOR_DEFINITIONS[config=*] = CONFIGURATION_$(CONFIGURATION) $(inherited)

更新:

如果您需要覆盖特定配置的设置,则可能会尝试编写类似以下内容的代码:

GCC_PREPROCESSOR_DEFINITIONS[config=*] = CONFIGURATION_$(CONFIGURATION) $(inherited)
GCC_PREPROCESSOR_DEFINITIONS[config=Debug] = DEBUG=1 CONFIGURATION_$(CONFIGURATION) $(inherited)

遗憾的是这种方法行不通,但把第二个声明放到一个仅在Debug配置中才加载的文件中,可以正确地覆盖设置。

GCC_PREPROCESSOR_DEFINITIONS[config=*] = ... 语法在 Xcode 5 中有效。我在特定目标的 .xcconfig 文件中使用它来将中心定义的项目范围构建设置附加到特定目标设置中:BLA[config=*] = $(BLA_TARGET_SPECIFIC) $(BLA_PROJECT_WIDE) - bassim

4

这里有一个相关问题的答案,可能对这个特定问题有所帮助。它描述了一种技巧,即每个层级组成一部分定义,然后在叶级xcconfig中将它们全部组合起来。


1
这在我的Xcode 2.4.1中有效:
GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS) NEW_VALUE"
有时你需要允许几秒钟的时间,在编辑配置文件和更改出现在目标的“构建信息”之间。

1
XCode 3.2运气不太好 :( - Martin Cote

0
您想要使用占位符 $(inherited) 来表示从较低级别继承的值,例如:
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited) NEW_VALUE"

10
这个看起来是完美答案,但是错了。$(inherited)xcconfig文件内部不起作用;特别是,你不能使用它来扩展从一个已包含的文件中继承的定义。 - Jens Ayton
2
那么如何进行扩展? - Van Du Tran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接