beamPackages.buildRebar3: update to use extendMkDerivation and hooks

This commit is contained in:
Adam C. Stephens
2026-02-23 21:48:59 -05:00
parent 2fc6539b48
commit 405d11fcce
6 changed files with 115 additions and 114 deletions
+66 -113
View File
@@ -1,132 +1,85 @@
{ {
erlang,
beamCopySourceHook,
beamModuleInstallHook,
rebar3CompileHook,
rebar3WithPlugins,
rebarDevendorPatchHook,
libyaml,
openssl,
lib,
stdenv, stdenv,
writeText, writeText,
erlang,
rebar3WithPlugins,
openssl,
libyaml,
lib,
}: }:
{ lib.extendMkDerivation {
name, constructDrv = stdenv.mkDerivation;
version, excludeDrvArgNames = [
src, "beamDeps"
setupHook ? null, "buildPlugins"
buildInputs ? [ ], ];
beamDeps ? [ ], extendDrvArgs =
buildPlugins ? [ ], finalAttrs:
postPatch ? "", {
installPhase ? null, beamDeps ? [ ],
buildPhase ? null, buildPlugins ? [ ],
configurePhase ? null,
meta ? { },
erlangCompilerOptions ? [ ],
# Deterministic Erlang builds remove full system paths from debug information
# among other things to keep builds more reproducible. See their docs for more:
# https://www.erlang.org/doc/man/compile
erlangDeterministicBuilds ? true,
...
}@attrs:
let enableDebugInfo ? false,
rebar3 = rebar3WithPlugins { erlangCompilerOptions ? [ ],
plugins = buildPlugins; # Deterministic Erlang builds remove full system paths from debug information
}; # among other things to keep builds more reproducible. See their docs for more:
# https://www.erlang.org/doc/man/compile
erlangDeterministicBuilds ? true,
...
}@args:
let
rebar3Custom = rebar3WithPlugins {
plugins = buildPlugins;
};
in
{
pname = args.name;
name = "erlang${erlang.version}-${args.name}-${finalAttrs.version}";
shell = nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [
drv: rebarDevendorPatchHook
stdenv.mkDerivation { beamCopySourceHook
name = "interactive-shell-${drv.name}"; beamModuleInstallHook
buildInputs = [ drv ]; rebar3CompileHook
}; ];
customPhases = lib.filterAttrs (_: v: v != null) { buildInputs = (args.buildInputs or [ ]) ++ [
inherit erlang
setupHook rebar3Custom
configurePhase openssl
buildPhase libyaml
installPhase ];
;
};
pkg = propagatedBuildInputs = lib.unique beamDeps;
self:
stdenv.mkDerivation (
attrs
// {
pname = name;
name = "${name}-${version}";
inherit version;
buildInputs = buildInputs ++ [
erlang
rebar3
openssl
libyaml
];
propagatedBuildInputs = lib.unique beamDeps;
inherit src;
env = {
ERL_COMPILER_OPTIONS = ERL_COMPILER_OPTIONS =
let let
options = erlangCompilerOptions ++ lib.optionals erlangDeterministicBuilds [ "deterministic" ]; options = erlangCompilerOptions ++ lib.optionals erlangDeterministicBuilds [ "deterministic" ];
in in
"[${lib.concatStringsSep "," options}]"; "[${lib.concatStringsSep "," options}]";
# stripping does not have any effect on beam files beamModuleName = args.name;
# it is however needed for dependencies with NIFs };
# false is the default but we keep this for readability
dontStrip = false;
setupHook = writeText "setupHook.sh" '' setupHook = writeText "setupHook.sh" ''
addToSearchPath ERL_LIBS "$1/lib/erlang/lib/" addToSearchPath ERL_LIBS "$1/lib/erlang/lib/"
''; '';
postPatch = '' meta = {
rm -f rebar rebar3 inherit (erlang.meta) platforms;
''
+ postPatch;
preConfigure = ''
# Copy the source so it can be used by mix projects
# do this before building to avoid build artifacts but after patching
# to include any modifications
mkdir -p $out/src
cp -r "." "$out/src"
'';
buildPhase = ''
runHook preBuild
HOME=. rebar3 bare compile --paths "."
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p "$out/lib/erlang/lib/${name}-${version}"
for reldir in src ebin priv include; do
[ -d "$reldir" ] || continue
# $out/lib/erlang/lib is a convention used in nixpkgs for compiled BEAM packages
cp -Hrt "$out/lib/erlang/lib/${name}-${version}" "$reldir"
done
runHook postInstall
'';
meta = {
inherit (erlang.meta) platforms;
}
// meta;
passthru = {
packageName = name;
env = shell self;
inherit beamDeps;
};
} }
// customPhases // (args.meta or { });
);
in passthru = {
lib.fix pkg inherit beamDeps;
};
};
}
@@ -105,6 +105,8 @@ let
mixBuildDirHook mixBuildDirHook
mixCompileHook mixCompileHook
mixAppConfigPatchHook mixAppConfigPatchHook
rebar3CompileHook
rebarDevendorPatchHook
; ;
}; };
in in
@@ -9,7 +9,15 @@ beamModuleInstallHook() {
mkdir -p "$out/lib/erlang/lib/${beamModuleName}-${version}" mkdir -p "$out/lib/erlang/lib/${beamModuleName}-${version}"
for reldir in _build/{$MIX_BUILD_PREFIX,shared}/lib/${beamModuleName}/{src,ebin,priv,include}; do # default to rebar3
local fromDir=(./{ebin,priv,include})
# replace if mix project
if [ -n "$MIX_BUILD_PREFIX" ]; then
fromDir=(_build/{$MIX_BUILD_PREFIX,shared}/lib/"${beamModuleName}"/{src,ebin,priv,include})
fi
for reldir in "${fromDir[@]}"; do
if test -d "$reldir"; then if test -d "$reldir"; then
# Some builds produce symlinks (eg: phoenix priv directory). They must # Some builds produce symlinks (eg: phoenix priv directory). They must
# be followed with -H flag. # be followed with -H flag.
@@ -19,4 +19,12 @@
mixAppConfigPatchHook = makeSetupHook { mixAppConfigPatchHook = makeSetupHook {
name = "mix-config-patch-hook.sh"; name = "mix-config-patch-hook.sh";
} ./mix-app-config-patch-hook.sh; } ./mix-app-config-patch-hook.sh;
rebar3CompileHook = makeSetupHook {
name = "rebar3-compile-hook.sh";
} ./rebar3-compile-hook.sh;
rebarDevendorPatchHook = makeSetupHook {
name = "rebar-devendor-patch-hook.sh";
} ./rebar-devendor-patch-hook.sh;
} }
@@ -0,0 +1,13 @@
# shellcheck shell=bash
#
# It's common to vendor a copy of rebar/rebar3 in repos, but we want to remove those
rebarDevendorPatchHook() {
echo "Executing rebarDevendorPatchHook"
rm -f rebar rebar
echo "Finished rebarDevendorPatchHook"
}
prePatchHooks+=(rebarDevendorPatchHook)
+17
View File
@@ -0,0 +1,17 @@
# shellcheck shell=bash
rebar3CompileHook() {
echo "Executing rebar3CompileHook"
runHook preBuild
HOME=. rebar3 bare compile --paths "."
runHook postBuild
echo "Finished rebar3CompileHook"
}
if [ -z "${dontRebar3Compile-}" ] && [ -z "${buildPhase-}" ]; then
buildPhase=rebar3CompileHook
fi