コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2021年6月24日 >>> 2021年6月24日
link もっと後

2021年6月24日

プログラムからLLVMを実行する その2 - プリプロセス編

目次: LLVM

準備が終わりましたらClang/LLVMをプログラムから呼びましょう。

LLVMでプリプロセスだけを実行するプログラム

int main(int argc, char *argv[])
{
	bool success;

	clang::CompilerInstance CI;
	clang::CompilerInvocation &build = CI.getInvocation();

	// 引数の配列を作成する
	std::vector<const char*> vec_args;
	vec_args.push_back("-I/usr/include/c++/10");
	vec_args.push_back("-I/usr/include/x86_64-linux-gnu/c++/10");
	vec_args.push_back("-I/usr/include/c++/10/backward");
	vec_args.push_back("-I/usr/lib/llvm-11/lib/clang/11.0.1/include");
	vec_args.push_back("-I/usr/include/x86_64-linux-gnu");
	vec_args.push_back("-I/usr/include");
	vec_args.push_back("-I/path/to/llvm-project/_install/include");

	// エラーメッセージを出力するために使われるクラス
	llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID = new clang::DiagnosticIDs();
	llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts = new clang::DiagnosticOptions();
	clang::TextDiagnosticBuffer *diagBuffer = new clang::TextDiagnosticBuffer();
	clang::DiagnosticsEngine diags(diagID, diagOpts, diagBuffer);
	CI.createDiagnostics(diagBuffer, false);

	// コンパイラ呼び出し用のインスタンスを作成する
	llvm::ArrayRef<const char*> ref_args(vec_args.data(), vec_args.data() + vec_args.size());
	success = clang::CompilerInvocation::CreateFromArgs(build, ref_args, diags);

	// コンパイラフロントエンドのオプション設定
	//   入力ソースコード: test.cpp
	//   出力ソースコード: test.preproc.cpp
	const char *source_file = "test.cpp";
	const char *preproc_file = "test.preproc.cpp";
	clang::FrontendOptions &fe   = build.getFrontendOpts();
	clang::InputKind ik          = clang::InputKind(clang::Language::CXX);
	clang::FrontendInputFile fif = clang::FrontendInputFile(source_file, ik);

	fe.Inputs.clear();
	fe.Inputs.push_back(fif);
	fe.OutputFile.assign(preproc_file);

	// プリプロセスのオプション設定
	//   言語: C++11
	clang::PreprocessorOptions &po = build.getPreprocessorOpts();
	clang::LangOptions *la         = build.getLangOpts();
	llvm::Triple triple            = llvm::Triple();
	build.setLangDefaults(*la, ik, triple, po.Includes, clang::LangStandard::lang_cxx11);

	// 下記のようにオプションの一部だけ変えることもできる
	//la->CPlusPlus = true;
	//la->CPlusPlus11 = true;

	// プリプロセスのオプション
	//   コメント、定義済みマクロなどは出力しない
	clang::PreprocessorOutputOptions &poo = build.getPreprocessorOutputOpts();
	poo.ShowCPP = true;
	poo.ShowComments = false;
	poo.ShowLineMarkers = false;
	poo.ShowMacros = false;
	poo.ShowMacroComments = false;
	poo.RewriteIncludes = false;

	// プリプロセス実行(失敗したらエラーログを出力する)
	clang::PrintPreprocessedAction Preprocess;
	success = CI.ExecuteAction(Preprocess);
	if (!success) {
		get_build_log(diagBuffer, (CI.hasSourceManager()) ? &CI.getSourceManager() : nullptr);
	}
}

残念ながらこの呼び出し方が正解とは断言できません。探した限りではどう呼び出すべきか書かれたドキュメントも見当たりませんでした。上記の例はpoclを参考にしており、大きな間違いはないはずですが……。何かやらかしていたら教えていただけると嬉しいです。

