使用Xcode,如何从命令输出中定义预处理宏?

7
如题所述,我希望能够在构建过程中运行特定命令,并将其输出作为预处理器宏的定义。
目前,我有几个用户定义变量(在project.pbxproj文件中),我可以使用它们的值来填充宏定义,如下所示:
GCC_PREPROCESSOR_DEFINITIONS = (
"STRINGIFY(x)=@#x",
"_MACRO=STRINGIFY(${MACRO})",
);
MACRO = foo;
我可以根据不同的方案(例如Debug vs. Release)设置MACRO的不同值,这非常有用。但是,我无法弄清楚如何通过运行命令来设置它。
3个回答

11

我可以想到三个选项:

环境变量:如果你从命令行构建,你可以在调用构建命令之前导出一个变量(export ENVMACRO=superfoo),并在Xcode配置文件中使用它OTHER_CFLAGS=-DMACRO=$(ENVMACRO)。你需要使用.xcconfig文件来配置目标。

运行脚本构建阶段:自定义脚本生成头文件。

MACROVALUE=$(run-command-to-obtain-value)
echo "#define MACRO ($MACROVALUE)" > $(SRCROOT)/path/to/header.h

在我的测试中,你需要一个空的头文件才能正确编译。还有其他选项,比如使用sed或任何其他命令修改现有文件。

自定义构建规则:处理输入文件并创建输出文件的自定义脚本。类似于运行脚本构建阶段但稍微好一些,因为它只会在输入文件被修改时运行脚本。例如,创建一个.macro文件并处理它以更新头文件。

在Xcode > Target > Build rules中,添加新的自定义规则。

处理方式*.macro

自定义脚本:

HEADER="${SRCROOT}/Config.h"
cd ${SRCROOT}
echo "// Do not edit" > $HEADER
cat "${INPUT_FILE_PATH}" | while read line
do
    macro="`echo $line | cut -d= -f1`"
    cmd="`echo $line | cut -d= -f2-`"
    value=$($cmd)
    echo "#define ${macro} @\"${value}\"" >> $HEADER
done
echo "// Updated on "`date` >> $HEADER

输出文件: $(SRCROOT)/Project.h

Project.macro 包含键值对 MACRO=一行命令。例如这两个毫无意义的例子:

COMMIT=git log --pretty=format:%h -n 1
BUILDYEAR=date +%Y

生成的文件将如下所示:

// Do not edit
#define COMMIT @"c486178"
#define BUILDYEAR @"2011"
// Updated on Sat Oct 29 14:40:41 CEST 2011
每次 Project.macro 更改时,生成的头文件将会更新。

谢谢-我选择了第二个选项。在我的情况下,我希望命令在每次构建时运行。唯一的问题是,如果头文件的内容与新生成的内容不相同(为了避免依赖变化),我就不会写入实际的头文件。但我也非常喜欢第三个选项。 - michael

0

我认为更好的解决方案是在项目构建设置中仅声明一个预处理器宏(例如,DEBUG用于调试,RELEASE用于发布),然后在您的Prefix.pch文件中检查该值以决定定义哪些其他宏,例如:

// Use NSLOG and NSASSERT so that they are only output in debug mode
#ifdef DEBUG

//#warning You are running in Debug mode
#define NSLOG NSLog
#define NSASSERT NSAssert
#define NSASSERT1 NSAssert1

#else

#define NSLOG if(false)NSLog
#define NSASSERT(X, Y)  \
if(!(X)) {          \
NSLogOkay(Y);       \
}                   
#define NSASSERT1(X, Y, Z)  \
if(!(X)) {              \
NSLogOkay(Y, Z);        \
}                       

#endif

0
如果有人感兴趣,我使用的解决方案是添加一个新的构建阶段,运行一个脚本手动生成包含所需宏的头文件。这并不优雅,我仍然希望有更好的解决方案,但它可以工作。

1
恭喜你解决了问题。请确保将你的答案标记为“已接受”,以便其他人能够从你的成功中学习。干杯~ - Andrew Kozak

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