Split libpkl libraries between shared and static libs (#1812)

This adds a `libpkl-static.pc` so pkg-config users can link either
statically or dynamically via `pkg-config --libs libpkl`, or
`pkg-config --libs libpkl-static`.

Additionally, this fixes an issue where the replace tokens wasn't
doing anything, leaving the `@version@` token intact in the archive.

Additionally, this adds an `-install_name` when building the dylib for macOS.

Co-authored-by: Islon Scherer <islonscherer@gmail.com>
This commit is contained in:
Daniel Chao
2026-08-07 15:47:16 +00:00
committed by GitHub
co-authored by Islon Scherer
parent b3698683ab
commit c5896d76d0
4 changed files with 78 additions and 19 deletions
+20 -15
View File
@@ -251,16 +251,11 @@ val buildSharedLibrary =
frameworks.addAll("Foundation", "CoreServices")
linkerFlags.addAll("-current_version", project.version.toString())
linkerFlags.addAll("-compatibility_version", "0.1.0")
// libpkl_internal_s bundles Native Image's own JNI-named implementations of JDK native
// methods (e.g. Java_sun_nio_ch_UnixFileDispatcherImpl_write0), which by default get
// exported with global visibility. Loading libpkl.dylib into a JVM process (e.g. via JNA)
// then lets the host JVM's own native-method resolution bind to these internal
// implementations instead of the JDK's real ones, silently corrupting unrelated file I/O.
// Restrict the dylib's exported symbols to just the public pkl_* API to prevent this.
// prevent JNI symbols from being exported and clobbering the symbol table
val exportedSymbolsFile = file("src/main/c/pkl.exported_symbols")
inputs.file(exportedSymbolsFile)
linkerFlags.addAll("-exported_symbols_list", exportedSymbolsFile.absolutePath)
compilerArgs.addAll("-install_name", "@rpath/libpkl.dylib")
}
if (targetMachine.os.isWindows) {
@@ -276,9 +271,7 @@ val buildSharedLibrary =
if (targetMachine.os.isLinux) {
libraries.add("dl")
// Same symbol-collision hazard as the macOS case above (see comment there), but scoped via
// a GNU ld version script instead of an exported-symbols list.
// prevent JNI symbols from being exported and clobbering the symbol table
val versionScriptFile = file("src/main/c/pkl.map")
inputs.file(versionScriptFile)
linkerFlags.add("--version-script=${versionScriptFile.absolutePath}")
@@ -317,7 +310,7 @@ val distZip =
into(baseName)
}
tasks.assembleNative { dependsOn(distZip, distTar) }
tasks.assembleNative { dependsOn(distZip, distTar, processFiles) }
val processFiles =
tasks.register<Copy>("processFiles") {
@@ -329,9 +322,23 @@ val processFiles =
includeEmptyDirs = true
into(buildInfo.targetMachine.outputDir)
filesMatching("libpkl.pc") {
filter<ReplaceTokens>("tokens" to mapOf("version" to buildInfo.pklVersion))
val tokens = buildMap {
this["version"] = buildInfo.pklVersion
this["static_lib_filename"] = "libpkl.${buildInfo.os.staticLibraryExtension}"
this["extra_static_libs"] =
when {
buildInfo.os.isMacOS -> " -lz -framework Foundation -framework CoreServices"
buildInfo.os.isWindows -> ""
else -> " -lz"
}
this["extra_shared_libs"] =
when {
buildInfo.os.isMacOS -> " -lpkl"
buildInfo.os.isWindows -> " -l:libpkl_dll.lib"
else -> " -lpkl"
}
}
filesMatching("**/libpkl*.pc") { filter<ReplaceTokens>("tokens" to tokens) }
}
val testNativeJava =
@@ -428,8 +435,6 @@ val compileNativeTestDynamic =
libraryFiles.from(buildInfo.targetMachine.libraryDir.map { it.file("libpkl_dll.lib") })
} else {
libraries.add("pkl")
libraries.add("z")
libraries.add("pthread")
// Bake the library's location into the test executable so the dynamic loader can find
// libpkl.so/libpkl.dylib without needing LD_LIBRARY_PATH/DYLD_LIBRARY_PATH set at run time.
linkerFlags.add("-rpath")
@@ -0,0 +1,11 @@
prefix=${pcfiledir}/../..
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: libpkl
Description: C library for calling into Pkl's message passing API.
URL: https://pkl-lang.org/main/current/libpkl/index.html
Version: @version@
Libs: ${libdir}/@static_lib_filename@@extra_static_libs@
Cflags: -I${includedir}
@@ -7,5 +7,5 @@ Name: libpkl
Description: C library for calling into Pkl's message passing API.
URL: https://pkl-lang.org/main/current/libpkl/index.html
Version: @version@
Libs: -L${libdir} -lpkl -lz -lpthread
Libs: -L${libdir}@extra_shared_libs@
Cflags: -I${includedir}