世界を動かす技術を、日本語で。

C++モジュールの扱い方は?

概要

  • 本記事はC++モジュールに対する筆者個人の見解
  • C++モジュールの主目的は ビルド速度の劇的向上
  • 現状、期待された速度向上が実現されていない現状分析
  • 標準化プロセスや実装困難性の課題指摘
  • プロジェクト管理と設計アプローチの失敗例を解説

C++モジュールの現状と課題

  • 本記事は個人の意見 であり、Mesonや他組織の方針ではないことを強調
  • C++モジュールの開発者達の努力を否定する意図はなく、 現状を批判的に分析
  • C++モジュールが 5倍以上のコンパイル速度向上 (理想は10倍)を複数OSSで示せなければ、標準から除外すべきという立場
  • 現状のままでは、 リソース投入はサンクコストの罠 に陥る危険性
  • モジュール導入当初の主目的は ビルド高速化 であり、ヘッダーインクルード方式のO(N²)問題解消が狙い
  • しかし、次第に ビルドの分離性(バグ回避) が議論の中心となり、パフォーマンス向上の話題は後退
  • マクロ漏洩等のバグは 発生頻度が低く、多くの開発者にとっては深刻な問題ではない現実
  • 一方で、 ビルドの遅さは全てのC++開発者の大きな問題

標準化と実装の失敗

  • C++20でモジュールが標準化 されたが、5年以上経ってもまともに動作しない現状
  • 実装困難性を指摘した声もあったが、「絶対に必要だから」と 強引に標準化
  • 複数の関係者による証言からも、 進捗の遅さや実装の困難さ が浮き彫り
  • ビルドシステムとコンパイラの密結合 が求められるが、ISO標準はファイルの存在すら想定していない
  • 各関係者が 自分の得意な部分だけ を実装し、全体最適がなされていない
  • コンパイラ開発者との議論でも、「 コンパイラをビルドシステムにしたくない」との理由で全案却下される事例
  • Mesonへのモジュール対応も、 一時ファイルや追加フラグ管理の複雑さ で断念

プロジェクト管理と設計の問題

  • 複数組織横断の大規模プロジェクト には、強力なプロダクトオーナーが不可欠
    • 全体を統括し、各チームに指示を出せる権限者 の不在
    • 理論上も、そのような人物が存在し得ない構造
  • ソフトウェア設計の鉄則「 既存実装の標準化」を無視し、 壮大な設計先行 で進めた失敗例
  • 実装やプロトタイプを持たず、「必要だから今すぐ」と標準化を強行
  • 小規模な実験から始め、 段階的に拡張・性能測定・改善 を繰り返すべきだった

import stdによるモジュール活用とその限界

  • import std は、標準ライブラリに限定したモジュール適用事例
    • 依存関係がなく一括生成できる点で導入が容易
    • C++開発の遅さの多くは標準ライブラリのインクルードが原因
  • 実装は プリコンパイルドヘッダー(PCH)と本質的に同じ
    • 実際、GCCではモジュールファイルがPCHの流用であるとの情報
    • 速度向上もPCHと同程度(Visual Studioで10-20%、Clang/GCCで数%)
  • 抜本的な性能向上には至らない という見通し

5倍高速化の根拠と現状

  • 既存技術を上回る速度向上」が新機能の合理的条件
  • 筆者が独自設計した高速コンパイル向け標準ライブラリで 4倍の速度向上 を実現した事例
  • 既に4倍が達成可能なら、 5倍要求は妥当な基準
  • 速度向上が実証できないなら、 設計の根本的な見直し が必要

次の論点:C++モジュール設計と今後の展望

  • 既存のC++コンパイラ改修は非常に困難 であり、開発参入障壁が高い
  • モジュール開発を試すための Python製“モジュールプレイグラウンド” の紹介
  • 本質的な性能・運用上の課題が解決されない限り、 C++モジュールの将来は厳しい

Hackerたちの意見

90年代に、C++コンパイラ(Symantec C++)のためにプリコンパイルヘッダーを実装したんだ。モジュールみたいな感じだったよ。動作モードは2つあって、1つ目は全ての.hファイルをコンパイルして、一気にバイナリとして出力する方法。2つ目は、各.hファイルがそれぞれ独自のプリコンパイルヘッダーを作成する方法。モジュールみたいだよね?とにかく、たくさん学んだことがあって、特にC++に意味的な改善がないと、コンパイルは速くなるけど壊れやすいってことが分かった。この経験がDモジュールの設計に活かされたんだ。Dモジュールは本当に素晴らしい。モジュールに求めていたことが全て詰まってる。特に、モジュールの意味はどこからインポートされるかに完全に依存しないんだ。まあ、C++もDのモジュール設計を取り入れたらいいと思う。C++は25年の使用実績があるモジュールを手に入れることができて、かなり満足できるはず。そう、Cのプリプロセッサマクロが問題だってことは理解してる。俺のおすすめは、プリプロセッサを置き換える言語的な解決策を見つけること。C++はほぼそこまで来てるから、あとは仕上げてプリプロセッサをゴミ箱に捨てればいいんだ。

