首页 文章

Xcode:在每次直接修改源代码的构建之前运行脚本

提问于
浏览
52

我做了什么:

我有一个脚本

  • 阅读一些配置文件以生成源代码片段

  • 查找相关的Objective-C源文件和

  • 用步骤1中生成的代码替换源代码的某些部分 .

和一个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作为“运行脚本构建阶段” .

发生了什么:

在编译源代码之前运行了脚本构建阶段 .

但是,由于脚本在执行期间修改了源代码,因此我需要构建 twice 以获取最新版本的构建产品 . 这是我想象中发生的事情:

  • 第一次运行:Xcode收集依赖信息--->没有变化

  • 第一次运行:Xcode运行"Run Script Build Phase" --->源代码在Xcode后面改变了

  • 第一次运行:Xcode完成构建,认为没有什么需要更新

  • 第二次运行:Xcode收集依赖信息--->源已更改,需要重建!

  • 第二次运行:Xcode运行Run Script Build Phase“--->一切都是最新的

  • 第二次运行:Xcode继续编译

在阅读了Xcode documentation on Build Phases之后,我尝试添加一个源文件,每当脚本作为"Run Script Build Phases"的输出运行时都会更新,但没有任何改变 . 由于配置文件的数量可能在我的项目中有所不同,我不想指定每个输入和输出文件 .

问题:

如何让Xcode知道在“运行脚本构建阶段”期间所做的源文件更改?

编辑:

  • 补充说我在其他构建阶段之前放置了脚本构建阶段

5 回答

  • 75

    到目前为止提到的每种技术都是过度杀伤力 . 再现steve kim的可见性评论:

    在构建阶段选项卡中,只需将“运行脚本”步骤拖到更高的位置(例如,在“编译源”之前) .

    在XCode 6上测试过

  • 28

    这个解决方案可能已经过时了 . 请参阅较高的投票答案 .


    使用“外部目标”:

    • 从菜单中选择"Project"> "New Target..."

    • 选择"Mac OS X"> "Other"> "External Target"并将其添加到项目中

    • 打开其设置并填写脚本设置

    • 打开主目标's settings and add the new target as it' s直接依赖项的"General"选项卡

    现在新的"External Target"在主目标甚至开始收集依赖关系信息之前运行,因此在脚本执行期间所做的任何更改都应该包含在构建中 .

  • 1

    还有另一个稍微简单的选项,它不需要单独的目标,但只有当您的脚本每次都倾向于修改相同的源文件时它才可行 .

    首先,在这里's a brief explanation for anyone who'混淆了为什么Xcode有时需要你构建两次(或做一个干净的构建)以查看目标应用程序中反映的某些更改 . 如果源文件丢失,或者目标文件's last-modified date is earlier than the source file'的最后修改日期是第一个构建阶段的开始,则Xcode会编译源文件 . 如果你的项目运行了一个在预编译构建阶段修改源文件的脚本,那么Xcode赢了't notice that the source file's的最后修改日期已经改变了,所以只有当你第二次构建项目Xcode会注意到日期时它才会赢得't bother to recompile it. It'更改并重新编译该文件 .

    如果您的脚本每次都修改相同的源文件,这是一个简单的解决方案 . 只需在构建过程结束时添加一个Run Script构建阶段,如下所示:

    touch Classes/FirstModifiedFile.m Classes/SecondModifiedFile.m
    exit $?
    

    在构建过程结束时对这些源文件运行 touch 可确保它们始终具有比其目标文件更晚的最后修改日期,因此Xcode将每次重新编译它们 .

  • 3

    从Xcode 4开始,看起来如果将生成的文件添加到构建阶段的输出部分,它将遵循该设置,而不会生成 ... has been modified since the precompiled header was built 错误消息 .

    如果您的脚本每次只生成少量文件,这是一个不错的选择 .

  • 2

    我很长时间都在努力解决这个问题 . 答案是使用ento的“外部目标”解决方案 . 他是为什么会出现这个问题以及我们如何在实践中使用它...

    在编译plist之后,Xcode4构建步骤才会执行 . 当然,这很愚蠢,因为这意味着任何修改plist的预构建步骤都不会生效 . 但是如果你考虑一下,它们实际上会在NEXT上生效 Build . 这就是为什么有些人谈到了plist值的“缓存”,或者“我必须做2个版本才能使它工作” . 发生了什么是plist,然后你的脚本运行 . 下次构建时,plist使用修改后的文件构建,因此第二次构建 .

    ento的解决方案是我发现实际做一个真正的预构建步骤的一种方法 . 不幸的是我还发现,如果没有干净的构建,它不会导致plist更新,我修复了它 . 以下是我们如何在plist中使用数据驱动的用户值:

    • 添加一个指向python脚本并传递一些参数的外部构建系统项目

    • 将用户定义的构建设置添加到构建中 . 这些是你传递给python的参数(更多关于为什么我们以后这样做)

    • python脚本读取一些输入JSON文件并构建一个plist预处理器头文件并触及主应用程序plist

    • 主项目已打开"preprocess plist files"并指向此预处理器文件

    在主应用程序plist文件上使用touch会导致主目标每次都生成plist . 我们将构建设置作为参数传递的原因是我们的命令行构建可以覆盖设置:

    • 将用户定义的变量"foo"添加到预建项目中 .

    • 在预构建中,您可以使用$(foo)将值传递给python脚本 .

    • 在命令行中,您可以添加foo = test以传入新值 .

    python脚本使用基本设置文件,并允许用户定义的设置文件覆盖默认值 . 你做了一个改变,并立即在plist中结束 . 我们只将它用于必须在plist中的设置 . 对于其他任何事情,这是浪费精力....生成一个json文件或类似的东西,并在运行时加载它:)

    我希望这会有所帮助......这是一个艰难的日子 .

相关问题