我有以下脚本尝试打印出给定C ++文件中的所有AST节点。这在使用简单文件(在同一目录中的头文件等)上使用它时可以正常工作。
#!/usr/bin/env python
from argparse import ArgumentParser, FileType
from clang import cindex
def node_info(node):
return {'kind': node.kind,
'usr': node.get_usr(),
'spelling': node.spelling,
'location': node.location,
'file': node.location.file.name,
'extent.start': node.extent.start,
'extent.end': node.extent.end,
'is_definition': node.is_definition()
}
def get_nodes_in_file(node, filename, ls=None):
ls = ls if ls is not None else []
for n in node.get_children():
if n.location.file is not None and n.location.file.name == filename:
ls.append(n)
get_nodes_in_file(n, filename, ls)
return ls
def main():
arg_parser = ArgumentParser()
arg_parser.add_argument('source_file', type=FileType('r+'),
help='C++ source file to parse.')
arg_parser.add_argument('compilation_database', type=FileType('r+'),
help='The compile_commands.json to use to parse the source file.')
args = arg_parser.parse_args()
compilation_database_path = args.compilation_database.name
source_file_path = args.source_file.name
clang_args = ['-x', 'c++', '-std=c++11', '-p', compilation_database_path]
index = cindex.Index.create()
translation_unit = index.parse(source_file_path, clang_args)
file_nodes = get_nodes_in_file(translation_unit.cursor, source_file_path)
print [p.spelling for p in file_nodes]
if __name__ == '__main__':
main()
但是,当我运行脚本并提供一个在其父目录中有compile_commands.json文件的有效C ++文件时,我得到clang.cindex.TranslationUnitLoadError: Error parsing translation unit.
。这段代码使用带有clang的CMake运行并构建得很好,但我似乎无法弄清楚如何正确地传递指向compile_commands.json的参数。
我也很难在clang文档中找到此选项,但无法使-ast-dump
起作用。但是,通过传递文件路径,clang-check工作正常!
答案 0 :(得分:7)
您自己接受的答案不正确。 libclang
does support compilation databases和so does cindex.py,libclang python绑定。
混淆的主要原因可能是libclang知道/使用的编译标志只是可以传递给clang前端的所有参数的子集。编译数据库受支持但不能自动运行:必须手动加载和查询。这样的事情应该有效:
#!/usr/bin/env python
from argparse import ArgumentParser, FileType
from clang import cindex
compilation_database_path = args.compilation_database.name
source_file_path = args.source_file.name
index = cindex.Index.create()
# Step 1: load the compilation database
compdb = cindex.CompilationDatabase.fromDirectory(compilation_database_path)
# Step 2: query compilation flags
try:
file_args = compdb.getCompileCommands(source_file_path)
translation_unit = index.parse(source_file_path, file_args)
file_nodes = get_nodes_in_file(translation_unit.cursor, source_file_path)
print [p.spelling for p in file_nodes]
except CompilationDatabaseError:
print 'Could not load compilation flags for', source_file_path
答案 1 :(得分:0)
据我所知,Libclang不支持编译数据库但Libtooling不支持。为了解决这个问题,我将-I
的路径作为参数,最后自行解析,找到感兴趣的文件和相关的包含(-isystem
和{{1}}包含)。
答案 2 :(得分:0)
接受的答案似乎已被弃用,至少它对我不起作用,我不得不这样做:
import clang.cindex
def main():
index = clang.cindex.Index.create()
compdb = clang.cindex.CompilationDatabase.fromDirectory(
"dir/")
source_file_path = 'path/to/file.cpp'
commands = compdb.getCompileCommands(source_file_path)
file_args = []
for command in commands:
for argument in command.arguments:
file_args.append(argument)
file_args = file_args[3:-3]
print(file_args)
translation_unit = index.parse(source_file_path, args=file_args)
comment_tokens = GetDoxygenCommentTokens(translation_unit)
if __name__ == "__main__":
main()
基本上我必须遍历命令和参数来创建一个字符串,然后消除一些特定于 g++ 的标志。