1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

モジュール化されたC++プログラムをビルドする

Posted at

モジュール機能を使ったC++ソースファイルをコンパイルするためには、そのソースファイルがインポートするモジュールのCMI1が必要になります。CMIはモジュールインターフェース単位から作成されます。

CMIに関する仕様は処理系によってまちまちなので、モジュール機能を使う場合はこのあたりの仕様に注意を払うとよいでしょう。

環境

  • GCC 14.2.0
  • Clang 18.1.8

サンプルプログラム

main.cpp
import <string_view>;

import bbb;

int main()
{
    greet_twice("world");
}
aaa.cppm
export module aaa;

import <string_view>;

export void greet(std::string_view);
aaa.cpp
module aaa;

import <iostream>;

void greet(std::string_view name)
{
    std::cout << "hello, " << name << std::endl;
}
bbb.cppm
export module bbb;

import <string_view>;

export void greet_twice(std::string_view);
bbb.cpp
module bbb;

import aaa;

void greet_twice(std::string_view name)
{
    greet(name);
    greet(name);
}

GCC

GCCではCMIはモジュールインターフェース単位をコンパイルすることで作成されます。CMIは作業ディレクトリ直下のgcm.cacheディレクトリに保存されます。モジュール名とCMIファイル名は次のように対応します。

モジュール名 CMIファイル名
abc abc.gcm
abc.def abc.def.gcm
abc:xyz abc-xyz.gcm

CMIは必要になった際に自動的にgcm.cacheから探されるので、コンパイラに明示的にCMIファイル名を渡す必要はありません。

上のサンプルプログラムをビルドするためのコマンドは次のようになります。

CXX=g++
CXXFLAGS='-std=c++20 -fmodules-ts -fPIC'
LDFLAGS='-pie'

$CXX $CXXFLAGS -x c++-system-header -c iostream
$CXX $CXXFLAGS -x c++-system-header -c string_view

$CXX $CXXFLAGS -x c++ -c -o aaa.cppm.o aaa.cppm
$CXX $CXXFLAGS -c -o aaa.cpp.o aaa.cpp
$CXX $CXXFLAGS -x c++ -c -o bbb.cppm.o bbb.cppm
$CXX $CXXFLAGS -c -o bbb.cpp.o bbb.cpp
$CXX $CXXFLAGS -c -o main.cpp.o main.cpp

$CXX $LDFLAGS -o greet-twice main.cpp.o aaa.cppm.o aaa.cpp.o bbb.cppm.o bbb.cpp.o
-x lang
ソースファイルの種類を指定する。
-fmodules-ts
C++のモジュール機能を使用する。

Clang

ClangではCMI2はモジュールインターフェース単位をプリコンパイルすることで作成されます。CMIは拡張子が.pcmであるという点を除いてGCCと同じように命名されます。GCCの場合とは異なりCMIが格納される既定の場所は存在しないので、CMIの場所をコンパイラに伝える必要があります。

また、モジュールインターフェース単位のオブジェクトファイルはCMIをさらにコンパイルすることで作成されます。

上のサンプルプログラムをClangを使ってビルドするためのコマンドは次のようになります。

CXX=clang++
CXXFLAGS='-std=c++20 -fprebuilt-module-path=. -fPIC'
LDFLAGS='-pie'

$CXX $CXXFLAGS -x c++-system-header --precompile -o iostream.pcm iostream
$CXX $CXXFLAGS -x c++-system-header --precompile -o string_view.pcm string_view

CXXFLAGS+=' -fmodule-file=iostream.pcm'
CXXFLAGS+=' -fmodule-file=string_view.pcm'

$CXX $CXXFLAGS --precompile -o aaa.pcm aaa.cppm
$CXX $CXXFLAGS --precompile -o bbb.pcm bbb.cppm

$CXX $CXXFLAGS -c -o aaa.cppm.o aaa.pcm
$CXX $CXXFLAGS -c -o bbb.cppm.o bbb.pcm

$CXX $CXXFLAGS -c -o aaa.cpp.o aaa.cpp
$CXX $CXXFLAGS -c -o bbb.cpp.o bbb.cpp
$CXX $CXXFLAGS -c -o main.cpp.o main.cpp

$CXX $LDFLAGS -o greet-twice main.cpp.o aaa.cppm.o aaa.cpp.o bbb.cppm.o bbb.cpp.o
--precompile
モジュールインターフェース単位のプリコンパイルを行う。
-fprebuilt-module-path=path
CMI探索パスを追加する。
-fmodule-file=file
使用するCMIを追加する。

現段階ではヘッダーユニットのCMIは-fmodule-fileを使って指定することしかできませんが、この制限は将来的には取り払われる予定とのことです。その場合は次の2行は必要なくなります。

CXXFLAGS+=' -fmodule-file=iostream.pcm'
CXXFLAGS+=' -fmodule-file=string_view.pcm'

-fmodule-outputオプションを使えばGCCのようにCMIの作成とオブジェクトファイルの作成を同時に行うことができます。

$CXX $CXXFLAGS -fmodule-output=aaa.pcm -c -o aaa.cppm.o aaa.cppm
$CXX $CXXFLAGS -fmodule-output=bbb.pcm -c -o bbb.cppm.o bbb.cppm

この場合CMIのコンパイルは必要なくなりますが、ビルド処理の並列化可能性が少しだけ悪化します。

  1. Compiled Module Interface (コンパイル済みモジュールインターフェース)

  2. Clangの用語法では Built Module Interface (ビルド済みモジュールインターフェース)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?