ビルドもできるヘッダオンリーライブラリ

長いことまともな記事を書いていないのでリハビリをします。

ヘッダオンリーライブラリとして使えるものの、必要な場合はコンパイルできる、というライブラリはチラホラ見かける。例えば spdlog はその一つで、 "header only/compiled library" を名乗っている。

GitHub - gabime/spdlog: Fast C++ logging library.

ヘッダオンリーライブラリは、単にダウンロードしてきてインクルードパスに入れさえすれば使えるという手軽さがいいところだが、当然コンパイル時間が伸びてしまう。ビルドと環境構築にある程度慣れており、何度もビルドするためにコンパイル時間を短縮したい人には、ビルド済みバイナリとして使える機能があると尚良い。

仕組みを簡単に書いておく。しかしこれは説明をする必要がないくらい単純だ。

  1. まず、普通にコンパイルできるライブラリを書く。
  2. MYLIBNAME_HEADER_ONLYもしくはMYLIBNAME_COMPILEDのようなマクロを作り、それによって MYLIBNAME_INLINEを空にしたりinlineにしたりする。

以上。

しかしながら、template関数は基本的にはヘッダにしか書けない。インスタンス化する時に中身が見えないと困るからだ。ただし、ここで先んじていくつかのよく使う型に関するインスタンスを陽に定義しておいて、ビルド時間を少々削減することもできる。extern templateだ。

// .hpp
template<typename T>
void func(const T&) {/*...*/}

#if !defined(MYLIBNAME_HEADER_ONLY)
extern template void func(const int&);
extern template void func(const double&);
#endif
// .cpp
template void func(const int&);
template void func(const double&);

これによってテンプレート関数もビルド済み関数として提供できる。

とはいえ、これはある程度要求されるインスタンス化が決まっている状況でないとあまりビルドは早くならない。

toml11でもビルド済みバイナリを提供する機能を書いてみていたが、かなり労力をかけないとコンパイル時間がほぼ変わらなさそうだったので、今のところお蔵入りになっている。でもtoml11のコンパイル時間が激遅なのは自分でも悩みの種なのでまた書いてみよう。多分、単純にコードが長いということが問題っぽいんだが。

最近書いている数値計算用のライブラリにはこの機能を実装している。そちらはgslにも依存しているので単にビルド済みだけでよかったかもしれないが、単にやってみたかったのでやった。

以上、モジュール時代にはそぐわなくなるであろう話でした。年単位で前にモジュールとして使えるようなライブラリを作ってみようとしたらモジュールが使えるコンパイラがMSVCしか出てこなくて諦めたことがあった(当方個人ではwindowsマシンを所有しておりません)。今はgccでもclangでも-fmodules-tsを使えばいいのか。今度やってみます。

その当時はモジュールとしてもモジュール以前としても使えるようなライブラリをどうやって作るかみたいなことを調べていて、そういえば boost-ext/ut がまさにそういうライブラリだったなと思い出した。

github.com

今度もう一回やってみてまとめようと思う。リハビリ終わり。