NixOS / bundlers

Aggregated bundlers [maintainer=@tomberek, @Artturin]
MIT License
102 stars 15 forks source link

Reproduce guix pack -RR #18

Open SomeoneSerge opened 8 months ago

SomeoneSerge commented 8 months ago

Provide a flake "bundler" recovering the approach described in https://hpc.guix.info/blog/2020/05/faster-relocatable-packs-with-fakechroot/:

tomberek commented 5 months ago

@SomeoneSerge Put this together a few days ago. Patchelf and replaceDependency a new glibc into place that will read $PREFIX/etc/ld.so.cache that is pre-populated using the contents of writeClosure.

with import <nixpkgs> { };
let
  wrap =
    drv:
    let
      # Remove rpath from all binaries and set new interpreter with cache
      new_drv = runCommand "${drv.name}-wrapped" { nativeBuildInputs = [ pkgs.patchelfUnstable ]; } ''
        mkdir $out
        ln -st $out ${drv}/*
        rm -rf $out/bin
        mkdir -p $out/bin
        cp -r ${drv}/bin/* $out/bin/.
        chmod +w $out/bin/*
        for f in $out/bin/*; do
          patchelf --remove-rpath $f || true
          patchelf --set-interpreter ${new_glibc}/lib/${
            if drv.system == "x86_64-linux"
            then "ld-linux-x86-64.so.2"
            else "ld-linux-aarch64.so.1" } $f || true
        done
      '';

      # Replace self-references in glibc
      new_glibc = replaceDependency {
        drv = new_glibc_pre;
        oldDependency = glibc.out;
        newDependency = new_glibc_pre;
      };

      # Create a new glibc derivation that has a targetet ld.so.cache
      new_glibc_pre = buildEnv {
        name = pkgs.glibc.out.name;
        paths = [
          (pkgs.runCommand "something" { nativeBuildInputs = [ pkgs.glibc.bin ]; } ''
            mkdir $out
            mkdir -p $out/etc
            mkdir -p $out/lib
            cp -R ${glibc.out}/* $out/

            chmod +w $out/etc

            cat ${pkgs.writeClosure drv} \
            | xargs printf "%s\n" \
            | xargs -I{} find {} -iname "lib*.so*" -execdir pwd \; \
            | sort -u > $out/etc/ld.so.conf

            ldconfig -f $out/etc/ld.so.conf -C $out/etc/ld.so.cache
          '')
        ];
      };
    in
    new_drv;
in
builtins.mapAttrs (name: drv: wrap (pkgs.lib.getBin drv)) pkgs
tomberek commented 5 months ago

the loader supporting a "LD_CACHE_FILE" or similar would allow this to not require a such a wrapping

SomeoneSerge commented 5 months ago

AFAIU this implements a per-dso cache while reusing cache.nixos.org. How does this help with relocatability however?

P.S. Side note: I had struggled to figure out how to properly use replaceDependency and this is the first working example that I see. I expect transitive/propagated dependencies are still linking to the unwrapped interpreters?