web-dev-qa-db-ja.com

Xcode:ソースコードを直接変更するすべてのビルドの前にスクリプトを実行する

私がしたこと:

私はそのスクリプトを持っています

  1. 構成ファイルをいくつか読んで、ソースコードスニペットを生成します。
  2. 関連するObjective-Cソースファイルを見つけて、
  3. ソースコードの一部を手順1で生成したコードに置き換えます。

そして、makeターゲットとして特別なタイムスタンプファイルを持ち、ターゲットソースとして構成ファイルを持つMakefile:

SRC = $(Shell find ../config -iname "*.txt")
STAMP = $(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME).stamp
$(STAMP): $(SRC)
    python inject.py
    touch $(STAMP)

プロジェクトターゲットのビルドフェーズのスタックの最上部に、このMakefileを「Run Script Build Phase」として追加しました。

どうした:

スクリプトビルドフェーズは、ソースをコンパイルする前に実行されました。

ただし、スクリプトは実行中にソースコードを変更するため、ビルド製品の最新バージョンを取得するためにtwiceをビルドする必要がありました。これが私が想像していることです。

  1. 最初の実行:Xcodeは依存関係情報を収集します--->変更なし
  2. 1回目の実行:Xcodeが「Run Script Build Phase」を実行します---> Xcodeの背後でソースが変更されます
  3. 最初の実行:Xcodeはビルドを終了し、更新する必要はないと考えます
  4. 2回目の実行:Xcodeは依存関係情報を収集します--->ソースが変更されました。再構築が必要です!
  5. 2回目の実行:Xcodeは、スクリプトのビルドフェーズを実行します」--->すべてが最新です
  6. 2回目の実行:Xcodeはコンパイルに進みます

ビルドフェーズに関するXcodeドキュメント を読んだ後、スクリプトが「スクリプトビルドフェーズの実行」の出力として実行されるたびに更新されることがわかっているソースファイルを追加しようとしましたが、何も変わりませんでした。構成ファイルの数はプロジェクトによって異なる場合があるため、すべての入力ファイルと出力ファイルを指定する必要はありません。

質問:

「スクリプトビルドフェーズの実行」中に行われたソースファイルの変更をXcodeに認識させるにはどうすればよいですか?

編集:

  • スクリプトのビルドフェーズを他のビルドフェーズの前に配置したことを追加しました
55
ento

これまでに説明したすべてのテクニックは過剰です。 steve kim の可視性に関するコメントの再現:

[ビルドフェーズ]タブで、[スクリプトの実行]ステップをより高い場所(たとえば、[ソースのコンパイル]の前)にドラッグします。

XCode 6でテスト済み

82
marinosb

このソリューションはおそらく時代遅れです。代わりに上位の回答を参照してください。


「外部ターゲット」を使用:

  1. メニューから[プロジェクト]> [新しいターゲット...]を選択します
  2. [Mac OS X]> [その他]> [外部ターゲット]を選択して、プロジェクトに追加します
  3. その設定を開き、スクリプトの設定を入力します
  4. メインターゲットの設定の[全般]タブを開き、新しいターゲットを直接依存関係として追加します

これで、新しい「外部ターゲット」が実行されますbeforeメインターゲットは依存関係情報の収集を開始するので、スクリプトの実行中に行われた変更はビルドに含まれます。

28
ento

別のターゲットを必要としないもう少しシンプルなオプションがありますが、スクリプトが毎回同じソースファイルを変更する傾向がある場合にのみ実行可能です。

まず、ターゲットアプリに反映された特定の変更を確認するために、Xcodeで2回ビルド(またはクリーンビルド)が必要になる場合がある理由について混乱している人のための簡単な説明を以下に示します。 Xcodeは、生成するオブジェクトファイルが見つからない場合、またはオブジェクトファイルの最終変更日がソースファイルの最終変更日よりも早い場合、ソースファイルをコンパイルします最初のビルドフェーズの開始時。プロジェクトがプリコンパイルビルドフェーズでソースファイルを変更するスクリプトを実行する場合、Xcodeはソースファイルの最終変更日が変更されたことに気付かないため、それを再コンパイルする必要はありません。 Xcodeが日付の変更に気付き、ファイルを再コンパイルするのは、プロジェクトを2回目にビルドするときだけです。

スクリプトが毎回同じソースファイルを変更する場合の簡単なソリューションを次に示します。 Run Scriptビルドフェーズを追加するだけですビルドプロセスの最後このように:

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

ビルドプロセスの最後にこれらのソースファイルでtouchを実行すると、オブジェクトファイルよりも最終更新日が常に遅くなることが保証されるため、Xcodeは毎回それらを再コンパイルします。

3
cduhn

Xcode 4では、生成されたファイルをビルドフェーズの出力セクションに追加すると、その設定が尊重され、... has been modified since the precompiled header was builtエラーメッセージ。

これは、スクリプトが毎回少数のファイルのみを生成する場合に適したオプションです。

2
Senseful

私もこれに長い間苦労しました。答えは、entoの「外部ターゲット」ソリューションを使用することです。彼は、なぜこの問題が発生し、実際にどのように使用するのか...

Xcode4ビルドステップは、plistがコンパイルされるまで実行されません。もちろん、これはばかげています。なぜなら、plistを変更するビルド前の手順は有効にならないからです。しかし、あなたがそれについて考えるなら、それらは実際に有効になります...次のビルドで。そのため、一部の人々はplist値の「キャッシュ」または「機能させるには2つのビルドを行う必要があります」について話しました。何が起こるかというと、plistがビルドされ、スクリプトが実行されます。次回のビルドでは、変更されたファイルを使用してplistがビルドされるため、2番目のビルドになります。

entoのソリューションは、実際にビルド前のステップを実際に行うことがわかった1つの方法です。残念ながら、クリーンビルドなしではplistが更新されないこともわかったので、修正しました。 plistにデータ駆動型のユーザー値がある方法は次のとおりです。

  1. pythonスクリプトを指し、いくつかの引数を渡す外部ビルドシステムプロジェクトを追加します。
  2. ユーザー定義のビルド設定をビルドに追加します。これらはpythonに渡す引数です(これについては後で説明します)
  3. pythonスクリプトはいくつかの入力JSONファイルを読み取り、plistプリプロセッサヘッダーファイルを構築し、メインアプリのplistに触れます
  4. メインプロジェクトでは、「プリプロセスplistファイル」がオンになっており、このプリプロセッサフ​​ァイルをポイントしています

メインアプリのplistファイルをタッチすると、メインターゲットが毎回plistを生成します。ビルド設定をパラメーターとして渡す理由は、コマンドラインビルドが設定をオーバーライドできるようにするためです。

  1. ユーザー定義変数「foo」をビルド前プロジェクトに追加します。
  2. プレビルドでは、$(foo)を使用してpythonスクリプトに値を渡すことができます。
  3. コマンドラインでfoo = testを追加して、新しい値を渡すことができます。

pythonスクリプトは、基本設定ファイルを使用し、ユーザー定義の設定ファイルがデフォルトをオーバーライドできるようにします。変更を加えると、すぐにplistになります。これは、それ以外の場合は、労力の無駄です...代わりにjsonファイルなどを生成し、実行時にロードします:)

これがお役に立てば幸いです...これを理解するのに数日は苦労しました。

1
mstelzer