こんにちは、情熱開発部の青柳です。
梅雨が明けなくても厳しい暑さで溶けそうです。
C++は標準化委員会が活発に活動し進化していますが、今回は言語機能とは少し外れてC++Moduleのコンパイル時の動きに関して調べてみたいと思います。
C++Moduleとは
弊社のブログ【C++】C++20のモジュールとincludeの違いについて詳しく調べてみたでも取り上げられたことがあります。
C++20の新機能のうちの一つでこれまでのHeaderIncludeに代わるプログラムソース分割の仕組みです。
詳しい説明は上記ブログやCPPReferenceに譲ります。
これを使えばビルド時間が短くなり(場合による)、Include順番に悩まされたりプリプロセッサの影響やマクロの定義に悩まされる事がなくなるようです。
今回はModuleがビルド時にどう動くのかを見ていき、深入りはできませんが、上記がどのように達成されるのかを感じてみたいと思います。
早速ビルドしてみる
今回は折角Microsoft様が対応して例を出してくれているのでMicrosoftLearnの
チュートリアル: コマンド ラインからモジュールを使用して C++ 標準ライブラリ (STL) をインポートする
を見ていきましょう。
こちらはC++23で対応するStandardLibraryのModule化の例になりますので、書かれている通り
Visual Studio 2022 17.5 以降
をご利用ください。
stdとstd.compatの二種類あるようですが今回はstdのみビルドします。
早速x86 Matove Tools Command Promptをスタートメニューから立ち上げ、ビルド結果を格納するフォルダに移動しましょう。
移動したら以下のコマンドを入力します。
cl /std:c++latest /EHsc /nologo /W4 /c "%VCToolsInstallDir%\modules\std.ixx"
![](https://i0.wp.com/logicalbeat.jp/wp01/wp-content/uploads/2024/07/image-1-1.jpg?resize=162%2C70&ssl=1)
これで
std.ifc
と
std.obj
の二つのファイルが出来ていることが確認できるはずです。
.objファイルは何となくわかりますが.ifcファイルはなんでしょうか。
とりあえず気にせず次に進みます。次は.cppの作成ですね。
// requires /std:c++latest
import std;
int main()
{
std::cout << "Import the STL library for best performance\n";
std::vector<int> v{5, 5, 5};
for (const auto& e : v)
{
std::cout << e;
}
}
stdと名前の付いたModuleをimportしているようです。
#include <iostream>
#include <vector>
はしなくてよく、はるかに高速にコンパイルできると書かれています、早速コンパイルしましょう。
cl /c /std:c++latest /EHsc /nologo /W4 /reference "std=std.ifc" importExample.cpp
/reference “<モジュール名>=<モジュールファイル名>”
というコンパイルオプションが見られます、またその他のコンパイルオプションもモジュールをビルドしたオプションと同一の必要があります。
コンパイルが成功すれば
importExample.obj
が出来るはずです。あとはLinkを実行して.exeを作ります。
link importExample.obj std.obj
これで.exeが吐き出されたはずです。
一連の流れからわかる通り、.ifcファイルを使ってimportExample.objを作り、std.objとリンクさせ.exeを作成しています。
どうやらビルドの際のModuleの動きとしては.ifcなるファイルが肝のようです。
![](https://i0.wp.com/logicalbeat.jp/wp01/wp-content/uploads/2024/07/moduleImportAndLink.jpg?resize=640%2C512&ssl=1)
Binary Module Interface
.ifcファイルはBinary Module Interfaceと呼ばれているもののようです(以下BMI)。
このBMIはコンパイラ毎に仕様が違い。
clangは .pcm
gccは .gcm
msvcは .ifc
となっています。(つまりビルドしたModuleは移植性がないのですね)
このBMIはどのような内容になっているのでしょうか。
![](https://i0.wp.com/logicalbeat.jp/wp01/wp-content/uploads/2024/07/image-2.png?resize=640%2C479&ssl=1)
CppCon2017 Building C++ Modules – Boris Kolpackov – CppCon 2017
で触れられていて、字句解析された結果や.objに近いものが入っているそうです。
それならばコンパイラ固有だったり、コンパイラオプションに気を配る事が必要なのも必然です。
上の例のうち.ifcはMicrosoft様がOSSProjectをGithubで公開しているのでそちらも見てみます
ifc-spec
![](https://i0.wp.com/logicalbeat.jp/wp01/wp-content/uploads/2024/07/image.jpg?resize=216%2C720&ssl=1)
かなりごついですね。詳しく触れることは出来ないのですが、DeclarationやSyntaxTreeなどが確認できます。
確かにコンパイルされた結果のようなものが入っているようです。
またModuleのビルドにはModule間の依存関係を解決しなければいけないのですが解決の方法はあるようで、CMakeのBlogに少し説明されていました。
Moduleって本当に役に立つの?
さて、色々苦難がありつつ導入されたModuleですがあまり具体的な例がなく懐疑的になられる方もいるかもしれません。
私も本格的に使った事が無いので答えられないのですが、Webで趣味のゲームエンジンをModule対応された方がおられたのでそちらを引用させていただきます。
Annileen Devlog #2 – C++20 and Modules
(ビルド結果だけでなく移行のプロセスも書いて頂いて非常に興味深い内容でした)
![](https://i0.wp.com/logicalbeat.jp/wp01/wp-content/uploads/2024/07/image-1.png?resize=600%2C398&ssl=1)
Annileen Devlog #2 – C++20 and Modulesより引用
一部の場合でビルド時間が長くなっていますが、基本的にビルド時間は短くなるようです。
上の例では14秒ほど短くなっています、ビルド時間はどうしても悩まされるので少なくできるならしたいですね。
とはいうものの
ブログ内でも触れられていてWebでもよく目にするのですがModuleを使っているとInteliSenseが突然壊れたりなどするようです。
(VisualStudioもInteliSenseに関しては今だ試験運用です)
またビルドシステムの方へ目を向けてみるとCMakeはModuleに対応しているようですが、Ninjaなどが対応されているか分かりませんでした。
そして仮にIDEやビルドシステムが対応していても、開発環境で使えるかはまた別の話です。
終りに
浅くでしたがBMIについて触れてみました。
上のようにすぐに使えるようになるという状況ではなさそうですが、使えるようになった時に困らないように使える時は積極的に使っていきたいと思います。
このブログを書くにあたって以下の記事を参考にさせていただきました、ありがとうございました。
Effectiveさお [C++] Modulesのコンパイル(MSVC ver)とBMIについて
Annileen Devlog #2 – C++20 and Modules
cpprefjp モジュール [P1103R3]
Microsoft Learn C++ のモジュールの概要
Microsoft Learn チュートリアル: コマンド ラインからモジュールを使用して C++ 標準ライブラリ (STL) をインポートする
CppCon2017 Building C++ Modules – Boris Kolpackov – CppCon 2017
CppCon2019 practical_cpp_modules__boris_kolpackov__cppcon_2019
CppCon2023 modules-the-packaging-and-binary-redistribution-story
kitware import CMake; C++20 Modules
【免責事項】
本サイトでの情報を利用することによる損害等に対し、
株式会社ロジカルビートは一切の責任を負いません。