= libpkl
include::ROOT:partial$component-attributes.adoc[]

libpkl is a C library for driving Pkl evaluation.

It is designed to be a low-level API that interacts with Pkl via the xref:bindings-specification:message-passing-api.adoc[message passing API].
It is meant to be paired with higher level logic written in a host language within the context of a Pkl language binding library.
The higher level logic deals with implementing the evaluator API, and serializing/deserializing messages according to the message passing API.

== Linking to libpkl

It is possible to link to libpkl either as a static library or a dynamic library.

Statically linking to libpkl means that it is possible to copy libpkl's library code directly into your own library or executable at compile time, meaning that it is self-contained.
However, this impacts the binary size of your application, as libpkl's library files are around 100MB.

On the other hand, dynamically linking to libpkl has negligible impact on binary size, but requires that end users have libpkl installed on their OS.

== Distribution

We publish archives that contain header files, as well as both shared and static libraries.

The distributions are published as releases on GitHub, and can be downloaded for the appropriate OS/architecture.

The archives contain both statically linked and dynamically linked binaries for each OS.

The archive has the following structure:

[source]
----
.
└── libpkl-<version>-<os>-<arch>
    ├── include
    │   └── pkl.h
    ├── lib
    │   ├── libpkl.<shared library extension>
    │   ├── libpkl.<static library extension>
    │   └── pkgconfig
    │       ├── libpkl-static.pc
    │       └── libpkl.pc
    ├── LICENSE.txt
    ├── README.md
    └── THIRD-PARTY-NOTICES.txt
----

The file extensions are as follows:
|===
|OS |Static Library Extension |Shared library extension

|macOS
|`.a`
|`.dylib`

|Linux
|`.a`
|`.so`

|Windows
|`.lib`
|`.dll`
|===

=== Linking to the static vs. shared library

The simplest way to configure your compiler to link to either the static or the shared library is to use https://en.wikipedia.org/wiki/Pkg-config[pkg-config].

The libpkl library ships with two pkg-config files: `libpkl.pc`, and `libpkl-static.pc`.

The normal `libpkl.pc` links to the shared library.

To unambiguously link to the static library, use `libpkl-static.pc`.

For example, when using `cc`:

[source,shell]
----
# Link against the shared library
cc -o myprogram myprogram.c $(pkg-config --libs --cflags libpkl)

# Link against the static library
cc -o myprogram myprogram.c $(pkg-config --static --libs --cflags libpkl-static)
----


If libpkl is installed in a non-system directory, set `PKG_CONFIG_PATH` to the subpath `lib/pkgconfig` within the directory that contains libpkl. For example, given libpkl directory `/path/to/libpkl`, the environment variable should have `/path/to/libpkl/lib/pkgconfig`.

NOTE: Windows can use pkg-config through the https://www.msys2.org/docs/pkgconfig/[MSYS2 toolchain]. Using pkg-config on Windows implies compiling with gcc-style compiler like https://code.visualstudio.com/docs/cpp/config-mingw[MinGW], instead of MSVC.

[NOTE]
====
It's also possible to link to the static library with the normal `libpkl.pc`.

For example:

[source,shell]
----
cc -Wl,-Bstatic $(pkg-config --libs --cflags libpkl)
----
====

== Building libpkl from source

To build libpkl from source, the apple/pkl repository first must be cloned down to a host OS.

Build machine requirements:

* Java 21 or higher
* zlib
* C compiler
** `cc` (gcc, clang) toolchain on Unix
** MSVC toolchain on Windows

Example:

[source,shell]
----
git clone git@github.com:apple/pkl.git
cd pkl/
./gradlew libpkl:buildNative
----

This results in two directories of interest:

* `libpkl/build/distributions/`: directory containing archives (`.zip` on Windows, `.tar.gz` on macOS/Linux) of C libraries.
* `libpkl/build/native-libs/<os>-<arch>`: directory containing the built library files (the inner structure of the archive).

Cross-compilation is not supported.

== ABI compatibility

libpkl is ABI compatible across Pkl versions.
The underlying Pkl version can be accessed using the `pkl_version()` method.
