various: avoid throwing for invalid platforms combinations in CI (#426645)

This commit is contained in:
Philip Taron
2025-07-20 15:23:40 -07:00
committed by GitHub
5 changed files with 293 additions and 267 deletions
@@ -1,4 +1,5 @@
{
config,
lib,
stdenv,
makeWrapper,
@@ -21,7 +22,7 @@ let
# some builds need that clarity.
#
ndkBuildInfoFun =
{ config, ... }:
fallback:
{
x86_64-apple-darwin = {
double = "darwin-x86_64";
@@ -30,10 +31,10 @@ let
double = "linux-x86_64";
};
}
.${config} or (throw "Android NDK doesn't support building on ${config}, as far as we know");
.${stdenv.buildPlatform.config} or fallback;
ndkTargetInfoFun =
{ config, ... }:
fallback:
{
i686-unknown-linux-android = {
triple = "i686-linux-android";
@@ -52,10 +53,14 @@ let
triple = "aarch64-linux-android";
};
}
.${config} or (throw "Android NDK doesn't support targetting ${config}, as far as we know");
.${stdenv.targetPlatform.config} or fallback;
buildInfo = ndkBuildInfoFun stdenv.buildPlatform;
targetInfo = ndkTargetInfoFun stdenv.targetPlatform;
buildInfo = ndkBuildInfoFun (
throw "Android NDK doesn't support building on ${stdenv.buildPlatform.config}, as far as we know"
);
targetInfo = ndkTargetInfoFun (
throw "Android NDK doesn't support targetting ${stdenv.targetPlatform.config}, as far as we know"
);
androidSdkVersion =
if
@@ -74,119 +79,123 @@ let
);
in
lib.recurseIntoAttrs rec {
# Misc tools
binaries = stdenv.mkDerivation {
pname = "${targetPrefix}ndk-toolchain";
inherit (androidndk) version;
nativeBuildInputs = [
makeWrapper
autoPatchelfHook
];
propagatedBuildInputs = [ androidndk ];
passthru = {
inherit targetPrefix;
isClang = true; # clang based cc, but bintools ld
inherit (llvmPackages.clang.cc) hardeningUnsupportedFlagsByTargetPlatform;
};
dontUnpack = true;
dontBuild = true;
dontStrip = true;
dontConfigure = true;
dontPatch = true;
autoPatchelfIgnoreMissingDeps = true;
installPhase = ''
# https://developer.android.com/ndk/guides/other_build_systems
mkdir -p $out
cp -r ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double} $out/toolchain
find $out/toolchain -type d -exec chmod 777 {} \;
if !config.allowAliases && (ndkBuildInfoFun null == null || ndkTargetInfoFun null == null) then
# Don't throw without aliases to not break CI.
null
else
lib.recurseIntoAttrs rec {
# Misc tools
binaries = stdenv.mkDerivation {
pname = "${targetPrefix}ndk-toolchain";
inherit (androidndk) version;
nativeBuildInputs = [
makeWrapper
autoPatchelfHook
];
propagatedBuildInputs = [ androidndk ];
passthru = {
inherit targetPrefix;
isClang = true; # clang based cc, but bintools ld
inherit (llvmPackages.clang.cc) hardeningUnsupportedFlagsByTargetPlatform;
};
dontUnpack = true;
dontBuild = true;
dontStrip = true;
dontConfigure = true;
dontPatch = true;
autoPatchelfIgnoreMissingDeps = true;
installPhase = ''
# https://developer.android.com/ndk/guides/other_build_systems
mkdir -p $out
cp -r ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double} $out/toolchain
find $out/toolchain -type d -exec chmod 777 {} \;
if [ ! -d $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion} ]; then
echo "NDK does not contain libraries for SDK version ${androidSdkVersion}";
if [ ! -d $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion} ]; then
echo "NDK does not contain libraries for SDK version ${androidSdkVersion}";
exit 1
fi
ln -vfs $out/toolchain/sysroot/usr/lib $out/lib
ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.so $out/lib/
ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.a $out/lib/
chmod +w $out/lib/*
ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}/*.so $out/lib/
ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}/*.o $out/lib/
echo "INPUT(-lc++_static)" > $out/lib/libc++.a
ln -s $out/toolchain/bin $out/bin
ln -s $out/toolchain/${targetInfo.triple}/bin/* $out/bin/
for f in $out/bin/${targetInfo.triple}-*; do
ln -s $f ''${f/${targetInfo.triple}-/${targetPrefix}}
done
for f in $(find $out/toolchain -type d -name ${targetInfo.triple}); do
ln -s $f ''${f/${targetInfo.triple}/${targetPrefix}}
done
rm -f $out/bin/${targetPrefix}ld
ln -s $out/bin/lld $out/bin/${targetPrefix}ld
(cd $out/bin;
for tool in llvm-*; do
ln -sf $tool ${targetPrefix}$(echo $tool | sed 's/llvm-//')
ln -sf $tool $(echo $tool | sed 's/llvm-//')
done)
ln -sf $out/bin/yasm $out/bin/${targetPrefix}as
ln -sf $out/bin/yasm $out/bin/as
patchShebangs $out/bin
'';
meta = {
description = "The Android NDK toolchain, tuned for other platforms";
license = with lib.licenses; [ unfree ];
teams = [ lib.teams.android ];
};
};
binutils = wrapBintoolsWith {
bintools = binaries;
libc = targetAndroidndkPkgs.libraries;
};
clang = wrapCCWith {
cc = binaries // {
# for packages expecting libcompiler-rt, etc. to come from here (stdenv.cc.cc.lib)
lib = targetAndroidndkPkgs.libraries;
};
bintools = binutils;
libc = targetAndroidndkPkgs.libraries;
extraBuildCommands = ''
echo "-D__ANDROID_API__=${stdenv.targetPlatform.androidSdkVersion}" >> $out/nix-support/cc-cflags
# Android needs executables linked with -pie since version 5.0
# Use -fPIC for compilation, and link with -pie if no -shared flag used in ldflags
echo "-target ${targetInfo.triple} -fPIC" >> $out/nix-support/cc-cflags
echo "-z,noexecstack -z,relro -z,now -z,muldefs" >> $out/nix-support/cc-ldflags
echo 'expandResponseParams "$@"' >> $out/nix-support/add-flags.sh
echo 'if [[ ! (" ''${params[@]} " =~ " -shared ") && ! (" ''${params[@]} " =~ " -no-pie ") ]]; then NIX_LDFLAGS_${suffixSalt}+=" -pie"; fi' >> $out/nix-support/add-flags.sh
echo "-Xclang -mnoexecstack" >> $out/nix-support/cc-cxxflags
if [ ${targetInfo.triple} == arm-linux-androideabi ]; then
# https://android.googlesource.com/platform/external/android-cmake/+/refs/heads/cmake-master-dev/android.toolchain.cmake
echo "--fix-cortex-a8" >> $out/nix-support/cc-ldflags
fi
'';
};
# Bionic lib C and other libraries.
#
# We use androidndk from the previous stage, else we waste time or get cycles
# cross-compiling packages to wrap incorrectly wrap binaries we don't include
# anyways.
libraries = runCommand "bionic-prebuilt" { } ''
lpath=${buildAndroidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double}/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}
if [ ! -d $lpath ]; then
echo "NDK does not contain libraries for SDK version ${androidSdkVersion} <$lpath>"
exit 1
fi
ln -vfs $out/toolchain/sysroot/usr/lib $out/lib
ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.so $out/lib/
ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.a $out/lib/
mkdir -p $out/lib
cp $lpath/*.so $lpath/*.a $out/lib
chmod +w $out/lib/*
ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}/*.so $out/lib/
ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}/*.o $out/lib/
echo "INPUT(-lc++_static)" > $out/lib/libc++.a
ln -s $out/toolchain/bin $out/bin
ln -s $out/toolchain/${targetInfo.triple}/bin/* $out/bin/
for f in $out/bin/${targetInfo.triple}-*; do
ln -s $f ''${f/${targetInfo.triple}-/${targetPrefix}}
done
for f in $(find $out/toolchain -type d -name ${targetInfo.triple}); do
ln -s $f ''${f/${targetInfo.triple}/${targetPrefix}}
done
rm -f $out/bin/${targetPrefix}ld
ln -s $out/bin/lld $out/bin/${targetPrefix}ld
(cd $out/bin;
for tool in llvm-*; do
ln -sf $tool ${targetPrefix}$(echo $tool | sed 's/llvm-//')
ln -sf $tool $(echo $tool | sed 's/llvm-//')
done)
ln -sf $out/bin/yasm $out/bin/${targetPrefix}as
ln -sf $out/bin/yasm $out/bin/as
patchShebangs $out/bin
cp $lpath/* $out/lib
'';
meta = {
description = "The Android NDK toolchain, tuned for other platforms";
license = with lib.licenses; [ unfree ];
teams = [ lib.teams.android ];
};
};
binutils = wrapBintoolsWith {
bintools = binaries;
libc = targetAndroidndkPkgs.libraries;
};
clang = wrapCCWith {
cc = binaries // {
# for packages expecting libcompiler-rt, etc. to come from here (stdenv.cc.cc.lib)
lib = targetAndroidndkPkgs.libraries;
};
bintools = binutils;
libc = targetAndroidndkPkgs.libraries;
extraBuildCommands = ''
echo "-D__ANDROID_API__=${stdenv.targetPlatform.androidSdkVersion}" >> $out/nix-support/cc-cflags
# Android needs executables linked with -pie since version 5.0
# Use -fPIC for compilation, and link with -pie if no -shared flag used in ldflags
echo "-target ${targetInfo.triple} -fPIC" >> $out/nix-support/cc-cflags
echo "-z,noexecstack -z,relro -z,now -z,muldefs" >> $out/nix-support/cc-ldflags
echo 'expandResponseParams "$@"' >> $out/nix-support/add-flags.sh
echo 'if [[ ! (" ''${params[@]} " =~ " -shared ") && ! (" ''${params[@]} " =~ " -no-pie ") ]]; then NIX_LDFLAGS_${suffixSalt}+=" -pie"; fi' >> $out/nix-support/add-flags.sh
echo "-Xclang -mnoexecstack" >> $out/nix-support/cc-cxxflags
if [ ${targetInfo.triple} == arm-linux-androideabi ]; then
# https://android.googlesource.com/platform/external/android-cmake/+/refs/heads/cmake-master-dev/android.toolchain.cmake
echo "--fix-cortex-a8" >> $out/nix-support/cc-ldflags
fi
'';
};
# Bionic lib C and other libraries.
#
# We use androidndk from the previous stage, else we waste time or get cycles
# cross-compiling packages to wrap incorrectly wrap binaries we don't include
# anyways.
libraries = runCommand "bionic-prebuilt" { } ''
lpath=${buildAndroidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double}/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}
if [ ! -d $lpath ]; then
echo "NDK does not contain libraries for SDK version ${androidSdkVersion} <$lpath>"
exit 1
fi
mkdir -p $out/lib
cp $lpath/*.so $lpath/*.a $out/lib
chmod +w $out/lib/*
cp $lpath/* $out/lib
'';
}
}
+1 -1
View File
@@ -24,7 +24,7 @@ let
majorVersion = lib.versions.major ndkVersion;
in
import ./androidndk-pkgs.nix {
inherit lib;
inherit config lib;
inherit (buildPackages)
makeWrapper
autoPatchelfHook
@@ -1,4 +1,5 @@
{
config,
lib,
stdenv,
fetchFromGitHub,
@@ -57,6 +58,8 @@ let
true
else
versionOlder (versions.major (getVersion erlang)) maxShiftMajor;
minAssert = versionAtLeast (getVersion erlang) minimumOTPVersion;
bothAssert = minAssert && maxAssert;
elixirShebang =
if stdenv.hostPlatform.isDarwin then
@@ -70,82 +73,84 @@ let
erlc_opts = [ "deterministic" ] ++ optionals debugInfo [ "debug_info" ];
in
assert assertMsg (versionAtLeast (getVersion erlang) minimumOTPVersion) compatibilityMsg;
assert assertMsg maxAssert compatibilityMsg;
if !config.allowAliases && !bothAssert then
# Don't throw without aliases to not break CI.
null
else
assert assertMsg bothAssert compatibilityMsg;
stdenv.mkDerivation {
pname = "${baseName}";
stdenv.mkDerivation {
pname = "${baseName}";
inherit src version debugInfo;
inherit src version debugInfo;
nativeBuildInputs = [ makeWrapper ];
buildInputs = [ erlang ];
nativeBuildInputs = [ makeWrapper ];
buildInputs = [ erlang ];
env = {
LANG = "C.UTF-8";
LC_TYPE = "C.UTF-8";
DESTDIR = placeholder "out";
PREFIX = "/";
ERL_COMPILER_OPTIONS = "[${concatStringsSep "," erlc_opts}]";
};
env = {
LANG = "C.UTF-8";
LC_TYPE = "C.UTF-8";
DESTDIR = placeholder "out";
PREFIX = "/";
ERL_COMPILER_OPTIONS = "[${concatStringsSep "," erlc_opts}]";
};
preBuild = ''
patchShebangs ${escriptPath} || true
'';
# copy stdlib source files for LSP access
postInstall = ''
for d in lib/*; do
cp -R "$d/lib" "$out/lib/elixir/$d"
done
'';
postFixup = ''
# Elixir binaries are shell scripts which run erl. Add some stuff
# to PATH so the scripts can run without problems.
for f in $out/bin/*; do
b=$(basename $f)
if [ "$b" = mix ]; then continue; fi
wrapProgram $f \
--prefix PATH ":" "${
lib.makeBinPath [
erlang
coreutils
curl
bash
]
}"
done
substituteInPlace $out/bin/mix \
--replace "/usr/bin/env elixir" "${elixirShebang}"
'';
passthru.updateScript = nix-update-script {
extraArgs = [
"--version-regex"
"v(${lib.versions.major version}\\.${lib.versions.minor version}\\.[0-9\\-rc.]+)"
"--override-filename"
"pkgs/development/interpreters/elixir/${lib.versions.major version}.${lib.versions.minor version}.nix"
];
};
pos = builtins.unsafeGetAttrPos "sha256" args;
meta = with lib; {
homepage = "https://elixir-lang.org/";
description = "Functional, meta-programming aware language built on top of the Erlang VM";
longDescription = ''
Elixir is a functional, meta-programming aware language built on
top of the Erlang VM. It is a dynamic language with flexible
syntax and macro support that leverages Erlang's abilities to
build concurrent, distributed and fault-tolerant applications
with hot code upgrades.
preBuild = ''
patchShebangs ${escriptPath} || true
'';
license = licenses.asl20;
platforms = platforms.unix;
teams = [ teams.beam ];
};
}
# copy stdlib source files for LSP access
postInstall = ''
for d in lib/*; do
cp -R "$d/lib" "$out/lib/elixir/$d"
done
'';
postFixup = ''
# Elixir binaries are shell scripts which run erl. Add some stuff
# to PATH so the scripts can run without problems.
for f in $out/bin/*; do
b=$(basename $f)
if [ "$b" = mix ]; then continue; fi
wrapProgram $f \
--prefix PATH ":" "${
lib.makeBinPath [
erlang
coreutils
curl
bash
]
}"
done
substituteInPlace $out/bin/mix \
--replace "/usr/bin/env elixir" "${elixirShebang}"
'';
passthru.updateScript = nix-update-script {
extraArgs = [
"--version-regex"
"v(${lib.versions.major version}\\.${lib.versions.minor version}\\.[0-9\\-rc.]+)"
"--override-filename"
"pkgs/development/interpreters/elixir/${lib.versions.major version}.${lib.versions.minor version}.nix"
];
};
pos = builtins.unsafeGetAttrPos "sha256" args;
meta = with lib; {
homepage = "https://elixir-lang.org/";
description = "Functional, meta-programming aware language built on top of the Erlang VM";
longDescription = ''
Elixir is a functional, meta-programming aware language built on
top of the Erlang VM. It is a dynamic language with flexible
syntax and macro support that leverages Erlang's abilities to
build concurrent, distributed and fault-tolerant applications
with hot code upgrades.
'';
license = licenses.asl20;
platforms = platforms.unix;
teams = [ teams.beam ];
};
}
@@ -1,4 +1,5 @@
{
config,
lib,
fetchFromGitHub,
erlang,
@@ -37,6 +38,8 @@ let
mainVersion = versions.major (getVersion erlang);
maxAssert = versionAtLeast maximumOTPVersion mainVersion;
proper = buildHex {
name = "proper";
version = "1.4.0";
@@ -45,82 +48,85 @@ let
};
in
assert (assertMsg (versionAtLeast maximumOTPVersion mainVersion)) ''
LFE ${version} is supported on OTP <=${maximumOTPVersion}, not ${mainVersion}.
'';
buildRebar3 {
name = baseName;
inherit src version;
nativeBuildInputs = [
makeWrapper
erlang
];
beamDeps = [ proper ];
patches = [
./fix-rebar-config.patch
./dedup-ebins.patch
] ++ patches;
doCheck = true;
checkTarget = "travis";
makeFlags = [
"-e"
"MANDB=''"
"PREFIX=$$out"
];
# These installPhase tricks are based on Elixir's Makefile.
# TODO: Make, upload, and apply a patch.
installPhase = optionalString (versionOlder version "1.3") ''
local libdir=$out/lib/lfe
local ebindir=$libdir/ebin
local bindir=$libdir/bin
rm -Rf $ebindir
install -m755 -d $ebindir
install -m644 _build/default/lib/lfe/ebin/* $ebindir
install -m755 -d $bindir
for bin in bin/lfe{,c,doc,script}; do install -m755 $bin $bindir; done
install -m755 -d $out/bin
for file in $bindir/*; do ln -sf $file $out/bin/; done
if !config.allowAliases && !maxAssert then
# Don't throw without aliases to not break CI.
null
else
assert assertMsg maxAssert ''
LFE ${version} is supported on OTP <=${maximumOTPVersion}, not ${mainVersion}.
'';
buildRebar3 {
name = baseName;
# Thanks again, Elixir.
postFixup = ''
# LFE binaries are shell scripts which run erl and lfe.
# Add some stuff to PATH so the scripts can run without problems.
for f in $out/bin/*; do
wrapProgram $f \
--prefix PATH ":" "${
makeBinPath [
erlang
coreutils
bash
]
}:$out/bin"
substituteInPlace $f --replace "/usr/bin/env" "${coreutils}/bin/env"
done
'';
inherit src version;
meta = with lib; {
description = "Best of Erlang and of Lisp; at the same time!";
longDescription = ''
LFE, Lisp Flavoured Erlang, is a lisp syntax front-end to the Erlang
compiler. Code produced with it is compatible with "normal" Erlang
code. An LFE evaluator and shell is also included.
nativeBuildInputs = [
makeWrapper
erlang
];
beamDeps = [ proper ];
patches = [
./fix-rebar-config.patch
./dedup-ebins.patch
] ++ patches;
doCheck = true;
checkTarget = "travis";
makeFlags = [
"-e"
"MANDB=''"
"PREFIX=$$out"
];
# These installPhase tricks are based on Elixir's Makefile.
# TODO: Make, upload, and apply a patch.
installPhase = optionalString (versionOlder version "1.3") ''
local libdir=$out/lib/lfe
local ebindir=$libdir/ebin
local bindir=$libdir/bin
rm -Rf $ebindir
install -m755 -d $ebindir
install -m644 _build/default/lib/lfe/ebin/* $ebindir
install -m755 -d $bindir
for bin in bin/lfe{,c,doc,script}; do install -m755 $bin $bindir; done
install -m755 -d $out/bin
for file in $bindir/*; do ln -sf $file $out/bin/; done
'';
homepage = "https://lfe.io";
downloadPage = "https://github.com/rvirding/lfe/releases";
# Thanks again, Elixir.
postFixup = ''
# LFE binaries are shell scripts which run erl and lfe.
# Add some stuff to PATH so the scripts can run without problems.
for f in $out/bin/*; do
wrapProgram $f \
--prefix PATH ":" "${
makeBinPath [
erlang
coreutils
bash
]
}:$out/bin"
substituteInPlace $f --replace "/usr/bin/env" "${coreutils}/bin/env"
done
'';
license = licenses.asl20;
teams = [ teams.beam ];
platforms = platforms.unix;
};
}
meta = with lib; {
description = "Best of Erlang and of Lisp; at the same time!";
longDescription = ''
LFE, Lisp Flavoured Erlang, is a lisp syntax front-end to the Erlang
compiler. Code produced with it is compatible with "normal" Erlang
code. An LFE evaluator and shell is also included.
'';
homepage = "https://lfe.io";
downloadPage = "https://github.com/rvirding/lfe/releases";
license = licenses.asl20;
teams = [ teams.beam ];
platforms = platforms.unix;
};
}
+9 -3
View File
@@ -5097,11 +5097,10 @@ with pkgs;
# The GCC used to build libc for the target platform. Normal gccs will be
# built with, and use, that cross-compiled libc.
gccWithoutTargetLibc =
assert stdenv.targetPlatform != stdenv.hostPlatform;
let
libc1 = binutilsNoLibc.libc;
in
wrapCCWith {
(wrapCCWith {
cc = gccFun {
# copy-pasted
inherit noSysDirs;
@@ -5127,7 +5126,14 @@ with pkgs;
bintools = binutilsNoLibc;
libc = libc1;
extraPackages = [ ];
};
}).overrideAttrs
(prevAttrs: {
meta = prevAttrs.meta // {
badPlatforms =
(prevAttrs.meta.badPlatforms or [ ])
++ lib.optionals (stdenv.targetPlatform == stdenv.hostPlatform) [ stdenv.hostPlatform.system ];
};
});
inherit (callPackage ../development/compilers/gcc/all.nix { inherit noSysDirs; })
gcc9