NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
18.27k stars 14.25k forks source link

Suggestion: allow mostly-static builds targeting Darwin #214611

Open Thesola10 opened 1 year ago

Thesola10 commented 1 year ago

Describe the bug

I understand that purely static binaries are not supported under Darwin, due to the unstable system call ABI. My suggestion is that pkgsStatic, on Darwin or cross-compiling to Darwin, should produce static libraries, which would result in dynamic binaries which only depend on libSystem.dylib. This would be useful for single-file software for embedding, as well as simplifying distribution of Nix-built binaries on systems without Nix.

Steps To Reproduce

Steps to reproduce the behavior:

  1. Build nixpkgs#legacyPackages.x86_64-darwin.pkgsStatic.nix
  2. Run llvm-otool -L result/bin/nix
  3. Resulting derivation is a dynamic executable with dependencies elsewhere in the Nix Store

Expected behavior

Resulting executable would only depend on /usr/lib/libSystem.B.dylib

Notify maintainers

@NixOS/darwin-maintainers

Thesola10 commented 1 year ago

Currently attempting to override builds on the basis that gcc actually discards --static on Darwin and thus produces dynamic binaries with static libraries, but I'm running into a bunch of infinite recursion errors.

My overlay for reference:

self: super:
{ stdenv = super.stdenv //
  { hostPlatform = super.stdenv.hostPlatform // { isStatic = true; };
    targetPlatform = super.stdenv.targetPlatform // { isStatic = true; };
  };
  targetPackages = super.targetPackages //
  { darwin = super.targetPackages.darwin //
    { LibsystemCross = super.targetPackages.darwin.Libsystem;
    };
  };
}
Thesola10 commented 1 year ago

Okay, I have a working Nixpkgs expression for building "static" executables targeting Darwin (on Darwin only).

let sys = "x86_64-darwin";
in import <nixpkgs> {
  localSystem = sys;
  crossSystem = {
    isStatic = true;
    system = sys;
  };
  overlays = [
    (self: super: {
      darwin = super.darwin // {
        Libsystem = super.buildPackages.darwin.Libsystem;
        LibsystemCross = super.buildPackages.darwin.Libsystem;
      };

      libcCross = super.buildPackages.darwin.Libsystem;

      targetPackages = self;
    })
  ];
}
Thesola10 commented 1 year ago

stdenv.cc needs to be patched to link against our static libcxx and libcxxabi... but I can't figure out how to do that without causing an infinite recursion.

uri-canva commented 1 year ago

I'm fixing nixStatic on darwin, and that's how pkgsStatic works on darwin currently:

$ otool -L /nix/store/rpyh2k1kcp01gj2k3nicllrxmp2jhhhf-nix-static-aarch64-apple-darwin-2.13.3/bin/nix
/nix/store/rpyh2k1kcp01gj2k3nicllrxmp2jhhhf-nix-static-aarch64-apple-darwin-2.13.3/bin/nix:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1770.255.0)
$ otool -L /run/current-system/sw/bin/nix
/run/current-system/sw/bin/nix:
    /nix/store/jr79z629fzph2pmskn5ay9b0s4zwjqhw-libsodium-1.0.18/lib/libsodium.23.dylib (compatibility version 27.0.0, current version 27.0.0)
    /nix/store/ncz3w3a24ivylxhc8njy0jybhrf4ygzi-editline-1.17.1/lib/libeditline.1.dylib (compatibility version 2.0.0, current version 2.2.0)
    /nix/store/206349alakwa2dk3sw9c6kjd1z11v7nx-lowdown-1.0.0-lib/lib/liblowdown.1.dylib (compatibility version 0.0.0, current version 0.0.0)
    /nix/store/y4cxibf59qzabp1bmvvm7qsp59b9gsng-nix-2.11.1/lib/libnixexpr.dylib (compatibility version 0.0.0, current version 0.0.0)
    /nix/store/yhlp33586jb3a2dbnlx40qkq6pmvfhj5-boehm-gc-8.2.2/lib/libgc.1.dylib (compatibility version 7.0.0, current version 7.1.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
    /nix/store/y4cxibf59qzabp1bmvvm7qsp59b9gsng-nix-2.11.1/lib/libnixmain.dylib (compatibility version 0.0.0, current version 0.0.0)
    /nix/store/y4cxibf59qzabp1bmvvm7qsp59b9gsng-nix-2.11.1/lib/libnixfetchers.dylib (compatibility version 0.0.0, current version 0.0.0)
    /nix/store/y4cxibf59qzabp1bmvvm7qsp59b9gsng-nix-2.11.1/lib/libnixstore.dylib (compatibility version 0.0.0, current version 0.0.0)
    /nix/store/y4cxibf59qzabp1bmvvm7qsp59b9gsng-nix-2.11.1/lib/libnixutil.dylib (compatibility version 0.0.0, current version 0.0.0)
    /nix/store/y4cxibf59qzabp1bmvvm7qsp59b9gsng-nix-2.11.1/lib/libnixcmd.dylib (compatibility version 0.0.0, current version 0.0.0)
    /nix/store/rdn99pvs6krf6fbd20a1b1m93pzjm485-libcxxabi-11.1.0/lib/libc++abi.1.dylib (compatibility version 1.0.0, current version 1.0.0)
    /nix/store/h321ql04pxlnxhswx7zaglidpiaf9gdm-libcxx-11.1.0/lib/libc++.1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
Thesola10 commented 1 year ago

This overlay produces a completely freestanding Nix binary for macOS

nixie-dev/nixie:static-bins/nixpkgs-darwin-static.nix

but I'd appreciate an upstreamed solution

andrewcrook commented 1 year ago

FYI I have also seen people use Zig to compile C programs statically on macOS. Zig can be used as a drop in C compiler because its language has C support. It can also cross compile iirc.

uri-canva commented 1 year ago

Good point, I've only thought about it in the context of cross compiling, see https://discourse.nixos.org/t/poc-zig-based-cross-compiling/22844 for example.

Thesola10 commented 1 year ago

Fixed by #235990

reckenrode commented 1 year ago

Should this be closed when static builds still don’t work on x86_64-darwin?

winterqt commented 1 year ago

Agreed, let's keep this open till all supported Darwin platforms have working static builds.

reckenrode commented 1 year ago

Fortunately, that should be coming pretty soon.

I have a branch with working x86_64-darwin cross-compilation, which includes mostly-static builds. I need to make sure I didn’t break the stdenv or aarch64-darwin cross-compilation, so it’ll probably be a few days before I can open the PR.