Skip to content

Commit e968f47

Browse files
committed
#16 basic function parsing support
Add raw pointer type for (void *) C types Some correction to jextract parser for typedefs
1 parent c00f722 commit e968f47

File tree

18 files changed

+451
-107
lines changed

18 files changed

+451
-107
lines changed

annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/Libcurl.java

+15-13
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,37 @@
1111
import io.github.digitalsmile.annotation.structure.Enums;
1212
import io.github.digitalsmile.annotation.structure.Struct;
1313
import io.github.digitalsmile.annotation.structure.Structs;
14-
import io.github.digitalsmile.gpio.libcurl.enums.CURLCode;
15-
import io.github.digitalsmile.gpio.libcurl.enums.CURLOption;
16-
import io.github.digitalsmile.gpio.libcurl.opaque.CurlInstance;
14+
import io.github.digitalsmile.gpio.libcurl.enums.CURLcode;
15+
import io.github.digitalsmile.gpio.libcurl.enums.CURLoption;
16+
import io.github.digitalsmile.gpio.libcurl.opaque.CURL;
1717

1818
@NativeMemory(headers = "libcurl/curl/include/curl/curl.h")
1919
@NativeMemoryOptions(systemIncludes = {
20-
"/usr/lib/gcc/x86_64-linux-gnu/12/include/"
21-
}, debugMode = true, processRootConstants = true)
20+
//"/usr/lib/gcc/x86_64-linux-gnu/12/include/"
21+
"/usr/lib/llvm-15/lib/clang/15.0.7/include/"
22+
}, debugMode = true, processRootConstants = true, systemHeader = true)
2223
@Structs({
23-
@Struct(name = "CURL", javaName = "CurlInstance")
24+
// @Struct(name = "CURL", javaName = "CurlInstance")
2425
})
2526
@Enums({
26-
@Enum(name = "CURLcode", javaName = "CURLCode"),
27-
@Enum(name = "CURLoption", javaName = "CURLOption")
27+
// @Enum(name = "CURLcode", javaName = "CURLCode"),
28+
// @Enum(name = "CURLoption", javaName = "CURLOption")
2829
})
30+
@NativeMemoryLibrary
2931
public interface Libcurl {
3032

3133
@NativeManualFunction(name = "curl_easy_init", library = "/usr/lib/x86_64-linux-gnu/libcurl.so")
32-
CurlInstance easyInit() throws NativeMemoryException;
34+
CURL easyInit() throws NativeMemoryException;
3335

3436
@NativeManualFunction(name = "curl_global_init", library = "/usr/lib/x86_64-linux-gnu/libcurl.so")
35-
CURLCode globalInit(long flags) throws NativeMemoryException;
37+
CURLcode globalInit(long flags) throws NativeMemoryException;
3638

3739
@NativeManualFunction(name = "curl_easy_setopt", library = "/usr/lib/x86_64-linux-gnu/libcurl.so")
38-
CURLCode easySetOpt(CurlInstance curl, CURLOption option, String value) throws NativeMemoryException;
40+
CURLcode easySetOpt(CURL curl, CURLoption option, String value) throws NativeMemoryException;
3941

4042
@NativeManualFunction(name = "curl_easy_setopt", library = "/usr/lib/x86_64-linux-gnu/libcurl.so")
41-
CURLCode easySetOpt(CurlInstance curl, CURLOption option, @ByAddress long value) throws NativeMemoryException;
43+
CURLcode easySetOpt(CURL curl, CURLoption option, @ByAddress long value) throws NativeMemoryException;
4244

4345
@NativeManualFunction(name = "curl_easy_perform", library = "/usr/lib/x86_64-linux-gnu/libcurl.so")
44-
CURLCode easyPerform(CurlInstance curl) throws NativeMemoryException;
46+
CURLcode easyPerform(CURL curl) throws NativeMemoryException;
4547
}
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,43 @@
11
package io.github.digitalsmile.gpio.libcurl;
22

33
import io.github.digitalsmile.annotation.NativeMemoryException;
4-
import io.github.digitalsmile.gpio.libcurl.enums.CURLCode;
5-
import io.github.digitalsmile.gpio.libcurl.enums.CURLOption;
4+
import io.github.digitalsmile.gpio.libcurl.enums.CURLcode;
5+
import io.github.digitalsmile.gpio.libcurl.enums.CURLoption;
66
import org.junit.jupiter.api.Test;
77

