[iOS+Swift] 実機とシミュレータで使用可能なフレームワークの作成方法

# 背景
　iOS向けにSwiftで実装したフレームワークを、Xcodeで*普通に*コンパイル・インストールすると、出来上がったフレームワークにはiOS Simulator向けのバイナリ(すなわちx86_64バイナリ)が含まれません。
　本ドキュメントでは、ARM用とx86用両方のバイナリを含んだ、ユニバーサルバイナリ形式のフレームワークの作成方法を紹介します。
 作成日: 2016/09/22
 更新日: 2016/12/04

# 参考文献
* [How to build Cocoa Touch Framework for i386 and x86_64 architecture?](http://stackoverflow.com/questions/28652650/how-to-build-cocoa-touch-framework-for-i386-and-x86-64-architecture): StackOverflowの記事です。アイテム17の解決方法を参考にしています
* [iOS用Staticライブラリのビルドおよびインストール方法](http://qiita.com/wheel/items/54c87aea3c7cd468f0d2): Qiitaの私の過去記事です。Objective-Cの実装のstatic linkライブラリの作成方法であり、本記事とは対象が異なりますが、問題解決方法のアプローチは同じです。

# 開発環境
* IDE: Xcode version 8.0
* Target OS: iOS 10
* Language: Swift 3

# 課題の解決方法
アプローチは以下の通りです:
1. ARM向け、およびx86向け各々のフレームワークを準備する
2. 両方のファイルをマージする
3. 特に、ライブラリ本体については、lipoコマンドで、ユニバーサルバイナリを生成します

以下、手順の詳細について説明します。

## XcodeのBuild Setting
iOS向けのフレームワーク実装プロジェクト(言語はSwift）のBuild Settingにて、次を設定します。

<table>
<tr>
  <th>カテゴリ</th>
  <th>項目名</th>
  <th>設定値</th>
  <th>説明</th>
</tr>
<tr>
  <td>Architectures</td>
  <td>Valid architectures</td>
  <td><code>arm64 armv7 armv7s i386 x86_64</code></td>
  <td>シミュレータ用のi386, x86_64を追加します</td>
</tr>
<tr>
  <td>Deployment</td>
  <td>Installation Directory</td>
  <td>フレームワークのインストール先フォルダ名</td>
  <td>フレームワークのインストール先を指定します</td>
</tr>
<tr>
  <td>Deployment</td>
  <td>Skip Install</td>
  <td>NO</td>
  <td>インストール処理可能にします</td>
</tr>
<tr>
  <td>Search Paths</td>
  <td>Framework Search Paths</td>
  <td>参照するフレームワークのフォルダ</td>
  <td>別のフレームワークとリンクする場合に設定します</td>
</tr>
</table>

## Install処理の追加
### Installターゲットの追加
Xcodeにフレームワークをインストールするためのターゲットを追加します。
* ターゲットの種類は、`Cross Platform`から`External Build System`とします。
* `Build Phase`の`Target Dependences`には、インストールするフレームワークのビルドフェーズを指定してください。
* `Info`のExternal Build Tool ConfigurationのArgumentsには、`-f <以下に示すMakefileのファイル名>`としてください。

### install_ios.mk スクリプト
スクリプトの内容を以下に挙げます。同じ内容をgistの[install_ios.mk](https://gist.github.com/steelwheels/4ddf11aee467740d23d820b5a3e62ac1)に登録しています。

スクリプト中の`PROJECT_NAME`と`INSTALL_PATH`は拙作の[Canary Framework](https://github.com/steelwheels/Canary)の設定です。リポジトリの`Script/install_ios.mk`で下記スクリプトファイルを使用しています。

```
#
# install_ios.mk
#
# Reference URL: http://stackoverflow.com/questions/28652650/how-to-build-cocoa-touch-framework-for-i386-and-x86-64-architecture
#

INSTALL_PATH ?= $(HOME)/local/Frameworks

OS_DIR     = $(INSTALL_PATH)/iphoneos
SIM_DIR	   = $(INSTALL_PATH)/iphonesimulator

install: dummy
	# Build framework for device
	xcodebuild install -scheme $(PROJECT_NAME) \
	  -project $(PROJECT_NAME).xcodeproj \
	  -configuration Release \
	  -sdk iphoneos \
	  ONLY_ACTIVE_ARCH=NO DSTROOT=/ \
	  INSTALL_PATH=$(INSTALL_PATH)/iphoneos

	# Build framework for simulator
	xcodebuild install -scheme $(PROJECT_NAME) \
	  -project $(PROJECT_NAME).xcodeproj \
	  -configuration Release \
	  -sdk iphonesimulator \
	  ONLY_ACTIVE_ARCH=NO DSTROOT=/ \
	  INSTALL_PATH=$(INSTALL_PATH)/iphonesimulator

 	# Copy framework
	(cd $(OS_DIR); tar cf - $(PROJECT_NAME).framework) \
	| (cd $(INSTALL_PATH) ; tar xfv -) 
	(cd $(SIM_DIR)/$(PROJECT_NAME).framework/Modules ; \
	  tar cf - $(PROJECT_NAME).swiftmodule) \
	| (cd $(INSTALL_PATH)/$(PROJECT_NAME).framework/Modules ; tar xfv -)

	# Merge frameworks
	lipo -create \
	  -output $(INSTALL_PATH)/$(PROJECT_NAME).framework/$(PROJECT_NAME) \
	  $(OS_DIR)/$(PROJECT_NAME).framework/$(PROJECT_NAME) \
	  $(SIM_DIR)/$(PROJECT_NAME).framework/$(PROJECT_NAME) 

dummy:



```