ヘッダーをモジュール化することによるメリット
- モジュール化したヘッダーファイルはコンパイル(バイナリー化)されるので、コンパイル時間が短縮される。
ヘッダーのincludeの場合、コンパイラーはヘッダーがincludeされるたびに前処理とテキスト解析を行う。
従ってheaderファイルがM個あり、それぞれN個のファイルにincludeされていた場合、
上記のinclude処理はMxN回行われる事となる。しかしモジュールのimport処理の場合は、pchファイルと同じようにヘッダーファイルを1回コンパイルしてバイナリー化するため、処理はヘッダーのコンパイル処理とモジュールの組み込み処理に分解することが出来、処理数はM+Nへと減らすことが出来る。
- モジュール化されたヘッダーがincludeされた場合、clangは自動的にモジュールのimportを行ってくれる。
module.modulemapファイルでヘッダーをモジュール化するだけで、
自動的にモジュールとして読み込まれる。暗黙的submodule宣言を使えば、ディレクトリ配下のヘッダーファイルをそのままファイル名を用いてモジュール化することが出来る。
- ヘッダーを一つのファイルにまとめることが出来る。
module.modulemapファイルにはコメントも記述することが出来る。
- マクロのincludeによる他ソースファイルへの破壊を防ぐことが出来る。
module間同士は互いに独立し、影響を及ぼさない。
- 現在Appleから用意されているフレームワークはすでにモジュール化されているため、裏では自動的にモジュールとしてインポートされている。
- モジュールをインポートすれば、フレームワークのリンクを追加する必要はなくライブラリー化して配布する際に、相手にフレームワークの追加をお願いする必要がなくなる。
AVFoundation.frameworkを使いたい場合は、
@import AVFoundation;
とモジュールのimportを行えば、AVFoundation.frameworkのリンクを追加する必要がなくなる。
ヘッダーのモジュール化方法
暗黙的submodule宣言で一括してヘッダーファイルをそのままモジュール化する方法
1. ソースディレクトリ配下にmodule.modulemapファイルを作成する。
modulemapファイルはheaderファイルと同様に、ターゲットに追加しないことに注意。
2. 暗黙的submodule宣言でディレクトリ配下のヘッダーファイル全てモジュール化する。
module ModTest2 {
umbrella ""
explicit module * {
export *
}
}
ModTest2ディレクトリ配下のヘッダーファイルを全てモジュール化する。
ヘッダーをモジュール化した場合の注意1
- モジュール化されたヘッダーはinclude/importした場合、Xcode(clang)は自動的にモジュールのインポートに差し替える。
- モジュール間同士は独立している。
上記の理由によってヘッダーのincludeの場合は以下は問題なく動作するが、
a.hをモジュール化するとコンパイルエラーとなる。
NSString * const STR = @"This is a pen!"
#import <Foundation/Foundation.h>
#import "a.h"
int main (void) {
NSLog(@"%@", STR);
return 0;
}
以下のようにa.hをモジュール化する。
module A {
header "a.h"
}
上記でコンパイルを行うとa.hがコインパイル出来ずにエラーとなる。
(NSStringが解釈できない)
上記はmain.mでヘッダーのinclude/importとは違って、
モジュールのインポートは互いに影響を与えないため、a.hをモジュール化すると、
ゆえに解決策として、a.hファイル内でFoundationモジュールをインポートする必要がある。
まとめ
上記のようにヘッダーのincludeとモジュールのimportは動作が異なるため、一部だけをモジュール化するというのは好ましくないと思われる。
しかし暗黙的サブモジュール宣言を使用すれば、ソースファイルが格納されているディレクトリ配下に、modulemapファイルを定義して配置するだけでヘッダーを全てモジュール化出来る。
それ以外に、SDKヘッダーで定義されているヘッダーをそれぞれモジュール化することも出来る。
またモジュールはclangの機能であるが、明示的にモジュールをインポートする必要が無いため、その他のコンパイラで使用される可能性があるコードは引き続きヘッダーのinclude/importを宣言するだけで構わない。またコンパイルする際にmodule.modulemapファイルをclangに渡す必要もない。
そして何より、すでにAppleが用意しているフレームワークは全てモジュール化されている。
モジュールマップ言語については、以下を参照してください。
clang modulesについて
http://qiita.com/ysn551/items/6f783af2b65c2c4d4631