開発しているアプリによっては、自身で管理していないSDKなどの使用が必要となることがあります。SDKのインストールパスは大体同じ場合が多いと思いますが、任意の場所にインストール可能な場合、マシンや開発者によってインストール先が異なる場合もあります。
そのようなときに、プロジェクトファイルに直接、検索パスを設定してしまうと、Gitからプロジェクトファイルをプルするたびに、検索パスを自分の設定に合わせて変更しなければいけなくなってしまいます。逆に自分がコミットするときには、プロジェクトファイルを含めないように自分で注意しなければいけなくなってしまいます。
この記事ではこのような事態を回避するための方法を解説します。
ビルド設定ファイルの作成
プロジェクトファイルに設定される値が、環境依存になることが問題の原因です。回避するには、マシンごとに設定値が変わるようにビルド設定ファイルを作成します。
ビルド設定ファイルの作成方法と、それをプロジェクトに適用する方法については、以下の記事を参照してください。
上記の記事を参考に、次の3つのビルド設定ファイルを作成します。
Debug.xcconfig
Release.xcconfig
SearchPath.xcconfig
名前の通り、デバッグビルドにDebug.xcconfig
、リリースビルドにRelease.xcconfig
を設定します。次にDebug.xcconfig
とRelease.xcconfig
に以下のように記述します。
#include "SearchPath.xcconfig"
検索パスの変更
iOSアプリやmacOSアプリの場合、検索パスというと次の3つが一般的に使われます。
- フレームワーク検索パス
- ヘッダーファイル検索パス
- ライブラリ検索パス
検索パスはビルド設定のSearch Paths
の中に設定項目がまとまっています。
フレームワーク検索パス
フレームワーク検索パスはリンカーがフレームワークとリンクするときに、フレームワークを検索するディレクトリパスです。ビルド設定のSearch Paths
のFramework Search Paths
に設定します。
ヘッダーファイル検索パス
ヘッダーファイル検索パスは、C言語、C++、Objective-C/C++のコードから、ヘッダファイルをインクルードするときに、コンパイラがヘッダーファイルを検索するディレクトリパスです。ビルド設定のSearch Paths
のHeader Search Paths
に設定します。
ライブラリ検索パス
ライブラリ検索パスは、リンカーが共有ライブラリおよびスタティックライブラリとリンクするときに、ライブラリを検索するディレクトリパスです。ビルド設定のSearch Paths
のLibrary Search Paths
に設定します。
ビルド設定ファイルを使った変更方法
ビルド設定ファイルを使って、検索パスを指定するには、ビルド設定ファイルで以下の設定にディレクトリパスを設定します。
検索パス | ビルド設定ファイルの設定 |
---|---|
フレームワーク検索パス |
FRAMEWORK_SEARCH_PATHS
|
ヘッダーファイル検索パス |
HEADER_SEARCH_PATHS
|
ライブラリ検索パス |
LIBRARY_SEARCH_PATHS
|
検索パスには複数のディレクトリパスをスペース区切りで指定可能です。ディレクトリパスにスペースが含まれる場合は、クオーテーションマークで囲みます。
本記事では、SearchPath.xcconfig
ファイル内に記述します。たとえば、次のように記述します。
FRAMEWORK_SEARCH_PATHS = /usr/local/share/mydevice-sdk/frameworks $(inherited)
HEADER_SEARCH_PATHS = /usr/local/share/mydevice-sdk/includes $(inherited)
LIBRARY_SEARCH_PATHS = /usr/local/share/mydevice-sdk/libs $(inherited)
$(inherited)
を使って、デフォルトや上位で設定している値も継承して使用するようにしましょう。
また、この例では$(inherited)
よりも前に自分の設定を書くことで、継承したディレクトリよりも、ビルド設定ファイルで指定するディレクトリを優先するように指定しています。本例では、デバイスのSDKを利用するシナリオを想定しています。原則として重複は避けた方が良いものの、SDKがデフォルトで提供するヘッダーファイルと同名のファイルをSDK側で提供している場合、そのファイルがSDK専用にカスタマイズされている可能性があります。このような場合、SDK側のファイルを優先して使用すべきです。そのため、本例ではSDK側の設定を優先するようにしています。
Gitの管理対象から除外する
しかし、これだけではマシン固有の設定になりません。SearchPath.xcconfig
ファイルは、各マシンごとに異なると想定しています。そのため、SearchPath.xcconfig
を.gitignore
に記述し、Gitの管理対象から除外しましょう。
そのようにすることで、必ず、マシン毎(クローン毎)にSearchPath.xcconfig
ファイルを、作ることを強制できます。
ただし、この「作成を強制する」方式にはCI(継続的インテグレーション)との組み合わせた場合に問題が発生する、可能性があるという弱点があります。
CI用のファイルはどうするか?
このようにして、SearchPath.xcconfig
をGitからクローンした環境毎に作成することを強制すると、困ってしまうのがCI(継続的インテグレーション)はどうするかです。
ビルド設定ファイルは、複数回同じ設定項目を設定すると、後から書いた方が優先されるという特徴が有ります。それを利用して次のようにデフォルト値を定義してしまうという方法があります。
この定義はCIによって使われます。
#include "SearchPath-default.xcconfig"
#include? "SearchPath.xcconfig"
これにより、SearchPath.xcconfig
の作成を強制することはできなくなりますが、ローカル環境ではSearchPath.xcconfig
を作成し、SearchPath-default.xcconfig
に記述された設定を上書きすることが可能になります。
SearchPath.xcconfig
では#include?
という、?
が付いたインクルード文を使用します。この#include?
は、対象のファイルが存在しなくてもビルドエラーにはならず、ファイルが存在する場合にのみインクルードします。
上書きする必要がないときは、SearchPath.xcconfig
は作成せずにビルドし、CIとは別のディレクトリにSDKを置いているときにはSearchPath.xccconfig
を作成して、設定を上書きして運用できるようになります。
デバッグ版とリリース版を分ける
デバッグ版とリリース版とで、ライブラリやフレームワークも切り替えたい場合があります。SDKがデバッグ版のライブラリとリリース版のライブラリを提供しているというときです。
このような場合は、SearchPath.xcconfig
ファイルもデバッグ用とリリース用を作成します。たとえば、次のようなファイル名にします。
SearchPath-debug.xcconfig
SearchPath-release.xcconfig
次に、Debug.xcconfig
とRelease.xcconfig
で、読み込むファイルを変更します。
Debug.xcconfig
には次のように記述します。
#include "SearchPath-debug.xcconfig"
Release.xcconfig
には次のように記述します。
#include "SearchPath-release.xcconfig"
Xcodeでビルド設定を確認すると、期待通り、デバッグ用とリリース用で異なる検索パスが正しく設定されていることを確認できます。