Node.js native addon build and cross-compile library using Zig
zig-build
provides an interface for building native C/C++ Node-API addons or any native code. Unlike node-gyp
and cmake-js
, it is not a wrapper around a build system and directly calls the compiler. It doesn't depend on the system compiler and instead downloads a copy of Zig and uses its Clang wrapper, and benefits from its many features.
- First class cross-compilation support
- Automatic build caching
- Statically linked libc++ to use any C++ standard on any target
- Custom glibc version targeting
zig-build
aims to be a modern alternative to node-gyp
, and as such only offers first-class support for Node-API (previously NAPI) addons and not legacy NAN ones. Node headers for the current version are downloaded and added to the include path as Node-API is version agnostic, and automatically downloading version-specific headers is a non-goal. zig-build
will also detect and automatically include node-addon-api
if it is present.
Also following this focus on modern approaches, zig-build
doesn't provide any way to download native addons at install time. We instead recommend using optionalDependencies
with os
and cpu
specific npm packages containing their respective native addons, which are supported by all modern package managers, provide a much better user experience and reduce the amount of runtime dependencies.
Unlike node-gyp
, zig-build
is provided as a library and not a CLI. You will need to create a script file and import the build
function, with the upside that the build configuration can profit from the expressivity of JavaScript. Another difference is that zig-build
focuses on cross-compilation, and the compilation target will not be implied to be the current machine and must be specified explicitly.
Many options are available, for a full reference see index.ts
.
# using npm
npm install --save-dev zig-build
# optional
npm install --save-dev node-addon-api
# using yarn
yarn add --dev zig-build
# optional
yarn add --dev node-addon-api
import { build } from "zig-build"
const config = {
sources: ["addon.cc", "util.cc"],
std: "c++17",
}
await build({
windows: {
target: "x86_64-windows",
output: "windows/addon.node",
...config,
},
"linux-x64": {
target: "x86_64-linux-gnu",
output: "linux-x64/addon.node",
...config,
},
"linux-arm64": {
target: "aarch64-linux-gnu",
output: "linux-arm64/addon.node",
...config,
},
})
await build({
addon: {
target: "x86_64-linux-gnu",
sources: ["addon.cc"],
output: "addon.node",
nodeVersion: "18.0.0",
},
})
await build({
addon: {
target: "x86_64-linux-gnu",
sources: ["addon.cc"],
output: "addon.node",
defines: {
TARGET_NODE: true, // -DTARGET_NODE
ADDON_VERSION: "1.2.3", // -DADDON_VERSION=1.2.3
ADDON_REV: 4, // -DADDON_REV=4
},
},
})
await build({
addon: {
target: "x86_64-linux-gnu",
sources: ["addon.cc"],
output: "addon.node",
libraries: ["z", "private"], // -lz -lprivate
librariesSearch: ["libprivate-vendored"], // -Llibprivate-vendored
rpath: "$ORIGIN", // -Wl,-rpath,$ORIGIN
},
})
await build({
addon: {
target: "x86_64-linux-gnu",
sources: ["addon.cc"],
output: "addon.node",
cflags: ["-Wl,-soname,napiaddon"],
},
})
Thanks to Zig, Linux gnu
targets support specifying a custom glibc version, which makes it possible to run the addon on older Linux distribution, which bundle older glibc versions, even if it was built against a much more recent version of glibc.
await build({
addon: {
target: "x86_64-linux-gnu",
glibc: "2.17",
sources: ["addon.cc"],
output: "addon.node",
},
})
While it inherits Zig's upsides, zig-build
also inherits its caveats.
- Incompatibility with
g++
andclang++
. This generally applies to any C++ code; all objects should be built with the same compiler. - Incompatibility with MSVC. Since this is a cross-compiler which needs to run on any target, Windows targets use
mingw
. - Statically linking
libc++
. This is often useful but not always desirable and there are reasons to prefer dynamically linking against the systemlibstdc++
. - Not using the system compiler. There a many reasons to need or prefer using the system compiler, in which cases
zig-build
is simply not appropriate.
Contributions are welcome ! For major changes, please first open an issue to discuss before opening a PR.