88
import static org.junit.jupiter.api.Assertions.assertEquals;
99

1010
public class LibcurlTest {
1111

12+
// @Test
13+
// public void libcurl() throws NativeMemoryException {
14+
// try (var libcurl = new LibcurlNative()) {
15+
// var code = libcurl.globalInit(CurlConstants.CURL_GLOBAL_DEFAULT);
16+
// assertEquals(code, CURLCode.CURLE_OK);
17+
// var curl = libcurl.easyInit();
18+
// code = libcurl.easySetOpt(curl, CURLOption.CURLOPT_URL, "https://example.com");
19+
// assertEquals(code, CURLCode.CURLE_OK);
20+
// code = libcurl.easySetOpt(curl, CURLOption.CURLOPT_FOLLOWLOCATION, 1L);
21+
// assertEquals(code, CURLCode.CURLE_OK);
22+
//
23+
// code = libcurl.easyPerform(curl);
24+
// assertEquals(code, CURLCode.CURLE_OK);
25+
// }
26+
// }
27+
1228
@Test
1329
public void libcurl() throws NativeMemoryException {
1430
try (var libcurl = new LibcurlNative()) {
1531
var code = libcurl.globalInit(CurlConstants.CURL_GLOBAL_DEFAULT);
16-
assertEquals(code, CURLCode.CURLE_OK);
32+
assertEquals(code, CURLcode.CURLE_OK);
1733
var curl = libcurl.easyInit();
18-
code = libcurl.easySetOpt(curl, CURLOption.CURLOPT_URL, "https://example.com");
19-
assertEquals(code, CURLCode.CURLE_OK);
20-
code = libcurl.easySetOpt(curl, CURLOption.CURLOPT_FOLLOWLOCATION, 1L);
21-
assertEquals(code, CURLCode.CURLE_OK);
34+
code = libcurl.easySetOpt(curl, CURLoption.CURLOPT_URL, "https://example.com");
35+
assertEquals(code, CURLcode.CURLE_OK);
36+
code = libcurl.easySetOpt(curl, CURLoption.CURLOPT_FOLLOWLOCATION, 1L);
37+
assertEquals(code, CURLcode.CURLE_OK);
2238

2339
code = libcurl.easyPerform(curl);
24-
assertEquals(code, CURLCode.CURLE_OK);
40+
assertEquals(code, CURLcode.CURLE_OK);
2541
}
2642
}
2743
}

annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.github.digitalsmile.gpio.shared;
22

33

4-
import io.github.digitalsmile.gpio.shared.structs.Stat;
4+
import io.github.digitalsmile.gpio.shared.system.Stat;
55
import org.junit.jupiter.api.Test;
66

77
import java.nio.file.Path;

annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTestTwo.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import io.github.digitalsmile.annotation.function.Returns;
88
import io.github.digitalsmile.annotation.structure.Struct;
99
import io.github.digitalsmile.annotation.structure.Structs;
10-
import io.github.digitalsmile.gpio.shared.structs.Stat;
10+
import io.github.digitalsmile.gpio.shared.system.Stat;
1111

1212
@NativeMemory(headers = "/usr/include/x86_64-linux-gnu/sys/stat.h")
1313
@NativeMemoryOptions(systemHeader = true)

annotation-processor/src/main/java/io/github/digitalsmile/NativeProcessor.java

+27-5
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,25 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
106106
}
107107

108108
if (automaticFunctionElements != null) {
109-
validator.validateAutomaticFunctions(parsed, automaticFunctionElements);
109+
var functions = flatten(parsed).stream().filter(n -> n.getNodeType().isFunction()).toList();
110+
validator.validateAutomaticFunctions(functions, automaticFunctionElements);
111+
112+
List<FunctionNode> autoFunctions = new ArrayList<>();
113+
for (NativeMemoryNode node : functions) {
114+
List<ParameterNode> parameters = new ArrayList<>();
115+
for (NativeMemoryNode parameterNode : node.nodes()) {
116+
parameters.add(new ParameterNode(parameterNode.getName(), parameterNode, false, false));
117+
}
118+
119+
var type = ((FunctionOriginalType) node.getType()).returns();
120+
//processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, type.typeName() + " " + type.carrierClass());
121+
autoFunctions.add(new FunctionNode(node.getName(), null,
122+
new NativeMemoryNode(type.typeName(), type, 0, Position.NO_POSITION), parameters, null));
123+
}
124+
var autoFunctionComposer = new AutoFunctionComposer(processingEnv.getMessager());
125+
var name = rootElement.getSimpleName().toString();
126+
var output = autoFunctionComposer.compose(packageName, PrettyName.getObjectName(name), autoFunctions);
127+
createGeneratedFile(packageName, PrettyName.getObjectName(name + "AutoFunctions"), output);
110128
}
111129

