やりたいこと
複数のヘッダファイルを1つに出来るとwandboxに張るとき便利。なのでまとめたい
自作他作問わず、ヘッダオンリーなライブラリあるとする
これのサンプルコード等をwandboxで動けるようにすると,サンプルコードがブラウザで動いて紹介などで便利だ
しかし、ヘッダファイルが複数あると様々な面倒ごとがある(wandboxに張るのが面倒とか)
なので1つのファイルにまとめる
やる
方針
- プリプロセッサ展開(
clang -E
)して、ほしいヘッダ全部いい感じに展開済みファイルを生成する- この際標準ライブラリが展開されると面倒なので展開されないようにする
- これだと今度は標準ライブラリ不足になるので必要そうなライブラリの
#include
文を適当に追加する
- これだと今度は標準ライブラリ不足になるので必要そうなライブラリの
- この際標準ライブラリが展開されると面倒なので展開されないようにする
- 作ったファイル(下ではout.hpp)をwandboxに張る
$ HEADER_DIR=${ヘッダのあるディレクトリ}
$ MAIN_FILE=${必要なヘッダをincludeするだけのcppファイル}
$ find ${HEADER_DIR} -type f | xargs perl -nle '/^#include.*<(\w+)>/ and print "#include <$1>"' |sort |uniq >> out.hpp
$ clang -E ${MAIN_FILE} -P -nostdinc++ -I ${HEADER_DIR} >> out.hpp
おそらくfatal error: hoge: No such file or directory
がでるが無視してよい
解説
$ find ${HEADER_DIR} -type f | xargs perl -nle '/^#include.*<(\w+)>/ and print "#include <$1>"' |sort |uniq >> out.hpp
必要な標準ライブラリを抜き出す。
考えるのが面倒なのでライブラリ中に現れた/
とかを含まないincludeっぽい文面全部抜き出す
存在する標準ライブラリ全部書けばいい気がしたが、対象環境がC++17なのか20なのかわからなかったのでこのような方法にした
$ clang -E ${MAIN_FILE} -P -nostdinc++ -I ${HEADER_DIR} >> out.hpp
- -E : プリプロセッサで展開してstdoutに出力する
- -P: ほしくない出力を抑制する(linkmakerの出力を抑制する。詳しくはmanみて)
- -nostdinc++: 標準ライブラリをincludeしない
- out.hppに標準ライブラリが展開されると面倒なのでincludeしないようにする
- 当然clangに怒られる(
No such file or directory
)が、欲しい部分は出力されるので大丈夫 - これが仕様なのかは知らない
- なお、gccではこのようにならない
コンパイルそのものに必要なオプションが他にある場合は適宜何とかする
例
ヘッダオンリーなjsonライブラリ nlohmann/json で試してみる
$ find json/include/ -type f | xargs perl -nle '/^#include.*<(\w+)>/ and print "#include <$1>"' |sort |uniq >> out.hpp
$ cat json.cpp
# include <nlohmann/json.hpp>
$ clang -E json.cpp -P -nostdinc++ -I json/include >> out.hpp
In file included from json.cpp:1:
json/include/nlohmann/json.hpp:37:10: fatal error: 'algorithm' file not found
# include <algorithm> // all_of, find, for_each
^~~~~~~~~~~
1 error generated.
生成されたout.hppをwandboxに適当な名前で貼って完成
完成品: https://wandbox.org/permlink/mNio8fruFbGBdt2z
ほか
- ブラウザで動くサンプルコードを君のライブラリのreadmeに張ろう
- いやなんかもっとスマートな方法あるでしょ。教えてくれ
- 最初sproutで例作ってたんだけどsprout展開したファイルがでかすぎてwandboxが413返してきた。そういう日もある