From 1dd67a91bd8e90e2744f5b1f07130b9507f6f656 Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Tue, 18 Mar 2025 14:55:50 +0000 Subject: [PATCH 01/10] Add SPICE: "C library for Pkl" --- spices/SPICE-0015-c-library-for-pkl.adoc | 77 ++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 spices/SPICE-0015-c-library-for-pkl.adoc diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc new file mode 100644 index 0000000..97dea0b --- /dev/null +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -0,0 +1,77 @@ += C library for Pkl + +* Proposal: link:./SPICE-0015-c-library-for-pkl.adoc[SPICE-0015] +* Author: https://github.com/kushalp[Kushal Pisavadia] +* Status: TBD +* Implemented in: Pkl +* Category: Language + +== Introduction + +This SPICE proposes a native C library for Pkl that can be used to implement native bindings from other languages such as Swift, Go, or Python. + +This would allow bindings such as `pkl-swift` and `pkl-go` to bind to Pkl without needing to spawn a child process. + +== Motivation + +By offering C bindings, Pkl can increase its utility and applicability across more domains, attracting a broader developer base. +These bindings would also allow language integrations to have a much smaller footprint than existing approaches requiring an external process. + +== Proposed Solution + +A new shared library will be produced that allows users to initialise a Pkl evaluator, send messages to it, and receive messages from it. + +== Detailed design + +We would utilise the https://www.graalvm.org/latest/reference-manual/native-image/guides/build-native-shared-library/[native shared library functionality] of `native-image` to build upon the existing code that we already have. + +However, as we’re exposing a C API to our users, we shouldn’t expose GraalVM behaviours for future-compatibility. + +Pkl already has a https://pkl-lang.org/main/current/bindings-specification/message-passing-api.html[Message Passing API] with MsgPack that we can utilise here. + +.native_pkl_interface.c +[source,c] +---- +// The Pkl Message Response Handler that a user should implement. +// +// The resulting messages from `pkl_send` will be sent to this +// handler using a callback style. +typedef void (*PklMessageResponseHandler)(int length, char* message); + +// Initialises and allocates a Pkl executor. +// +// Returns -1 if there was insufficient memory. +int pkl_init(pkl_options_t *options); + +// Send a message to Pkl, providing the length and a pointer to the first byte. +// +// Returns: +// - -1 if the Pkl executor hasn't been initialised. +// - 0 on success +int pkl_send_message(int length, char* message); + +// Registers a Message Handler that will receive the result of Pkl executions. +void pkl_register_response_handler(PklMessageResponseHandler handler); + +// Cleans up any resources that were created as part of the `pkl_init` process. +int pkl_close(); +---- + +== Compatibility + +The biggest concerns around the supported (dynamic library) approach by `native-image` would be the number of dynamic libraries we'd require present on the target instance. +We should strive to reduce the number of dynamic libraries required where possible. + +One option could be to create a static shared library, which is suggested as part of this issue and would need to be investigated: https://github.com/oracle/graal/issues/3053 + +== Future directions + +https://openjdk.org/jeps/472[JEP 472: Prepare to Restrict the Use of JNI] is coming to JDK24 and may be relevant in the future. + +== Alternatives considered + +TBD + +== Acknowledgements + +N/A From 5035a520c8d581f0ddc073d1d3d32b346c3542f4 Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Tue, 18 Mar 2025 15:55:27 +0000 Subject: [PATCH 02/10] Remove `options` on `pkl_init` --- spices/SPICE-0015-c-library-for-pkl.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index 97dea0b..f11da82 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -41,7 +41,7 @@ typedef void (*PklMessageResponseHandler)(int length, char* message); // Initialises and allocates a Pkl executor. // // Returns -1 if there was insufficient memory. -int pkl_init(pkl_options_t *options); +int pkl_init(); // Send a message to Pkl, providing the length and a pointer to the first byte. // From 0df102b4d378ba00f05e0b1ef8dfe53eca0308ad Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Tue, 18 Mar 2025 21:47:16 +0000 Subject: [PATCH 03/10] `pkl_init`: returns 0 on success, or a non-zero value on failure --- spices/SPICE-0015-c-library-for-pkl.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index f11da82..58d19f3 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -40,7 +40,7 @@ typedef void (*PklMessageResponseHandler)(int length, char* message); // Initialises and allocates a Pkl executor. // -// Returns -1 if there was insufficient memory. +// Returns 0 on success, or a non-zero value on failure. int pkl_init(); // Send a message to Pkl, providing the length and a pointer to the first byte. From 656b266556aa05e112b95be2c773eb2fd065810d Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Tue, 18 Mar 2025 21:52:11 +0000 Subject: [PATCH 04/10] Switch to doxygen-style comments --- spices/SPICE-0015-c-library-for-pkl.adoc | 38 +++++++++++++++--------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index 58d19f3..fda538d 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -32,28 +32,38 @@ Pkl already has a https://pkl-lang.org/main/current/bindings-specification/messa .native_pkl_interface.c [source,c] ---- -// The Pkl Message Response Handler that a user should implement. -// -// The resulting messages from `pkl_send` will be sent to this -// handler using a callback style. +/** +* @brief The Pkl Message Response Handler that a user should implement. +* +* The resulting messages from `pkl_send` will be sent to this +* handler using a callback style. +*/ typedef void (*PklMessageResponseHandler)(int length, char* message); -// Initialises and allocates a Pkl executor. -// -// Returns 0 on success, or a non-zero value on failure. +/** +* @brief Initialises and allocates a Pkl executor. +* +* @return non-zero value on failure. +* @return 0 on success. +*/ int pkl_init(); -// Send a message to Pkl, providing the length and a pointer to the first byte. -// -// Returns: -// - -1 if the Pkl executor hasn't been initialised. -// - 0 on success +/** +* @brief Send a message to Pkl, providing the length and a pointer to the first byte. +* +* @return -1 if the Pkl executor hasn't been initialised. +* @return 0 on success. +*/ int pkl_send_message(int length, char* message); -// Registers a Message Handler that will receive the result of Pkl executions. +/** +* @brief Registers a Message Handler that will receive the result of Pkl executions. +*/ void pkl_register_response_handler(PklMessageResponseHandler handler); -// Cleans up any resources that were created as part of the `pkl_init` process. +/** +* @brief Cleans up any resources that were created as part of the `pkl_init` process. +*/ int pkl_close(); ---- From 785c002766a362c5d9debe04417859e549cf7631 Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Tue, 25 Mar 2025 12:06:04 +0000 Subject: [PATCH 05/10] `pkl_init` registers the callback `handler` --- spices/SPICE-0015-c-library-for-pkl.adoc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index fda538d..f5d3f35 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -46,7 +46,7 @@ typedef void (*PklMessageResponseHandler)(int length, char* message); * @return non-zero value on failure. * @return 0 on success. */ -int pkl_init(); +int pkl_init(PklMessageResponseHandler handler); /** * @brief Send a message to Pkl, providing the length and a pointer to the first byte. @@ -56,11 +56,6 @@ int pkl_init(); */ int pkl_send_message(int length, char* message); -/** -* @brief Registers a Message Handler that will receive the result of Pkl executions. -*/ -void pkl_register_response_handler(PklMessageResponseHandler handler); - /** * @brief Cleans up any resources that were created as part of the `pkl_init` process. */ From 2c819ccffeadf4ffd1f41acee8d2204cf0fa76fd Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Tue, 25 Mar 2025 12:06:39 +0000 Subject: [PATCH 06/10] Be explicit about return codes --- spices/SPICE-0015-c-library-for-pkl.adoc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index f5d3f35..34b56d1 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -43,7 +43,7 @@ typedef void (*PklMessageResponseHandler)(int length, char* message); /** * @brief Initialises and allocates a Pkl executor. * -* @return non-zero value on failure. +* @return -1 on failure. * @return 0 on success. */ int pkl_init(PklMessageResponseHandler handler); @@ -51,13 +51,16 @@ int pkl_init(PklMessageResponseHandler handler); /** * @brief Send a message to Pkl, providing the length and a pointer to the first byte. * -* @return -1 if the Pkl executor hasn't been initialised. +* @return -1 on failure. * @return 0 on success. */ int pkl_send_message(int length, char* message); /** * @brief Cleans up any resources that were created as part of the `pkl_init` process. +* +* @return -1 on failure. +* @return 0 on success. */ int pkl_close(); ---- From beeaa06698c0306de6c3a0613a75bed402bc72e4 Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Tue, 3 Jun 2025 14:15:04 +0100 Subject: [PATCH 07/10] Update doc comments to match what's in-progress on `apple/pkl` --- spices/SPICE-0015-c-library-for-pkl.adoc | 50 +++++++++++++----------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index 34b56d1..8d20172 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -32,36 +32,40 @@ Pkl already has a https://pkl-lang.org/main/current/bindings-specification/messa .native_pkl_interface.c [source,c] ---- -/** -* @brief The Pkl Message Response Handler that a user should implement. * -* The resulting messages from `pkl_send` will be sent to this -* handler using a callback style. -*/ -typedef void (*PklMessageResponseHandler)(int length, char* message); + * The callback that gets called when a message is received from Pkl. + * + * @param length The length the message bytes + * @param message The message itself + * @param userData User-defined data passed in from pkl_init. + */ +typedef void (*PklMessageResponseHandler)(int length, char *message, void *userData); /** -* @brief Initialises and allocates a Pkl executor. -* -* @return -1 on failure. -* @return 0 on success. -*/ -int pkl_init(PklMessageResponseHandler handler); + * Initialises and allocates a Pkl executor. + * + * @param handler The callback that gets called when a message is received from Pkl. + * @param userData User-defined data that gets passed to handler. + * + * @return -1 on failure, 0 on success. + */ +int pkl_init(PklMessageResponseHandler handler, void *userData); /** -* @brief Send a message to Pkl, providing the length and a pointer to the first byte. -* -* @return -1 on failure. -* @return 0 on success. -*/ -int pkl_send_message(int length, char* message); + * Send a message to Pkl, providing the length and a pointer to the first byte. + * + * @param length The length of the message, in bytes. + * @param message The message to send to Pkl. + * + * @return -1 on failure, 0 on success. + */ +int pkl_send_message(int length, char *message); /** -* @brief Cleans up any resources that were created as part of the `pkl_init` process. -* -* @return -1 on failure. -* @return 0 on success. -*/ + * Cleans up any resources that were created as part of the `pkl_init` process. + * + * @return -1 on failure, 0 on success. + */ int pkl_close(); ---- From df1c64e3e149bd53be1343e361914357a3e34183 Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Mon, 14 Jul 2025 17:01:45 +0100 Subject: [PATCH 08/10] Fix broken opening comment --- spices/SPICE-0015-c-library-for-pkl.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index 8d20172..cc3d828 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -32,7 +32,7 @@ Pkl already has a https://pkl-lang.org/main/current/bindings-specification/messa .native_pkl_interface.c [source,c] ---- -* +/** * The callback that gets called when a message is received from Pkl. * * @param length The length the message bytes From d09845e6e42cb38dec926f106dab2e89043bde98 Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Mon, 14 Jul 2025 17:03:57 +0100 Subject: [PATCH 09/10] Be consistent, use `userData` everywhere --- spices/SPICE-0015-c-library-for-pkl.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index cc3d828..68c6e7d 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -39,7 +39,7 @@ Pkl already has a https://pkl-lang.org/main/current/bindings-specification/messa * @param message The message itself * @param userData User-defined data passed in from pkl_init. */ -typedef void (*PklMessageResponseHandler)(int length, char *message, void *userData); +typedef void (*PklMessageResponseHandler)(int length, char *message, const void *userData); /** * Initialises and allocates a Pkl executor. From 78ac110d6d949650746d1e3bad0201c55f6e5b2a Mon Sep 17 00:00:00 2001 From: Kushal Pisavadia Date: Mon, 14 Jul 2025 17:07:36 +0100 Subject: [PATCH 10/10] `pkl_version` provides the Pkl version within the native library --- spices/SPICE-0015-c-library-for-pkl.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spices/SPICE-0015-c-library-for-pkl.adoc b/spices/SPICE-0015-c-library-for-pkl.adoc index 68c6e7d..ebc4273 100644 --- a/spices/SPICE-0015-c-library-for-pkl.adoc +++ b/spices/SPICE-0015-c-library-for-pkl.adoc @@ -67,6 +67,13 @@ int pkl_send_message(int length, char *message); * @return -1 on failure, 0 on success. */ int pkl_close(); + +/** + * Returns the version of Pkl in use. + * + * @return a string with the version information. + */ +char* pkl_version(); ---- == Compatibility