はい、承知いたしました。Xcodeでのビルドエラー「Command PhaseScriptExecution failed with a nonzero exit code」の詳細な説明と直し方について、約5000語の記事を作成します。
Xcodeビルドエラー「Command PhaseScriptExecution failed」の完全ガイド:原因特定から解決策まで
はじめに
iOSやmacOSアプリケーションを開発している際に、Xcodeでビルドを実行すると遭遇する可能性のある様々なエラー。その中でも、「Command PhaseScriptExecution failed with a nonzero exit code
」というエラーは、多くの開発者にとって頭を悩ませる問題の一つです。このエラーは、ビルドプロセスの特定の段階で実行されるスクリプトが、正常終了しなかったことを示しています。
このエラーメッセージ自体は非常に一般的であり、具体的な原因を直接的に示しているわけではありません。そのため、エラーが発生した際には、その背後にある本当の問題を特定するための調査が必要になります。原因はプロジェクトの設定ミス、スクリプトの内容の誤り、権限の問題、依存関係ツールの不整合、開発環境の問題など、多岐にわたります。
この記事では、「Command PhaseScriptExecution failed with a nonzero exit code
」エラーに焦点を当て、エラーが発生するメカニズム、効果的な原因特定の方法、そして遭遇しやすい具体的な原因とその詳細な解決策について、網羅的に解説します。さらに、トラブルシューティングの際のコツや、将来的なエラー発生を防ぐための予防策についても触れていきます。この記事を読むことで、同様のエラーに遭遇した際に、冷静かつ的確に対応できるようになることを目指します。
「Command PhaseScriptExecution failed」エラーとは何か?
Xcodeのビルドプロセスは、いくつかの段階(フェーズ)を経て実行されます。これらのフェーズには、ソースコードのコンパイル、ライブラリのリンク、リソースファイルのコピーなどがあります。そして、その中に「Run Script Phase」(スクリプト実行フェーズ)と呼ばれるものがあります。
Run Script Phaseとは
Run Script Phaseは、開発者がビルドプロセス中に任意のシェルスクリプトを実行できるフェーズです。このフェーズは非常に柔軟性が高く、さまざまな用途で利用されます。一般的な使用例としては以下のようなものがあります。
- 依存関係管理ツールの連携: CocoaPodsやCarthageなどの依存関係管理ツールは、ビルドプロセス中に必要なフレームワークをコピーしたり、設定ファイルを生成したりするためにRun Script Phaseを利用します。例えば、CocoaPodsは
Embed Pods Frameworks
やCopy Pods Resources
といったスクリプトを実行します。 - コード生成: モックオブジェクトの生成、Protocol Buffersのコンパイル、SwiftLintなどの静的解析ツールの実行など、ビルド前にコードを生成・検証するためにスクリプトが使われます。
- ファイル操作: ビルド成果物の整理、特定のファイルのコピーや移動、バージョン情報の埋め込みなどを行います。
- カスタムビルドステップ: プロジェクト固有の複雑なビルド処理を自動化します。
エラーメッセージの意味
Command PhaseScriptExecution failed with a nonzero exit code
というエラーメッセージは、まさにこのRun Script Phaseで実行されたスクリプトが、非ゼロの終了コードを返して終了したことを意味します。
- 終了コード (Exit Code): コマンドやスクリプトは、その実行結果を示すために終了コードを返します。慣習的に、終了コードが
0
である場合は「成功」を、0以外
の値である場合は「失敗」(何らかのエラーが発生した)を示します。 - nonzero exit code: つまり、「0以外の終了コード」であり、スクリプトが正常に完了しなかったことを明確に示しています。
したがって、Command PhaseScriptExecution failed with a nonzero exit code
は、「ビルド中に実行されたスクリプトがエラーを発生させて中断しました」ということをXcodeが報告しているメッセージなのです。
エラー発生時の典型的な状況
このエラーは、以下のような状況で発生しやすい傾向があります。
- プロジェクトに新しいライブラリ(特にCocoaPodsやCarthage経由)を追加または更新した後。
- Gitなどでプロジェクト設定ファイル(
.xcodeproj
,.xcworkspace
,Podfile
,Cartfile
など)をマージした後。 - Xcodeのバージョンをアップデートした後。
- macOSのバージョンをアップデートした後。
- プロジェクトのビルド設定(Build Settings)を変更した後。
- 手動でRun Script Phaseを追加または編集した後。
- 開発環境(パス、権限、インストールされているツールなど)に変更があった後。
これらの状況は、ビルドプロセスで実行されるスクリプトの内容や、スクリプトが依存する外部環境に影響を与える可能性があるため、エラーの原因となり得ます。
エラーの原因を特定するためのステップ
Command PhaseScriptExecution failed with a nonzero exit code
エラーの解決は、原因の特定にかかっています。エラーメッセージ自体が抽象的なため、詳細なログを読み解くことが不可欠です。以下に、原因特定のための具体的なステップを解説します。
Step 1: 詳細なエラーログを確認する
エラーが発生したら、まずXcodeのレポートナビゲーターを開き、詳細なビルドログを確認します。ここには、エラーが発生した正確なコマンド、その出力、およびエラーコードが含まれています。
- レポートナビゲーターを開く: Xcodeのウィンドウの左側にあるナビゲーターエリアで、一番右端のアイコン(吹き出しのような形)をクリックします。これがレポートナビゲーターです。
- ビルド失敗のエントリーを選択: レポートナビゲーターには、過去のビルド履歴が一覧表示されます。最新の失敗したビルドのエントリー(通常、赤色のアイコンが表示されています)を選択します。
- 詳細ログを展開する: 選択したビルドエントリーの右側に表示される詳細ペインで、ビルドプロセスの各ステップが表示されます。失敗したステップ(通常、赤色の感嘆符が表示されています)を展開します。多くの場合、
Run Script
フェーズの中にエラーが含まれています。 - 「Transcript」を確認する: 失敗したRun Scriptフェーズを展開すると、その実行ログが表示されます。「Transcript」または同様の項目をクリックして、ログ全体を表示します。
- エラーメッセージを探す: ログの中に、
error:
,Errno
,command not found
,Permission denied
,No such file or directory
,Segmentation fault
などのキーワードを探します。これらのキーワードの周辺に、エラーの直接的な原因を示す情報が含まれています。
ログ読解のポイント:
- エラーメッセージの直前・直後: エラーメッセージだけでなく、その数行前と数行後も確認しましょう。スクリプトが最後に実行しようとしたコマンドや、エラーが発生する直前の処理が記録されていることが多いです。
- エラーコード: ログの最後に、エラーコード(例:
Exit status 1
,Exit code 65
など)が表示されることがあります。特定の終了コードは特定の問題を示す場合がありますが、多くは一般的な失敗を示すだけです。重要なのは、その前に出力されているエラーメッセージです。 - 実行されたコマンド: ログには、失敗したスクリプト内で実行された具体的なコマンドが表示されていることがあります。このコマンドを特定することで、何が失敗したのかが分かります。
- ファイルパスやディレクトリ名: エラーメッセージに含まれるファイルパスやディレクトリ名(例:
/path/to/your/file.sh: No such file or directory
)は、問題の対象を特定する上で非常に重要です。 - スクリプトの識別: 複数のRun Scriptフェーズがある場合、ログのどこかにエラーが発生したスクリプトの名前やパス(例:
PhaseScriptExecution [スクリプト名] ...
)が記載されているはずです。
Step 2: エラーが発生したフェーズとスクリプトを特定する
詳細ログでエラーの発生源がPhaseScriptExecution
であることを確認したら、次は具体的にどのRun Scriptフェーズでエラーが起きているのかを特定します。
- Project Editorを開く: プロジェクトナビゲーターでプロジェクトファイル(
.xcodeproj
または.xcworkspace
)を選択し、中央のエディターエリアでプロジェクト設定を表示します。 - 対象ターゲットを選択: エディターエリアの上部で、ビルドが失敗したターゲットを選択します。
- Build Phasesタブを選択: ターゲット設定のタブの中から「Build Phases」を選択します。
- Run Scriptフェーズを確認: Build Phasesの一覧の中に、一つまたは複数の「Run Script」フェーズが表示されています。ログで特定したスクリプト名や内容と照らし合わせ、エラーが発生したRun Scriptフェーズを特定します。
- スクリプトの内容を確認: 該当するRun Scriptフェーズを展開し、中に記述されているシェルスクリプトの内容を確認します。
このステップにより、エラーが「どのスクリプト」で発生しているのかが明確になります。多くの場合、このスクリプトはCocoaPodsやCarthageが生成したものか、開発者が手動で追加したカスタムスクリプトです。
Step 3: 環境要因を考慮する
エラーはスクリプトの内容だけでなく、それが実行される環境にも影響されます。以下の点も確認しておくと、原因特定の手助けになります。
- macOSのバージョン、Xcodeのバージョン: 互換性の問題がないか確認します。特に最近アップデートした場合は、それが原因である可能性があります。
- Command Line Tools: XcodeのPreferences -> Locations -> Command Line Toolsで、適切なバージョンのCommand Line Toolsが選択されているか確認します。
- シェル環境: スクリプトが
bash
やzsh
など、特定のシェルを想定している場合があります。XcodeのRun Scriptフェーズの設定で、どのシェルが使われているか確認できます。また、ターミナルで実行するスクリプトとXcode内で実行するスクリプトでは、環境変数(特にPATH
)が異なる場合があることを意識します。 - Apple Silicon (M1/M2/M3) Mac: Intel MacからApple Silicon Macに移行した場合、またはその逆の場合、アーキテクチャの違い(x86_64 vs arm64)や、Rosetta 2環境での実行の有無が問題となることがあります。
これらのステップを経て、エラーが発生した具体的な箇所(ログのエラーメッセージ、実行されたコマンド、関連するファイルパス)と、それがどのようなスクリプトで、どのような環境で実行されているのかを把握することが、解決への第一歩となります。
一般的な原因とそれぞれの解決策
原因特定のためのステップを踏んだら、次は具体的な解決策を試していきます。ここでは、Command PhaseScriptExecution failed
エラーの一般的な原因とその解決策を詳述します。
原因 1: スクリプトの内容に問題がある
これは最も直接的な原因の一つです。Run Scriptフェーズに記述されたスクリプト自体に誤りがある場合です。
-
考えられる問題点:
- シェルスクリプトのシンタックスエラー。
- 存在しないコマンドやプログラムを実行しようとしている(
command not found
)。 - 存在しないファイルやディレクトリを参照している(
No such file or directory
)。 - コマンドの引数が間違っている。
- スクリプト内で使用しているパスが間違っている(絶対パス、相対パスの誤り)。
- 特定の環境変数に依存しているが、その値が期待通りでない、または定義されていない。
- スクリプト内で無限ループや長時間かかる処理が実行されている(タイムアウト)。
- スクリプトが予期しない入力を受け取ったり、予期しない出力を生成したりしている。
- スクリプト内で呼び出している別のプログラムがエラーになっている(
Segmentation fault
やIllegal instruction
など、低レベルなエラー)。
-
解決策:
- スクリプトの確認と修正: Build Phasesで該当のRun Scriptフェーズを開き、スクリプトの内容を一行ずつ確認します。typo、コマンド名、ファイルパス、オプションなどが正しいかチェックします。
-
ターミナルでのテスト実行: エラーが発生したスクリプトの内容をコピーし、Xcodeのビルド環境に近い状態でターミナルで実行してみます。ただし、Xcodeのビルドプロセス中に設定される環境変数(
SRCROOT
,BUILD_DIR
など)は手動で設定する必要があります。これらの変数は、Xcodeのビルドログに表示されていることが多いです。例えば、以下のスクリプト断片をターミナルでテストする前に、SRCROOT="[プロジェクトルートへのパス]"
のように設定します。
“`bash
# スクリプトの先頭によくある環境変数の定義例
export SRCROOT=”${SRCROOT}”
export BUILD_DIR=”${BUILD_DIR}”
export CONFIGURATION_TEMP_DIR=”${CONFIGURATION_TEMP_DIR}”テストしたいコマンド
your_command –option “$SRCROOT/path/to/file”
``
set -x
ターミナルで実行することで、エラーメッセージがより詳細に表示されることがあります。
3. **デバッグ出力の追加**: スクリプトの先頭にを追加すると、スクリプトが実行する各コマンドとその引数が標準エラー出力に表示されるようになります。これにより、どのコマンドでエラーが発生しているか、どのような引数が渡されているかを確認できます。また、
set -eを追加すると、いずれかのコマンドが非ゼロの終了コードを返した場合、スクリプトが即座に終了します。これにより、エラーが発生した正確な場所を特定しやすくなります。
command not found
4. **パスの問題**:や
No such file or directoryが出る場合は、コマンドのパスが通っているか、ファイルやディレクトリのパスが正しいか確認します。スクリプト内で絶対パスを使用するか、スクリプトの先頭で
PATH環境変数を明示的に設定する(例:
export PATH=/usr/local/bin:$PATH)ことで解決することがあります。
“$SRCROOT/My Project/file.txt”`)。これにより、シェルがパスを正しく解釈するようになります。
5. **引用符の使用**: ファイルパスや変数にスペースや特殊文字が含まれる可能性がある場合は、パス全体をダブルクォーテーションで囲みます(例:
原因 2: ファイルやディレクトリへのアクセス権限がない (Permission Denied)
スクリプトが、読み取り、書き込み、または実行しようとしているファイルやディレクトリに対する適切な権限を持っていない場合に発生します。
-
考えられる問題点:
- スクリプト自身に実行権限がない。
- スクリプトが書き込もうとしているディレクトリ(例えば、ビルド成果物ディレクトリ、Derived Dataディレクトリなど)に書き込み権限がない。
- スクリプトが参照しようとしているファイルに読み取り権限がない。
- システム整合性保護 (SIP) によって、特定のシステム領域への書き込みが制限されている。
- ユーザーやグループの権限設定が間違っている。
-
解決策:
- 対象のファイル/ディレクトリの権限確認: エラーメッセージに示されているファイルまたはディレクトリに対して、現在のユーザーが必要な権限を持っているか確認します。ターミナルで
ls -l /path/to/item
コマンドを実行すると、ファイルやディレクトリの権限情報(読み取りr, 書き込みw, 実行x)と所有者、グループが表示されます。
bash
ls -l /path/to/your/file_or_directory
# 例: -rw-r--r-- 1 username staff ... file.txt (所有者: 読み書き可, グループ: 読み取り可, その他: 読み取り可)
# 例: drwxr-xr-x 3 username staff ... mydirectory (所有者: 読み書き実行可, グループ: 読み取り実行可, その他: 読み取り実行可) - 権限の変更: 必要に応じて、
chmod
コマンドで権限を変更します。例えば、スクリプトファイルに実行権限がない場合は、chmod +x /path/to/your/script.sh
で実行権限を追加します。ディレクトリへの書き込み権限が必要な場合は、chmod u+w /path/to/your/directory
などとします。ただし、システムディレクトリや他のユーザーが共有するファイルに対して安易に権限を変更するのは危険です。 - 所有者の確認:
ls -l
で表示される所有者が、Xcodeを実行しているユーザーと異なる場合、権限の問題が発生しやすいです。必要に応じてchown
コマンドで所有者を変更します(sudo chown username:groupname /path/to/item
)。 - Derived Dataのクリーンアップ: 以前のビルドプロセスが生成したロックファイルや一時ファイルが原因で権限問題が発生することがあります。Product -> Clean Build Folder (Shift + Cmd + K) を実行し、さらにDerived Dataディレクトリを手動で削除してみます。Derived Dataの場所は通常
~/Library/Developer/Xcode/DerivedData
です。Finderでこのディレクトリに移動し、プロジェクト名の付いたフォルダを削除します。 - Run ScriptフェーズのSandboxing: XcodeのBuild Settingsにある「User Script Sandboxing」設定がオンになっていると、スクリプトの実行環境が制限され、特定のファイルやディレクトリへのアクセスがブロックされることがあります。これが原因と考えられる場合は、一時的にこの設定をオフにして試してみることもできます(ただし、セキュリティ上の理由から通常はオンが推奨されます)。
- CocoaPods関連の権限問題: CocoaPodsで
pod install
やpod update
を実行する際に、sudo
を使用してしまった場合、Pod関連のファイルやディレクトリの所有者がrootになってしまい、その後のビルドで権限エラーが発生することがあります。この場合、sudo chown -R $(whoami):staff .
をプロジェクトルートディレクトリで実行し、所有者を現在のユーザーに戻してから、クリーンビルドやDerived Dataの削除を試みます。
- 対象のファイル/ディレクトリの権限確認: エラーメッセージに示されているファイルまたはディレクトリに対して、現在のユーザーが必要な権限を持っているか確認します。ターミナルで
原因 3: パスに関する問題 (No such file or directory, command not found)
スクリプトが期待するファイルやコマンドが見つからない場合に発生します。これは、パスの設定ミスや環境変数の不整合が原因です。
-
考えられる問題点:
- スクリプト内で指定されているファイルやディレクトリへのパスが間違っている。
- スクリプトが必要とする実行可能ファイル(コマンド)へのパスが、Xcodeのシェル環境の
PATH
環境変数に含まれていない。 - 開発者がターミナルで使用しているシェル設定(例:
~/.bash_profile
,~/.zshrc
)で設定されたPATH
が、Xcodeのビルド環境には反映されていない。 - 相対パスを使用しているが、スクリプトの実行場所(カレントディレクトリ)が期待と異なる。
-
解決策:
- フルパスの使用: スクリプト内でコマンドを実行する際に、コマンド名だけでなくフルパスを指定します。例えば、
swiftlint
コマンドを実行する場合、そのインストールパスが/usr/local/bin/swiftlint
であれば、スクリプト内で/usr/local/bin/swiftlint
と記述します。コマンドのフルパスは、ターミナルでwhich [command_name]
コマンドで確認できます。
bash
# 例: swiftlint のフルパスを使用
/usr/local/bin/swiftlint --config .swiftlint.yml -
PATH環境変数の設定: Run Scriptフェーズのスクリプトの先頭で、必要なディレクトリを含むように
PATH
環境変数を設定します。
“`bash
# 例: /usr/local/bin を PATH に追加
export PATH=/usr/local/bin:$PATHこれで swiftlint のようにコマンド名だけで実行可能になる
swiftlint –config .swiftlint.yml
複数のパスを追加する場合は、コロンで区切ります。
bash
export PATH=”/usr/local/bin:/usr/bin:/bin:$PATH”
``
/bin/sh
3. **XcodeのShell設定確認**: Run Scriptフェーズの設定で、使用するシェルが指定できます(例:,
/bin/bash,
/bin/zsh)。デフォルトは
/bin/shですが、
bashや
zshの拡張機能に依存するスクリプトの場合は、適切なシェルが設定されているか確認します。
SRCROOT
4. **環境変数などの確認**: スクリプト内で
$SRCROOTなどのXcode定義の環境変数を使用している場合、その値が正しいか確認します。ログにこれらの変数の値が出力されるように、スクリプトの先頭などで
echo “SRCROOT: $SRCROOT”`のようなデバッグ出力を追加すると良いでしょう。
5. シンボリックリンクの確認: スクリプトがシンボリックリンクを参照している場合、リンク先が存在するか、またそのパスが正しいか確認します。
- フルパスの使用: スクリプト内でコマンドを実行する際に、コマンド名だけでなくフルパスを指定します。例えば、
原因 4: 依存関係管理ツール (CocoaPods, Carthage, SPM) の問題
CocoaPods、Carthage、Swift Package Manager (SPM) は、ビルドプロセスに深く統合されており、それぞれがRun Scriptフェーズを利用します。これらのツールの設定ミスや不整合は、高頻度でCommand PhaseScriptExecution failed
エラーの原因となります。
-
CocoaPods関連の問題:
pod install
やpod update
が正常に完了していない。.xcworkspace
ファイルではなく、.xcodeproj
ファイルを開いてビルドしている。CocoaPodsを使用しているプロジェクトは、必ず.xcworkspace
ファイルを開く必要があります。- Podsプロジェクト自体のビルドに失敗している(ライブラリ自体のコンパイルエラーなど)。
Pods-[TargetName]-frameworks.sh
やPods-[TargetName]-resources.sh
といった、CocoaPodsが生成するスクリプトでエラーが発生している。これらのスクリプトは、Podsプロジェクトでビルドされたフレームワークやリソースをメインプロジェクトに組み込む役割を担います。- CocoaPodsのバージョン、またはPodfileで指定されているライブラリのバージョンが、Xcodeのバージョンやプロジェクト設定と互換性がない。
-
Apple Silicon Mac環境で、Rosetta 2環境とネイティブ環境が混在している(例: ターミナルでRosettaなしで
pod install
したが、XcodeはRosettaで実行している、またはその逆)。 -
解決策(CocoaPods):
.xcworkspace
を開く: 最も基本的な確認事項です。必ず.xcworkspace
ファイルを開いてビルドしてください。pod install
を再実行: ターミナルでプロジェクトルートディレクトリに移動し、pod install
を再実行します。エラーが出ないか確認します。- CocoaPodsのクリーンアップ: 問題が解決しない場合、CocoaPodsの統合を一度解除してから再統合します。
bash
pod deintegrate # プロジェクトからPodsの統合を解除
pod clean # CocoaPodsのキャッシュなどをクリーンアップ
pod install # 再度統合
pod deintegrate
はプロジェクトのPod関連設定を削除するため、実行前にプロジェクトファイルをGitなどでコミットしておくことを推奨します。 - Derived Dataの削除とクリーンビルド: 前述の通り、CocoaPods関連のキャッシュもDerived Dataに含まれていることがあります。Derived Dataディレクトリを手動で削除し、Product -> Clean Build Folderを実行してから再度ビルドします。
- Podfile.lockの確認:
Podfile.lock
ファイルがGit管理されており、他の開発者と差異がないか確認します。 - Podfileの内容確認: 追加・更新したPodのバージョン指定や、ターゲットの設定に間違いがないか確認します。
- Apple Silicon Mac環境: Rosetta 2環境での問題を疑う場合、ターミナルをRosettaで開いて(FinderでTerminalアプリを選び、「情報を見る」から「”Rosetta” を使用して開く」にチェックを入れる)
pod install
を実行してみます。Xcodeも同様に設定して試すか、Build SettingsでExcluded Architectures (arm64 for simulator) を調整して試みます。
-
Carthage関連の問題:
carthage update
やcarthage build
が正常に完了していない。- Run Scriptフェーズ(通常は
copy-frameworks
スクリプトを実行)の設定が間違っている。特に、Input FilesとOutput Filesのパス設定。 - Carthageでビルドされたフレームワークが、指定されたパスに存在しない。
-
Carthageでビルドされたフレームワークが、正しいアーキテクチャ(シミュレーター、デバイスなど)に対応していない。
-
解決策(Carthage):
- Carthageビルドの再実行: ターミナルでプロジェクトルートディレクトリに移動し、
carthage update --platform iOS
などのコマンドを再実行し、エラーが出ないか確認します。必要に応じて--no-use-binaries
オプションを試します。 - Run Scriptフェーズの確認: Build Phasesの
Run Script
フェーズ(通常はcopy-frameworks
スクリプトを実行しているもの)を開きます。- スクリプトのパスが正しいか確認します(例:
/usr/local/bin/carthage copy-frameworks
)。 - Input Files: Carthageで追加したフレームワークのパス(例:
$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework
など)が正しく設定されているか確認します。 - Output Files: アプリケーションバンドル内にコピーされるフレームワークの最終的なパス(例:
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Alamofire.framework
など)が正しく設定されているか確認します。Input/Output Filesの設定ミスは、ファイルが見つからないエラーによく繋がります。
- スクリプトのパスが正しいか確認します(例:
- フレームワークの存在確認: Carthage/Buildディレクトリの中に、必要なフレームワークが期待通りの名前で存在するか確認します。
- Derived Dataの削除とクリーンビルド: Derived Dataを削除し、クリーンビルドを試みます。
- Carthageビルドの再実行: ターミナルでプロジェクトルートディレクトリに移動し、
-
Swift Package Manager (SPM) 関連の問題:
- SPM依存関係の解決に失敗している。
- バイナリターゲットの場合、そのパス設定が間違っている。
-
キャッシュの問題。
-
解決策(SPM):
- パッケージ依存関係の解決: File -> Swift Packages -> Resolve Package Versionsを選択し、依存関係を再解決します。
- Derived Dataの削除とクリーンビルド: Derived Dataを削除し、クリーンビルドを試みます。SPM関連のファイルもDerived Dataにキャッシュされるため、これが有効なことが多いです。
原因 5: キャッシュやDerived Dataの問題
Xcodeのビルドシステムは、ビルド時間を短縮するために様々なキャッシュを利用します。しかし、このキャッシュが破損したり、古い情報を含んでいたりすると、予期しないビルドエラーが発生することがあります。Command PhaseScriptExecution failed
エラーも、キャッシュの問題が間接的な原因となることがあります。
-
考えられる問題点:
- 以前のビルドで生成された一時ファイルや中間生成物が不整合を引き起こしている。
- クリーンビルドやDerived Data削除を行わずに、大幅なコード変更や設定変更を行った。
-
解決策:
- クリーンビルドの実行: Product -> Clean Build Folder (Shift + Cmd + K) を実行します。これにより、ビルド成果物ディレクトリがクリーンアップされます。
- Derived Dataの手動削除: クリーンビルドだけでは解決しない場合、Derived Dataディレクトリを完全に削除します。XcodeのPreferences -> LocationsでDerived Dataのパスを確認し、Finderでそのディレクトリを開き、該当プロジェクトのフォルダを削除します。
- デフォルトのパス:
~/Library/Developer/Xcode/DerivedData
- 削除方法: Finderで「移動」メニューから「フォルダへ移動…」を選択し、
~/Library/Developer/Xcode/DerivedData
と入力してEnterキーを押します。表示されたフォルダの中から、エラーが発生しているプロジェクト名のフォルダを探して削除します。
- デフォルトのパス:
Derived Dataの削除は、ビルドキャッシュや中間生成物を完全にクリアするため、多くの種類のビルドエラーに有効な「おまじない」として広く知られています。ただし、次にビルドする際には全てのファイルを最初からビルドし直すため、時間がかかります。
原因 6: 環境変数やビルド設定
Run Scriptフェーズは、Xcodeのビルド設定で定義された様々な環境変数にアクセスできます。これらの環境変数の値がスクリプトの期待と異なる場合や、ビルド設定自体の問題がスクリプトの実行に影響を与える場合があります。
-
考えられる問題点:
- スクリプトが依存する環境変数(例:
BUILD_SETTING_VALUE
)が、Build Settingsで正しく設定されていない、または期待と異なる値になっている。 - Build Settingsのパス設定(Header Search Paths, Library Search Paths, Framework Search Pathsなど)が、スクリプトが参照するファイルに影響を与えている。
- ビルド設定(例: Build Active Architecture Only, Optimization Level, Provisioning Profileなど)が、スクリプト内で使用されるツールやコマンドの挙動に影響を与えている。
- スクリプトが依存する環境変数(例:
-
解決策:
- 環境変数の値を確認: エラーログに
echo
コマンドで出力させた環境変数の値が、期待通りか確認します。 - Build Settingsの確認: Project EditorのBuild Settingsタブを開き、関連しそうな設定(特にパス設定、コード署名設定、ビルドオプションなど)を確認します。他の正常にビルドできるプロジェクトの設定と比較するのも有効です。
- Run ScriptフェーズのShell設定: スクリプトを実行するシェル (
/bin/sh
,/bin/bash
,/bin/zsh
など) が正しく選択されているか確認します。 - User-Defined Settingの確認: 独自のUser-Defined Settingを追加している場合、その名前や値に間違いがないか確認します。
- 環境変数の値を確認: エラーログに
原因 7: XcodeやmacOSのバージョン互換性
XcodeやmacOSのバージョンが、プロジェクト、依存関係ツール、または特定のライブラリと互換性がない場合に、ビルドエラーが発生することがあります。特に、新しいmacOSやXcodeがリリースされた直後や、古いプロジェクトを新しい環境で開いた場合によく起こります。Apple Silicon Macへの移行もこの範疇に含まれます。
-
考えられる問題点:
- Xcodeの新しいバージョンが、特定のスクリプトコマンド(例: 古いコマンドラインツール)をサポートしなくなった。
- 古いライブラリや依存関係ツールが、新しいXcodeやmacOSのセキュリティ変更やファイルシステム構造の変更に対応していない。
- Apple Silicon Mac上で、Universalバイナリとしてビルドされていないツールやライブラリを使用しようとしている。
- Rosetta 2環境とネイティブ環境の切り替えが不適切。
-
解決策:
- Xcode/macOSのアップデート: 可能であれば、XcodeとmacOSを最新バージョンにアップデートします。ただし、最新バージョンにアップデートしたことが原因の場合は、一時的に以前のバージョンに戻すことも検討が必要になる場合があります(特に依存関係ツールやライブラリがまだ最新OSに対応していない場合)。
- 依存関係ツールのアップデート: CocoaPods, Carthageなどのバージョンを最新にアップデートします。
- ライブラリの対応確認: 使用しているライブラリやフレームワークが、現在のXcode/macOSバージョン、そしてApple Silicon環境に対応しているか確認します。GitHubのIssue Trackerなどで関連情報が見つかることがあります。
- Apple Silicon Mac環境の調整:
- 特定のライブラリやツールがarm64アーキテクチャに対応していない場合、ターゲットのBuild Settings -> Architectures -> Excluded Architectures に
arm64
を追加して、シミュレータービルド時にarm64を除外することを試みます(ただし、これは一時的な回避策であり、最終的にはライブラリの更新が必要です)。 - CocoaPodsなど、ターミナルで実行するコマンドがアーキテクチャの問題を起こしている場合、ターミナルをRosettaで実行して
pod install
などを試みます。
- 特定のライブラリやツールがarm64アーキテクチャに対応していない場合、ターゲットのBuild Settings -> Architectures -> Excluded Architectures に
- Command Line Toolsの確認: Xcode Preferences -> Locationsで、現在使用しているXcodeバージョンに対応するCommand Line Toolsが選択されていることを確認します。
原因 8: ファイルパスの長さ制限や特殊文字
非常に長いファイルパスや、パスに含まれるスペース、特殊文字(例: &
, (
, )
, ;
, '
, "
, <
, >
, |
など)が、スクリプト内で正しく処理されない場合にエラーが発生することがあります。特に、他のプラットフォーム(例: Windows)からプロジェクトをコピーしてきた場合などに長いパスが問題になることがあります。
-
考えられる問題点:
- ファイルパスがOSやファイルシステムの制限を超えている。
- スクリプト内でパスを扱う際に、スペースや特殊文字が正しくエスケープ(例:
を
\
とする)または引用符で囲まれていない。
-
解決策:
- プロジェクトの移動: プロジェクトフォルダを、ルートディレクトリに近い、より短いパスの場所に移動します(例:
~/Develop/MyProject
)。 - パスの引用符: スクリプト内で変数やコマンドの引数としてパスを扱う際は、必ずダブルクォーテーションで囲みます(例:
cp "$SOURCE_PATH" "$DESTINATION_PATH"
)。これにより、パスにスペースが含まれていても全体が1つの引数として扱われます。 - ファイル名の変更: 可能であれば、パスに含まれる特殊文字を含むファイルやディレクトリの名前を変更します。
- プロジェクトの移動: プロジェクトフォルダを、ルートディレクトリに近い、より短いパスの場所に移動します(例:
原因 9: その他の外部ツールやスクリプトの問題
プロジェクトに組み込んでいるLintツール(SwiftLint, RealmSwiftLintなど)、コード生成ツール、特定のライブラリが提供するカスタムスクリプトなどがエラーの原因となることもあります。
-
考えられる問題点:
- インストールされているツールのバージョンがプロジェクトと互換性がない。
- ツールの設定ファイル(例:
.swiftlint.yml
)に誤りがある。 - ツール自体がクラッシュしている(
Segmentation fault
など)。
-
解決策:
- ツールの再インストール/アップデート: 問題のツールをHomebrewなどで再インストールまたはアップデートします。
- 設定ファイルの確認: ツールの設定ファイルの内容が正しいか確認します。
- ツールの単独実行: エラーログから特定したコマンドを、ターミナルでプロジェクトルートディレクトリから手動で実行し、エラーが発生するか確認します。
トラブルシューティングのコツと高度なデバッグ
エラー解決をより効率的に進めるための追加のコツや、より詳細なデバッグ方法を紹介します。
- エラーログ全体を保存・共有: エラーログは非常に多くの情報を含んでいます。解決できない場合は、ログ全体をファイルに保存したり、他の開発者に共有したりする際に役立ちます。
- Gitで変更を戻す: Gitを使用している場合、エラーが発生する直前のコミットに戻してビルドできるか確認します。これにより、原因が直前の変更点にあるのか、それとも別の要因(環境設定の変更など)にあるのかを切り分けることができます。直前の変更点に原因がある場合は、その変更を細かく見直すことで問題箇所を発見しやすくなります。
- 最小限のプロジェクトでの再現: もし可能であれば、新しい空のプロジェクトを作成し、問題の原因となっていると思われる部分(例: 特定のPod、特定のRun Scriptフェーズ)だけを移植して、エラーが再現するか試します。これにより、問題がプロジェクト全体の複雑さに起因するのか、それとも特定の要素に起因するのかを判断できます。
- Stack OverflowやGitHub Issuesの検索: エラーメッセージの特定のキーワード(特に、スクリプト名、ツール名、エラーコード、ログに出力された具体的なエラーメッセージ)を使って、Stack Overflowや対象ライブラリのGitHub Issue Trackerを検索します。同じ問題に遭遇した他の開発者の質問や解決策が見つかることが多いです。
- コミュニティへの質問: 解決策が見つからない場合は、開発コミュニティ(Stack Overflow, Qiita, デベロッパーフォーラムなど)で質問を投稿します。その際は、以下の情報を含めると、より的確なアドバイスを得やすくなります。
- 使用しているXcode、macOSのバージョン
- エラーが発生したRun Scriptフェーズの名前や内容
- 詳細なエラーログ全体
- プロジェクトで使用している依存関係管理ツール(CocoaPods, Carthage, SPMなど)とそのバージョン
- エラーが発生する直前に行った変更(ライブラリ追加、設定変更など)
- これまでに試した解決策とその結果
- Xcodeのビルド診断設定: XcodeのBuild Settingsには、ビルドの診断に役立つ様々な設定があります。例えば、
Other [C/C++/Swift] Flags
にデバッグフラグを追加したり、Compilation Modeを変更したりすることで、ビルドプロセスの挙動を詳細に観察できる場合があります(ただし、これは高度なデバッグ手法であり、通常のCommand PhaseScriptExecution failed
エラーには直接関係しないことも多いです)。
予防策
Command PhaseScriptExecution failed
エラーは完全に避けるのが難しい場合もありますが、いくつかの予防策を講じることで、発生頻度を減らしたり、発生した際の原因特定を容易にしたりすることができます。
- 変更は少量ずつ行う: プロジェクトの設定変更や新しいライブラリの追加は、一度にまとめて行わず、少量ずつ行い、その都度ビルドして動作確認を行います。これにより、問題が発生した場合に、どの変更が原因であるかを特定しやすくなります。
- Gitを積極的に利用する: 変更を加える前に頻繁にコミットを行います。これにより、問題が発生した場合に容易に以前の状態に戻すことができます。実験的な変更を行う際は、一時的なブランチを作成して作業するのも良い方法です。
.gitignore
を適切に設定する: Derived DataディレクトリやPodfile.lock以外のPods関連ファイルなど、環境固有のファイルやビルドキャッシュはGit管理から除外します。これにより、チーム開発において環境の違いによる問題を減らすことができます。- Run Scriptフェーズをシンプルに保つ: Run Scriptフェーズには、必要最低限の処理のみを記述するように心がけます。複雑な処理は、別途シェルスクリプトファイルとして作成し、Run Scriptフェーズからはその外部スクリプトを呼び出す形式にします。これにより、スクリプトの管理やデバッグが容易になります。
- パスを扱う際は引用符を忘れずに: スクリプト内でファイルパスや変数を使用する際は、スペースや特殊文字が含まれる可能性を考慮し、常にダブルクォーテーションで囲む習慣をつけます。
- CI/CD環境の活用: 可能であれば、継続的インテグレーション/継続的デリバリー (CI/CD) 環境を構築し、Gitにプッシュするたびに自動でビルドを実行します。これにより、開発者のローカル環境に依存しないクリーンな環境でのビルド状況を常に把握でき、問題の早期発見に繋がります。
まとめ
Xcodeビルドエラー「Command PhaseScriptExecution failed with a nonzero exit code
」は、開発者が遭遇しやすい一般的なエラーの一つです。このエラーは、ビルドプロセスのRun Scriptフェーズで実行されたスクリプトが、何らかの原因で正常に完了しなかったことを示しています。
エラー解決の鍵は、抽象的なエラーメッセージに惑わされず、詳細なビルドログを丹念に読み解くことにあります。ログからエラーが発生した具体的なスクリプト、実行されたコマンド、エラーメッセージ、関連するファイルパスなどを特定することが、原因究明の第一歩となります。
一般的な原因としては、スクリプト自体の記述ミス、ファイルやディレクトリへのアクセス権限の問題、パスの設定ミス、CocoaPodsやCarthageといった依存関係管理ツールの設定不備や不整合、そしてXcodeのキャッシュやDerived Dataの不整合などが挙げられます。また、開発環境(Xcode/macOSバージョン、Apple Silicon環境など)の問題も無視できません。
解決策は原因に応じて多岐にわたりますが、多くの場合、以下の基本的なトラブルシューティングから始めるのが有効です。
- Product -> Clean Build Folder (Shift + Cmd + K) を実行する。
- Derived Dataディレクトリを手動で削除する。
- CocoaPodsやCarthageを使用している場合は、それぞれのツール固有のクリーンアップや再インストール、依存関係の再解決(
pod install
,carthage update
, SPMのResolve Package Versionsなど)を試みる。
これらの基本的なステップで解決しない場合は、ビルドログに立ち戻り、エラーメッセージやコマンドを元に、この記事で解説した具体的な原因候補(スクリプト内容、権限、パス、環境変数など)を一つずつ潰していく根気強い調査が必要です。
Command PhaseScriptExecution failed
エラーは、一見難解に思えますが、その本質は「特定のスクリプト実行が失敗した」というシンプルなものです。ログを正確に読み、原因候補を体系的に検証していくことで、ほとんどの場合、解決にたどり着くことができます。この記事が、あなたがこのエラーに遭遇した際の助けとなり、問題解決の一助となれば幸いです。
Happy Coding!