Docs

Packaging

Build outputs, dynamic library loading, Docker packaging, and runtime integration notes.

Open Markdown

The playground FFI artifact is a native shared library plus proa.h. The host process loads the library and calls exported C ABI functions.

Build Outputs

Use the matching library and header from a published playground package. A plain cargo build -p proa_demo --release does not link, because the demo includes RSJS islands and the linked pipeline currently exposes only binary and example targets, not the cdylib.

Native outputs in the package:

PlatformLibrary
macOSffi/libproa_demo.dylib
Linuxffi/libproa_demo.so
Windowsffi/proa_demo.dll

The downloadable playground package places the library and header under ffi/.

Dynamic Loader Paths

For C programs, set an rpath or configure the platform loader:

# macOS: normalize the current archive's build-machine install name first.
install_name_tool -id @rpath/libproa_demo.dylib ./ffi/libproa_demo.dylib
cc -o demo demo.c -L./ffi -lproa_demo -Wl,-rpath,@loader_path/ffi

# Linux
cc -o demo demo.c -L./ffi -lproa_demo -Wl,-rpath,'$ORIGIN/ffi'

The current Apple Silicon archive embeds an absolute install name from its build machine. install_name_tool -id repairs your local copy before linking; otool -D ./ffi/libproa_demo.dylib should then report @rpath/libproa_demo.dylib. The executable's rpath locates the library beside it. Rebuild already-linked executables after changing the library identity.

Python and Ruby load the library by its explicit filename. Resolve that path from the deployed application's directory rather than assuming its working directory. Go's C bridge also needs linker search paths and an rpath, as shown in the Go example.

Docker

Use the x86_64 Linux archive from Ecosystem Apps, including when building on macOS or Windows. The image runs Linux executables; a macOS or Windows download cannot run inside it. The current Linux archive omits a Dockerfile, so add this one at the extracted package root:

Dockerfile
FROM oven/bun:1.3.10 AS bun
FROM node:22-bookworm-slim
COPY --from=bun /usr/local/bin/bun /usr/local/bin/bun
WORKDIR /app
COPY . .
RUN npm install --include=dev --prefix hono-ssr \
    && npm install --include=dev --prefix react-ssr-shared \
    && chmod +x proa-playground
ENV PORT=3001
EXPOSE 3001
# The archived binary has an obsolete build-machine path for its companions.
# Start them explicitly from this package, on the ports it expects.
CMD ["sh", "-c", "(cd hono-ssr && PORT=3100 node --import tsx server.ts) & (cd hono-ssr && PORT=3200 bun server.ts) & exec ./proa-playground"]

Build and run it for the archive's architecture:

docker build --platform linux/amd64 -t proa/playground .
docker run --rm --platform linux/amd64 -p 127.0.0.1:3001:3001 proa/playground

Open http://localhost:3001. Node and Bun provide the comparison engines; the native Proa server and FFI library come from the Linux archive. The archived server also contains a build-machine companion path, so this example starts Node and Bun explicitly from the package directory. Keep dev dependencies during installation because the packaged Node server uses tsx. This is a showcase package; pin dependency lockfiles and image digests before using it as a repeatable benchmark baseline.

Host Integration Checklist

Production Shape

The demo library exports fixed showcase functions. A production integration should expose functions that match the host application's route and props model, then keep the same ownership rules:

int32_t render_product_json(
    const uint8_t *json_ptr,
    uintptr_t json_len,
    uint8_t **out_ptr,
    uintptr_t *out_len
);

Keep the ABI narrow. Prefer JSON or another stable byte protocol at the boundary instead of exposing many host-language-specific structs.

Search

Type at least 2 characters