Skip to content

Support cross-target native builds and optional static shepherd linking - #20

Open
mjrusso wants to merge 4 commits into
nyo16:masterfrom
mjrusso:pr/cross-build
Open

mjrusso wants to merge 4 commits into
nyo16:masterfrom
mjrusso:pr/cross-build

Conversation

@mjrusso

@mjrusso mjrusso commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

This PR makes it easier to build the shepherd executable and NIF library for deployment environments that differ from the build machine.

Previously, the build wrote intermediate object files into c_src/, even when the final binaries were directed elsewhere. It now compiles and links each component in one step, writing all output into PRIV_DIR. This allows packaging tools to build directly into a release directory without modifying the source tree.

The change also fixes shepherd compilation and adds an option to reduce its runtime dependencies:

  • Compile the shepherd with -fPIE. This produces position-independent code, which the existing linker configuration requires. Previously, builds depended on the compiler enabling this by default.

  • Add SHEPHERD_STATIC=1 on Linux. This embeds the C library into the shepherd executable, allowing it to run on hosts where the build’s C library is unavailable. The executable remains position-independent. Unsupported macOS and sanitizer combinations produce an explicit error.

  • Document cross-target builds. The README shows how to select a target compiler, matching Erlang runtime headers, and a release output directory. These builds must run on Linux because platform flags are selected from the build host.

  • Remove unused build configuration. Drop obsolete object-file rules and unused erl_interface lookups.

The NIF remains a shared library and must be built for the Erlang runtime that will load it.

CI coverage added:

  • Verify that building into an external PRIV_DIR leaves the source tree unchanged.
  • On Alpine, verify that the statically linked shepherd is position-independent, requires no dynamic interpreter, and starts successfully.

Nothing reads `ERL_INTERFACE_INCLUDE_DIR` or `ERL_INTERFACE_LIB_DIR`. Both
are recursively expanded, so their `erl` calls never ran.
`-fPIE` appeared only in the shepherd's link flags, so the compiler never
received it. The `-pie` link then worked only with compilers that produce
position-independent code by default. Others failed with "recompile with
-fPIE".

Add `SHEPHERD_CFLAGS` with `-fPIE`, matching `NIF_CFLAGS`, and remove
`-fPIE` from the link flags.
The build wrote object files into `c_src/`, so a build into another
`PRIV_DIR` still changed the source tree. A parallel build into a new
`PRIV_DIR` could also link before the directory existed.

Compile and link each binary in one command, and remove `c_src/*.o` from
`.gitignore`. Make `PRIV_DIR` an order-only prerequisite of both binaries.
Remove `-I$(C_SRC_DIR)`, which the quoted includes do not need.

CI now builds into a separate `PRIV_DIR` before any other build step and
fails if `c_src/` or `priv/` changes.
Burrito ships a musl BEAM to hosts that may have only glibc. The NIF uses
the libc that the BEAM loads, but the shepherd is a separate executable
and needs its own libc.

Add `SHEPHERD_STATIC=1` to link the shepherd as a static PIE. It requires
a static libc, such as musl's. Reject it on macOS, which has no static
libc, and with `SANITIZE=1`, because the sanitizer runtimes do not link
statically.

Document a cross-target build with `zig cc`, which links musl targets
statically without this option. Add an Alpine CI step that links a static
shepherd and checks that it is a PIE with no program interpreter and
that it starts.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant