beamPackages.mixRelease doesn't remove the Erlang dependency when ERTS is bundled

Based on what I’m reading in the mixRelease function, the Nix version of Erlang should be removed if it detects that ERTS is bundled with the release. However, this is not happening (for me?)

My code

flake.nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    nix2container = {
      url = "github:nlewo/nix2container";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs =
    {
      self,
      nixpkgs,
      nix2container,
    }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
      nix2containerPkgs = nix2container.packages.${system};

      simius = import ./package.nix { inherit pkgs; };
      container = import ./container.nix {
        inherit pkgs;
        inherit simius;
        inherit (nix2containerPkgs) nix2container;
      };
    in
    {
      inherit simius;
      packages.${system}.container = container;
    };
}
package.nix
{ pkgs }:

let
  beamPkgs = pkgs.beam.packagesWith pkgs.beam.interpreters.erlang_27;
  elixir = beamPkgs.elixir_1_18;

  pname = "simius";
  version = "0.1.0";
  src = ./.;

  mixFodDeps = beamPkgs.fetchMixDeps {
    pname = "mix-deps-${pname}";
    inherit src version;
    hash = "sha256-f5lYBn3CjE2qyRe2ysNr/nM1qW+5fgD466jmI+nmUCA=";
  };
in
beamPkgs.mixRelease {
  inherit
    pname
    version
    src
    mixFodDeps
    elixir
    ;
}
result
$ nix build .#simius

$ eza --tree -L 1 result/
result
├── bin
├── erts-15.2
├── lib
└── releases

ERTS is included in the release, which should remove the Erlang dependency, however:

result references
❯ nix-store -q --references result
/nix/store/65h17wjrrlsj2rj540igylrx7fqcd6vq-glibc-2.40-36
/nix/store/5mh7kaj2fyv8mk4sfq1brwxgc02884wi-bash-5.2p37
/nix/store/a3c47r5z1q2c4rz0kvq8hlilkhx2s718-gawk-5.3.1
/nix/store/abm77lnrkrkb58z6xp1qwjcr1xgkcfwm-gnused-4.9
/nix/store/bpq1s72cw9qb2fs8mnmlw6hn2c7iy0ss-gcc-14-20241116-lib
/nix/store/cqlaa2xf6lslnizyj9xqa8j0ii1yqw0x-zlib-1.3.1
/nix/store/h1ydpxkw9qhjdxjpic1pdc2nirggyy6f-openssl-3.3.2
/nix/store/4s9rah4cwaxflicsk5cndnknqlk9n4p3-coreutils-9.5
/nix/store/lji0hh2w2rv6q9mal3vpxbg413d57vfd-systemd-256.8
/nix/store/wm1qn5jqrxpcjkc640gq8a90ns5gw3cn-ncurses-6.4.20221231
---> /nix/store/186j3w6wqlqqc8c2sljxhw72ffvc5h0p-erlang-27.2 <---
/nix/store/aap6cq56amx4mzbyxp2wpgsf1kqjcr1f-gnugrep-3.11
/nix/store/p45ncjrrn76qhbp95gbmwm33gmkl4kyr-simius-0.1.0

Erlang is still included. Am I doing something wrong?

reading the mixRelease code and comments, it says that it removes runtime references in the output erlang files, not Nix store references to erlang. This makes sense right, since we have them in the Nix store, looking for erlang at runtime would cause issues, or at least is useless. The nix store -q -references command returns the store path references of the derivation, i.e. build time dependencies.
A Mix release is self-contained, so the output of the command is not runtime deps here. In fact if you look at result/erts-15.2/bin, you’ll see compiled erlang binaries (erl, erlc, etc) i.e. the binaries you need at runtime.

How would I make use of this release without including the erlang build-time dependency?

When I make use of it like this, I end up with erlang in the container’s nix store:

container.nix
{
  pkgs,
  nix2container,
  simius,
}:

# TODO: figure out why simius gets rebuilt even when it isn't touched
let
  minimalLocales = pkgs.glibcLocales.override {
    allLocales = false;
    locales = [ "en_US.UTF-8/UTF-8" ];
  };
in
nix2container.buildImage {
  name = "simius";
  config = {
    env = [
      "LOCALE_ARCHIVE=${minimalLocales}/lib/locale/locale-archive"
      "LANG=en_US.UTF-8"
      "LANGUAGE=en_US:en"
      "LC_ALL=en_US.UTF-8"
    ];
    entrypoint = [ "${simius}/bin/simius" ];
    cmd = [ "start" ];
  };
  layers = [
    (nix2container.buildLayer {
      # a list of derivations copied to the image root directory
      copyToRoot = [
        (pkgs.buildEnv {
          name = "busybox";
          paths = with pkgs; [
            # a `sh` is required
            busybox # includes `sh` and many other utils without wasting much space
          ];
          pathsToLink = [ "/bin" ];
        })
      ];
    })
  ];
}

If I understand you correctly, I would need to only include the runtime dependencies in the container, but this also includes the build time dependencies?

