使用 xcode,如何从命令的输出定义预处理器宏?

发布于 2024-12-12 19:29:31 字数 299 浏览 2 评论 0原文

正如主题所说,我希望能够在构建期间运行特定命令,并使其输出成为预处理器宏的定义。

现在,我有几个用户定义的变量(在project.pbxproj中),我可以使用它们的值来填充宏定义,如下所示:

GCC_PREPROCESSOR_DEFINITIONS = (
“STRINGIFY(x)=@#x”,
"_MACRO=STRINGIFY(${MACRO})",
);
宏= foo;

我可以将 MACRO 设置为每个方案的不同值(例如调试与发布),这非常有用。但是,我不知道如何通过运行命令来设置它。

As the topic says, I want to be able to run a specific command during build, and have its output be the definition of a preprocessor macro.

Right now, I have several user-defined variables (in project.pbxproj) and I am able to use their values to fill macro definitions, as follows:

GCC_PREPROCESSOR_DEFINITIONS = (
"STRINGIFY(x)=@#x",
"_MACRO=STRINGIFY(${MACRO})",
);
MACRO = foo;

I can set MACRO to a different value per scheme (e.g Debug vs. Release) which is very useful. But, I cannot figure out how to set it by running a command.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小瓶盖 2024-12-19 19:29:31

我可以想到 3 个选项:

环境变量:如果您从命令行构建,则可以在调用构建命令之前导出一个变量 (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 中 >目标>构建规则,添加新的自定义规则。

进程*.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=one-liner-command。就像这两个无意义的例子一样:

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 更改时,生成的标头都会更新。

I can think of 3 options:

Environment variable: If you build from command line you can export a variable (export ENVMACRO=superfoo) before invoking the build command and use it in an Xcode configuration file OTHER_CFLAGS=-DMACRO=$(ENVMACRO). You need to configure the target with the .xcconfig file.

Run Script Build Phase: Custom script that generates a header file.

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

In my tests you need an empty header file to be able to compile properly. There are other options like modifying an existing file using sed or any other command.

Custom Build Rule: Custom script that process an input file and creates an output file. Similar to Run Script build phase but slightly better because it will run the script only when the input file has been modified. For example, create a .macro file and process it to update a header file.

In Xcode > Target > Build rules, add new custom rule.

Process: *.macro

Custom script:

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

Output files: $(SRCROOT)/Project.h

Project.macro contains pairs MACRO=one-liner-command. Like these two non-sense examples:

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

Generated file will look like:

// Do not edit
#define COMMIT @"c486178"
#define BUILDYEAR @"2011"
// Updated on Sat Oct 29 14:40:41 CEST 2011

Each time Project.macro changes, the generated header will be updated.

疯狂的代价 2024-12-19 19:29:31

如果有人好奇,我使用的解决方案是添加一个新的构建阶段,该阶段运行一个脚本,该脚本手动生成带有我想要的宏的头文件。它并不优雅,我仍然更喜欢更好的东西,但它确实有效。

If anyone is curious, the solution I've used is to add a new build phase that runs a script that manually generates a header file with the macros that I want. It's not elegant, and I would still prefer something better, but it works.

你与昨日 2024-12-19 19:29:31

我认为更好的解决方案是在项目构建设置中仅声明一个预处理器宏(例如用于调试的 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

I think a better solution would be to declare just one preprocessor macro in the project build settings (e.g. DEBUG for debug, RELEASE for release) and then in your Prefix.pch file you can check for the value in order to decide what other macros to define, e.g.:

// 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文