Skip to content

18 · Modules

C and C++ with extern

Native functions, C++ objects and vcpkg packages with the native provider.

On this page

Import the language from the native plugin. Zolo signatures describe the boundary; the function body uses C17 or C++17. These programs run with the CLI and an installed plugin.

Call C functions with exact integers and import a function from a companion file.

43-extern-c.zolo
use plugin native::{c}

extern c fn exact(value: int) -> int {
    return value;
}

extern c fn length(value: str) -> int {
    #include <string.h>
    return (int64_t)strlen(value);
}

extern c fn bytes_length(value: bytes) -> int {
    return (int64_t)value.len;
}

extern c fn data() -> bytes {
    static const unsigned char raw[] = {0, 127, 255};
    zolo_bytes value = {raw, sizeof(raw)};
    return value;
}

extern c fn call(callback: fn(int) -> int) -> int {
    zolo_value input = zolo_i64(40), output = zolo_nil();
    int status = zolo_callback_call(callback, &input, 1, &output);
    int64_t value = output.integer;
    zolo_callback_release(callback, &output);
    return status == 0 ? value : -1;
}

print(exact(9007199254740993)) // expected: 9007199254740993
print(length("hello C")) // expected: 7
print(bytes_length(data())) // expected: 3
print(call(|value| value + 2)) // expected: 42

Requires the Zolo CLI/host — open in the playground or run locally.

Construct a public C++ class with .new, call methods and await a native operation.

44-extern-cpp.zolo
use plugin native::{cpp}

extern cpp from "./native_fixtures/Person.cpp" use {Person}

extern cpp fn greet(name: str) -> str {
    return "Hello " + name;
}

extern cpp async fn later(value: int) -> int {
    #include <chrono>
    #include <thread>
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    return value + 1;
}

extern cpp fn call(callback: fn(int) -> int) -> int {
    return callback(40);
}

let person = Person.new(name: "Ana", age: 30)
print(person.greet()) // expected: Hello Ana
print(person.birthday()) // expected: 31
person.age = 32
print(person.age) // expected: 32
print(Person.twice(21)) // expected: 42
print(greet("C++")) // expected: Hello C++
print(await later(41)) // expected: 42
print(call(|value| value + 2)) // expected: 42

Requires the Zolo CLI/host — open in the playground or run locally.

int maps to signed 64-bit integers, float to double, and str to a length-aware UTF-8 adapter in C or std::string in C++. Narrow integer conversions are checked. C strings reject embedded NUL. Collections and copied records use the explicit zolo_value adapter described in the plugin guide. Pointers, ownership-dependent APIs, varargs and open templates need a concrete wrapper with a supported signature.

Paths follow the importing Zolo file: extern cpp from "./Person.cpp" use {Person}. Public C++ constructors, methods, fields and static methods are available through ordinary Zolo calls. Objects retain their native state and identity within the compiled module.

Callbacks and async

C++ callback parameters such as fn(int) -> int become a callable adapter: the authored body can call callback(41). C uses zolo_callback_call and zolo_callback_release from the bridge header. Callbacks borrow their lifetime from the current invocation and support nested Zolo calls. Do not retain them or invoke them from an unrelated native thread.

extern cpp async fn schedules native work on an invocation worker. await returns its result while callbacks run on the owning Zolo runtime. Cancellation closes callback and result delivery; native work may continue until its own cancellation mechanism stops it. Arbitrary C++ futures need an explicit adapter.

Libraries and deployment

Declare vcpkg ports once for the provider:

Prepare fmt once and preserve an exact integer through native formatting.

43-extern-cpp-vcpkg.zolo
use plugin native::{cpp}

// zolo install prepares the pinned vcpkg library once; auto policy may prepare
// it at the first run. Prepared executables reuse sealed library bytes.
extern cpp deps {
    fmt = { version = "11.0.2", default_features = true }
}

extern cpp fn formatted(value: int) -> str {
    #include <fmt/format.h>
    return fmt::format("exact {}", value);
}

print(formatted(9007199254740993)) // expected: exact 9007199254740993

Requires the Zolo CLI/host — open in the playground or run locally.

use plugin native::{cpp}

extern cpp deps {
    "fmt" = "11.0.2"
}

extern cpp fn message(value: int) -> str {
    #include <fmt/format.h>
    return fmt::format("answer: {}", value);
}

print(message(42))

Prepare explicitly with zolo install main.zolo, then run with zolo run main.zolo --offline --frozen. Projects use [foreign.native.dependencies] in zolo.toml. The selected vcpkg baseline, triplet, features and CRT become part of the locked environment. On Windows, the default is x64-windows-static; choose a compatible triplet deliberately.

Preparation needs Clang and the platform's native headers/linker. ZOLO_CLANG selects Clang. Editor queries additionally use clangd and never load authored code or execute its initializers. Compiled artifacts retain their native library, package assets and source snapshots. VM, native and LLVM use the same artifact, including dynamic, embedded and static plugin packaging, without the original source or compiler at deployment.

C++ exceptions become Zolo errors with an authored function frame. Precise inner throw statements require native debug information. Native crashes and undefined behavior retain their native process semantics. Hosted wasm-aot execution is unavailable. Runtime acceptance currently covers Windows x64; other platforms need independent validation.

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

enpt-br