forge/README.md

3.9 KiB

forge

nimble shield

A basic toolchain to forge (cross-compile) your multi-platform nim binaries.

Why?

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

Installation

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

Usage

Forge provide two key methods to compile your nim source forge cc and forge release.

forge cc

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

forge release

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

Acknowledgements

Thanks to Andrew Kelley and the many zig contributors.