記錄java調用eclipse cdt 解析c++文件
環(huán)境:
jdk1.8
eclipse cdt 9.11.1
需求:
java 解析c++中的類,屬性類型,屬性名稱,函數(shù),函數(shù)參數(shù),返回值。
注意點:
如果你是外網編碼,移植依賴和代碼到內網的時候
運行可能出現(xiàn) class not found xxxx , 這個依賴其實是對的。
解決辦法:
將內網的maven的setting.xml 與外網的倉庫地址相同就能解決
具體需要一致內容地點:
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共倉庫</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
依賴:
1. cdt 下載
https://archive.eclipse.org/tools/cdt/releases/9.11/cdt-9.11.1/
2. pom添加依賴:
<dependencies> <!-- CDT 核心 --> <dependency> <groupId>org.eclipse.cdt</groupId> <artifactId>org.eclipse.cdt.core</artifactId> <version>9.11.1</version> <scope>system</scope> <systemPath>${project.basedir}/libs/org.eclipse.cdt.core_6.11.1.202006011430.jar</systemPath> </dependency> <!-- Eclipse runtime 必要依賴 --> <dependency> <groupId>org.eclipse.platform</groupId> <artifactId>org.eclipse.core.runtime</artifactId> <version>3.13.0</version> </dependency> <dependency> <groupId>org.eclipse.platform</groupId> <artifactId>org.eclipse.core.jobs</artifactId> <version>3.9.3</version> </dependency> <dependency> <groupId>org.eclipse.platform</groupId> <artifactId>org.eclipse.core.contenttype</artifactId> <version>3.6.0</version> </dependency> <dependency> <groupId>org.eclipse.platform</groupId> <artifactId>org.eclipse.equinox.common</artifactId> <version>3.9.0</version> </dependency> <!-- 日志服務 --> <dependency> <groupId>org.eclipse.platform</groupId> <artifactId>org.eclipse.equinox.supplement</artifactId> <version>1.8.0</version> </dependency> </dependencies>
解析代碼:
package org.example;
import org.eclipse.cdt.core.dom.ast.*;
import org.eclipse.cdt.core.dom.ast.cpp.*;
import org.eclipse.cdt.core.dom.ast.gnu.cpp.GPPLanguage;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.*;
import java.util.HashMap;
public class CDTParseExample {
public static void main(String[] args) throws Exception {
// 1. 指定要解析的頭文件路徑
String filePath = "C:\\Users\\dell\\AppData\\Roaming\\JetBrains\\IntelliJIdea2025.2\\extensions\\xxxxxx.h";
FileContent fileContent = FileContent.createForExternalFileLocation(filePath);
// 2. 模擬 include / 宏定義信息
HashMap<String, String> macros = new HashMap<>();
macros.put("__cplusplus", "1");
macros.put("XXXXX_DLL", ""); // 避免 class XXXXX_DLL 出錯
macros.put("FRDTOMOON_ID", "int"); // 如果有類似 typedef 也要補
macros.put("CAbstractEntity", "int"); // 臨時占位
macros.put("C_DBIDriver", "int");
macros.put("CTableQuery", "int");
IScannerInfo scannerInfo = new ScannerInfo(macros, new String[] {
"C:\\Users\\dell\\AppData\\Roaming\\JetBrains\\IntelliJIdea2025.2\\extensions"
});
IncludeFileContentProvider fileContentProvider = IncludeFileContentProvider.getEmptyFilesProvider();
// 3. 創(chuàng)建 TranslationUnit
IASTTranslationUnit translationUnit = GPPLanguage.getDefault().getASTTranslationUnit(
fileContent,
scannerInfo,
fileContentProvider,
null,
ITranslationUnit.AST_PARSE_INACTIVE_CODE,
new DefaultLogService()
);
// 4. 遍歷 AST,找到類定義
// 假設你已經有 IASTTranslationUnit tu(通過 GPPLanguage.getDefault().getASTTranslationUnit(...))
translationUnit.accept(new ASTVisitor(true) {
{
// 一定要打開這些 flag
shouldVisitDeclarations = true;
shouldVisitDeclSpecifiers = true;
shouldVisitNamespaces = true;
// 如果頭文件內有宏可能屏蔽成員,考慮打開:
// includeInactiveNodes = true;
}
// 處理命名空間(可選)
@Override
public int visit(ICPPASTNamespaceDefinition namespaceDefinition) {
System.out.println("namespace: " + (namespaceDefinition.getName() != null ? namespaceDefinition.getName() : "<anon>"));
// namespace 內部聲明也會單獨觸發(fā) visit(IASTDeclaration),
// 這里可以選擇直接遍歷 namespaceDefinition.getDeclarations() 或交由 visit(IASTDeclaration) 處理。
return PROCESS_CONTINUE;
}
@Override
public int visit(IASTProblem problem) {
System.out.println("Parser problem: " + problem.getMessage()
+ " at " + problem.getFileLocation().getFileName()
+ ":" + problem.getFileLocation().getStartingLineNumber());
return PROCESS_CONTINUE;
}
// 處理所有聲明(包括 class/struct 的聲明)
@Override
public int visit(IASTDeclaration declaration) {
// 只關心簡單聲明(class/struct 在 simpleDecl 的 declSpec 中)
if (declaration instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) declaration;
IASTDeclSpecifier declSpec = simpleDecl.getDeclSpecifier();
// 如果這是 class/struct 的定義(復合類型)
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
ICPPASTCompositeTypeSpecifier classSpec = (ICPPASTCompositeTypeSpecifier) declSpec;
System.out.println("Class/Struct: " + classSpec.getName());
// 關鍵點:成員就在 classSpec.getMembers()
IASTDeclaration[] members = classSpec.getMembers();
for (IASTDeclaration member : members) {
// 我們主要關心成員變量(IASTSimpleDeclaration 且 declarators 非空 且 不是函數(shù))
if (member instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration memberDecl = (IASTSimpleDeclaration) member;
IASTDeclarator[] decs = memberDecl.getDeclarators();
if (decs != null && decs.length > 0) {
// 如果 declarator 不是函數(shù) declarator,則為字段
if (!(decs[0] instanceof IASTFunctionDeclarator)) {
String type = memberDecl.getDeclSpecifier() != null ?
memberDecl.getDeclSpecifier().getRawSignature() : "<unknown>";
for (IASTDeclarator d : decs) {
// 安全取名(有時 getName() 為空)
String name = (d.getName() != null) ? d.getName().toString() : d.getRawSignature();
System.out.println(" field: " + name + " | type: " + type);
}
}
}
}
// 如果成員是函數(shù)定義,也可以在這里處理(可選)
else if (member instanceof IASTFunctionDefinition) {
IASTFunctionDefinition fd = (IASTFunctionDefinition) member;
String fname = fd.getDeclarator() != null && fd.getDeclarator().getName() != null ?
fd.getDeclarator().getName().toString() : "<anon>";
System.out.println(" method-def: " + fname);
}
}
}
// 如果這是頂層 enum(也可能出現(xiàn)在類內)
else if (declSpec instanceof ICPPASTEnumerationSpecifier) {
// 可按需處理
}
}
// 另外,如果遇到類外的函數(shù)定義(有函數(shù)體),也可以處理
else if (declaration instanceof IASTFunctionDefinition) {
// 處理類外限定名的函數(shù)定義(例如 CAbstractRead::serialize)
IASTFunctionDefinition funcDef = (IASTFunctionDefinition) declaration;
IASTFunctionDeclarator fd = funcDef.getDeclarator();
if (fd != null) {
System.out.println("Top-level function def: " + fd.getName());
}
}
return PROCESS_CONTINUE;
}
});
// 5. 從 binding 里提取字段
for (IASTDeclaration decl : translationUnit.getDeclarations()) {
if (decl instanceof IASTSimpleDeclaration) continue;
if (decl instanceof ICPPASTCompositeTypeSpecifier) {
ICPPASTCompositeTypeSpecifier cls = (ICPPASTCompositeTypeSpecifier) decl;
ICPPClassType binding = (ICPPClassType) cls.getName().resolveBinding();
if (binding != null) {
System.out.println("類名: " + binding.getName());
for (ICPPField field : binding.getDeclaredFields()) {
System.out.println("成員變量: " + field.getName() +
" , 類型: " + field.getType().toString());
}
}
}
}
}
private static void handleClassMember(IASTDeclaration member) {
if (member instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration memberDecl = (IASTSimpleDeclaration) member;
IASTDeclarator[] declarators = memberDecl.getDeclarators();
if (declarators.length == 0) return;
// 變量
if (!(declarators[0] instanceof IASTFunctionDeclarator)) {
String type = memberDecl.getDeclSpecifier().getRawSignature();
for (IASTDeclarator d : declarators) {
String name = d.getName().toString();
System.out.println(" 字段: " + name + " | 類型: " + type);
}
}
}
}
}
代碼注意點:
//上面代碼中的這里可以把 c++里面的宏跳過定義處理,如果你的頭文件有定義宏,并且沒有在這put上,可能會解析失敗 HashMap<String, String> macros = new HashMap<>();

浙公網安備 33010602011771號