Suppose I have a Bazel project with this structure:
WORKSPACE
- includes
- a.h
- BUILD
- includes_b
- b.h
- BUILD
with the following files:
includes/BUILD
cc_library(
name = "a",
srcs = [],
hdrs = [
"a.h",
],
deps = [],
visibility = ["//visibility:public"]
)
includes/a.h
struct A{
public:
int val;
};
includes_b/BUILD
cc_library(
name = "b",
srcs = [],
hdrs = [
"b.h",
],
deps = ["//includes:a"],
visibility = ["//visibility:public"]
)
includes_b/b.h
#include "includes/a.h"
struct B{
public:
int val2;
A a;
};
I am using linclang in Python to parse C++ source code: my script is the following:
import clang.cindex
import typing
def traverse(node, output_struct, file_parsed):
print(node.spelling, node.kind)
if node.kind == clang.cindex.CursorKind.STRUCT_DECL:
if node.semantic_parent.spelling != "std":
print("struct", node.spelling, "; parent: ",
node.semantic_parent.spelling)
if node.semantic_parent.spelling == file_parsed:
traverse.current_namespace = ""
output_struct[node.spelling] = {
"type": "struct",
"attributes": [],
"namespace": traverse.current_namespace
}
elif node.kind == clang.cindex.CursorKind.CLASS_DECL:
if node.semantic_parent.spelling != "std":
print("class", node.spelling, "; parent: ",
node.semantic_parent.spelling)
elif node.kind == clang.cindex.CursorKind.ENUM_DECL:
if node.semantic_parent.spelling != "std":
print("field", node.spelling, "; parent: ",
node.semantic_parent.spelling)
if node.semantic_parent.spelling == file_parsed:
traverse.current_namespace = ""
output_struct[node.spelling] = {
"type": "enum",
"attributes": [],
"namespace": traverse.current_namespace
}
elif node.kind == clang.cindex.CursorKind.ENUM_CONSTANT_DECL:
if node.semantic_parent.spelling != "std":
print("enum_const", node.spelling, "; enum value: ",
node.enum_value, "; parent: ", node.semantic_parent.spelling)
output_struct[node.semantic_parent.spelling]["attributes"].append(
(node.spelling, node.enum_value))
elif node.kind == clang.cindex.CursorKind.NAMESPACE:
print("namespace", node.spelling, "; parent: ",
node.semantic_parent.spelling)
if node.semantic_parent.spelling == file_parsed:
traverse.current_namespace = node.spelling
elif node.semantic_parent.spelling == traverse.current_namespace:
traverse.current_namespace += "::" + node.spelling
elif node.kind == clang.cindex.CursorKind.FIELD_DECL:
# enum_type, enum_value, semantic_parent, lexical_parent
if node.semantic_parent.spelling != "std":
print("field declaration", node.spelling, node.type.spelling,
"; parent: ", node.semantic_parent.spelling)
if node.semantic_parent.spelling in output_struct.keys(): # fpos not found
output_struct[node.semantic_parent.spelling]["attributes"].append(
(node.spelling, node.type.spelling))
print("+++++++++++++++++Sons of " + node.spelling +"+++++++++++++++++++++++++++++++++")
for child in node.get_children():
print(child.spelling)
print("+++++++++++++++++++++END SONS+++++++++++++++++++++++++++++")
for child in node.get_children():
traverse(child, output_struct=output_struct, file_parsed=file_parsed)
if __name__ == "__main__":
index = clang.cindex.Index.create()
file_parsed = "/absolute/path/clang_test/includes_b/b.h"
parsed_struct = {}
translation_unit = index.parse(
file_parsed, args=['-x', 'c++', '-std=c++14'])
traverse(translation_unit.cursor, parsed_struct, file_parsed)
print(parsed_struct)
The problem is the following: the a
attribute of struct B
, instead of being recognised as A
type, is regognised as int
type, because apparently types unrecognised by clang are by default int
.
The problem is that within the Bazel project, relative paths are used, so clang is unable to locate the header a.h
parsing the file b.h
. Prove of this is the fact that if I change the include with the absolute path, then everything works and a
is recognised as of type A
and also a.h
is parsed.
How can I make libclang parse also the header a.h
when analysing the b.h
file? I was thinking to extract the working directory with os.getcwd()
and then pre-pend it to the include string, but I cannot find the point where libclang analyse the include directory.
I have tried to use the clang.cindex.CursorKind.INCLUSION_DIRECTIVE
but no node of this kind was defined.
How can I tell libclang where to search that header file?