Skip to content

Commit e4ca22c

Browse files
committed
Address PR comments
1 parent 0fd8ab3 commit e4ca22c

File tree

10 files changed

+152
-120
lines changed

10 files changed

+152
-120
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
antlr = "4.+"
33
assertj = "3.+"
44
checksumPlugin = "1.4.0"
5+
clangfmt = "10.0.1"
56
clikt = "5.+"
67
commonMark = "0.+"
78
downloadTaskPlugin = "5.6.0"

libpkl/libpkl.gradle.kts

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
11
/*
2-
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* https://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
2+
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
@file:Suppress("unused")
17+
1618
plugins {
1719
pklAllProjects
1820
pklGraalVm
1921
pklJavaLibrary
20-
pklJavaExecutable
2122
pklNativeLifecycle
2223
}
2324

24-
// assumes that `pklJavaExecutable` is also applied
25-
val executableSpec = project.extensions.getByType<ExecutableSpec>()
26-
2725
val stagedMacAmd64NativeLibrary: Configuration by configurations.creating
2826
val stagedMacAarch64NativeLibrary: Configuration by configurations.creating
2927
val stagedLinuxAmd64NativeLibrary: Configuration by configurations.creating
@@ -57,18 +55,6 @@ dependencies {
5755
stagedWindowsAmd64NativeLibrary(sharedLibrary("windows-amd64.exe"))
5856
}
5957

60-
executable {
61-
name = "libpkl_internal"
62-
63-
// TODO(kushal): Why is all of this necessary now? Can it be stripped back?
64-
javaName = "libpkl"
65-
documentationName = "Pkl Native Library"
66-
publicationName = "libpkl"
67-
javaPublicationName = "libpkl"
68-
mainClass = "org.pkl.libpkl.LibPkl"
69-
website = "TODO"
70-
}
71-
7258
private fun extension(osAndArch: String) =
7359
when (osAndArch.split("-").dropWhile { it == "alpine" }.first()) {
7460
"linux" -> "so"
@@ -85,7 +71,7 @@ private fun extension(osAndArch: String) =
8571
private fun nativeLibraryOutputFiles(osAndArch: String) =
8672
project.layout.buildDirectory.dir("libs/$osAndArch").map { outputDir ->
8773
// TODO(kushal): dashes/underscores for library files? C convention assumes underscores.
88-
val libraryName = executableSpec.name
74+
val libraryName = "libpkl_internal"
8975
val libraryOutputFiles =
9076
listOf(
9177
"lib${libraryName}.${extension(osAndArch)}",
@@ -125,8 +111,8 @@ private fun NativeImageBuild.setClasspath() {
125111
val macNativeLibraryAmd64 by
126112
tasks.registering(NativeImageBuild::class) {
127113
outputDir = project.layout.buildDirectory.dir("libs/macos-amd64")
128-
imageName = executableSpec.name
129-
mainClass = executableSpec.mainClass
114+
imageName = "libpkl_internal"
115+
mainClass = "org.pkl.libpkl.LibPkl"
130116
amd64()
131117
setClasspath()
132118
extraNativeImageArgs = listOf("--shared")
@@ -137,8 +123,8 @@ val macNativeLibraryAmd64 by
137123
val macNativeLibraryAarch64 by
138124
tasks.registering(NativeImageBuild::class) {
139125
outputDir = project.layout.buildDirectory.dir("libs/macos-aarch64")
140-
imageName = executableSpec.name
141-
mainClass = executableSpec.mainClass
126+
imageName = "libpkl_internal"
127+
mainClass = "org.pkl.libpkl.LibPkl"
142128
aarch64()
143129
setClasspath()
144130
extraNativeImageArgs = listOf("--shared")
@@ -149,8 +135,8 @@ val macNativeLibraryAarch64 by
149135
val linuxNativeLibraryAmd64 by
150136
tasks.registering(NativeImageBuild::class) {
151137
outputDir = project.layout.buildDirectory.dir("libs/linux-amd64")
152-
imageName = executableSpec.name
153-
mainClass = executableSpec.mainClass
138+
imageName = "libpkl_internal"
139+
mainClass = "org.pkl.libpkl.LibPkl"
154140
amd64()
155141
setClasspath()
156142
extraNativeImageArgs = listOf("--shared")
@@ -161,8 +147,8 @@ val linuxNativeLibraryAmd64 by
161147
val linuxNativeLibraryAarch64 by
162148
tasks.registering(NativeImageBuild::class) {
163149
outputDir = project.layout.buildDirectory.dir("libs/linux-aarch64")
164-
imageName = executableSpec.name
165-
mainClass = executableSpec.mainClass
150+
imageName = "libpkl_internal"
151+
mainClass = "org.pkl.libpkl.LibPkl"
166152
aarch64()
167153
setClasspath()
168154

@@ -180,8 +166,8 @@ val linuxNativeLibraryAarch64 by
180166
val alpineNativeLibraryAmd64 by
181167
tasks.registering(NativeImageBuild::class) {
182168
outputDir = project.layout.buildDirectory.dir("libs/alpine-linux-amd64")
183-
imageName = executableSpec.name
184-
mainClass = executableSpec.mainClass
169+
imageName = "libpkl_internal"
170+
mainClass = "org.pkl.libpkl.LibPkl"
185171
amd64()
186172
setClasspath()
187173

@@ -198,8 +184,8 @@ val alpineNativeLibraryAmd64 by
198184
val windowsNativeLibraryAmd64 by
199185
tasks.registering(NativeImageBuild::class) {
200186
outputDir = project.layout.buildDirectory.dir("libs/windows-amd64")
201-
imageName = executableSpec.name
202-
mainClass = executableSpec.mainClass
187+
imageName = "libpkl_internal"
188+
mainClass = "org.pkl.libpkl.LibPkl"
203189
amd64()
204190
setClasspath()
205191
extraNativeImageArgs = listOf("--shared", "-Dfile.encoding=UTF-8")
@@ -317,3 +303,14 @@ tasks.withType<Test> {
317303

318304
useJUnitPlatform()
319305
}
306+
307+
private val licenseHeaderFile by lazy {
308+
rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt")
309+
}
310+
311+
spotless {
312+
cpp {
313+
licenseHeaderFile(licenseHeaderFile, "// ")
314+
target("src/main/c/*.c", "src/main/c/*.h")
315+
}
316+
}

libpkl/src/main/c/pkl.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
/*
2+
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
// pkl.c
17+
118
#include <stdlib.h>
219
#include <stdio.h>
320
#include <pthread.h>
@@ -14,7 +31,7 @@
1431
pthread_mutex_t graal_mutex;
1532
graal_isolatethread_t *isolatethread = NULL;
1633

17-
int pkl_init(PklMessageResponseHandler handler) {
34+
int pkl_init(PklMessageResponseHandler handler, void *payload) {
1835
if (isolatethread != NULL) {
1936
perror("pkl_init: isolatethread is already initialised");
2037
return -1;
@@ -30,20 +47,19 @@ int pkl_init(PklMessageResponseHandler handler) {
3047
}
3148

3249
isolatethread = pkl_internal_init();
33-
pkl_internal_register_response_handler(isolatethread, handler);
50+
pkl_internal_register_response_handler(isolatethread, handler, payload);
3451
pkl_internal_server_start(isolatethread);
3552
pthread_mutex_unlock(&graal_mutex);
3653

3754
return 0;
3855
};
3956

40-
41-
int pkl_send_message(int length, char *message, void *handlerContext) {
57+
int pkl_send_message(int length, char *message) {
4258
if (pthread_mutex_lock(&graal_mutex) != 0) {
4359
return -1;
4460
}
4561

46-
pkl_internal_send_message(isolatethread, length, message, handlerContext);
62+
pkl_internal_send_message(isolatethread, length, message);
4763
pthread_mutex_unlock(&graal_mutex);
4864

4965
return 0;

libpkl/src/main/c/pkl.h

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,52 @@
1+
/*
2+
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
// pkl.h
17+
118
/**
2-
* @brief The Pkl Message Response Handler that a user should implement.
3-
*
4-
* The resulting messages from `pkl_send` will be sent to this handler using a callback style.
5-
*/
6-
typedef void (*PklMessageResponseHandler)(int length, char *message, void *handlerContext);
19+
* The callback that gets called when a message is received from Pkl.
20+
*
21+
* @param length The length the message bytes
22+
* @param message The message itself
23+
* @param payload User-defined data passed to pkl_init.
24+
*/
25+
typedef void (*PklMessageResponseHandler)(int length, char *message, void *payload);
726

