Dynamic libraries¶
You can load functions from dynamic libraries by specifying each function's signature, with the following syntax at the top-level:
dylib "dynamic_library_path" {
function_return_type function_name(function_arg_type_1, function_arg_type_2, ..., function_arg_type_n);
}
For example:
dylib "my_test.dylib" {
int add(int, int);
float add(float, float);
string add(string, string);
int sum(int[], int);
}
fn fib(n) {
if n <= 1 {
return n;
}
return fib(my_test::add(n, -1)) + fib(my_test::add(n,-2));
}
fn main() {
print(my_test::add(6, 1));
print(fib(25));
}
Logical names vs. paths¶
The string after dylib can be either a logical library name or a path,
and Candela resolves them differently so a single Candela file works across
platforms:
- A bare logical name (no path separator and no extension, e.g.
m,sqlite3,z) is mapped to your OS's library filename convention and located by the system loader's normal search paths:libz.soon Linux,libz.dylibon macOS,z.dllon Windows. Prefer this for system libraries; the same source resolves the right file on every platform.
// Resolves to libz.so / libz.dylib / z.dll depending on the OS.
dylib "z" {
string zlibVersion();
}
fn main() { print(z::zlibVersion()); }
- A path (anything with a path separator, or an explicit extension) is resolved relative to the importing Candela file. If the extension is omitted, Candela chooses the correct one for your OS and also tries an architecture-specific build if one exists next to it, then falls back to the plain per-OS filename. This is the form for libraries you ship alongside your program.
// On macOS, tries "./my_test-aarch64.dylib" (or "-x86_64", per your CPU),
// then falls back to "./my_test.dylib". Same idea with ".so" on Linux and
// ".dll" on Windows.
dylib "./my_test" {
int add(int, int);
int sum(int[], int);
}
fn main() { print(my_test::add(6, 1)); }
An absolute path or an explicit filename (with extension) is honored as written.
In .cdlb bytecode artifacts¶
When you candela build a program into a .cdlb artifact, dynamic-library
imports are captured by reference, not by value: the artifact records the
logical library name, each imported symbol, and its signature, never the shared
object's bytes. When candela-vm loads the artifact it re-opens the library
through the OS loader and re-binds the symbols by name, applying the same per-OS
name mapping described above. A .cdlb built on one platform therefore resolves
the right library file on another, as long as that library is installed on the
machine that runs it.