21 , nativeBuildInputs ? [ ]
24 , enableDebugInfo ? false
28 # Mix dependencies provided as a fixed output derivation
31 # Mix dependencies generated by mix2nix
33 # This assumes each dependency is built by buildMix or buildRebar3. Each
34 # dependency needs to have a setup hook to add the lib path to $ERL_LIBS.
35 # This is how Mix finds dependencies.
38 , elixir ? inputs.elixir
39 , hex ? inputs.hex.override { inherit elixir; }
41 # Remove releases/COOKIE
43 # People have different views on the nature of cookies. Some believe that they are
44 # secrets, while others believe they are just ids for clustering nodes instead of
47 # If you think cookie is secret, you can set this attr to true, then it will be
48 # removed from nix store. If not, you can set it to false.
50 # For backward compatibility, it is set to true by default.
52 # You can always specify a custom cookie by using RELEASE_COOKIE environment
53 # variable, regardless of the value of this attr.
56 # This reduces closure size, but can lead to some hard to understand runtime
57 # errors, so use with caution. See e.g.
58 # https://github.com/whitfin/cachex/issues/205
59 # https://framagit.org/framasoft/mobilizon/-/issues/1169
65 # Remove non standard attributes that cannot be coerced to strings
66 overridable = builtins.removeAttrs attrs [ "compileFlags" "mixNixDeps" ];
68 assert mixNixDeps != { } -> mixFodDeps == null;
69 assert stripDebug -> !enableDebugInfo;
71 stdenv.mkDerivation (overridable // {
72 nativeBuildInputs = nativeBuildInputs ++
74 [ erlang elixir hex git ] ++
76 (builtins.attrValues mixNixDeps) ++
77 # other compile-time deps
78 [ findutils makeWrapper ];
80 buildInputs = buildInputs;
83 MIX_DEBUG = if enableDebugInfo then 1 else 0;
86 DEBUG = if enableDebugInfo then 1 else 0; # for Rebar3 compilation
87 # The API with `mix local.rebar rebar path` makes a copy of the binary
88 # some older dependencies still use rebar.
89 MIX_REBAR = "${rebar}/bin/rebar";
90 MIX_REBAR3 = "${rebar3}/bin/rebar3";
96 export MIX_HOME="$TEMPDIR/mix"
97 export HEX_HOME="$TEMPDIR/hex"
100 export REBAR_GLOBAL_CONFIG_DIR="$TEMPDIR/rebar3"
101 export REBAR_CACHE_DIR="$TEMPDIR/rebar3.cache"
103 ${lib.optionalString (mixFodDeps != null) ''
104 # Compilation of the dependencies will require that the dependency path is
105 # writable, thus a copy to the $TEMPDIR is inevitable here.
106 export MIX_DEPS_PATH="$TEMPDIR/deps"
107 cp --no-preserve=mode -R "${mixFodDeps}" "$MIX_DEPS_PATH"
109 '' + (attrs.postUnpack or "");
111 configurePhase = attrs.configurePhase or ''
114 ${./mix-configure-hook.sh}
116 # This is needed for projects that have a specific compile step
117 # the dependency needs to be compiled in order for the task
120 # Phoenix projects for example will need compile.phoenix.
121 mix deps.compile --no-deps-check --skip-umbrella-children
123 # Symlink dependency sources. This is needed for projects that require
124 # access to the source of their dependencies. For example, Phoenix
125 # projects need javascript assets to build asset bundles.
126 ${lib.optionalString (mixNixDeps != { }) ''
129 ${lib.concatMapStringsSep "\n" (dep: ''
130 dep_name=$(basename ${dep} | cut -d '-' -f2)
131 dep_path="deps/$dep_name"
132 if [ -d "${dep}/src" ]; then
133 ln -s ${dep}/src $dep_path
135 '') (builtins.attrValues mixNixDeps)}
138 # Symlink deps to build root. Similar to above, but allows for mixFodDeps
139 # Phoenix projects to find javascript assets.
140 ${lib.optionalString (mixFodDeps != null) ''
144 runHook postConfigure
147 buildPhase = attrs.buildPhase or ''
150 mix compile --no-deps-check ${lib.concatStringsSep " " compileFlags}
155 installPhase = attrs.installPhase or ''
158 mix release --no-deps-check --path "$out"
164 # Remove files for Microsoft Windows
165 rm -f "$out"/bin/*.bat
167 # Wrap programs in $out/bin with their runtime deps
168 for f in $(find $out/bin/ -type f -executable); do
170 --prefix PATH : ${lib.makeBinPath [
177 '' + lib.optionalString removeCookie ''
178 if [ -e $out/releases/COOKIE ]; then
179 rm $out/releases/COOKIE
181 '' + lib.optionalString stripDebug ''
182 # Strip debug symbols to avoid hardreferences to "foreign" closures actually
183 # not needed at runtime, while at the same time reduce size of BEAM files.
184 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
187 # TODO: remove erlang references in resulting derivation
189 # # Step 1 - investigate why the resulting derivation still has references to erlang.
191 # The reason is that the generated binaries contains erlang reference. Here's a repo to
192 # demonstrate the problem - <https://github.com/plastic-gun/nix-mix-release-unwanted-references>.
195 # # Step 2 - remove erlang references from the binaries
197 # As said in above repo, it's hard to remove erlang references from `.beam` binaries.
199 # We need more experienced developers to resolve this issue.
204 # When resolving this issue, it is convenient to fail the build when erlang is referenced,
205 # which can be achieved by using:
207 # disallowedReferences = [ erlang ];