UNIX系OSをターゲットにしたC/C++ベースのライブラリにはAutotoolsの生成したconfigure
スクリプトが同梱されているのが普通です。configure
スクリプトが環境ごとの差分を調査・吸収することで、同じソースコードで多くの環境に対応することができる仕組みになっています。
しかし、そうしたライブラリをXcodeプロジェクトに導入する場合、configure
に頼らず*.c
と*.h
だけをプロジェクトにコピーして手動対応するような事例が存在するようです。iOS開発が長い方々はXcodeとAutotoolsを組み合わせて使う方がハマりそうだ、という直感が働くのかもしれません。
調べてみると、クロスコンパイル対応のビルドツールのパスがXcode付属のxcrun
コマンドで取り出せるので、これを利用してCC
やCFLAGS
を設定すればXcodeプロジェクトでもAutotoolsの恩恵を受けられることがわかりました。たとえば、次のようにすればiOS向けの*.a
がビルドできます(対象のライブラリ作者がクロスコンパイル対応を考えていない場合など、ビルドに失敗する可能性もあります)。
$ make distclean
$ SDKROOT="$(xcrun --sdk iphoneos --show-sdk-path)" \
CC="$(xcrun --sdk iphoneos -f clang)" \
CPP="$(xcrun --sdk iphoneos -f cc) -E -D __arm__=1" \
CFLAGS="-isysroot $(xcrun --sdk iphoneos --show-sdk-path) -arch armv7 -arch armv7s -arch arm64 -miphoneos-version-min=7.0" \
RANLIB="$(xcrun --sdk iphoneos -f ranlib)" \
LIBTOOL="$(xcrun --sdk iphoneos -f libtool)" \
./configure \
--host=arm-apple-darwin \
--prefix="$(pwd)/build" \
--disable-shared
$ make
実際のプロジェクトに適用するような場合はもうすこし整理してシェルスクリプトなどにするのが良いでしょう。
シミュレータ用のスタティックライブラリも同様に作った上でlipo
コマンドでユニバーサルライブラリにすれば、Xcodeプロジェクトに取り込むことができます。
ワークアラウンド
基本的にはxcrun
経由で使えばiOS向けのクロスコンパイルができるはずなのですが、実はCプリプロセッサcpp
が単体ではマトモに動きません(clang
でコンパイルする分には問題ありません)。
普段はcpp
単体で起動することはほとんど無いと思いますが、./configure
中ではcpp
のチェックが走るため、次のようなエラーが出たりします。
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/assert.h:42:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/cdefs.h:707:2: error: Unsupported architecture
#error Unsupported architecture
^
1 error generated.
これはcpp
のクロスコンパイル対応が中途半端になっていることが原因です。ARM用のヘッダを読み込むくせにマクロ定数__x86_64__
が定義された状態なので、一部ヘッダの#error
に引っかかってしまうのです。
これを回避するため、上の例ではcc -E
でマクロ定数__arm__
を明示的に定義しています。
この問題にAppleの中の人が気づいていないとは思えないんですが、結構昔から修正されていないような気がします。