C++のテンプレートがこれを機能させるためには、何を変えなきゃいけないの?モジュール内でテンプレートを定義して、他の場所でインスタンス化したり特殊化したりするのは特に難しそうだね。

モジュールの標準化プロセス中に、誰かから意見を求められたことはある?Dは最も明白な先行技術のように見えるけど、モジュールの標準化プロセスは特に呪われてた感じがする。

仕事を終わらせて、プリプロセッサをゴミ箱に捨てちゃえばいいんだよね。そう、これがC++の問題の核心だと思う。スタンダード委員会が引いた線が悪くて、モジュールのエンコーディングがほぼ不可能になってる。良いモジュールシステムと速いインクリメンタルビルドを持つ他の言語では、プリプロセッサスタイルのクレイジーなことは、かなり厳しい境界がないと許可されない。少し間違った形になった言語(例えば、Rustのprocマクロみたいな)でも、そういうメタプログラミングがどこでどう行われるかに制約がある。プリプロセッサがゴミ箱に捨てられなくても、モジュールシステムからは除外されるべきだよ。メタプログラミングは、明確なインターフェースと相互作用を持つ言語の機能であるべき。例えば、Javaではアノテーションプロセッサが最終的にコード生成機能を引き起こす。アノテーションがなければ、メタプログラミングもなし。完璧ではないけど、C/C++のフリーなマクロシステムよりはずっとマシだよ。もう一つの選択肢はGoのやり方。コンパイラにコードを生成させるんじゃなくて、ビルドシステムにコード生成を担当させる(コードジェネレーターを呼び出す)。それなら、必要なときに開発者がその遅延を選べるから、ずっと良くなると思う。

自分が関わったC++プロジェクトで、Cヘッダーをインクルードして、普通に動くことに頼らなかったものは思いつかないな。C++の「モジュラー」からCマクロを禁止する方法ってあるのかな?(Cの依存関係をすべて調べて、何らかのラッパーを書く/生成しなきゃならないのは、多くの人には受け入れられないだろうけど。)

C++モジュールはインポート時のマクロに影響されないし、マクロをエクスポートすることもないから、問題は何なんだろう?

コンパイルを5倍速くするための賢い方法は、ほぼ10年前に実装されて、驚くほどうまくいったのに、完全に無視されたんだ。スタンダード委員会から進展は期待してないよ。興味があればこちらをどうぞ: https://github.com/yrnkrn/zapcc 次にスタンダード委員会に完全に無視される大きな進展は、100%メモリ安全なC/C++コンパイラで、これも実装済みで驚くほどうまくいくよ: https://github.com/pizlonator/fil-c

これは何の魔法だ。何年もHNを読んでたけど、メモリ安全なC++を持ち出す人を初めて見たよ。なんでこれがヘッドラインに載ってないの?何か問題があるの、ビルド時間とか?それを手に入れるために家を売らなきゃいけないの? 編集: ああ、トレードオフが分かった: hollerithが2024年2月21日に投稿 | 前 | 次 [–] >Fil-Cは、私のテストによるとレガシーCより約200倍遅いです。

コンパイルを5倍速くするための賢い方法は、ほぼ10年前に実装されて、素晴らしく機能したのに、完全に無視された。スタンダード委員会から進展は期待してないよ。興味があれば、これだよ: https://github.com/yrnkrn/zapcc もちろん、完全に無視されたよ。スタンダード委員会がコンパイラでキャッシングを強制すると思った?それは彼らの仕事じゃないから。 > 次にスタンダード委員会に完全に無視される大きな進展は、100%メモリ安全なC/C++コンパイラで、これも実装されていて素晴らしく機能する: https://github.com/pizlonator/fil-c また—スタンダード委員会がこのコンパイラの使用を強制すると思ったの?スタンダード委員会はコンパイラを「標準化」しないんだよ…

なんで誰がzapccをccacheの代わりに使うべきなの?もしそれがコンパイラの内部データを全部保存するってことなら、確かに高くつきそうだよね。これらのコンパイラツールが言語の革新をもたらすわけじゃないってことは、知ってると思うけど。どちらも本番環境には向いてないし、正しく動かないとデバッグもめっちゃ難しそう。

コンパイルを5倍速くするための合理的な方法は、ほぼ10年前に実装されて、すごくうまくいったのに、完全に無視されてしまった。スタンダード委員会からの進展は期待してないよ。興味があればここにあるよ:https://github.com/yrnkrn/zapcc ccacheのようなツールは20年以上前から存在していて、導入するのは実行可能ファイルをインストールして環境フラグを設定するだけで済むんだ。zapccがccacheが提供していない何をもたらすと思う?

zapccは本当に期待できそうだね!残念ながら、メンテナンスされてないみたいで、5年間コミットが見当たらないんだ。

Hacker Newsで議論の続きを見る