Skip to content

Xcode 运行脚本构建警告

问题描述

在 Xcode 构建过程中,您可能会遇到以下警告提示:

warning build: Run script build phase 'Module name' will be run during every build because it does not specify any outputs.

这个警告表示指定的运行脚本构建阶段没有声明任何输出文件。因此 Xcode 无法确定该脚本是否需要重新运行:

  • Xcode 的构建系统依靠输入/输出文件的依赖关系来判断脚本是否需要执行
  • 当缺少输出声明时,Xcode 会假设脚本每次运行都可能产生不同结果
  • 导致该脚本在每次构建时都会重新执行,降低构建效率

未指定输出的脚本警告示例

根本原因

Xcode 的增量构建机制要求为脚本指定输入和输出:

  • 输入文件:脚本依赖的资源文件(可选)
  • 输出文件:脚本执行产生的生成文件(必需)
  • 系统会比较输入/输出文件的修改时间戳,仅在必要时运行脚本

重要提示

忽略此警告可能导致构建时间显著增加,尤其是在大型项目中。

解决方案

方法一:添加输出文件(推荐)

此方法通过声明输出文件让 Xcode 启用依赖分析:

  1. 打开目标项目的 Build Phases 标签页

  2. 定位显示警告的运行脚本阶段

  3. 在脚本末尾添加标记文件生成命令(如果脚本本身不产生输出文件):

    bash
    # 在脚本末添加以下命令
    touch "${BUILT_PRODUCTS_DIR}/script_output.timestamp"

    在脚本中添加标记文件命令

  4. Output Files 区域添加生成的标记文件路径:

    $(BUILT_PRODUCTS_DIR)/script_output.timestamp
  5. 保存设置并重新构建项目

进阶技巧

如果脚本实际产生文件,应直接指定这些真实输出路径而非标记文件:

bash
# 实际示例:代码生成脚本
swiftgen run --config ./swiftgen.yml
# Output Files 应添加生成的文件路径
$PROJECT_DIR/Generated/Assets.swift
$PROJECT_DIR/Generated/Strings.swift

方法二:针对性处理 CocoaPods 脚本(自动修复)

当警告来自 CocoaPods 生成的脚本时(如 [CP] Embed Pods Frameworks),添加以下代码到 Podfile 末尾:

ruby
post_integrate do |installer|
  projects = [installer.aggregate_targets[0]&.user_project, installer.pods_project].compact
  
  projects.each do |project|
    project.targets.each do |target|
      target.build_phases.grep(Xcodeproj::Project::Object::PBXShellScriptBuildPhase).each do |phase|
        next unless phase.name.start_with?('[CP]') 
        next unless (phase.input_paths || []).empty? 
        next unless (phase.output_paths || []).empty?
        
        phase.always_out_of_date = "1"
      end
    end
    project.save
  end
end

执行流程:

完成后执行:

bash
pod install

原理说明

此脚本会自动为无输入/输出的 CocoaPods 脚本设置 always_out_of_date 标记,等同于在 Xcode 中手动取消勾选 "Based on dependency analysis"

方法三:禁用依赖分析(不推荐)

仅作为临时解决方案:

  1. 在 Build Phases 中选择目标脚本
  2. 取消勾选 Based on dependency analysis 选项
  3. 保存设置

性能警告

此方法会导致脚本在每次构建时强制执行,可能显著增加构建时间(特别是耗时的脚本)。

附加建议

输入文件规范

对于有明确依赖的脚本,应在 Input Files 区域添加依赖路径:

$(PODS_ROOT)/Target Support Files/Pods-App/Pods-App-frameworks.sh
$PROJECT_DIR)/config.json

SwiftLint 示例项目

参考开源实现:SwiftLint构建阶段配置示例

总结

解决方案适用场景构建效率
添加输出文件自定义脚本⭐️⭐️⭐️⭐️⭐️
Podfile 自动修复CocoaPods 脚本⭐️⭐️⭐️
禁用依赖分析临时方案

最佳实践推荐

  1. 优先尝试为脚本添加真实输出文件
  2. CocoaPods 相关问题使用 Podfile 自动化修复
  3. 始终避免禁用依赖分析选项,除非脚本执行极快

通过正确声明脚本的输入/输出文件,可显著提升 Xcode 增量构建效率,同时消除恼人的构建警告。