事实证明,此故障的可调试性非常缺乏。我跟踪了一堆 libclang 绑定源,希望找到解决周围缺乏可调试性的解决方法TranslationUnitLoadError
是从 python 中抛出的。
即使您使用 ctypes,这里似乎也存在一些基本限制errcheck
callback https://docs.python.org/3.7/library/ctypes.html#ctypes._FuncPtr.errcheck就像下面的...
# MODIFIED cindex.py
def errcheck_callable(result, func, arguments):
print(f"ERROR---result={result}, func={func}, arguments={arguments}")
import pdb
pdb.set_trace()
functionList = [
...
("clang_parseTranslationUnit",
[Index, c_interop_string, c_void_p, c_int, c_void_p, c_int, c_int],
c_object_p,
errcheck_callable, # <--- makes this dll function a bit more debugable during call to `register_function`
),
...
]
然而,翻译单元失败期间触发的错误回调中没有太多内容:
> /Users/USERX/python3.7/site-packages/clang/cindex.py(155)errcheck_callable()
-> print(f"ERROR---result={result}, func={func}, arguments={arguments}")
ERROR---result=<clang.cindex.LP_c_void_p object at 0x10b1aa9d8>, func=<_FuncPtr object at 0x10b1bf5c0>, arguments=(<clang.cindex.Index object at 0x10aea1e48>, None, <clang.cindex.c_char_p_Array_62 object at 0x10b1aa620>, 62, None, 0, 0)
(Pdb) result.contents
*** ValueError: NULL pointer access
有一个待处理的FIXME
comment https://github.com/llvm/llvm-project/blob/e29a2e6be4e114b4233a2e0feedb74b2f34cf782/clang/bindings/python/clang/cindex.py#L151-L159几年前添加了有关 libclang 固有的可调试性差距的内容clang_parseTranslationUnit
.
# FIXME: Make libclang expose additional error information in this scenario.
这篇文章中进行了一些讨论使用 libclang 的 Python 绑定处理解析错误 http://clang-developers.42468.n3.nabble.com/Dealing-with-parse-errors-with-Python-bindings-of-libclang-td4052953.html。最好的建议似乎来自将调试器附加到 libclang 的想法:
...您也许可以让调试器继续运行clang_parseTranslationUnit
并检查那里的错误状态。
为了深入了解一些内部原理,libclang 基本上是通过 ctypes 加载到 python 中的call https://github.com/llvm/llvm-project/blob/4e85ca9562a588eba491e44bcbf73cb2f419780f/clang/bindings/python/clang/cindex.py#L4172 to cdll.LoadLibrary
创建一个CDLL https://docs.python.org/3/library/ctypes.html#ctypes.CDLL实例。然后定义了一组硬编码的函数functionList
因为一组元组都是通过注册的register_functions
赋予它们更深的蟒蛇存在感。实际上TranslationUnitLoadError
gets raised https://github.com/llvm/llvm-project/blob/4e85ca9562a588eba491e44bcbf73cb2f419780f/clang/bindings/python/clang/cindex.py#L2828-L2835类内方法TranslationUnit.from_source
它直接调用该行中的 libclang 函数
ptr = conf.lib.clang_createTranslationUnit(index, fspath(filename))
我相信这是可调试性被截断的地方,因为底层source https://github.com/llvm/llvm-project/blob/7b518dcb291e740c3e957d93c2b4046bc8a97f00/clang/tools/libclang/CIndex.cpp#L3587-L3603因为 python 绑定是 C,而不是 C++,所以没有异常处理像冒泡一样SEH异常 https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.sehexception?view=netframework-4.8对于.net 来说会。使用该运行时,您可以调试非托管代码。然而这里没有等价物。
您可以跟踪翻译单元变量TU
从其调用堆栈向下source https://github.com/llvm/llvm-project/blob/d4c9e13324443c0324148156d54d2c7c81393327/clang/tools/libclang/CIndex.cpp#L3587-L3603...
CXTranslationUnit
clang_parseTranslationUnit(CXIndex CIdx,
const char *source_filename,
const char *const *command_line_args,
int num_command_line_args,
struct CXUnsavedFile *unsaved_files,
unsigned num_unsaved_files,
unsigned options) {
CXTranslationUnit TU;
enum CXErrorCode Result = clang_parseTranslationUnit2(
CIdx, source_filename, command_line_args, num_command_line_args,
unsaved_files, num_unsaved_files, options, &TU);
如果我发现任何更实质性的内容,我会更新这个答案。鉴于这种可调试性差距,直接从 C++ 进行 libclang 分析可能会更有效,如下所示fella http://bastian.rieck.me/blog/posts/2016/baby_steps_libclang_function_extents/执行此操作,或者使用命令行工具clang-query
喜欢详细的here https://devblogs.microsoft.com/cppblog/exploring-clang-tooling-part-2-examining-the-clang-ast-with-clang-query/