«

[C++] Modulesのコンパイル(MSVC ver)とBMIについて

この記事は C++ Advent Calendar 2021 1日目(初日!)の記事です。

少し前からC++に Modules がやってきました
C++20 対応のメジャーどころのコンパイラ(MSVC/gcc/Clang など)で使うことができます

個人的にはビックウェーブが来たーーーと思ってまして、つねづねポチポチと Modules について調べていました

それを少しまとめたいと思います

モジュールの説明

昔ながらのプリコンパイルヘッダの概念を、今風にした感じでしょうか

ヘッダファイルをインクルードしていたものを Modules に置き換えることが出来ます

ヘッダファイルだと、

インクルードの順番に気を付けたり
コンパイル時間が長くなったり
インクルードガード書いたりと
ゆーてローテク文字列だったのですが、

それがバイナリとして公式に提供されました

Modulesを記載するファイル

各コンパイラによって(推奨)拡張子が異なります

  • MSVC (cl.exe)

    • Foo.ixx
  • Clang

    • Foo.cppm
  • GCC

    • Foo.cc
    • Foo.cp
    • Foo.cxx
    • Foo.cpp
    • Foo.c++
    • Foo.C

(参考)

以下、、MSVCで話を進めます
(コンパイラによって異なる所が多いので)

モジュールファイルについて

MSVC の場合、モジュールにしたいファイルは .ixx という拡張子を付けます
(Clangだと .cppm、GCCだと .cxx とかになります)

サンプルはこんな感じ

hello.ixx

1
2
3
4
5
6
// hello.ixx:
export module MyHello;

export int f() {
    return 42;
 }

利用する側はこんな感じで↓↓↓ import すれば使えます
(従来は #include "hello.h" とか書いていた場所です!)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// main.cpp 
#include <iostream>
#include <cstdlib>

import MyHello;  // モジュール使うよの宣言

int main() {
  auto a = f();

  std::cout << f();
}

サンプルだけ見ると、なんてことのないコードですね
メイン関数は #include してた箇所を inport に変更しただけです

モジュールをバイナリ化する

モジュールを記載する .ixx ファイルは、.ifc にプリコンパイルでバイナリ化されます

ややこしいのが、コンパイラによってこのあたりの呼び名が異なってて、こんな感じ

MSVC Clang
モジュールファイル名  → .ixx .cppm
モジュールファイルをプリコンパイルしたもの→ .ifc .pcm

ちなみに「モジュールファイルをプリコンパイルしたもの」を BMI と呼び、
Binary Module Interface の略になります

この BMI ファイルを各 cpp ファイルなどが import することになります

(参考)

VC++でのコンパイル方法

単純のため、まずはコマンドラインでやってみます

利用したVC++バージョンはこちら

コマンドは2つ

1
2
> cl /c /std:c++20 /EHsc hello.ixx
> cl /std:c++20 /EHsc /reference MyHello=MyHello.ifc main.cpp hello.obj

1つ目のコマンドでモジュールをプリコンパイルし、
2つ目のコマンドで obj をリンク、そして main.exe の出力をします

<1. モジュールのプリコンパイル>

C:\my\dev\sample_module01>cl /c /std:c++20 hello.ixx
Microsoft (R) C/C++ Optimizing Compiler Version 19.30.30705 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

hello.ixx

これで、hello.objMyHello.ifc が出来ました

(余談)cl.exe はモジュールのコンパイル時に同時に2つ(.obj.ifc)のファイルを出力してくれて楽です

Clang は別々のコマンドで出力するので、cl.exe とは少し作り方が異なっています
.pcm ( VC++で言うところの .ifc) を出力した後、それを元に .o ( VC++の .obj) を出力します
このあたりはまだ次回に投稿したいです

<2. 実行ファイル生成>

C:\my\dev\sample_module01>cl /std:c++20 /EHsc /reference MyHello=MyHello.ifc main.cpp hello.obj
Microsoft (R) C/C++ Optimizing Compiler Version 19.30.30705 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
Microsoft (R) Incremental Linker Version 14.30.30705.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj
hello.obj

main.exe が出来ました

実行してみます

C:\my\dev\sample_module01>main.exe
42

問題なし(^^♪

(備考)コンパイルオプションの注意点

VC++のコマンドラインオプションが

  • モジュールを作ったとき
  • モジュールを使うとき

これらの間で一致していないとき、ワーニングが出ました(C5050

main.cpp(7): warning C5050: Possible incompatible environment while importing module ‘MyHello’: _CPPUNWIND is defined in current command line and not in module command line

そのため今回、hello.ixx 内では <iostream> は利用していないのですが、/EHsc オプションを付けています

(参考)

BMIってなによ?

プリコンパイルされた Binary Module Interface って何なのでしょうか?
この中身は一体?

さんざん調べましたが、大した情報が載ってないですね。。。

これ、BMIというのは Modules を扱うための概念のようです

これはコンパイルの過程のものなので、各コンパイラベンダーが作る箇所であり、明確に公開情報として詳細が提示されているわけではなさそうです
現時点では概念がちらほらと記載されているだけのようでした

実際に、プリコンパイルで作られた .ifc.pcm の中身は

  • プリプロセスで利用した情報とか
  • ASTのダンプ
  • Objみたいなもの

がひとまとめにされてるようです

という記述を見つけましたが、出展元が判らなくなったので、思い出したら追記します。。。

(2021/12/4追記)
CppCon2019の資料が参考になりました!
Practical Cpp Modules - CppCon 2019
https://github.com/CppCon/CppCon2019/blob/master/Presentations/practical_cpp_modules/practical_cpp_modulesboris_kolpackovcppcon_2019.pdf

もちろん、コンパイラによって、さらにバージョンによっても形式は様々なんでしょう

モジュールの配布ってどうやるの?

モジュールのバイナリを配布することはできないです
共有する場合はあくまでソースコードと共に配布になります

また、作られた BMI、つまり .ifc.pcm ファイルは不変的なバイナリではないみたいです

ライブラリのように配布はできないのですね。。。

(余談)Modules の提案を推し進めている Gabriel Dos Reisさん は、Common Module Interface Format を作りたいみたいですが…
具体的に今の段階では、配布目的のものは出ていないようです

(参考)

所感

まだ2021年12月の時点では、Modules 機能が完全に動作するコンパイラもないみたいですし
そもそも各コンパイラによって記載方法や推奨が異なるので、なんとも道半ばな印象はあります

Modules を利用するための手順やお作法も多く、また情報も限られているので、取り組みにくいですね

マイクロソフトの VC++チームブログ は、コンパイラベンダーとして結構 Moduleds の具体的な情報を出しているように感じました
(Clangももうちょっと頑張って。。。あとGCC。。。おまえはやる気あるのか。。。)

Modules に関して取り組まれている人たちの歴史はとても長く
かつ現在のヘッダファイルがベストだとは思えないので
個人的に一押ししたい機能だと改めて思いました

所感その2

C++ Advent Calendar!

ずいぶん昔に一度だけ参加したことがあったのですが、それからなーんにもしてませんでした

今回、意を決して投稿できて良かったです

かなりよく調べたつもりですけど、間違いなどあったら気軽に @hr_sao まで教えていただけると嬉しいです

C++楽しい~♪

comments powered by Disqus