我在独立的 Java 应用程序中使用 Eclipse CDT 作为 C/C++ 头文件的解析器,其想法是从头文件中代码生成 JNI/JNA 绑定(bind)。
下载了 JAR 文件(很难找到,这个库没有 maven!)并解析了一个工作正常的简单头文件。
然而,当我尝试真正的头文件时,结果有些随机:返回的 AST 没有子级,只有一些预处理器声明存在,最奇怪的是只检测到两个注释。
这里是缩减代码:
final FileContent content = FileContent.createForExternalFileLocation("C:/VulkanSDK/1.1.101.0/Include/vulkan/vulkan.h");
final Map<String, String> definedMacros = new HashMap<>();
definedMacros.put("__cplusplus", "1");
final String[] includePaths = new String[0];
final IScannerInfo info = new ScannerInfo(definedMacros, includePaths);
final IncludeFileContentProvider emptyIncludes = IncludeFileContentProvider.getEmptyFilesProvider();
final IIndex index = EmptyCIndex.INSTANCE;
final int options = 0;
final IParserLogService log = new DefaultLogService();
final IASTTranslationUnit unit = GPPLanguage.getDefault().getASTTranslationUnit(content, info, emptyIncludes, index, options, log);
System.out.println("len="+unit.getChildren().length);
我要解析的头文件是针对 Vulkan 图形库的,它非常大所以这里是 link这是文件的前几位:
#ifndef VULKAN_H_
#define VULKAN_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright (c) 2015-2017 The Khronos Group Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#define VK_VERSION_1_0 1
#include "vk_platform.h"
getComments()
返回的两条评论是文件顶部的第一个大评论 block ,奇怪的是:
// VULKAN_H_
即它似乎已经决定预处理器语句是注释!?
尽管解析器接受了一个日志记录回调,但它没有告诉我任何信息,也没有报告任何问题。我怀疑我对 CDT 和预处理器语句有些不了解,但我找不到任何类似的问题(CDT 是一个非常小众的工具)。
我在代码中摆弄了所有我能想到的东西,包括各种选项参数,但我每次都得到相同的结果。正如我所说,解析其他更简单的头文件工作得很好。
有什么想法吗?有什么建议吗?
最佳答案
所以我是个白痴!
我认为并没有解析实际的头文件,而是设法加载了“ super ”头文件,然后#includes 我真正想要的文件。这个super-header包括各种其他header在平台上的切换等等,一个标准的方法。我发布的代码没有递归到#included 文件,所以结果正确为空!一旦我将代码指向正确的 header ,AST 就会按预期构建。
然而,这并不能解释看似随机的注释和奇怪的注释掉的 header 防护 - 我已经向 Eclipse CDT 开发人员提出了一个问题,因为(尽管我很愚蠢)结果完全让我震惊。
对于任何感兴趣的人来说,从头文件生成 JNA 结构和枚举的代码效果很好(尽管 CDT 本身并不是一个“真正的”库)。
这是一个从 C typedef enum
生成的示例枚举类:
package org.sarge.jove.platform.vulkan;
/**
* HEADER COMMENT
*/
public enum VkBorderColor {
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK(0),
VK_BORDER_COLOR_INT_TRANSPARENT_BLACK(1),
VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK(2),
VK_BORDER_COLOR_INT_OPAQUE_BLACK(3),
VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE(4),
VK_BORDER_COLOR_INT_OPAQUE_WHITE(5),
VK_BORDER_COLOR_BEGIN_RANGE(0),
VK_BORDER_COLOR_END_RANGE(5),
VK_BORDER_COLOR_RANGE_SIZE(6),
VK_BORDER_COLOR_MAX_ENUM(2147483647);
private final int value;
private VkBorderColor(int value) {
this.value = value;
}
/**
* @return Enum literal
*/
public int value() {
return value;
}
}
使用实际的 C/C++ 解析器意味着我可以访问实际的枚举值,即使是表达式。
这里是一个从 C struct
生成的 JNA 结构:
package org.sarge.jove.platform.vulkan;
import com.sun.jna.Structure;
import com.sun.jna.Structure.FieldOrder;
import com.sun.jna.Pointer;
import org.sarge.jove.platform.vulkan.VkStructureType;
/**
* HEADER COMMENT
*/
@FieldOrder({
"sType",
"pNext",
"physicalDeviceCount",
"physicalDevices",
"subsetAllocation"
})
public class VkPhysicalDeviceGroupProperties extends Structure {
public static class ByValue extends VkPhysicalDeviceGroupProperties implements Structure.ByValue { }
public static class ByReference extends VkPhysicalDeviceGroupProperties implements Structure.ByReference { }
public final int sType = VkStructureType.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES.value();
public Pointer pNext;
public int physicalDeviceCount;
public Pointer[] physicalDevices = new Pointer[32];
public int subsetAllocation;
}
许多 Vulkan 结构都有一个 sType
字段来标识结构的类型 (!),因此我可以自动神奇地将字段初始化为相应的生成枚举 - 太棒了。
再次使用 CDT 还意味着我可以处理 C 数组类型的映射和初始化数组字段(JNA 内存管理的要求)。
所以最后 CDT 的效果很好。
故事的寓意:记住你是个白痴。
关于java - Eclipse CDT解析C/C++头文件返回空AST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55044104/