827
/**
9-
* @brief Initialises and allocates a Pkl executor.
10-
*
11-
* @return -1 on failure.
12-
* @return 0 on success.
13-
*/
14-
int pkl_init(PklMessageResponseHandler handler);
28+
* Initialises and allocates a Pkl executor.
29+
*
30+
* @param handler The callback that gets called when a message is received from Pkl.
31+
* @param payload User-defined data that gets passed to handler.
32+
*
33+
* @return -1 on failure, 0 on success.
34+
*/
35+
int pkl_init(PklMessageResponseHandler handler, void *payload);
1536

1637
/**
17-
* @brief Send a message to Pkl, providing the length and a pointer to the first byte.
18-
*
19-
* @return -1 on failure.
20-
* @return 0 on success.
21-
*/
22-
int pkl_send_message(int length, char *message, void *handlerContext);
38+
* Send a message to Pkl, providing the length and a pointer to the first byte.
39+
*
40+
* @param length The length of the message, in bytes.
41+
* @param message The message to send to Pkl.
42+
*
43+
* @return -1 on failure, 0 on success.
44+
*/
45+
int pkl_send_message(int length, char *message);
2346

2447
/**
25-
* @brief Cleans up any resources that were created as part of the `pkl_init` process.
26-
*
27-
* @return -1 on failure.
28-
* @return 0 on success.
29-
*/
48+
* Cleans up any resources that were created as part of the `pkl_init` process.
49+
*
50+
* @return -1 on failure, 0 on success.
51+
*/
3052
int pkl_close();