112130
processFunctions(rootElement, manualFunctions, packageName, parsed, nativeOptions);
@@ -214,7 +232,8 @@ private List<NativeMemoryNode> processHeaderFiles(Element element, String[] head
214232
private void processOpaque(NativeMemoryNode node) {
215233
var opaqueComposer = new OpaqueComposer(processingEnv.getMessager());
216234
var output = opaqueComposer.compose(PrettyName.getObjectName(node.getName()), node);
217-
createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output);
235+
var packageName = PackageName.getPackageName(node.getName());
236+
createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output);
218237
}
219238

220239
private void processStructs(NativeMemoryNode node) {
@@ -223,7 +242,8 @@ private void processStructs(NativeMemoryNode node) {
223242
}
224243
var structComposer = new StructComposer(processingEnv.getMessager());
225244
var output = structComposer.compose(PrettyName.getObjectName(node.getName()), node);
226-
createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output);
245+
var packageName = PackageName.getPackageName(node.getName());
246+
createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output);
227247
}
228248

229249
private void processEnums(NativeMemoryNode node, boolean rootConstants) {
@@ -236,13 +256,15 @@ private void processEnums(NativeMemoryNode node, boolean rootConstants) {
236256
}
237257
var enumComposer = new EnumComposer(processingEnv.getMessager());
238258
var output = enumComposer.compose(PrettyName.getObjectName(name), node);
239-
createGeneratedFile(PackageName.getPackageName(name), PrettyName.getObjectName(name), output);
259+
var packageName = PackageName.getPackageName(node.getName());
260+
createGeneratedFile(packageName, PrettyName.getObjectName(name), output);
240261
}
241262

242263
private void processUnions(NativeMemoryNode node) {
243264
var structComposer = new StructComposer(processingEnv.getMessager(), true);
244265
var output = structComposer.compose(PrettyName.getObjectName(node.getName()), node);
245-
createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output);
266+
var packageName = PackageName.getPackageName(node.getName());
267+
createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output);
246268
}
247269

