Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{ stdenv, lib, elixir, erlang, findutils, hex, rebar, rebar3, fetchMixDeps, makeWrapper, git, ripgrep }@inputs:
2
3{ pname
4, version
5, src
6, nativeBuildInputs ? [ ]
7, buildInputs ? [ ]
8, meta ? { }
9, enableDebugInfo ? false
10, mixEnv ? "prod"
11, compileFlags ? [ ]
12
13 # mix fixed output derivation dependencies
14, mixFodDeps ? null
15
16 # mix dependencies generated by mix2nix
17 # this assumes each dependency is built by buildMix or buildRebar3
18 # each dependency needs to have a setup hook to add the lib path to $ERL_LIBS
19 # this is how mix will find dependencies
20, mixNixDeps ? { }
21
22, elixir ? inputs.elixir
23, hex ? inputs.hex.override { inherit elixir; }
24
25# This reduces closure size, but can lead to some hard to understand runtime
26# errors, so use with caution. See e.g.
27# https://github.com/whitfin/cachex/issues/205
28# https://framagit.org/framasoft/mobilizon/-/issues/1169
29, stripDebug ? false
30
31, ...
32}@attrs:
33let
34 # remove non standard attributes that cannot be coerced to strings
35 overridable = builtins.removeAttrs attrs [ "compileFlags" "mixNixDeps" ];
36in
37assert mixNixDeps != { } -> mixFodDeps == null;
38assert stripDebug -> !enableDebugInfo;
39
40stdenv.mkDerivation (overridable // {
41 # rg is used as a better grep to search for erlang references in the final release
42 nativeBuildInputs = nativeBuildInputs ++ [ erlang hex elixir makeWrapper git ripgrep ];
43 buildInputs = buildInputs ++ builtins.attrValues mixNixDeps;
44
45 MIX_ENV = mixEnv;
46 MIX_DEBUG = if enableDebugInfo then 1 else 0;
47 HEX_OFFLINE = 1;
48 DEBUG = if enableDebugInfo then 1 else 0; # for Rebar3 compilation
49 # the api with `mix local.rebar rebar path` makes a copy of the binary
50 # some older dependencies still use rebar
51 MIX_REBAR = "${rebar}/bin/rebar";
52 MIX_REBAR3 = "${rebar3}/bin/rebar3";
53
54 postUnpack = ''
55 export HEX_HOME="$TEMPDIR/hex"
56 export MIX_HOME="$TEMPDIR/mix"
57
58 # Rebar
59 export REBAR_GLOBAL_CONFIG_DIR="$TEMPDIR/rebar3"
60 export REBAR_CACHE_DIR="$TEMPDIR/rebar3.cache"
61
62 ${lib.optionalString (mixFodDeps != null) ''
63 # compilation of the dependencies will require
64 # that the dependency path is writable
65 # thus a copy to the TEMPDIR is inevitable here
66 export MIX_DEPS_PATH="$TEMPDIR/deps"
67 cp --no-preserve=mode -R "${mixFodDeps}" "$MIX_DEPS_PATH"
68 ''
69 }
70
71 '' + (attrs.postUnpack or "");
72
73 configurePhase = attrs.configurePhase or ''
74 runHook preConfigure
75
76 ${./mix-configure-hook.sh}
77 # this is needed for projects that have a specific compile step
78 # the dependency needs to be compiled in order for the task
79 # to be available
80 # Phoenix projects for example will need compile.phoenix
81 mix deps.compile --no-deps-check --skip-umbrella-children
82
83 runHook postConfigure
84 '';
85
86 buildPhase = attrs.buildPhase or ''
87 runHook preBuild
88
89 mix compile --no-deps-check ${lib.concatStringsSep " " compileFlags}
90
91 runHook postBuild
92 '';
93
94
95 installPhase = attrs.installPhase or ''
96 runHook preInstall
97
98 mix release --no-deps-check --path "$out"
99
100 runHook postInstall
101 '';
102
103 # Stripping of the binary is intentional
104 # even though it does not affect beam files
105 # it is necessary for NIFs binaries
106 postFixup = ''
107 if [ -e "$out/bin/${pname}.bat" ]; then # absent in special cases, i.e. elixir-ls
108 rm "$out/bin/${pname}.bat" # windows file
109 fi
110 # contains secrets and should not be in the nix store
111 # TODO document how to handle RELEASE_COOKIE
112 # secrets should not be in the nix store.
113 # This is only used for connecting multiple nodes
114 if [ -e $out/releases/COOKIE ]; then # absent in special cases, i.e. elixir-ls
115 rm $out/releases/COOKIE
116 fi
117 # removing unused erlang reference from resulting derivation to reduce
118 # closure size
119 if [ -e $out/erts-* ]; then
120 echo "ERTS found in $out - removing references to erlang to reduce closure size"
121 # there is a link in $out/erts-*/bin/start always
122 # TODO:
123 # sometimes there are links in dependencies like bcrypt compiled binaries
124 # at the moment those are not removed since substituteInPlace will
125 # error on binaries
126 for file in $(rg "${erlang}/lib/erlang" "$out" --files-with-matches); do
127 echo "removing reference to erlang in $file"
128 substituteInPlace "$file" --replace "${erlang}/lib/erlang" "$out"
129 done
130 fi
131 '' + lib.optionalString stripDebug ''
132 # strip debug symbols to avoid hardreferences to "foreign" closures actually
133 # not needed at runtime, while at the same time reduce size of BEAM files.
134 erl -noinput -eval 'lists:foreach(fun(F) -> io:format("Stripping ~p.~n", [F]), beam_lib:strip(F) end, filelib:wildcard("'"$out"'/**/*.beam"))' -s init stop
135 '';
136
137 # TODO investigate why the resulting closure still has
138 # a reference to erlang.
139 # uncommenting the following will fail the build
140 # disallowedReferences = [ erlang ];
141})