我有一个
的脚本和一个Makefile,它有一个特殊的时间戳文件作为make目标,配置文件作为目标源:
SRC = $(shell find ../config -iname "*.txt")
STAMP = $(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME).stamp
$(STAMP): $(SRC)
python inject.py
touch $(STAMP)
我将此Makefile添加为项目目标的构建阶段堆栈之上的“运行脚本构建阶段”。
在编译源代码之前运行了脚本构建阶段。
但是,由于脚本在执行期间修改了源代码,因此我需要构建两次以获取最新版本的构建产品。这就是我想象中发生的事情:
在阅读Xcode documentation on Build Phases之后,我尝试添加一个源文件,该文件在每次运行脚本时都会更新,作为“运行脚本构建阶段”的输出,但没有任何更改。由于配置文件的数量可能在我的项目中有所不同,我不想指定每个输入和输出文件。
如何让Xcode知道在“运行脚本构建阶段”期间所做的源文件更改?
答案 0 :(得分:80)
答案 1 :(得分:28)
这个解决方案可能已经过时了。请参阅更高的投票答案。
使用“外部目标”:
现在新的“外部目标”在之前运行主目标甚至开始收集依赖性信息,因此在脚本执行期间所做的任何更改都应该包含在构建中。
答案 2 :(得分:3)
还有一个稍微简单的选项,不需要单独的目标,但只有你的脚本每次都要修改相同的源文件时它才有可能。
首先,这里有一个简短的解释,对于那些为什么Xcode有时需要你构建两次(或做一个干净的构建)以查看目标应用程序中反映的某些更改的人感到困惑。如果源文件丢失,或者如果目标文件的上次修改日期早于源文件的上次修改日期,则在第一个构建阶段开始时,Xcode会编译源文件。如果您的项目运行的脚本在预编译构建阶段修改源文件,Xcode将不会注意到源文件的上次修改日期已更改,因此不会重新编译它。只有在第二次构建项目时,Xcode才会注意到日期更改并重新编译文件。
如果您的脚本每次都修改相同的源文件,这是一个简单的解决方案。只需在构建过程结束时添加运行脚本构建阶段 ,如下所示:
touch Classes/FirstModifiedFile.m Classes/SecondModifiedFile.m
exit $?
在构建过程结束时对这些源文件运行touch
可确保它们始终具有比其目标文件更晚的最后修改日期,因此Xcode将每次重新编译它们。
答案 3 :(得分:2)
从Xcode 4开始,看起来如果将生成的文件添加到构建阶段的输出部分,它将遵循该设置,而不会生成... has been modified since the precompiled header was built
错误消息。
如果您的脚本每次只生成少量文件,这是一个不错的选择。
答案 4 :(得分:1)
我很长时间都在努力解决这个问题。答案是使用ento的“外部目标”解决方案。他是为什么会出现这个问题,以及我们如何在实践中使用它......
在编译plist之后,Xcode4构建步骤才会执行。当然,这很愚蠢,因为这意味着任何修改plist的预构建步骤都不会生效。但是如果你考虑一下,它们实际上会在NEXT构建中生效。这就是为什么有些人谈到了plist值的“缓存”,或者“我必须做2个版本才能使它工作”。发生了什么是plist,然后你的脚本运行。下次构建时,plist使用修改后的文件构建,因此是第二次构建。
ento的解决方案是我发现实际做一个真正的预构建步骤的一种方法。不幸的是我还发现,如果没有干净的构建,它不会导致plist更新,我修复了它。以下是我们如何在plist中使用数据驱动的用户值:
在主app plist文件上使用touch会导致主目标每次都生成plist。我们将构建设置作为参数传递的原因是我们的命令行构建可以覆盖设置:
python脚本使用基本设置文件,并允许用户定义的设置文件覆盖默认值。你做了一个改变,并立即在plist中结束。我们只将它用于必须在plist中的设置。对于任何其他事情,这是浪费精力....生成一个json文件或类似的东西,并在运行时加载它:)
我希望这会有所帮助......这是一个艰难的日子,想出这个。
答案 5 :(得分:0)
@ento的外部目标解决方案自Xcode 11.5起不再起作用。解决方案是在运行脚本的Output Files
下添加所有将要更改的文件。
答案 6 :(得分:0)