$ podman run -it --rm --entrypoint=/bin/sh simius:05vg4yh3ffcjpf9jzgcx100mv7crkcfl
/ # ls /nix/store/ | grep erlang
186j3w6wqlqqc8c2sljxhw72ffvc5h0p-erlang-27.2

Back when I played with mixRelease, there was a comment in some generated script, that was an absolute path to the erlang compiler used to build the project.

I was under the impression that I contributed a patch to to the builder that would remove this reference, though I can not find it in the history, though I can see that there are mesures taken to remove any references.

So here we need to better debug what is holding the reference.

So please build your mixRelease result, and not some docker container, and use nix why-depends on it to see why it still refers to that erlang path.

1 Like

Like this?

$ nix build .#simius
$ nix-store -q --references ./result
/nix/store/65h17wjrrlsj2rj540igylrx7fqcd6vq-glibc-2.40-36
/nix/store/5mh7kaj2fyv8mk4sfq1brwxgc02884wi-bash-5.2p37
/nix/store/a3c47r5z1q2c4rz0kvq8hlilkhx2s718-gawk-5.3.1
/nix/store/abm77lnrkrkb58z6xp1qwjcr1xgkcfwm-gnused-4.9
/nix/store/bpq1s72cw9qb2fs8mnmlw6hn2c7iy0ss-gcc-14-20241116-lib
/nix/store/cqlaa2xf6lslnizyj9xqa8j0ii1yqw0x-zlib-1.3.1
/nix/store/h1ydpxkw9qhjdxjpic1pdc2nirggyy6f-openssl-3.3.2
/nix/store/4s9rah4cwaxflicsk5cndnknqlk9n4p3-coreutils-9.5
/nix/store/lji0hh2w2rv6q9mal3vpxbg413d57vfd-systemd-256.8
/nix/store/wm1qn5jqrxpcjkc640gq8a90ns5gw3cn-ncurses-6.4.20221231
/nix/store/186j3w6wqlqqc8c2sljxhw72ffvc5h0p-erlang-27.2
/nix/store/aap6cq56amx4mzbyxp2wpgsf1kqjcr1f-gnugrep-3.11
/nix/store/p45ncjrrn76qhbp95gbmwm33gmkl4kyr-simius-0.1.0
$ nix why-depends ./result /nix/store/186j3w6wqlqqc8c2sljxhw72ffvc5h0p-erlang-27.2
/nix/store/p45ncjrrn76qhbp95gbmwm33gmkl4kyr-simius-0.1.0
└───/nix/store/186j3w6wqlqqc8c2sljxhw72ffvc5h0p-erlang-27.2

The last time I used why-depends it showed me also the file that contained the reference…

Can you please check if there are any links in the result, that point to the erlang? Or do a grep for the the hash part?

$ grep -r 186j3w6wqlqqc8c2sljxhw72ffvc5h0p result/
/nix/store/85amyk92rg19l4fy0qmy7wr4jmq8p5z0-gnugrep-3.11/bin/grep: result/lib/elixir-1.18.1/ebin/elixir_parser.beam: binary file matches

Oh, that might be solved by allowing stripping.

If its not, the resulting beam file needs to be inspected deeper using a beam-disassembler.

1 Like

That seems to have done the trick!

$ nix-store -q --references ./result
/nix/store/65h17wjrrlsj2rj540igylrx7fqcd6vq-glibc-2.40-36
/nix/store/4s9rah4cwaxflicsk5cndnknqlk9n4p3-coreutils-9.5
/nix/store/5mh7kaj2fyv8mk4sfq1brwxgc02884wi-bash-5.2p37
/nix/store/a3c47r5z1q2c4rz0kvq8hlilkhx2s718-gawk-5.3.1
/nix/store/aap6cq56amx4mzbyxp2wpgsf1kqjcr1f-gnugrep-3.11
/nix/store/abm77lnrkrkb58z6xp1qwjcr1xgkcfwm-gnused-4.9
/nix/store/bpq1s72cw9qb2fs8mnmlw6hn2c7iy0ss-gcc-14-20241116-lib
/nix/store/cqlaa2xf6lslnizyj9xqa8j0ii1yqw0x-zlib-1.3.1
/nix/store/h1ydpxkw9qhjdxjpic1pdc2nirggyy6f-openssl-3.3.2
/nix/store/lji0hh2w2rv6q9mal3vpxbg413d57vfd-systemd-256.8
/nix/store/wm1qn5jqrxpcjkc640gq8a90ns5gw3cn-ncurses-6.4.20221231
/nix/store/k713g92hwkp0rxjwj447jz5w28mns4rs-simius-0.1.0

Do you happen to know to what extent this can actually be a problem?

# This reduces closure size, but can lead to some hard to understand runtime
# errors, so use with caution. See e.g.
# https://github.com/whitfin/cachex/issues/205
# https://framagit.org/framasoft/mobilizon/-/issues/1169
stripDebug ? false,

Stacktraces might lack proper source attribution, and also you can not access doc information anymore.

There might be more problems that I do not remember.