libpkl/src/main/java/org/pkl/libpkl/LibPkl.java

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package org.pkl.libpkl;
1717

18-
import java.io.IOException;
1918
import org.graalvm.nativeimage.IsolateThread;
2019
import org.graalvm.nativeimage.PinnedObject;
2120
import org.graalvm.nativeimage.c.function.CEntryPoint;
@@ -24,42 +23,40 @@
2423
import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer;
2524
import org.graalvm.nativeimage.c.type.CCharPointer;
2625
import org.graalvm.nativeimage.c.type.VoidPointer;
27-
import org.graalvm.word.WordFactory;
2826
import org.pkl.core.messaging.MessageTransports.Logger;
29-
import org.pkl.core.messaging.ProtocolException;
3027
import org.pkl.server.Server;
3128

3229
@SuppressWarnings("unused")
3330
public class LibPkl {
3431
public interface MessageCallbackFunctionPointer extends CFunctionPointer {
3532
@InvokeCFunctionPointer(transition = Transition.TO_NATIVE)
36-
void invoke(int length, CCharPointer msg, VoidPointer handlerContext);
33+
void invoke(int length, CCharPointer msg, VoidPointer userData);
3734
}
3835

3936
private static final Logger logger = new LibPklLogger();
4037
private static final NativeTransport transport =
4138
new NativeTransport(logger, LibPkl::handleSendMessageToNative);
4239
private static Server server;
4340
private static MessageCallbackFunctionPointer cb;
41+
private static VoidPointer userData;
4442

4543
private LibPkl() {}
4644

4745
@CEntryPoint(name = "pkl_internal_init", builtin = CEntryPoint.Builtin.CREATE_ISOLATE)
4846
static native IsolateThread pklInternalInit();
4947

5048
@CEntryPoint(name = "pkl_internal_send_message")
51-
public static void pklInternalSendMessage(
52-
IsolateThread thread, int length, CCharPointer ptr, VoidPointer handlerContext)
53-
throws ProtocolException, IOException {
49+
public static void pklInternalSendMessage(IsolateThread thread, int length, CCharPointer ptr) {
5450
logger.log("Got message from native");
55-
transport.sendMessage(length, ptr, handlerContext);
51+
transport.sendMessage(length, ptr);
5652
}
5753

5854
@CEntryPoint(name = "pkl_internal_register_response_handler")
5955
public static void pklInternalRegisterResponseHandler(
60-
IsolateThread thread, LibPkl.MessageCallbackFunctionPointer cb) {
56+
IsolateThread thread, LibPkl.MessageCallbackFunctionPointer cb, VoidPointer userData) {
6157
logger.log("Got handler to call from Pkl");
6258
LibPkl.cb = cb;
59+
LibPkl.userData = userData;
6360
}
6461

6562
@CEntryPoint(name = "pkl_internal_close", builtin = CEntryPoint.Builtin.TEAR_DOWN_ISOLATE)
@@ -76,13 +73,10 @@ public static void pklInternalServerStop(IsolateThread thread) {
7673
server.close();
7774
}
7875

79-
public static void handleSendMessageToNative(byte[] bytes, Object handlerContext) {
76+
public static void handleSendMessageToNative(byte[] bytes) {
8077
try (var pin = PinnedObject.create(bytes)) {
8178
// TODO: Provide a meaningful error the user if they haven't run `pkl_init`.
82-
if (cb != null) {
83-
// TODO: Propagate `handlerContext` through instead of `nullPointer`.
84-
cb.invoke(bytes.length, pin.addressOfArrayElement(0), WordFactory.nullPointer());
85-
}
79+
cb.invoke(bytes.length, pin.addressOfArrayElement(0), LibPkl.userData);
8680
}
8781
}
8882

libpkl/src/main/java/org/pkl/libpkl/NativeInputStream.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,24 @@ public class NativeInputStream extends InputStream {
2323
private final int length;
2424
private final CCharPointer ptr;
2525

26+
public NativeInputStream(int length, CCharPointer ptr) {
27+
super();
28+
this.length = length;
29+
this.ptr = ptr;
30+
}
31+
2632
@Override
2733
public int read() {
34+
if (available() <= 0) {
35+
return -1;
36+
}
2837
var result = ptr.read(offset);
2938
offset++;
30-
return result;
39+
return result & 0xFF;
3140
}
3241

3342
@Override
3443
public int available() {
3544
return length - offset;
3645
}
37-
38-
public NativeInputStream(int length, CCharPointer ptr) {
39-
super();
40-
this.length = length;
41-
this.ptr = ptr;
42-
}
4346
}

0 commit comments

Comments
 (0)