Executables
For programs with no JavaScript host, crossbind links a main() of yours, and the ports it uses, into a native executable for macOS, Linux and Windows, or into a WASI command for wasmtime. You can also run the upstream command-line tools of 12 ports straight from npm, or link the ports' archives into a build of your own.
Native executables
-e native links the main(int, char**) in src/native into an executable, where -e node would link a Node-API addon. A port joins through its desktop packages, one per platform you build:
| Platform | Output | Runs on |
|---|---|---|
linux | dist/<name>.linux-<arch> | glibc 2.28 or later, needing only libc, libm, libdl, libpthread and libgcc_s |
linuxmusl | dist/<name>.linuxmusl-<arch> | any Linux, musl or glibc: the executable is fully static |
darwin | dist/<name>.darwin-<arch> | macOS 11 or later |
win32 | dist/<name>.win32-<arch>.exe | Windows 10 or later, with the C++ runtime linked in |
<arch> is arm64 or x64, and a debug build (-b debug) adds .debug before the extension. -p host builds this machine's platform for both: darwin on macOS, win32 on Windows, and on Linux linux or linuxmusl by the C library Node.js runs on. -p linux,linuxmusl,darwin,win32 builds all four. Linux and Windows executables build in Docker, macOS ones only on a Mac, with Xcode's command line tools.
- Your own archive links whole; a port's archive keeps only what
mainreaches. - A port's data, such as
GDAL_DATAandproj.db, is copied todist/data, but nothing points the executable at it: setGDAL_DATAandPROJ_DATAbefore running it. -e node,nativemakes the addon and the executable from the same archives. A Rust package (export.type: 'cargo') makes no executable.- The test suite runs the glibc build on Debian 10, the musl build on Alpine and Debian 13 and the macOS build on its host; the Windows build is checked for the machine it targets, not run.
WASI commands
-p wasi -e wasi builds the same kind of program into one wasm32-wasip3 command component, with no JavaScript glue. It runs under a WASI 0.3 runtime with Wasm 3.0 exception support, such as wasmtime 47 or newer. Ports link in from their -wasi packages; the -wasm ones are built for Emscripten and do not link here.
The command and the data/ folder of its dependencies land in paths.output, .crossbind/build unless the config sets it. The program sees only the directories you preopen with --dir and the variables you pass with --env, and sockets work through wasi:sockets once granted with -S inherit-network=y -S allow-ip-name-lookup=y -S tcp=y. PROJ's page has the whole program, and every library page ends with one like it.
The build runs in the web Docker image, which ships the wasi-sdk. To build on the host instead, point crossbind at a wasi-sdk 34 or newer with the wasm32-wasip3 sysroot:
- Single-threaded: the WASI threads ABI is still in flux.
- No processes and no dynamic loading. What crossbind stubs out, such as the
dlopenfamily, fails at run time instead of at instantiation. - No Rust: there is no
wasm32-wasip3Rust target yet.
Prebuilt tools on npm
Where an upstream project ships command-line tools, a -standalone-wasi package carries them prebuilt for wasm32-wasip3. Nothing compiles; wasmtime 47 or newer has to be on PATH:
Each tool installs as <tool>-wasi, so it never shadows a native install of the same tool. The launcher preopens only the current directory, so paths must sit inside it; it mounts the data the package declares, such as GDAL's and PROJ's data folders and OpenSSL's CA bundle, sets the variables that point at them, and grants network access. To run a tool without installing it: npx -p @crossbind/port-gdal-standalone-wasi@beta gdal-wasi --version.
| Library | Package | Commands |
|---|---|---|
| cURL | @crossbind/port-curl-standalone-wasi | curl-wasi |
| Expat | @crossbind/port-expat-standalone-wasi | xmlwf-wasi |
| GDAL | @crossbind/port-gdal-standalone-wasi | 29 commands |
| GEOS | @crossbind/port-geos-standalone-wasi | geosop-wasi |
| GeoTIFF | @crossbind/port-geotiff-standalone-wasi | applygeo-wasi, geotifcp-wasi, listgeo-wasi |
| libjpeg-turbo | @crossbind/port-jpegturbo-standalone-wasi | cjpeg-wasi, djpeg-wasi, jpegtran-wasi |
| libTIFF | @crossbind/port-tiff-standalone-wasi | 18 commands |
| OpenSSL | @crossbind/port-openssl-standalone-wasi | openssl-wasi |
| PROJ | @crossbind/port-proj-standalone-wasi | cct-wasi, cs2cs-wasi, geod-wasi, gie-wasi, proj-wasi, projinfo-wasi |
| SQLite | @crossbind/port-sqlite3-standalone-wasi | sqlite3-wasi |
| WebP | @crossbind/port-webp-standalone-wasi | cwebp-wasi, dwebp-wasi, webpinfo-wasi |
| Zstandard | @crossbind/port-zstd-standalone-wasi | zstd-wasi |
A package's npm license field is the compound expression of everything statically linked into it, and the package ships the full license texts, a CycloneDX SBOM and a provenance record of its build.
Prebuilt archives in your own build
Each desktop package, @crossbind/port-<name>-<platform> for darwin, linux, linuxmusl and win32, ships one install tree per architecture that a C or C++ build of your own can link:
| Platform | Built with | Runs on |
|---|---|---|
linux | clang 19 and a static libc++ 19, against Debian 10 packages | glibc 2.28 or later |
linuxmusl | clang 19 and a static libc++ 19, against Alpine packages | musl 1.2.5 or later |
darwin | Xcode's clang and the system libc++ | macOS 11 or later |
win32 | llvm-mingw | Windows 10 or later, through the Universal C Runtime |
- The metadata finds the tree wherever it lands. pkg-config files resolve through
${pcfiledir}, but a package names its dependencies by library name only (-lproj), so put thelib/pkgconfigof every dependency package onPKG_CONFIG_PATHtoo. Where upstream installs CMake configs, pointCMAKE_PREFIX_PATHat the tree. - C++ means libc++. A package with C++ code, or one that links such a package, needs clang with
-stdlib=libc++, and libc++ 19 or later on Linux: GEOS, PROJ and Lerc, and what links them, such as libtiff, libgeotiff, SpatiaLite and GDAL. C packages such as zlib, zstd, SQLite and Expat link with any compiler. - Data has to be pointed at. Set
GDAL_DATAandPROJ_DATAto theshare/gdalandshare/projdirectories of their packages; the path compiled into the archives belongs to the machine that built them.
examples/native-executable is a complete program, a main() with a library linked in for every desktop platform, and npm create crossbind@beta -- my-tool Native Executable scaffolds it.