beamPackages.buildRebar3: update to use extendMkDerivation and hooks

This commit is contained in:
Adam C. Stephens
2026-02-22 16:20:00 -05:00
parent 2fc6539b48
commit 405d11fcce
6 changed files with 115 additions and 114 deletions

View File

@@ -1,132 +1,85 @@
{
erlang,
beamCopySourceHook,
beamModuleInstallHook,
rebar3CompileHook,
rebar3WithPlugins,
rebarDevendorPatchHook,
libyaml,
openssl,
lib,
stdenv,
writeText,
erlang,
rebar3WithPlugins,
openssl,
libyaml,
lib,
}:
{
name,
version,
src,
setupHook ? null,
buildInputs ? [ ],
beamDeps ? [ ],
buildPlugins ? [ ],
postPatch ? "",
installPhase ? null,
buildPhase ? null,
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:
lib.extendMkDerivation {
constructDrv = stdenv.mkDerivation;
excludeDrvArgNames = [
"beamDeps"
"buildPlugins"
];
extendDrvArgs =
finalAttrs:
{
beamDeps ? [ ],
buildPlugins ? [ ],
let
rebar3 = rebar3WithPlugins {
plugins = buildPlugins;
};
enableDebugInfo ? false,
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,
...
}@args:
let
rebar3Custom = rebar3WithPlugins {
plugins = buildPlugins;
};
in
{
pname = args.name;
name = "erlang${erlang.version}-${args.name}-${finalAttrs.version}";
shell =
drv:
stdenv.mkDerivation {
name = "interactive-shell-${drv.name}";
buildInputs = [ drv ];
};
nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [
rebarDevendorPatchHook
beamCopySourceHook
beamModuleInstallHook
rebar3CompileHook
];
customPhases = lib.filterAttrs (_: v: v != null) {
inherit
setupHook
configurePhase
buildPhase
installPhase
;
};
buildInputs = (args.buildInputs or [ ]) ++ [
erlang
rebar3Custom
openssl
libyaml
];
pkg =
self:
stdenv.mkDerivation (
attrs
// {
pname = name;
name = "${name}-${version}";
inherit version;
buildInputs = buildInputs ++ [
erlang
rebar3
openssl
libyaml
];
propagatedBuildInputs = lib.unique beamDeps;
inherit src;
propagatedBuildInputs = lib.unique beamDeps;
env = {
ERL_COMPILER_OPTIONS =
let
options = erlangCompilerOptions ++ lib.optionals erlangDeterministicBuilds [ "deterministic" ];
in
"[${lib.concatStringsSep "," options}]";
# stripping does not have any effect on beam files
# it is however needed for dependencies with NIFs
# false is the default but we keep this for readability
dontStrip = false;
beamModuleName = args.name;
};
setupHook = writeText "setupHook.sh" ''
addToSearchPath ERL_LIBS "$1/lib/erlang/lib/"
'';
setupHook = writeText "setupHook.sh" ''
addToSearchPath ERL_LIBS "$1/lib/erlang/lib/"
'';
postPatch = ''
rm -f rebar rebar3
''
+ 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;
};
meta = {
inherit (erlang.meta) platforms;
}
// customPhases
);
in
lib.fix pkg
// (args.meta or { });
passthru = {
inherit beamDeps;
};
};
}

View File

@@ -105,6 +105,8 @@ let
mixBuildDirHook
mixCompileHook
mixAppConfigPatchHook
rebar3CompileHook
rebarDevendorPatchHook
;
};
in

View File

@@ -9,7 +9,15 @@ beamModuleInstallHook() {
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
# Some builds produce symlinks (eg: phoenix priv directory). They must
# be followed with -H flag.

View File

@@ -19,4 +19,12 @@
mixAppConfigPatchHook = makeSetupHook {
name = "mix-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;
}

View File

@@ -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)

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