Need help with static linking of an executable

i’m trying to build a static executable. when i enable .linkage = .static i get this error:

error: error: using shared libraries requires dynamic linking

the dependent modules are both static libraries, and the two system libraries sodium/oprf are both available in /usr/lib/lib<name>.a, i even tried using linkSystemLibrary2() as commented out in my build.zig below, but that doesn’t help either. if i uncomment the .linkage = .static everything builds fine, but the result is dynamically linked against muslc.

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const pie = b.option(bool, "pie", "Build a Position Independent Executable") orelse true;
    const relro = b.option(bool, "relro", "Force all relocations to be read-only after processing") orelse true;
    const toml_package = b.dependency("zig-toml", .{
        .target = target,
        .optimize = optimize,
    });
    const toml_module = toml_package.module("toml");
    const bearssl_package = b.dependency("zig-bearssl", .{
        .target = target,
        .optimize = optimize,
    });
    const bearssl_module = bearssl_package.module("bearssl");
    const exe = b.addExecutable(.{
        .name = "server",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .linkage = .static,
    });

    exe.pie = pie;
    exe.link_z_relro = relro;
    exe.root_module.addImport("toml", toml_module);
    exe.root_module.addImport("bearssl", bearssl_module);
    exe.linkLibrary(bearssl_package.artifact("zig-bearssl"));
    //exe.linkSystemLibrary2("oprf", .{.preferred_link_mode = .static});
    //exe.linkSystemLibrary2("sodium", .{.preferred_link_mode = .static});
    exe.linkSystemLibrary("oprf");
    exe.linkSystemLibrary("sodium");
    exe.addSystemIncludePath(.{ .cwd_relative = "/usr/include/oprf/noiseXK/" });
    exe.addSystemIncludePath(.{ .cwd_relative = "/usr/include/oprf/noiseXK/karmel" });
    exe.addSystemIncludePath(.{ .cwd_relative = "/usr/include/oprf/noiseXK/karmel/minimal" });
    exe.addIncludePath(b.path("."));
    exe.addCSourceFile(.{ .file = b.path("src/workaround.c"), .flags = &[_][]const u8{"-Wall"} });
    //exe.linkLibC();

    b.installArtifact(exe);
    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}

Hello @stf
Welcome to ziggit :slight_smile:

Zig builder detected that a dynamic library is used. Unfortunately it does not display which one.
Check for zig-bearssl, oprf and sodium by commenting one of the exe.Link... statement each time.

1 Like

sodium and oprf both trigger this, despite the static libraries being available in /usr/lib

and thank your for your kind welcome! <3

Zig uses package config to configure system libraries.
When running pkg-config --libs --static libsodium do you have any output?
If not, zig cannot find libsodium.pc. Try to install the development version of libsodium (on debian and ubuntu running sudo apt-get install libsodium-dev). If there is a libsodium.pc try to set PKG_CONFIG_PATH.

oh, makes sense. however i think that the output of your suggested command is correct:

% pkg-config --libs --static libsodium
-lsodium -lpthread -pthread

can you show me an example .pc file that zig picks up correctly? because as far as i can tell, for static libs it is only needed to list all private deps of a lib that are not needed when dynamically linking. the -l<libname> is correct, and it is not custom to output .a files explicitly. in my local pkgconf dir i could not find any files containing explicit .a references to static libraries.

just checked -lpthread is only /usr/lib/libpthread.a - so also static.

In this build.zig for a zig wrapper around xlsxio, you are given the option to either dynamically link the shared.dll or statically link the static.a libraries of xlsxio.
linkSystemLibrary() is used for dynamic linking, while addObjectFile() is used to static linking.
Have you tried exe.addObjectFile(oprf.a/sodium.a)?

1 Like

i tried:

    exe.addObjectFile(.{ .cwd_relative = ("/usr/lib/libsodium.a") });
    exe.addObjectFile(.{ .cwd_relative = ("/usr/lib/liboprf.a") });

and indeed that works, but i was under the impression that linkSystemLibrary() is prefering static libraries to dynamic ones, and since both are available i expected the static ones to be picked up. i even found stack overflow question complaining about this behavior. anyway, i now get:

ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, with debug_info, not stripped

and that’s good with me, even if it doesn’t feel zigotic (is that a word?) to me.