C/C++ のソースをパースして TranslaionUnit を得る¶
path が parse のエントリポイントとなる。
from typing import NamedTuple, List, Optional
from clang import cindex
class Unsaved(NamedTuple):
name: str
content: str
def get_tu(entrypoint: str,
*,
include_dirs: List[str] = None,
flags: List[str] = None,
unsaved: Optional[List[Unsaved]] = None) -> cindex.TranslationUnit:
arguments = [
"-x",
"c++",
"-target",
"x86_64-windows-msvc",
"-fms-compatibility-version=18",
"-fdeclspec",
"-fms-compatibility",
"-std=c++17",
]
if include_dirs:
arguments.extend(f'-I{i}' for i in include_dirs)
if flags:
arguments.extend(flags)
# path of libclang.dll
cindex.Config.library_path = 'C:\\Program Files\\LLVM\\bin'
index = cindex.Index.create()
tu = index.parse(entrypoint, arguments, unsaved,
cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD |
cindex.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES)
return tu
unsaved file はメモリ上のファイルに仮の名前を与えてパースする仕組み。 エディタで未保存のファイルを対象にする他に、 複数のヘッダーを一度にパースしたい場合に まとめて include する一時ファイルをメモリ上で済ます用途がある。
// unsaved content
#include "a.h"
#include "b.h"
#include "c.h"
compiler 引数¶
arguments の与え方で vc の cl.exe
のようにふるまわせることができる。
-D による define
-I による include パス
c++17 などの対応レベル
などをよく使う。
flags¶
cindex.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES
など。関数の中身をスキップする。 言語バインディングの生成をする場合には関数のシグニチャのみが必要。
マクロの制御などもあり、指定しないと出現しない cursor がある。