Skip to content

Guide Linux Deployment

Kris edited this page May 23, 2026 · 1 revision

Linux Deployment: --static vs --dynamic

Native binaries produced by aro build link against the Swift runtime (libswiftCore.so, libswift_Concurrency.so, libFoundation.so, …). On Linux this matters because a fresh user-machine without a Swift install will refuse to start the binary:

./MyApp: error while loading shared libraries: libswiftCore.so: cannot open shared object file: No such file or directory

aro build offers two link modes to solve this — choose based on how much you control the target machine.

The Two Modes

Flag What it does Output
--static (default) Links Swift libraries as static archives from swift_static/linux/ (-Wl,-Bstatic … -Wl,-Bdynamic). A single binary. Foundation still needs to be present on the target (see "Why Foundation Stays Dynamic" below).
--dynamic Links Swift libraries as .sos, embeds rpath=$ORIGIN, and copies every required .so next to the binary. A directory: myapp/{myapp, libswiftCore.so.5, libFoundation.so, libswift_Concurrency.so, …}.

The two flags are mutually exclusive; passing both is a hard error.

aro build ./MyApp                     # static (default)
aro build ./MyApp --static            # explicit static
aro build ./MyApp --dynamic           # bundled .so directory

When To Pick Which

Pick --static when

  • You control the target image (e.g. you ship a Docker image built FROM ghcr.io/arolang/aro-runtime).
  • You're deploying to a managed Linux distribution where Foundation is or can be apt-installed (libfoundation-dev).
  • You want the smallest possible deployment artifact.

Pick --dynamic when

  • You don't know the target machine — handing the binary to a colleague, dropping it onto an arbitrary VM, attaching to a serverless function with a glibc-class runtime.
  • You want a tar.gz you can extract anywhere and run without an apt install step.
  • You're cross-compiling for a Linux machine you don't fully control.

Use the directory form like this:

$ aro build ./MyApp --dynamic
$ ls MyApp/
MyApp                       libFoundation.so.6           libswiftCore.so.5
libBlocksRuntime.so          libFoundationEssentials.so.6 libswiftDispatch.so
libFoundationNetworking.so.6 libswift_Concurrency.so.5    libswift_StringProcessing.so.5
…
$ tar czf MyApp.tar.gz MyApp/
$ scp MyApp.tar.gz target:
$ ssh target 'tar xzf MyApp.tar.gz && ./MyApp/MyApp'

The binary uses rpath=$ORIGIN, so the loader picks the Swift runtime up from the same directory as the binary.

How --static Works

Swift ships static archives next to its dynamic libraries. The findSwiftLibPath helper resolves to something like /usr/share/swift/usr/lib/swift/linux. The static sibling is /usr/share/swift/usr/lib/swift_static/linux and contains libswiftCore.a, libswift_Concurrency.a, libswiftGlibc.a, libswiftDispatch.a, libBlocksRuntime.a, libswift_StringProcessing.a, libswift_RegexParser.a, and libswiftSwiftOnoneSupport.a.

The linker invocation switches between modes using -Wl,-Bstatic / -Wl,-Bdynamic:

clang … <object files> -L/usr/share/swift/usr/lib/swift/linux \
                       -L/usr/share/swift/usr/lib/swift_static/linux \
        -Wl,-Bstatic -lswiftCore -lswift_Concurrency -lswiftGlibc \
                     -lswiftDispatch -lBlocksRuntime \
                     -lswift_StringProcessing -lswift_RegexParser \
        -Wl,-Bdynamic -lFoundation -lFoundationEssentials -lFoundationNetworking \
                     -lpthread -ldl -lm -lstdc++ -lz -lxml2 -lgit2 …

If swift_static/linux/ is missing from the toolchain (some minimal Swift installs strip it), aro build falls back to dynamic linking with the $ORIGIN rpath added — same effect as --dynamic without the .so copy.

Why Foundation Stays Dynamic

Foundation on Linux pulls in libcurl, libxml2, libicu, and a handful of other C libraries. Apple has not published a fully-static Foundation for upstream Swift on Linux, so libFoundation.a doesn't exist in swift_static/linux. Two ways to deal with it:

  1. Stay on --dynamiclibFoundation.so and friends end up next to the binary, no further action needed.
  2. Use a runtime imageghcr.io/arolang/aro-runtime already ships Foundation; --static produces a small binary that runs as-is inside that image.
  3. Use Apple's Static-Linux SDK (musl) — fully static, including Foundation. Not yet wired up in aro build; tracked separately.

Docker

Two-stage build with --dynamic (the binary plus .sos end up alongside each other in the runtime stage):

FROM ghcr.io/arolang/aro-buildsystem:latest AS builder
WORKDIR /app
COPY . .
RUN aro build . --dynamic --optimize

FROM debian:bookworm-slim
WORKDIR /app
COPY --from=builder /app/MyApp /app/
COPY --from=builder /app/lib*.so* /app/
CMD ["/app/MyApp"]

Or with --static and the ARO runtime image (smaller image, requires the runtime base):

FROM ghcr.io/arolang/aro-buildsystem:latest AS builder
WORKDIR /app
COPY . .
RUN aro build . --optimize        # --static is the default

FROM ghcr.io/arolang/aro-runtime:latest
WORKDIR /app
COPY --from=builder /app/MyApp ./MyApp
CMD ["./MyApp"]

See Also

Clone this wiki locally