A basic toolchain to forge (cross-compile) your multi-platform nim
binaries.
Nim
is a great language and the code is as portable as any other code written in C.
But who wants to manage C toolchains or CI/CD DSL's to cross-compile your code into easily sharable native executable binaries
In order to use forge
you must first install zig
as all compilation
is done using a thin wrapper around zig cc
.
Note
Future versions may use an automated/isolated zig
installation.
nimble install https://github.com/daylinmorgan/forge
Forge
provide two key methods to compile your nim
source forge cc
and forge release
.
To compile a single binary for a platform you can use forge cc
.
Example:
forge cc --target x86_64-linux-musl -- -d:release src/forge.nim -o:forge
This command is useful for generating many compiled binaries like you may be accustomed to seeing from go
or rust
cli's.
Forge release
will make attempts to infer many values based on the assumption that it's
likely run from the root directory of a nim
project with a <project>.nimble
You can either specify all commands on the CLI or use a config file.
Example:
forge release --target,=,x86_64-linux-musl,x86_64-macos-none --bin src/forge.nim
Result:
dist
├── forge-v2023.1001-x86_64-linux-musl
│ └── forge
└── forge-v2023.1001-x86_64-macos-none
└── forge
The output directories used for each binary are determined
by a format string: ${name}-v${version}-${target}
.
You can modify this with additional info at runtime like using
date instead of version string: --format "\${name}-$(date +'%Y%M%d')-\${target}"
.
You can also create a config file by default at ./.forge.cfg
that controls the behavior of forge release
:
# flags are specified at the top level
nimble # key without value for booleans
format = "${name}-${target}"
outdir = forge-dist
# use sections to list targets/bins with optional args
[target]
x86_64-linux-musl = "--debugInfo:on"
x86_64-linux-gnu
[bin]
src/forge
src/forgecc = "--opt:size" # use a custom flag for this binary
Example:
forge release --verbose --dryrun
Output:
forge release -V --dryrun
forge || config =
| nimble true
| outdir forge-dist
| format ${name}-${target}
| version 2023.1001
| targets:
| x86_64-linux-musl|--debugInfo:on
| x86_64-linux-gnu
| bins:
| src/forge
| src/forgecc|--opt:size
forge || dry run...see below for commands
forge || compiling 2 binaries for 2 targets
nimble c --cpu:amd64 --os:Linux --cc:clang --clang.exe='forgecc' --clang.linkerexe='forgecc' --passC:'-target x86_64-linux-musl' --passL:'-target x86_64-linux-musl' -d:release --outdir:'dist/forge-x86_64-linux-musl' --debugInfo:on src/forge
nimble c --cpu:amd64 --os:Linux --cc:clang --clang.exe='forgecc' --clang.linkerexe='forgecc' --passC:'-target x86_64-linux-musl' --passL:'-target x86_64-linux-musl' -d:release --outdir:'dist/forge-x86_64-linux-musl' --debugInfo:on --opt:size src/forgecc
nimble c --cpu:amd64 --os:Linux --cc:clang --clang.exe='forgecc' --clang.linkerexe='forgecc' --passC:'-target x86_64-linux-gnu' --passL:'-target x86_64-linux-gnu' -d:release --outdir:'dist/forge-x86_64-linux-gnu' src/forge
nimble c --cpu:amd64 --os:Linux --cc:clang --clang.exe='forgecc' --clang.linkerexe='forgecc' --passC:'-target x86_64-linux-gnu' --passL:'-target x86_64-linux-gnu' -d:release --outdir:'dist/forge-x86_64-linux-gnu' --opt:size src/forgecc
Thanks to Andrew Kelley and the many zig
contributors.