248270
private void processFunctions(Element rootElement, List<Element> functionElements, String packageName, List<NativeMemoryNode> parsed, NativeMemoryOptions nativeOptions) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package io.github.digitalsmile.composers;
2+
3+
import com.squareup.javapoet.*;
4+
import io.github.digitalsmile.PackageName;
5+
import io.github.digitalsmile.PrettyName;
6+
import io.github.digitalsmile.annotation.function.NativeCall;
7+
import io.github.digitalsmile.functions.FunctionNode;
8+
import io.github.digitalsmile.functions.ParameterNode;
9+
import io.github.digitalsmile.headers.mapping.*;
10+
11+
import javax.annotation.processing.Messager;
12+
import javax.lang.model.element.Modifier;
13+
import javax.tools.Diagnostic;
14+
import java.lang.foreign.MemorySegment;
15+
import java.util.List;
16+
import java.util.Map;
17+
18+
public class AutoFunctionComposer {
19+
private final Messager messager;
20+
21+
public AutoFunctionComposer(Messager messager) {
22+
this.messager = messager;
23+
}
24+
25+
public String compose(String packageName, String originalName, List<FunctionNode> nodes) {
26+
var classBuilder = TypeSpec.interfaceBuilder(originalName + "AutoFunctions")
27+
//.addModifiers(Modifier.PUBLIC)
28+
.addSuperinterface(ClassName.get(packageName, originalName));
29+
30+
for (FunctionNode node : nodes) {
31+
var method = MethodSpec.methodBuilder(PrettyName.getVariableName(node.functionName()));
32+
33+
var returnType = node.returnNode().getType();
34+
switch (returnType) {
35+
case ArrayOriginalType arrayOriginalType -> {
36+
method.returns(createType(arrayOriginalType));
37+
// if (arrayOriginalType.carrierClass().equals(String.class)) {
38+
// method.returns(String.class);
39+
// } else if (arrayOriginalType.carrierClass().equals(Object.class)) {
40+
// method.returns(Object.class.arrayType());
41+
// } else {
42+
// var typePackageName = PackageName.getPackageName(arrayOriginalType.typeName());
43+
// method.returns(ClassName.get(typePackageName, PrettyName.getObjectName(arrayOriginalType.typeName())));
44+
// }
45+
}
46+
case ObjectOriginalType objectOriginalType -> {
47+
method.returns(createType(objectOriginalType));
48+
// messager.printMessage(Diagnostic.Kind.ERROR, objectOriginalType.typeName() + " " + objectOriginalType.carrierClass());
49+
// if (objectOriginalType.carrierClass().equals(void.class)) {
50+
// method.returns(void.class);
51+
// } else {
52+
// var typePackageName = PackageName.getPackageName(objectOriginalType.typeName());
53+
// method.returns(ClassName.get(typePackageName, PrettyName.getObjectName(objectOriginalType.typeName())));
54+
// }
55+
}
56+
case PrimitiveOriginalType _ -> {
57+
method.returns(returnType.carrierClass());
58+
}
59+
default -> {
60+
}
61+
}
62+
63+
64+
//messager.printMessage(Diagnostic.Kind.ERROR, "F: " + node.functionName());
65+
for (ParameterNode parameterNode : node.functionParameters()) {
66+
//messager.printMessage(Diagnostic.Kind.ERROR, node.functionName() + " " + parameterNode.nativeMemoryNode().getName());
67+
var name = parameterNode.nativeMemoryNode().getName();
68+
if (name.isEmpty()) {
69+
name = "arg" + node.functionParameters().indexOf(parameterNode);
70+
}
71+
var parameterType = parameterNode.nativeMemoryNode().getType();
72+
var parameterName = PrettyName.getVariableName(name);
73+
switch (parameterType) {
74+
case ArrayOriginalType arrayOriginalType -> {
75+
method.addParameter(createType(arrayOriginalType), name);
76+
// if (arrayOriginalType.isObjectType()) {
77+
// if (arrayOriginalType.carrierClass().equals(String.class)) {
78+
// method.addParameter(String.class, name);
79+
// } else if (arrayOriginalType.carrierClass().equals(Object.class)) {
80+
// method.addParameter(Object.class.arrayType(), name);
81+
// } else {
82+
// var typePackageName = PackageName.getPackageName(arrayOriginalType.typeName());
83+
// method.addParameter(ClassName.get(typePackageName, PrettyName.getObjectName(arrayOriginalType.typeName())), name);
84+
// }
85+
// } else {
86+
// method.addParameter(arrayOriginalType.carrierClass().arrayType(), name);
87+
// }
88+
}
89+
case ObjectOriginalType objectOriginalType -> {
90+
method.addParameter(createType(objectOriginalType), name);
91+
// if (objectOriginalType.carrierClass().equals(void.class)) {
92+
// method.addParameter(MemorySegment.class, name);
93+
// } else {
94+
// var typePackageName = PackageName.getPackageName(objectOriginalType.typeName());
95+
// method.addParameter(ClassName.get(typePackageName, PrettyName.getObjectName(objectOriginalType.typeName())), parameterName);
96+
// }
97+
}
98+
case PrimitiveOriginalType _ -> {
99+
method.addParameter(parameterType.carrierClass(), parameterName);
100+
}
101+
default -> {
102+
}
103+
}
104+
105+
}
106+
107+
classBuilder.addMethod(method
108+
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
109+
}
110+
111+
112+
var builder = JavaFile.builder(packageName, classBuilder.build());
113+
var outputFile = builder.indent("\t").skipJavaLangImports(true).build();
114+
return outputFile.toString();
115+
}
116+
117+
118+
private TypeName createType(OriginalType type, boolean isArray) {
119+
var typeName = type.typeName();
120+
var clazz = type.carrierClass();
121+
if (type.carrierClass().equals(Object.class)) {
122+
var resolvedPackageName = PackageName.getPackageName(typeName);
123+
if (typeName.equals(String.class.getSimpleName())) {
124+
resolvedPackageName = "";
125+
}
126+
return ClassName.get(resolvedPackageName, PrettyName.getObjectName(typeName) + (isArray ? "[]" : ""));
127+
} else {
128+
return TypeName.get(isArray ? clazz.arrayType() : clazz);
129+
}
130+
}
131+
132+
private TypeName createType(OriginalType type) {
133+
return createType(type, false);
134+
}
135+
}

0 commit comments

Comments
 (0)