Skip to content

Resolving Xcode "Run Script Has No Outputs" Warning

Problem Statement

When building Xcode projects, you may encounter this warning:

Warning: Run script build phase 'Module name' will be run during every build because it does not specify any outputs. To address this warning, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis."

This occurs when Xcode detects a Run Script build phase without output files specified. Without outputs to monitor, Xcode can't determine if the script needs re-executing, causing it to run unnecessarily on every build and slowing down your development process.

Understanding Build Phase Optimization

Xcode uses two mechanisms to optimize build phases:

  1. Input files: Files the script depends on
  2. Output files: Files the script generates

When both are specified, Xcode skips executing the script if:

  • Input files haven't changed
  • Output files already exist

When absent, Xcode shows this warning and defaults to executing the script every time, increasing build times.

For Custom Scripts

  1. Open your project in Xcode
  2. Select your target → Build Phases
  3. Find the problematic Run Script phase
  4. Add an output file path in the "Output Files" section using Xcode path variables:
$(BUILT_PRODUCTS_DIR)/script_output.txt
  1. Modify your script to create this file:
sh
# Your script commands
# ...

# Create output file (prevents warning)
touch "${BUILT_PRODUCTS_DIR}/script_output.txt"
sh
#!/bin/sh
# Actual script logic
process_files.sh

# Generate output
touch "${BUILT_PRODUCTS_DIR}/script_output"
rb
post_integrate do |installer|
  installer.aggregate_targets[0].user_project.targets.each do |target|
    target.build_phases.grep(Xcodeproj::Project::Object::PBXShellScriptBuildPhase).each do |phase|
      if phase.name&.start_with?("[CP]") && 
         (phase.input_paths || []).empty? && 
         (phase.output_paths || []).empty?
        phase.output_paths = ["$(BUILT_PRODUCTS_DIR)/#{phase.name}.out"]
      end
    end
  end
  installer.aggregate_targets[0].user_project.save
end

Important Notes

  • If the script doesn't produce files, generate an empty file using touch
  • Use Xcode path variables for portability (BUILT_PRODUCTS_DIR, PROJECT_DIR)
  • Multiple outputs can be specified for complex scripts

Handling CocoaPods Script Phases

Many occurrences come from CocoaPods integration. Add this to your Podfile to automatically resolve:

rb
post_integrate do |installer|
  main_project = installer.aggregate_targets[0].user_project
  pods_project = installer.pods_project
  
  [main_project, pods_project].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? && phase.output_paths.empty?
        
        phase.output_paths = ["$(BUILT_PRODUCTS_DIR)/#{phase.name}.output"]
      end
    end
    project.save
  end
end

After adding:

  1. Run pod install
  2. Commit changes to project files

CocoaPods Version Compatibility

Check compatibility with your CocoaPods version before implementation. Tested with CocoaPods 1.11+.

Alternative: Disable Dependency Analysis (Last Resort)

For scripts that must run every time (e.g., security checks):

  1. Open Build Phases
  2. Select the Run Script phase
  3. Uncheck "Based on dependency analysis"

Performance Impact

This causes the script to execute on every build. Only use this option if:

  • Your script has non-deterministic output
  • Adding output dependencies is impossible
  • Script execution time is negligible

Framework-Specific Solutions

Flutter Projects

  1. Ensure correct FLUTTER_ROOT path in Build Settings
  2. Run these commands before building:
sh
flutter clean
flutter pub get
pod install --repo-update

Firebase Crashlytics

Add empty output to upload symbols script:

sh
# ... existing Crashlytics script
touch "${BUILT_PRODUCTS_DIR}/crashlytics_run.out"

And set $(BUILT_PRODUCTS_DIR)/crashlytics_run.out as output

Troubleshooting

If solutions don't resolve warning:

  1. Clean build folder (Product → Clean Build Folder)
  2. Delete derived data:
sh
rm -rf ~/Library/Developer/Xcode/DerivedData
  1. Verify deployment targets match across projects

When Output Files Don't Work

If Xcode still complains after adding outputs:

  1. Check paths exactly match in script and output declaration
  2. Ensure script doesn't delete output files after creation
  3. Verify script succeeds without errors

Best Practices Summary

  • Always declare outputs for deterministic scripts
  • Avoid disabling dependency analysis unless absolutely necessary
  • For CocoaPods, use automatic fix in Podfile
  • Use Xcode environment variables for path portability
  • Regularly audit build phases for unoptimized scripts

Following these methods eliminates the warning while keeping your build times optimized. Prefer output file declaration whenever possible for the most efficient builds.