Xcode6でヘッダーのモジュール化のすゝめ


#### ヘッダーをモジュール化することによるメリット
------------------------------------------

* モジュール化したヘッダーファイルはコンパイル（バイナリー化）されるので、コンパイル時間が短縮される。

> ヘッダーのincludeの場合、コンパイラーはヘッダーがincludeされるたびに前処理とテキスト解析を行う。
> 従ってheaderファイルがM個あり、それぞれN個のファイルにincludeされていた場合、
> 上記のinclude処理はMxN回行われる事となる。
>
> しかしモジュールのimport処理の場合は、pchファイルと同じようにヘッダーファイルを１回コンパイルしてバイナリー化するため、処理はヘッダーのコンパイル処理とモジュールの組み込み処理に分解することが出来、処理数はM+Nへと減らすことが出来る。


<br>


* モジュール化されたヘッダーがincludeされた場合、clangは自動的にモジュールのimportを行ってくれる。

> module.modulemapファイルでヘッダーをモジュール化するだけで、
自動的にモジュールとして読み込まれる。
>
> 暗黙的submodule宣言を使えば、ディレクトリ配下のヘッダーファイルをそのままファイル名を用いてモジュール化することが出来る。


<br>

* ヘッダーを一つのファイルにまとめることが出来る。

> module.modulemapファイルにはコメントも記述することが出来る。

<br>


* マクロのincludeによる他ソースファイルへの破壊を防ぐことが出来る。

> module間同士は互いに独立し、影響を及ぼさない。

<br>


* 現在Appleから用意されているフレームワークはすでにモジュール化されているため、裏では自動的にモジュールとしてインポートされている。

<br>

* モジュールをインポートすれば、フレームワークのリンクを追加する必要はなくライブラリー化して配布する際に、相手にフレームワークの追加をお願いする必要がなくなる。

> AVFoundation.frameworkを使いたい場合は、
> ```@import AVFoundation;```
> とモジュールのimportを行えば、AVFoundation.frameworkのリンクを追加する必要がなくなる。

<br>


#### ヘッダーのモジュール化方法 
-----------------------------

##### **暗黙的submodule宣言**で一括してヘッダーファイルをそのままモジュール化する方法

１. ソースディレクトリ配下にmodule.modulemapファイルを作成する。
![finder modulemapファイル.png](https://qiita-image-store.s3.amazonaws.com/0/70065/e35308c3-9329-9389-cf00-1fdb6d3dd9c9.png "finder modulemapファイル.png")



modulemapファイルはheaderファイルと同様に、ターゲットに追加しないことに注意。



２. 暗黙的submodule宣言でディレクトリ配下のヘッダーファイル全てモジュール化する。

![xcode modulemapファイル.png](https://qiita-image-store.s3.amazonaws.com/0/70065/638c4d58-1fc6-3de6-7523-093a5d29fa05.png "xcode modulemapファイル.png")

<br>

```modulemap
module ModTest2 {
    umbrella ""
    explicit module * {
        export *
    }
}
```
> ModTest2ディレクトリ配下のヘッダーファイルを全てモジュール化する。


<br>


#### ヘッダーをモジュール化した場合の注意1
-------------------------------------

* モジュール化されたヘッダーはinclude/importした場合、Xcode(clang)は自動的にモジュールのインポートに差し替える。
<br>

* モジュール間同士は独立している。
<br>


上記の理由によってヘッダーのincludeの場合は以下は問題なく動作するが、
a.hをモジュール化するとコンパイルエラーとなる。

```a.h
NSString * const STR = @"This is a pen!"
```

```main.m
#import <Foundation/Foundation.h>
#import "a.h"

int main (void) {
	
	NSLog(@"%@", STR);
	
	return 0;
}
```

以下のようにa.hをモジュール化する。

```module.modulemap
module A {
	header "a.h"
}
```

上記でコンパイルを行うとa.hがコインパイル出来ずにエラーとなる。
(NSStringが解釈できない）

![スクリーンショット 2015-02-28 21.33.32.png](https://qiita-image-store.s3.amazonaws.com/0/70065/92722feb-c2b3-3ab2-b0b5-b0558fcad247.png "スクリーンショット 2015-02-28 21.33.32.png")


上記はmain.mでヘッダーのinclude/importとは違って、
モジュールのインポートは互いに影響を与えないため、a.hをモジュール化すると、


ゆえに解決策として、a.hファイル内でFoundationモジュールをインポートする必要がある。






#### まとめ
上記のようにヘッダーのincludeとモジュールのimportは動作が異なるため、一部だけをモジュール化するというのは好ましくないと思われる。
しかし暗黙的サブモジュール宣言を使用すれば、ソースファイルが格納されているディレクトリ配下に、modulemapファイルを定義して配置するだけでヘッダーを全てモジュール化出来る。

それ以外に、SDKヘッダーで定義されているヘッダーをそれぞれモジュール化することも出来る。

またモジュールはclangの機能であるが、明示的にモジュールをインポートする必要が無いため、その他のコンパイラで使用される可能性があるコードは引き続きヘッダーのinclude/importを宣言するだけで構わない。またコンパイルする際にmodule.modulemapファイルをclangに渡す必要もない。


そして何より、すでにAppleが用意しているフレームワークは全てモジュール化されている。

<br>

---------------------------------------------

モジュールマップ言語については、以下を参照してください。

clang modulesについて
http://qiita.com/ysn551/items/6f783af2b65c2c4d4631

公式リファレンス
http://clang.llvm.org/docs/Modules.html