動作確認はLLVM 12で行いました。他のバージョンだとAPIの引数などが変わっているので、ビルドすら通らないと思います。LLVMの困ったところですね……。

インクルードパスの調べ方

上記のサンプルでは引数で -Iオプションを使ってインクルードパスを指定します。インクルードパスは頑張ってヘッダファイルがある場所を調べても良いですが、おそらく同じ名前のヘッダが複数の場所にあって混乱すると思いますから、PCで動作しているClang++ から拝借するのが簡単です。

clangのインクルードパスを調べる
$ clang++ test.cpp -v

Debian clang version 11.0.1-2
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10

...

#include "..." search starts here:
#include <...> search starts here:
 /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10
 /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10
 /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward
 /usr/lib/llvm-11/lib/clang/11.0.1/include
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

...

いろいろなメッセージが出力されますが、インクルードパスは "search starts here:" の辺りに書かれています。出力は特に捻りはなくディレクトリ名そのものですので、頭に -Iを足せばオプションの出来上がりです。

実行

プリプロセスを実行します。テスト用のプログラムは下記のとおりです。

テスト用のプログラム

#include <iostream>

int main(int argc, char *argv[])
{
	// This is comment
	std::cout << "Hello, world!!" << std::endl;
}

プリプロセス実行
$ make

$ ./clang_test

ファイル名などは完全に決め打ちのため引数は必要ありません。実行に成功するとプリプロセス後のソースコードtest.preproc.cppが作成されているはずです。

プリプロセス後のソースコード

namespace std
{
  typedef long unsigned int size_t;
  typedef long int ptrdiff_t;


  typedef decltype(nullptr) nullptr_t;

}

...

  static ios_base::Init __ioinit;


}

int main(int argc, char *argv[])
{

 std::cout << "Hello, world!!" << std::endl;
}

私の環境で実行したところ27,000行くらいあるファイルになりました。たった1つしかヘッダをincludeしてないのに凄まじい行数に展開されます。コメントは消えていますが、オプションを変更すれば残すこともできます。PreprocessorOutputOptionsのShowComments = trueにすると残ります。

プリプロセス後のソースコードをビルド&実行
$ g++ test.preproc.cpp

$ ./a.out
Hello, world!!

プリプロセス後のソースコードをg++ などに渡すとコンパイル可能なので、おそらく変な出力にはなっていないでしょう。

編集者:すずき(2023/09/24 09:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2021年6月24日 >>> 2021年6月24日
link もっと後

管理用メニュー

link 記事を新規作成

<2021>
<<<06>>>
--12345
6789101112
13141516171819
20212223242526
27282930---

最近のコメント5件

  • link 24年4月22日
    hdkさん (04/24 08:36)
    「うちのHHFZ4310は15年突破しまし...」
  • link 24年4月22日
    すずきさん (04/24 00:37)
    「ちゃんと数えてないですけど蛍光管が10年...」
  • link 24年4月22日
    hdkさん (04/23 20:52)
    「おお... うちのHHFZ4310より後...」
  • link 20年6月19日
    すずきさん (04/06 22:54)
    「ディレクトリを予め作成しておけば良いです...」
  • link 20年6月19日
    斎藤さん (04/06 16:25)
    「「Preferencesというメニューか...」

最近の記事3件

  • link 24年4月25日
    すずき (04/26 16:49)
    「[AVIFの変換] AVIFが読めないアプリケーションがたまにあるので、AVIF(AV1 Image File Format)...」
  • link 24年2月7日
    すずき (04/24 02:52)
    「[複数の音声ファイルのラウドネスを統一したい] PCやデジタル音楽プレーヤーで音楽を聞いていると、曲によって音量の大小が激しく...」
  • link 24年4月22日
    すずき (04/23 20:13)
    「[仕事部屋の照明が壊れた] いきなり仕事部屋のシーリングライトが消えました。蛍光管の寿命にしては去年(2022年10月19日の...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 04/26 16:49