探索C++頭文件解析方法(LLVM + Clang)

  最近一直在搞基於SWIG的C++接口翻譯Java代碼的工做。SWIG內部基於Bison(Yacc)的C/C++解析器,最近糾結於SWIG不能解析C++構造函數中的默認初始化賦值操做,想找一個可以補充此項能力的工具。html

  嘗試了Cast-xml,由於官網上說編譯須要依賴llvm+clang,結果浪費我半天的時間去研究怎麼編譯llvm+clang,耗費巨大的磁盤空間(12GB纔到70%)做罷。後來發現Ubuntu上能夠直接安裝編譯好的Cast-xml,試了一把發現解析出來的AST(抽象語法樹)根本就沒有初始值的相關的內容,只有大量的符號表之類的。坑~~幸好沒有在編譯llvm+clang的路上一根筋搞下去。前端

  又嘗試了好幾個cpp開源庫發現也不行,最後找到了一個名爲 CppHeaderParser (可pip安裝)的Python庫,用起來卻是很是簡單, 也可以分析頭文件並拿到函數原型,很是接近我須要的目標了!可萬萬沒想到竟然不解析函數體內容,功虧一簣啊。。。c++

  例如這樣一個頭文件:後端

 1 #ifndef _TEST_H
 2 #define _TEST_H
 3 
 4 #include <string>
 5 
 6 class MyClass {
 7 public:
 8     MyClass() : _iValue(123), _fValue(3.14) {
 9         _strValue = "Hello";
10     }
11 
12     int GetIValue() const;
13 
14 private:
15     int _iValue;
16     float _fValue;
17     std::string _strValue;
18 };
19 
20 #endif
View Code

  用 CppHeaderParser 解析出來的信息爲:架構

 1 class MyClass
 2 {
 3 public
 4     // Methods
 5    {'line_number': 8, 'parent': {'inherits': [], 'line_number': 6, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'MyClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 18, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_iValue', 'fundamental': True}, {'line_number': 19, 'constant': 0, 'reference': 0, 'raw_type': 'float', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'float', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_float', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_fValue', 'fundamental': True}, {'line_number': 20, 'constant': 0, 'reference': 0, 'raw_type': 'std::string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['std::string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'std::string', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': True, 'name': '_strValue', 'fundamental': 0}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{...}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'MyClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': True, 'name': 'GetIValue', 'pure_virtual': False, 'debug': '\t int GetIValue ( ) const ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': []}}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'MyClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'MyClass', 'pure_virtual': False, 'debug': '\t MyClass ( ) : \t _iValue ( 123 ) , \t _fValue ( 3.16 ) \t {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
 6    {'line_number': 15, 'parent': {'inherits': [], 'line_number': 6, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'MyClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 18, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_iValue', 'fundamental': True}, {'line_number': 19, 'constant': 0, 'reference': 0, 'raw_type': 'float', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'float', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_float', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_fValue', 'fundamental': True}, {'line_number': 20, 'constant': 0, 'reference': 0, 'raw_type': 'std::string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['std::string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'std::string', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': True, 'name': '_strValue', 'fundamental': 0}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 8, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'MyClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'MyClass', 'pure_virtual': False, 'debug': '\t MyClass ( ) : \t _iValue ( 123 ) , \t _fValue ( 3.16 ) \t {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}], 'private': []}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'MyClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': True, 'name': 'GetIValue', 'pure_virtual': False, 'debug': '\t int GetIValue ( ) const ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
 7 protected
 8 private
 9     // Properties
10     {'line_number': 18, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_iValue', 'fundamental': True}
11     {'line_number': 19, 'constant': 0, 'reference': 0, 'raw_type': 'float', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'float', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_float', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_fValue', 'fundamental': True}
12     {'line_number': 20, 'constant': 0, 'reference': 0, 'raw_type': 'std::string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['std::string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'std::string', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': True, 'name': '_strValue', 'fundamental': 0}
13 }
View Code

  確實有構造函數的初始化列表的內容,可是少了構造函數體中的賦值操做。總很差意思去要求全部人都必須用初始化列表來初始化吧?更況且確實有賦值語句給初值的狀況。。框架

  誰有更好的開源庫方法?多謝!ide

 

==========================================模塊化

  看來看去,感受只有clang最靠譜最有但願。快來看 LLVM 官方文檔,既能夠下載源碼,也能夠下載編譯好的包,很是靠譜!函數

  要利用clang來解析C++語法樹,感受仍是儘量用Python接口吧,方便啊,轉下一篇《利用Clang(Python接口)來解析C++》工具

 

1 參考LLVM介紹

  引用博文《LLVM原理和使用

  在理解LLVM時,咱們能夠認爲它包括了一個狹義的LLVM和一個廣義的LLVM。廣義的LLVM其實就是指整個LLVM編譯器架構,包括了前端、後端、優化器、衆多的庫函數以及不少的模塊;而狹義的LLVM其實就是聚焦於編譯器後端功能(代碼生成、代碼優化、JIT等)的一系列模塊和庫。

1.1 LLVM三段式架構

  (1)傳統編譯器的三段式:前端(Frontend)-- 優化器(Optimizer)-- 後端(Backend)

  (2)LLVM的三段式:

前端可使用不一樣的編譯工具對代碼文件作詞法分析以造成抽象語法樹AST,而後將分析好的代碼轉換成LLVM的中間表示IR(intermediate representation);中間部分的優化器只對中間表示IR操做,經過一系列的pass對IR作優化;後端負責將優化好的IR解釋成對應平臺的機器碼。LLVM的優勢在於,中間表示IR代碼編寫良好,並且不一樣的前端語言最終都轉換成同一種的IR。

1.2 Clang與LLVM的關係

  Clang是一個C++編寫、基於LLVM、發佈於LLVM BSD許可證下的C/C++/Objective-C/Objective-C++編譯器。那麼爲何已經有了GCC還要開發Clang呢?Clang相比於GCC有什麼優點呢?   其實,這也是Clang當初在設計開發的時候所主要考慮的緣由。Clang是一個高度模塊化開發的輕量級編譯器,它的編譯速度快、佔用內存小、很是方便進行二次開發。

  LLVM與Clang是C/C++編譯器套件。對於整個LLVM的框架來講,包含了Clang,由於Clang是LLVM的框架的一部分,是它的一個C/C++的前端。Clang使用了LLVM中的一些功能,目前知道的就是針對中間格式代碼的優化,或許還有一部分生成代碼的功能。從源代碼角度來說,clang是基於LLVM的一個工具。而功能的角度來講,LLVM能夠認爲是一個編譯器的後端,而clang是一個編譯器的前端。

1.3 LLVM 編譯流程

  LLVM編譯一個源文件的過程:預處理 -> 詞法分析 -> Token -> 語法分析 -> AST -> 代碼生成 -> LLVM IR -> 優化 -> 生成彙編代碼 -> Link -> 目標文件。

2 CLang工具命令

2.1 打印語法樹

  能夠用以下命令打印語法樹:

clang -Xclang -ast-dump -fsyntax-only -Iinclude -x c++ test.h > out.txt

2.2 打印分詞(詞法分析)

  以下命令:

clang -Xclang -dump-tokens -Iinclude test.h > out2.txt

2.3 打印語法分析(語法分析) 

  以下命令:

clang -fsyntax-only -Xclang -ast-dump -x c++ -Iinclude test.h > out3.txt
相關文章
相關標籤/搜索