Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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


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

ヘッダーの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ファイルを作成する。
finder modulemapファイル.png

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

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

xcode modulemapファイル.png


module ModTest2 {
    umbrella ""
    explicit module * {
        export *
    }
}

ModTest2ディレクトリ配下のヘッダーファイルを全てモジュール化する。


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


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

  • モジュール間同士は独立している。

上記の理由によってヘッダーの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

上記は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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした