Merge pull request #2 from auxolotl/stdenv
This commit is contained in:
commit
4d829429ca
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
/result
|
result
|
||||||
|
result-*
|
||||||
|
|
28
default.nix
Normal file
28
default.nix
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
let requiredVersion = import ./lib/minver.nix; in
|
||||||
|
|
||||||
|
if ! builtins ? nixVersion || builtins.compareVersions requiredVersion builtins.nixVersion == 1 then
|
||||||
|
|
||||||
|
abort ''
|
||||||
|
|
||||||
|
This version of Nixpkgs requires Nix >= ${requiredVersion}, please upgrade:
|
||||||
|
|
||||||
|
- If you are running NixOS, `nixos-rebuild' can be used to upgrade your system.
|
||||||
|
|
||||||
|
- Alternatively, with Nix > 2.0 `nix upgrade-nix' can be used to imperatively
|
||||||
|
upgrade Nix. You may use `nix-env --version' to check which version you have.
|
||||||
|
|
||||||
|
- If you installed Nix using the install script (https://nixos.org/nix/install),
|
||||||
|
it is safe to upgrade by running it again:
|
||||||
|
|
||||||
|
curl -L https://nixos.org/nix/install | sh
|
||||||
|
|
||||||
|
For more information, please see the NixOS release notes at
|
||||||
|
https://nixos.org/nixos/manual or locally at
|
||||||
|
${toString ./nixos/doc/manual/release-notes}.
|
||||||
|
|
||||||
|
If you need further help, see https://nixos.org/nixos/support.html
|
||||||
|
''
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
import ./pkgs/top-level/impure.nix
|
10
flake.lock
10
flake.lock
|
@ -2,15 +2,15 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1714253743,
|
"lastModified": 1715447595,
|
||||||
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
|
"narHash": "sha256-VsVAUQOj/cS1LCOmMjAGeRksXIAdPnFIjCQ0XLkCsT0=",
|
||||||
"owner": "auxolotl",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
|
"rev": "062ca2a9370a27a35c524dc82d540e6e9824b652",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "auxolotl",
|
"owner": "nixos",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
|
|
35
flake.nix
35
flake.nix
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:auxolotl/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
|
@ -13,14 +13,39 @@
|
||||||
|
|
||||||
nixPackages = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
nixPackages = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
||||||
|
|
||||||
# auxPackages = forAllSystems (system:
|
auxPackages = forAllSystems (system:
|
||||||
# (import ./. { inherit system; })
|
(
|
||||||
# );
|
let requiredVersion = import ./lib/minver.nix; in
|
||||||
|
|
||||||
|
if ! builtins ? nixVersion || builtins.compareVersions requiredVersion builtins.nixVersion == 1 then
|
||||||
|
abort ''
|
||||||
|
This version of Nixpkgs requires Nix >= ${requiredVersion}, please upgrade:
|
||||||
|
|
||||||
|
- If you are running NixOS, `nixos-rebuild' can be used to upgrade your system.
|
||||||
|
|
||||||
|
- Alternatively, with Nix > 2.0 `nix upgrade-nix' can be used to imperatively
|
||||||
|
upgrade Nix. You may use `nix-env --version' to check which version you have.
|
||||||
|
|
||||||
|
- If you installed Nix using the install script (https://nixos.org/nix/install),
|
||||||
|
it is safe to upgrade by running it again:
|
||||||
|
|
||||||
|
curl -L https://nixos.org/nix/install | sh
|
||||||
|
|
||||||
|
For more information, please see the NixOS release notes at
|
||||||
|
https://nixos.org/nixos/manual or locally at
|
||||||
|
${toString ./nixos/doc/manual/release-notes}.
|
||||||
|
|
||||||
|
If you need further help, see https://nixos.org/nixos/support.html
|
||||||
|
''
|
||||||
|
else
|
||||||
|
import ./pkgs/top-level/default.nix { localSystem = system; }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
# To test, run nix build .#tests.x86_64-linux.release
|
# To test, run nix build .#tests.x86_64-linux.release
|
||||||
tests = forAllSystems (system: {
|
tests = forAllSystems (system: {
|
||||||
systems = import ./lib/tests/systems.nix;
|
systems = import ./lib/tests/systems.nix;
|
||||||
release = import ./lib/tests/release.nix { pkgs = self.nixPackages.${system}; };
|
release = import ./lib/tests/release.nix { pkgs = self.auxPackages.${system}; };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Don't test properties of pkgs.lib, but rather the lib in the parent directory
|
# Don't test properties of pkgs.lib, but rather the lib in the parent directory
|
||||||
pkgs ? import /etc/nix/inputs/nixpkgs {} // { lib = throw "pkgs.lib accessed, but the lib tests should use nixpkgs' lib path directly!"; },
|
pkgs ? import /etc/nix/inputs/nixpkgs {} // { lib = throw "pkgs.lib accessed, but the lib tests should use nixpkgs' lib path directly!"; },
|
||||||
nix ? pkgs-nixVersions.stable,
|
nix ? pkgs-nixVersions.stable,
|
||||||
nixVersions ? [ pkgs-nixVersions.minimum nix pkgs-nixVersions.unstable ],
|
nixVersions ? [ pkgs-nixVersions.minimum nix pkgs-nixVersions.latest ],
|
||||||
pkgs-nixVersions ? import ./nix-for-tests.nix { inherit pkgs; },
|
pkgs-nixVersions ? import ./nix-for-tests.nix { inherit pkgs; },
|
||||||
}:
|
}:
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
pkgs.runCommand "nixpkgs-lib-tests-nix-${nix.version}" {
|
pkgs.runCommand "nixpkgs-lib-tests-nix-${nix.version}" {
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
(import ./check-eval.nix)
|
(import ./check-eval.nix)
|
||||||
|
# FIXME: reimplement maintainers and teams
|
||||||
# (import ./maintainers.nix {
|
# (import ./maintainers.nix {
|
||||||
# inherit pkgs;
|
# inherit pkgs;
|
||||||
# lib = import ../.;
|
# lib = import ../.;
|
||||||
|
|
68
maintainers/maintainer-list.nix
Normal file
68
maintainers/maintainer-list.nix
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/* List of NixOS maintainers.
|
||||||
|
```nix
|
||||||
|
handle = {
|
||||||
|
# Required
|
||||||
|
name = "Your name";
|
||||||
|
|
||||||
|
# Optional, but at least one of email, matrix or githubId must be given
|
||||||
|
email = "address@example.org";
|
||||||
|
matrix = "@user:example.org";
|
||||||
|
github = "GithubUsername";
|
||||||
|
githubId = your-github-id;
|
||||||
|
|
||||||
|
keys = [{
|
||||||
|
fingerprint = "AAAA BBBB CCCC DDDD EEEE FFFF 0000 1111 2222 3333";
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
- `handle` is the handle you are going to use in nixpkgs expressions,
|
||||||
|
- `name` is a name that people would know and recognize you by,
|
||||||
|
- `email` is your maintainer email address,
|
||||||
|
- `matrix` is your Matrix user ID,
|
||||||
|
- `github` is your GitHub handle (as it appears in the URL of your profile page, `https://github.com/<userhandle>`),
|
||||||
|
- `githubId` is your GitHub user ID, which can be found at `https://api.github.com/users/<userhandle>`,
|
||||||
|
- `keys` is a list of your PGP/GPG key fingerprints.
|
||||||
|
|
||||||
|
Specifying a GitHub account ensures that you automatically:
|
||||||
|
- get invited to the @NixOS/nixpkgs-maintainers team ;
|
||||||
|
- once you are part of the @NixOS org, OfBorg will request you review
|
||||||
|
pull requests that modify a package for which you are a maintainer.
|
||||||
|
|
||||||
|
`handle == github` is strongly preferred whenever `github` is an acceptable attribute name and is short and convenient.
|
||||||
|
|
||||||
|
If `github` begins with a numeral, `handle` should be prefixed with an underscore.
|
||||||
|
```nix
|
||||||
|
_1example = {
|
||||||
|
github = "1example";
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Add PGP/GPG keys only if you actually use them to sign commits and/or mail.
|
||||||
|
|
||||||
|
To get the required PGP/GPG values for a key run
|
||||||
|
```shell
|
||||||
|
gpg --fingerprint <email> | head -n 2
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! Note that PGP/GPG values stored here are for informational purposes only, don't use this file as a source of truth.
|
||||||
|
|
||||||
|
More fields may be added in the future, however, in order to comply with GDPR this file should stay as minimal as possible.
|
||||||
|
|
||||||
|
When editing this file:
|
||||||
|
* keep the list alphabetically sorted, check with:
|
||||||
|
nix-instantiate --eval maintainers/scripts/check-maintainers-sorted.nix
|
||||||
|
* test the validity of the format with:
|
||||||
|
nix-build lib/tests/maintainers.nix
|
||||||
|
|
||||||
|
See `./scripts/check-maintainer-github-handles.sh` for an example on how to work with this data.
|
||||||
|
|
||||||
|
When adding a new maintainer, be aware of the current commit conventions
|
||||||
|
documented at [CONTRIBUTING.md](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#commit-conventions)
|
||||||
|
file located in the root of the Nixpkgs repo.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
48
maintainers/team-list.nix
Normal file
48
maintainers/team-list.nix
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* List of maintainer teams.
|
||||||
|
name = {
|
||||||
|
# Required
|
||||||
|
members = [ maintainer1 maintainer2 ];
|
||||||
|
scope = "Maintain foo packages.";
|
||||||
|
shortName = "foo";
|
||||||
|
# Optional
|
||||||
|
enableFeatureFreezePing = true;
|
||||||
|
githubTeams = [ "my-subsystem" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
- `members` is the list of maintainers belonging to the group,
|
||||||
|
- `scope` describes the scope of the group.
|
||||||
|
- `shortName` short human-readable name
|
||||||
|
- `enableFeatureFreezePing` will ping this team during the Feature Freeze announcements on releases
|
||||||
|
- There is limited mention capacity in a single post, so this should be reserved for critical components
|
||||||
|
or larger ecosystems within nixpkgs.
|
||||||
|
- `githubTeams` will ping specified GitHub teams as well
|
||||||
|
|
||||||
|
More fields may be added in the future.
|
||||||
|
|
||||||
|
When editing this file:
|
||||||
|
* keep the list alphabetically sorted
|
||||||
|
* test the validity of the format with:
|
||||||
|
nix-build lib/tests/teams.nix
|
||||||
|
*/
|
||||||
|
|
||||||
|
{ lib }:
|
||||||
|
with lib.maintainers; {
|
||||||
|
llvm = {
|
||||||
|
members = [];
|
||||||
|
scope = "Maintain LLVM package sets and related packages";
|
||||||
|
shortName = "LLVM";
|
||||||
|
enableFeatureFreezePing = true;
|
||||||
|
};
|
||||||
|
lix = {
|
||||||
|
members = [];
|
||||||
|
};
|
||||||
|
python = {
|
||||||
|
members = [];
|
||||||
|
};
|
||||||
|
rust = {
|
||||||
|
members = [];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
14
pkgs/build-support/add-driver-runpath/default.nix
Normal file
14
pkgs/build-support/add-driver-runpath/default.nix
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{ lib, stdenv }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "add-driver-runpath";
|
||||||
|
|
||||||
|
# Named "opengl-driver" for legacy reasons, but it is the path to
|
||||||
|
# hardware drivers installed by NixOS
|
||||||
|
driverLink = "/run/opengl-driver" + lib.optionalString stdenv.isi686 "-32";
|
||||||
|
|
||||||
|
buildCommand = ''
|
||||||
|
mkdir -p $out/nix-support
|
||||||
|
substituteAll ${./setup-hook.sh} $out/nix-support/setup-hook
|
||||||
|
'';
|
||||||
|
}
|
29
pkgs/build-support/add-driver-runpath/setup-hook.sh
Normal file
29
pkgs/build-support/add-driver-runpath/setup-hook.sh
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Set RUNPATH so that driver libraries in /run/opengl-driver(-32)/lib can be found.
|
||||||
|
# This is needed to not rely on LD_LIBRARY_PATH which does not work with setuid
|
||||||
|
# executables. Fixes https://github.com/NixOS/nixpkgs/issues/22760. It must be run
|
||||||
|
# in postFixup because RUNPATH stripping in fixup would undo it. Note that patchelf
|
||||||
|
# actually sets RUNPATH not RPATH, which applies only to dependencies of the binary
|
||||||
|
# it set on (including for dlopen), so the RUNPATH must indeed be set on these
|
||||||
|
# libraries and would not work if set only on executables.
|
||||||
|
addDriverRunpath() {
|
||||||
|
local forceRpath=
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--) shift; break;;
|
||||||
|
--force-rpath) shift; forceRpath=1;;
|
||||||
|
--*)
|
||||||
|
echo "addDriverRunpath: ERROR: Invalid command line" \
|
||||||
|
"argument: $1" >&2
|
||||||
|
return 1;;
|
||||||
|
*) break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
for file in "$@"; do
|
||||||
|
if ! isELF "$file"; then continue; fi
|
||||||
|
local origRpath="$(patchelf --print-rpath "$file")"
|
||||||
|
patchelf --set-rpath "@driverLink@/lib:$origRpath" ${forceRpath:+--force-rpath} "$file"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
12
pkgs/build-support/add-opengl-runpath/default.nix
Normal file
12
pkgs/build-support/add-opengl-runpath/default.nix
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{ lib, stdenv }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "add-opengl-runpath";
|
||||||
|
|
||||||
|
driverLink = "/run/opengl-driver" + lib.optionalString stdenv.isi686 "-32";
|
||||||
|
|
||||||
|
buildCommand = ''
|
||||||
|
mkdir -p $out/nix-support
|
||||||
|
substituteAll ${./setup-hook.sh} $out/nix-support/setup-hook
|
||||||
|
'';
|
||||||
|
}
|
29
pkgs/build-support/add-opengl-runpath/setup-hook.sh
Normal file
29
pkgs/build-support/add-opengl-runpath/setup-hook.sh
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Set RUNPATH so that driver libraries in /run/opengl-driver(-32)/lib can be found.
|
||||||
|
# This is needed to not rely on LD_LIBRARY_PATH which does not work with setuid
|
||||||
|
# executables. Fixes https://github.com/NixOS/nixpkgs/issues/22760. It must be run
|
||||||
|
# in postFixup because RUNPATH stripping in fixup would undo it. Note that patchelf
|
||||||
|
# actually sets RUNPATH not RPATH, which applies only to dependencies of the binary
|
||||||
|
# it set on (including for dlopen), so the RUNPATH must indeed be set on these
|
||||||
|
# libraries and would not work if set only on executables.
|
||||||
|
addOpenGLRunpath() {
|
||||||
|
local forceRpath=
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--) shift; break;;
|
||||||
|
--force-rpath) shift; forceRpath=1;;
|
||||||
|
--*)
|
||||||
|
echo "addOpenGLRunpath: ERROR: Invalid command line" \
|
||||||
|
"argument: $1" >&2
|
||||||
|
return 1;;
|
||||||
|
*) break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
for file in "$@"; do
|
||||||
|
if ! isELF "$file"; then continue; fi
|
||||||
|
local origRpath="$(patchelf --print-rpath "$file")"
|
||||||
|
patchelf --set-rpath "@driverLink@/lib:$origRpath" ${forceRpath:+--force-rpath} "$file"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
122
pkgs/build-support/agda/default.nix
Normal file
122
pkgs/build-support/agda/default.nix
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
# Builder for Agda packages.
|
||||||
|
|
||||||
|
{ stdenv, lib, self, Agda, runCommand, makeWrapper, writeText, ghcWithPackages, nixosTests }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
attrValues
|
||||||
|
elem
|
||||||
|
filter
|
||||||
|
filterAttrs
|
||||||
|
isAttrs
|
||||||
|
isList
|
||||||
|
platforms
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (lib.strings)
|
||||||
|
concatMapStrings
|
||||||
|
concatMapStringsSep
|
||||||
|
optionalString
|
||||||
|
;
|
||||||
|
|
||||||
|
withPackages' = {
|
||||||
|
pkgs,
|
||||||
|
ghc ? ghcWithPackages (p: with p; [ ieee754 ])
|
||||||
|
}: let
|
||||||
|
pkgs' = if isList pkgs then pkgs else pkgs self;
|
||||||
|
library-file = writeText "libraries" ''
|
||||||
|
${(concatMapStringsSep "\n" (p: "${p}/${p.libraryFile}") pkgs')}
|
||||||
|
'';
|
||||||
|
pname = "agdaWithPackages";
|
||||||
|
version = Agda.version;
|
||||||
|
in runCommand "${pname}-${version}" {
|
||||||
|
inherit pname version;
|
||||||
|
nativeBuildInputs = [ makeWrapper ];
|
||||||
|
passthru = {
|
||||||
|
unwrapped = Agda;
|
||||||
|
inherit withPackages;
|
||||||
|
tests = {
|
||||||
|
inherit (nixosTests) agda;
|
||||||
|
allPackages = withPackages (filter self.lib.isUnbrokenAgdaPackage (attrValues self));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# Agda is a split package with multiple outputs; do not inherit them here.
|
||||||
|
meta = removeAttrs Agda.meta [ "outputsToInstall" ];
|
||||||
|
} ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
makeWrapper ${Agda.bin}/bin/agda $out/bin/agda \
|
||||||
|
--add-flags "--with-compiler=${ghc}/bin/ghc" \
|
||||||
|
--add-flags "--library-file=${library-file}"
|
||||||
|
ln -s ${Agda.bin}/bin/agda-mode $out/bin/agda-mode
|
||||||
|
'';
|
||||||
|
|
||||||
|
withPackages = arg: if isAttrs arg then withPackages' arg else withPackages' { pkgs = arg; };
|
||||||
|
|
||||||
|
extensions = [
|
||||||
|
"agda"
|
||||||
|
"agda-lib"
|
||||||
|
"agdai"
|
||||||
|
"lagda"
|
||||||
|
"lagda.md"
|
||||||
|
"lagda.org"
|
||||||
|
"lagda.rst"
|
||||||
|
"lagda.tex"
|
||||||
|
"lagda.typ"
|
||||||
|
];
|
||||||
|
|
||||||
|
defaults =
|
||||||
|
{ pname
|
||||||
|
, meta
|
||||||
|
, buildInputs ? []
|
||||||
|
, everythingFile ? "./Everything.agda"
|
||||||
|
, includePaths ? []
|
||||||
|
, libraryName ? pname
|
||||||
|
, libraryFile ? "${libraryName}.agda-lib"
|
||||||
|
, buildPhase ? null
|
||||||
|
, installPhase ? null
|
||||||
|
, extraExtensions ? []
|
||||||
|
, ...
|
||||||
|
}: let
|
||||||
|
agdaWithArgs = withPackages (filter (p: p ? isAgdaDerivation) buildInputs);
|
||||||
|
includePathArgs = concatMapStrings (path: "-i" + path + " ") (includePaths ++ [(dirOf everythingFile)]);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit libraryName libraryFile;
|
||||||
|
|
||||||
|
isAgdaDerivation = true;
|
||||||
|
|
||||||
|
buildInputs = buildInputs ++ [ agdaWithArgs ];
|
||||||
|
|
||||||
|
buildPhase = if buildPhase != null then buildPhase else ''
|
||||||
|
runHook preBuild
|
||||||
|
agda ${includePathArgs} ${everythingFile}
|
||||||
|
rm ${everythingFile} ${lib.interfaceFile Agda.version everythingFile}
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = if installPhase != null then installPhase else ''
|
||||||
|
runHook preInstall
|
||||||
|
mkdir -p $out
|
||||||
|
find \( ${concatMapStringsSep " -or " (p: "-name '*.${p}'") (extensions ++ extraExtensions)} \) -exec cp -p --parents -t "$out" {} +
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
# As documented at https://github.com/NixOS/nixpkgs/issues/172752,
|
||||||
|
# we need to set LC_ALL to an UTF-8-supporting locale. However, on
|
||||||
|
# darwin, it seems that there is no standard such locale; luckily,
|
||||||
|
# the referenced issue doesn't seem to surface on darwin. Hence let's
|
||||||
|
# set this only on non-darwin.
|
||||||
|
LC_ALL = optionalString (!stdenv.isDarwin) "C.UTF-8";
|
||||||
|
|
||||||
|
meta = if meta.broken or false then meta // { hydraPlatforms = platforms.none; } else meta;
|
||||||
|
|
||||||
|
# Retrieve all packages from the finished package set that have the current package as a dependency and build them
|
||||||
|
passthru.tests =
|
||||||
|
filterAttrs (name: pkg: self.lib.isUnbrokenAgdaPackage pkg && elem pname (map (pkg: pkg.pname) pkg.buildInputs)) self;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
mkDerivation = args: stdenv.mkDerivation (args // defaults args);
|
||||||
|
|
||||||
|
inherit withPackages withPackages';
|
||||||
|
}
|
17
pkgs/build-support/agda/lib.nix
Normal file
17
pkgs/build-support/agda/lib.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{ lib }:
|
||||||
|
{
|
||||||
|
/* Returns the Agda interface file to a given Agda file.
|
||||||
|
*
|
||||||
|
* The resulting path may not be normalized.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* interfaceFile pkgs.agda.version "./Everything.agda" == "_build/2.6.4.3/agda/./Everything.agdai"
|
||||||
|
* interfaceFile pkgs.agda.version "src/Everything.lagda.tex" == "_build/2.6.4.3/agda/src/Everything.agdai"
|
||||||
|
*/
|
||||||
|
interfaceFile = agdaVersion: agdaFile: "_build/" + agdaVersion + "/agda/" + lib.head (builtins.match ''(.*\.)l?agda(\.(md|org|rst|tex|typ))?'' agdaFile) + "agdai";
|
||||||
|
|
||||||
|
/* Takes an arbitrary derivation and says whether it is an agda library package
|
||||||
|
* that is not marked as broken.
|
||||||
|
*/
|
||||||
|
isUnbrokenAgdaPackage = pkg: pkg.isAgdaDerivation or false && !pkg.meta.broken;
|
||||||
|
}
|
143
pkgs/build-support/alternatives/blas/default.nix
Normal file
143
pkgs/build-support/alternatives/blas/default.nix
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
{ lib, stdenv
|
||||||
|
, lapack-reference, openblas
|
||||||
|
, isILP64 ? false
|
||||||
|
, blasProvider ? openblas }:
|
||||||
|
|
||||||
|
let
|
||||||
|
blasFortranSymbols = [
|
||||||
|
"caxpy" "ccopy" "cdotc" "cdotu" "cgbmv" "cgemm" "cgemv" "cgerc" "cgeru"
|
||||||
|
"chbmv" "chemm" "chemv" "cher" "cher2" "cher2k" "cherk" "chpmv" "chpr"
|
||||||
|
"chpr2" "crotg" "cscal" "csrot" "csscal" "cswap" "csymm" "csyr2k" "csyrk"
|
||||||
|
"ctbmv" "ctbsv" "ctpmv" "ctpsv" "ctrmm" "ctrmv" "ctrsm" "ctrsv" "dasum"
|
||||||
|
"daxpy" "dcabs1" "dcopy" "ddot" "dgbmv" "dgemm" "dgemv" "dger" "dnrm2"
|
||||||
|
"drot" "drotg" "drotm" "drotmg" "dsbmv" "dscal" "dsdot" "dspmv" "dspr"
|
||||||
|
"dspr2" "dswap" "dsymm" "dsymv" "dsyr" "dsyr2" "dsyr2k" "dsyrk" "dtbmv"
|
||||||
|
"dtbsv" "dtpmv" "dtpsv" "dtrmm" "dtrmv" "dtrsm" "dtrsv" "dzasum" "dznrm2"
|
||||||
|
"icamax" "idamax" "isamax" "izamax" "lsame" "sasum" "saxpy" "scabs1"
|
||||||
|
"scasum" "scnrm2" "scopy" "sdot" "sdsdot" "sgbmv" "sgemm" "sgemv"
|
||||||
|
"sger" "snrm2" "srot" "srotg" "srotm" "srotmg" "ssbmv" "sscal" "sspmv"
|
||||||
|
"sspr" "sspr2" "sswap" "ssymm" "ssymv" "ssyr" "ssyr2" "ssyr2k" "ssyrk"
|
||||||
|
"stbmv" "stbsv" "stpmv" "stpsv" "strmm" "strmv" "strsm" "strsv" "xerbla"
|
||||||
|
"xerbla_array" "zaxpy" "zcopy" "zdotc" "zdotu" "zdrot" "zdscal" "zgbmv"
|
||||||
|
"zgemm" "zgemv" "zgerc" "zgeru" "zhbmv" "zhemm" "zhemv" "zher" "zher2"
|
||||||
|
"zher2k" "zherk" "zhpmv" "zhpr" "zhpr2" "zrotg" "zscal" "zswap" "zsymm"
|
||||||
|
"zsyr2k" "zsyrk" "ztbmv" "ztbsv" "ztpmv" "ztpsv" "ztrmm" "ztrmv" "ztrsm"
|
||||||
|
"ztrsv"
|
||||||
|
];
|
||||||
|
|
||||||
|
version = "3";
|
||||||
|
canonicalExtension = if stdenv.hostPlatform.isLinux
|
||||||
|
then "${stdenv.hostPlatform.extensions.sharedLibrary}.${version}"
|
||||||
|
else stdenv.hostPlatform.extensions.sharedLibrary;
|
||||||
|
|
||||||
|
|
||||||
|
blasImplementation = lib.getName blasProvider;
|
||||||
|
blasProvider' = if blasImplementation == "mkl"
|
||||||
|
then blasProvider
|
||||||
|
else blasProvider.override { blas64 = isILP64; };
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
assert isILP64 -> blasImplementation == "mkl" || blasProvider'.blas64;
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "blas";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
outputs = [ "out" "dev" ];
|
||||||
|
|
||||||
|
meta = (blasProvider'.meta or {}) // {
|
||||||
|
description = "${lib.getName blasProvider} with just the BLAS C and FORTRAN ABI";
|
||||||
|
};
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
inherit isILP64;
|
||||||
|
provider = blasProvider';
|
||||||
|
implementation = blasImplementation;
|
||||||
|
};
|
||||||
|
|
||||||
|
dontBuild = true;
|
||||||
|
dontConfigure = true;
|
||||||
|
unpackPhase = "src=$PWD";
|
||||||
|
|
||||||
|
dontPatchELF = true;
|
||||||
|
|
||||||
|
installPhase = (''
|
||||||
|
mkdir -p $out/lib $dev/include $dev/lib/pkgconfig
|
||||||
|
|
||||||
|
libblas="${lib.getLib blasProvider'}/lib/libblas${canonicalExtension}"
|
||||||
|
|
||||||
|
if ! [ -e "$libblas" ]; then
|
||||||
|
echo "$libblas does not exist, ${blasProvider'.name} does not provide libblas."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$NM -an "$libblas" | cut -f3 -d' ' > symbols
|
||||||
|
for symbol in ${toString blasFortranSymbols}; do
|
||||||
|
grep -q "^$symbol_$" symbols || { echo "$symbol" was not found in "$libblas"; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
cp -L "$libblas" $out/lib/libblas${canonicalExtension}
|
||||||
|
chmod +w $out/lib/libblas${canonicalExtension}
|
||||||
|
|
||||||
|
'' + (if stdenv.hostPlatform.isElf then ''
|
||||||
|
patchelf --set-soname libblas${canonicalExtension} $out/lib/libblas${canonicalExtension}
|
||||||
|
patchelf --set-rpath "$(patchelf --print-rpath $out/lib/libblas${canonicalExtension}):${lib.getLib blasProvider'}/lib" $out/lib/libblas${canonicalExtension}
|
||||||
|
'' else lib.optionalString (stdenv.hostPlatform.isDarwin) ''
|
||||||
|
install_name_tool \
|
||||||
|
-id $out/lib/libblas${canonicalExtension} \
|
||||||
|
-add_rpath ${lib.getLib blasProvider'}/lib \
|
||||||
|
$out/lib/libblas${canonicalExtension}
|
||||||
|
'') + ''
|
||||||
|
|
||||||
|
if [ "$out/lib/libblas${canonicalExtension}" != "$out/lib/libblas${stdenv.hostPlatform.extensions.sharedLibrary}" ]; then
|
||||||
|
ln -s $out/lib/libblas${canonicalExtension} "$out/lib/libblas${stdenv.hostPlatform.extensions.sharedLibrary}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<EOF > $dev/lib/pkgconfig/blas.pc
|
||||||
|
Name: blas
|
||||||
|
Version: ${version}
|
||||||
|
Description: BLAS FORTRAN implementation
|
||||||
|
Libs: -L$out/lib -lblas
|
||||||
|
Cflags: -I$dev/include
|
||||||
|
EOF
|
||||||
|
|
||||||
|
libcblas="${lib.getLib blasProvider'}/lib/libcblas${canonicalExtension}"
|
||||||
|
|
||||||
|
if ! [ -e "$libcblas" ]; then
|
||||||
|
echo "$libcblas does not exist, ${blasProvider'.name} does not provide libcblas."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -L "$libcblas" $out/lib/libcblas${canonicalExtension}
|
||||||
|
chmod +w $out/lib/libcblas${canonicalExtension}
|
||||||
|
|
||||||
|
'' + (if stdenv.hostPlatform.isElf then ''
|
||||||
|
patchelf --set-soname libcblas${canonicalExtension} $out/lib/libcblas${canonicalExtension}
|
||||||
|
patchelf --set-rpath "$(patchelf --print-rpath $out/lib/libcblas${canonicalExtension}):${lib.getLib blasProvider'}/lib" $out/lib/libcblas${canonicalExtension}
|
||||||
|
'' else lib.optionalString stdenv.hostPlatform.isDarwin ''
|
||||||
|
install_name_tool \
|
||||||
|
-id $out/lib/libcblas${canonicalExtension} \
|
||||||
|
-add_rpath ${lib.getLib blasProvider'}/lib \
|
||||||
|
$out/lib/libcblas${canonicalExtension}
|
||||||
|
'') + ''
|
||||||
|
if [ "$out/lib/libcblas${canonicalExtension}" != "$out/lib/libcblas${stdenv.hostPlatform.extensions.sharedLibrary}" ]; then
|
||||||
|
ln -s $out/lib/libcblas${canonicalExtension} "$out/lib/libcblas${stdenv.hostPlatform.extensions.sharedLibrary}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp ${lib.getDev lapack-reference}/include/cblas{,_mangling}.h $dev/include
|
||||||
|
|
||||||
|
cat <<EOF > $dev/lib/pkgconfig/cblas.pc
|
||||||
|
Name: cblas
|
||||||
|
Version: ${version}
|
||||||
|
Description: BLAS C implementation
|
||||||
|
Cflags: -I$dev/include
|
||||||
|
Libs: -L$out/lib -lcblas
|
||||||
|
EOF
|
||||||
|
'' + lib.optionalString (blasImplementation == "mkl") ''
|
||||||
|
mkdir -p $out/nix-support
|
||||||
|
echo 'export MKL_INTERFACE_LAYER=${lib.optionalString isILP64 "I"}LP64,GNU' > $out/nix-support/setup-hook
|
||||||
|
ln -s $out/lib/libblas${canonicalExtension} $out/lib/libmkl_rt${stdenv.hostPlatform.extensions.sharedLibrary}
|
||||||
|
ln -sf ${blasProvider'}/include/* $dev/include
|
||||||
|
'');
|
||||||
|
}
|
113
pkgs/build-support/alternatives/lapack/default.nix
Normal file
113
pkgs/build-support/alternatives/lapack/default.nix
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
{ lib, stdenv
|
||||||
|
, lapack-reference, openblas
|
||||||
|
, isILP64 ? false
|
||||||
|
, lapackProvider ? openblas }:
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
version = "3";
|
||||||
|
canonicalExtension = if stdenv.hostPlatform.isLinux
|
||||||
|
then "${stdenv.hostPlatform.extensions.sharedLibrary}.${version}"
|
||||||
|
else stdenv.hostPlatform.extensions.sharedLibrary;
|
||||||
|
|
||||||
|
lapackImplementation = lib.getName lapackProvider;
|
||||||
|
lapackProvider' = if lapackImplementation == "mkl"
|
||||||
|
then lapackProvider
|
||||||
|
else lapackProvider.override { blas64 = isILP64; };
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
assert isILP64 -> lapackImplementation == "mkl" || lapackProvider'.blas64;
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "lapack";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
outputs = [ "out" "dev" ];
|
||||||
|
|
||||||
|
meta = (lapackProvider'.meta or {}) // {
|
||||||
|
description = "${lib.getName lapackProvider'} with just the LAPACK C and FORTRAN ABI";
|
||||||
|
};
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
inherit isILP64;
|
||||||
|
provider = lapackProvider';
|
||||||
|
implementation = lapackImplementation;
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: drop this forced rebuild, as it was needed just once.
|
||||||
|
rebuild_salt = if stdenv.isDarwin && stdenv.isx86_64 then "J4AQ" else null;
|
||||||
|
|
||||||
|
dontBuild = true;
|
||||||
|
dontConfigure = true;
|
||||||
|
unpackPhase = "src=$PWD";
|
||||||
|
|
||||||
|
dontPatchELF = true;
|
||||||
|
|
||||||
|
installPhase = (''
|
||||||
|
mkdir -p $out/lib $dev/include $dev/lib/pkgconfig
|
||||||
|
|
||||||
|
liblapack="${lib.getLib lapackProvider'}/lib/liblapack${canonicalExtension}"
|
||||||
|
|
||||||
|
if ! [ -e "$liblapack" ]; then
|
||||||
|
echo "$liblapack does not exist, ${lapackProvider'.name} does not provide liblapack."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -L "$liblapack" $out/lib/liblapack${canonicalExtension}
|
||||||
|
chmod +w $out/lib/liblapack${canonicalExtension}
|
||||||
|
|
||||||
|
'' + (lib.optionalString stdenv.hostPlatform.isElf ''
|
||||||
|
patchelf --set-soname liblapack${canonicalExtension} $out/lib/liblapack${canonicalExtension}
|
||||||
|
patchelf --set-rpath "$(patchelf --print-rpath $out/lib/liblapack${canonicalExtension}):${lapackProvider'}/lib" $out/lib/liblapack${canonicalExtension}
|
||||||
|
'') + ''
|
||||||
|
|
||||||
|
if [ "$out/lib/liblapack${canonicalExtension}" != "$out/lib/liblapack${stdenv.hostPlatform.extensions.sharedLibrary}" ]; then
|
||||||
|
ln -s $out/lib/liblapack${canonicalExtension} "$out/lib/liblapack${stdenv.hostPlatform.extensions.sharedLibrary}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -D ${lib.getDev lapack-reference}/include/lapack.h $dev/include/lapack.h
|
||||||
|
|
||||||
|
cat <<EOF > $dev/lib/pkgconfig/lapack.pc
|
||||||
|
Name: lapack
|
||||||
|
Version: ${version}
|
||||||
|
Description: LAPACK FORTRAN implementation
|
||||||
|
Cflags: -I$dev/include
|
||||||
|
Libs: -L$out/lib -llapack
|
||||||
|
EOF
|
||||||
|
|
||||||
|
liblapacke="${lib.getLib lapackProvider'}/lib/liblapacke${canonicalExtension}"
|
||||||
|
|
||||||
|
if ! [ -e "$liblapacke" ]; then
|
||||||
|
echo "$liblapacke does not exist, ${lapackProvider'.name} does not provide liblapacke."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -L "$liblapacke" $out/lib/liblapacke${canonicalExtension}
|
||||||
|
chmod +w $out/lib/liblapacke${canonicalExtension}
|
||||||
|
|
||||||
|
'' + (lib.optionalString stdenv.hostPlatform.isElf ''
|
||||||
|
patchelf --set-soname liblapacke${canonicalExtension} $out/lib/liblapacke${canonicalExtension}
|
||||||
|
patchelf --set-rpath "$(patchelf --print-rpath $out/lib/liblapacke${canonicalExtension}):${lib.getLib lapackProvider'}/lib" $out/lib/liblapacke${canonicalExtension}
|
||||||
|
'') + ''
|
||||||
|
|
||||||
|
if [ -f "$out/lib/liblapacke.so.3" ]; then
|
||||||
|
ln -s $out/lib/liblapacke.so.3 $out/lib/liblapacke.so
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp ${lib.getDev lapack-reference}/include/lapacke{,_mangling,_config,_utils}.h $dev/include
|
||||||
|
|
||||||
|
cat <<EOF > $dev/lib/pkgconfig/lapacke.pc
|
||||||
|
Name: lapacke
|
||||||
|
Version: ${version}
|
||||||
|
Description: LAPACK C implementation
|
||||||
|
Cflags: -I$dev/include
|
||||||
|
Libs: -L$out/lib -llapacke
|
||||||
|
EOF
|
||||||
|
'' + lib.optionalString (lapackImplementation == "mkl") ''
|
||||||
|
mkdir -p $out/nix-support
|
||||||
|
echo 'export MKL_INTERFACE_LAYER=${lib.optionalString isILP64 "I"}LP64,GNU' > $out/nix-support/setup-hook
|
||||||
|
ln -s $out/lib/liblapack${canonicalExtension} $out/lib/libmkl_rt${stdenv.hostPlatform.extensions.sharedLibrary}
|
||||||
|
ln -sf ${lapackProvider'}/include/* $dev/include
|
||||||
|
'');
|
||||||
|
}
|
145
pkgs/build-support/appimage/appimage-exec.sh
Executable file
145
pkgs/build-support/appimage/appimage-exec.sh
Executable file
|
@ -0,0 +1,145 @@
|
||||||
|
#!@shell@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
if [ -n "$DEBUG" ] ; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
PATH="@path@:$PATH"
|
||||||
|
apprun_opt=true
|
||||||
|
OWD=$(readlink -f .)
|
||||||
|
# can be read by appimages: https://docs.appimage.org/packaging-guide/environment-variables.html
|
||||||
|
export OWD
|
||||||
|
|
||||||
|
# src : AppImage
|
||||||
|
# dest : let's unpack() create the directory
|
||||||
|
unpack() {
|
||||||
|
local src="$1"
|
||||||
|
local out="$2"
|
||||||
|
|
||||||
|
# https://github.com/AppImage/libappimage/blob/ca8d4b53bed5cbc0f3d0398e30806e0d3adeaaab/src/libappimage/utils/MagicBytesChecker.cpp#L45-L63
|
||||||
|
local appimageSignature;
|
||||||
|
appimageSignature="$(LC_ALL=C readelf -h "$src" | awk 'NR==2{print $10$11;}')"
|
||||||
|
local appimageType;
|
||||||
|
appimageType="$(LC_ALL=C readelf -h "$src" | awk 'NR==2{print $12;}')"
|
||||||
|
|
||||||
|
# check AppImage signature
|
||||||
|
if [ "$appimageSignature" != "4149" ]; then
|
||||||
|
echo "Not an AppImage file"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$appimageType" in
|
||||||
|
"01")
|
||||||
|
echo "Uncompress $(basename "$src") of type $appimageType"
|
||||||
|
mkdir "$out"
|
||||||
|
pv "$src" | bsdtar -x -C "$out" -f -
|
||||||
|
;;
|
||||||
|
|
||||||
|
"02")
|
||||||
|
# This method avoid issues with non executable appimages,
|
||||||
|
# non-native packer, packer patching and squashfs-root destination prefix.
|
||||||
|
|
||||||
|
# multiarch offset one-liner using same method as AppImage
|
||||||
|
# see https://gist.github.com/probonopd/a490ba3401b5ef7b881d5e603fa20c93
|
||||||
|
offset=$(LC_ALL=C readelf -h "$src" | awk 'NR==13{e_shoff=$5} NR==18{e_shentsize=$5} NR==19{e_shnum=$5} END{print e_shoff+e_shentsize*e_shnum}')
|
||||||
|
echo "Uncompress $(basename "$src") of type $appimageType @ offset $offset"
|
||||||
|
unsquashfs -q -d "$out" -o "$offset" "$src"
|
||||||
|
chmod go-w "$out"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# "03")
|
||||||
|
# get ready, https://github.com/TheAssassin/type3-runtime
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo Unsupported AppImage Type: "$appimageType"
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "$(basename "$src") is now installed in $out"
|
||||||
|
}
|
||||||
|
|
||||||
|
apprun() {
|
||||||
|
|
||||||
|
SHA256=$(sha256sum "$APPIMAGE" | awk '{print $1}')
|
||||||
|
export APPDIR="${XDG_CACHE_HOME:-$HOME/.cache}/appimage-run/$SHA256"
|
||||||
|
|
||||||
|
#compatibility
|
||||||
|
if [ -x "$APPDIR/squashfs-root" ]; then APPDIR="$APPDIR/squashfs-root"; fi
|
||||||
|
|
||||||
|
if [ ! -x "$APPDIR" ]; then
|
||||||
|
mkdir -p "$(dirname "$APPDIR")"
|
||||||
|
unpack "$APPIMAGE" "$APPDIR"
|
||||||
|
else echo "$(basename "$APPIMAGE")" installed in "$APPDIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export PATH="$PATH:$PWD/usr/bin"
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap() {
|
||||||
|
|
||||||
|
# quite same in appimageTools
|
||||||
|
export APPIMAGE_SILENT_INSTALL=1
|
||||||
|
|
||||||
|
if [ -n "$APPIMAGE_DEBUG_EXEC" ]; then
|
||||||
|
cd "$APPDIR" || true
|
||||||
|
exec "$APPIMAGE_DEBUG_EXEC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$APPDIR/AppRun" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: appimage-run [appimage-run options] <AppImage> [AppImage options]
|
||||||
|
|
||||||
|
-h show this message
|
||||||
|
-d debug mode
|
||||||
|
-x <directory> : extract appimage in the directory then exit.
|
||||||
|
-w <directory> : run uncompressed appimage directory (used in appimageTools)
|
||||||
|
|
||||||
|
[AppImage options]: Options are passed on to the appimage.
|
||||||
|
If you want to execute a custom command in the appimage's environment, set the APPIMAGE_DEBUG_EXEC environment variable.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
while getopts "x:w:dh" option; do
|
||||||
|
case "${option}" in
|
||||||
|
d) set -x
|
||||||
|
;;
|
||||||
|
x) # eXtract
|
||||||
|
unpack_opt=true
|
||||||
|
APPDIR=${OPTARG}
|
||||||
|
;;
|
||||||
|
w) # WrapAppImage
|
||||||
|
export APPDIR=${OPTARG}
|
||||||
|
wrap_opt=true
|
||||||
|
;;
|
||||||
|
h) usage
|
||||||
|
;;
|
||||||
|
*) usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
|
if [ -n "$wrap_opt" ] && [ -d "$APPDIR" ]; then
|
||||||
|
wrap "$@"
|
||||||
|
exit
|
||||||
|
else
|
||||||
|
APPIMAGE="$(realpath "$1")" || usage
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$unpack_opt" ] && [ -f "$APPIMAGE" ]; then
|
||||||
|
unpack "$APPIMAGE" "$APPDIR"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$apprun_opt" ] && [ -f "$APPIMAGE" ]; then
|
||||||
|
apprun
|
||||||
|
wrap "$@"
|
||||||
|
exit
|
||||||
|
fi
|
210
pkgs/build-support/appimage/default.nix
Normal file
210
pkgs/build-support/appimage/default.nix
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
{ lib
|
||||||
|
, bash
|
||||||
|
, binutils-unwrapped
|
||||||
|
, coreutils
|
||||||
|
, gawk
|
||||||
|
, libarchive
|
||||||
|
, pv
|
||||||
|
, squashfsTools
|
||||||
|
, buildFHSEnv
|
||||||
|
, pkgs
|
||||||
|
}:
|
||||||
|
|
||||||
|
rec {
|
||||||
|
appimage-exec = pkgs.substituteAll {
|
||||||
|
src = ./appimage-exec.sh;
|
||||||
|
isExecutable = true;
|
||||||
|
dir = "bin";
|
||||||
|
path = lib.makeBinPath [
|
||||||
|
bash
|
||||||
|
binutils-unwrapped
|
||||||
|
coreutils
|
||||||
|
gawk
|
||||||
|
libarchive
|
||||||
|
pv
|
||||||
|
squashfsTools
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
extract = args@{ name ? "${args.pname}-${args.version}", postExtract ? "", src, ... }: pkgs.runCommand "${name}-extracted" {
|
||||||
|
buildInputs = [ appimage-exec ];
|
||||||
|
} ''
|
||||||
|
appimage-exec.sh -x $out ${src}
|
||||||
|
${postExtract}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# for compatibility, deprecated
|
||||||
|
extractType1 = extract;
|
||||||
|
extractType2 = extract;
|
||||||
|
wrapType1 = wrapType2;
|
||||||
|
|
||||||
|
wrapAppImage = args@{
|
||||||
|
src,
|
||||||
|
extraPkgs,
|
||||||
|
meta ? {},
|
||||||
|
...
|
||||||
|
}: buildFHSEnv
|
||||||
|
(defaultFhsEnvArgs // {
|
||||||
|
targetPkgs = pkgs: [ appimage-exec ]
|
||||||
|
++ defaultFhsEnvArgs.targetPkgs pkgs ++ extraPkgs pkgs;
|
||||||
|
|
||||||
|
runScript = "appimage-exec.sh -w ${src} --";
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ];
|
||||||
|
} // meta;
|
||||||
|
} // (removeAttrs args (builtins.attrNames (builtins.functionArgs wrapAppImage))));
|
||||||
|
|
||||||
|
wrapType2 = args@{ src, extraPkgs ? pkgs: [ ], ... }: wrapAppImage
|
||||||
|
(args // {
|
||||||
|
inherit extraPkgs;
|
||||||
|
src = extract (lib.filterAttrs (key: value: builtins.elem key [ "name" "pname" "version" "src" ]) args);
|
||||||
|
|
||||||
|
# passthru src to make nix-update work
|
||||||
|
# hack to keep the origin position (unsafeGetAttrPos)
|
||||||
|
passthru = lib.pipe args [
|
||||||
|
lib.attrNames
|
||||||
|
(lib.remove "src")
|
||||||
|
(removeAttrs args)
|
||||||
|
] // args.passthru or { };
|
||||||
|
});
|
||||||
|
|
||||||
|
defaultFhsEnvArgs = {
|
||||||
|
# Most of the packages were taken from the Steam chroot
|
||||||
|
targetPkgs = pkgs: with pkgs; [
|
||||||
|
gtk3
|
||||||
|
bashInteractive
|
||||||
|
gnome.zenity
|
||||||
|
xorg.xrandr
|
||||||
|
which
|
||||||
|
perl
|
||||||
|
xdg-utils
|
||||||
|
iana-etc
|
||||||
|
krb5
|
||||||
|
gsettings-desktop-schemas
|
||||||
|
hicolor-icon-theme # dont show a gtk warning about hicolor not being installed
|
||||||
|
];
|
||||||
|
|
||||||
|
# list of libraries expected in an appimage environment:
|
||||||
|
# https://github.com/AppImage/pkg2appimage/blob/master/excludelist
|
||||||
|
multiPkgs = pkgs: with pkgs; [
|
||||||
|
desktop-file-utils
|
||||||
|
xorg.libXcomposite
|
||||||
|
xorg.libXtst
|
||||||
|
xorg.libXrandr
|
||||||
|
xorg.libXext
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXfixes
|
||||||
|
libGL
|
||||||
|
|
||||||
|
gst_all_1.gstreamer
|
||||||
|
gst_all_1.gst-plugins-ugly
|
||||||
|
gst_all_1.gst-plugins-base
|
||||||
|
libdrm
|
||||||
|
xorg.xkeyboardconfig
|
||||||
|
xorg.libpciaccess
|
||||||
|
|
||||||
|
glib
|
||||||
|
gtk2
|
||||||
|
bzip2
|
||||||
|
zlib
|
||||||
|
gdk-pixbuf
|
||||||
|
|
||||||
|
xorg.libXinerama
|
||||||
|
xorg.libXdamage
|
||||||
|
xorg.libXcursor
|
||||||
|
xorg.libXrender
|
||||||
|
xorg.libXScrnSaver
|
||||||
|
xorg.libXxf86vm
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libSM
|
||||||
|
xorg.libICE
|
||||||
|
freetype
|
||||||
|
curlWithGnuTls
|
||||||
|
nspr
|
||||||
|
nss
|
||||||
|
fontconfig
|
||||||
|
cairo
|
||||||
|
pango
|
||||||
|
expat
|
||||||
|
dbus
|
||||||
|
cups
|
||||||
|
libcap
|
||||||
|
SDL2
|
||||||
|
libusb1
|
||||||
|
udev
|
||||||
|
dbus-glib
|
||||||
|
atk
|
||||||
|
at-spi2-atk
|
||||||
|
libudev0-shim
|
||||||
|
|
||||||
|
xorg.libXt
|
||||||
|
xorg.libXmu
|
||||||
|
xorg.libxcb
|
||||||
|
xorg.xcbutil
|
||||||
|
xorg.xcbutilwm
|
||||||
|
xorg.xcbutilimage
|
||||||
|
xorg.xcbutilkeysyms
|
||||||
|
xorg.xcbutilrenderutil
|
||||||
|
libGLU
|
||||||
|
libuuid
|
||||||
|
libogg
|
||||||
|
libvorbis
|
||||||
|
SDL
|
||||||
|
SDL2_image
|
||||||
|
glew110
|
||||||
|
openssl
|
||||||
|
libidn
|
||||||
|
tbb
|
||||||
|
wayland
|
||||||
|
mesa
|
||||||
|
libxkbcommon
|
||||||
|
vulkan-loader
|
||||||
|
|
||||||
|
flac
|
||||||
|
freeglut
|
||||||
|
libjpeg
|
||||||
|
libpng12
|
||||||
|
libpulseaudio
|
||||||
|
libsamplerate
|
||||||
|
libmikmod
|
||||||
|
libthai
|
||||||
|
libtheora
|
||||||
|
libtiff
|
||||||
|
pixman
|
||||||
|
speex
|
||||||
|
SDL_image
|
||||||
|
SDL_ttf
|
||||||
|
SDL_mixer
|
||||||
|
SDL2_ttf
|
||||||
|
SDL2_mixer
|
||||||
|
libappindicator-gtk2
|
||||||
|
libcaca
|
||||||
|
libcanberra
|
||||||
|
libgcrypt
|
||||||
|
libvpx
|
||||||
|
librsvg
|
||||||
|
xorg.libXft
|
||||||
|
libvdpau
|
||||||
|
alsa-lib
|
||||||
|
|
||||||
|
harfbuzz
|
||||||
|
e2fsprogs
|
||||||
|
libgpg-error
|
||||||
|
keyutils.lib
|
||||||
|
libjack2
|
||||||
|
fribidi
|
||||||
|
p11-kit
|
||||||
|
|
||||||
|
gmp
|
||||||
|
|
||||||
|
# libraries not on the upstream include list, but nevertheless expected
|
||||||
|
# by at least one appimage
|
||||||
|
libtool.lib # for Synfigstudio
|
||||||
|
xorg.libxshmfence # for apple-music-electron
|
||||||
|
at-spi2-core
|
||||||
|
pciutils # for FreeCAD
|
||||||
|
pipewire # immersed-vr wayland support
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
35
pkgs/build-support/binary-cache/default.nix
Normal file
35
pkgs/build-support/binary-cache/default.nix
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{ lib, stdenv, coreutils, jq, python3, nix, xz }:
|
||||||
|
|
||||||
|
# This function is for creating a flat-file binary cache, i.e. the kind created by
|
||||||
|
# nix copy --to file:///some/path and usable as a substituter (with the file:// prefix).
|
||||||
|
|
||||||
|
# For example, in the Nixpkgs repo:
|
||||||
|
# nix-build -E 'with import ./. {}; mkBinaryCache { rootPaths = [hello]; }'
|
||||||
|
|
||||||
|
{ name ? "binary-cache"
|
||||||
|
, rootPaths
|
||||||
|
}:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
inherit name;
|
||||||
|
|
||||||
|
__structuredAttrs = true;
|
||||||
|
|
||||||
|
exportReferencesGraph.closure = rootPaths;
|
||||||
|
|
||||||
|
preferLocalBuild = true;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ coreutils jq python3 nix xz ];
|
||||||
|
|
||||||
|
buildCommand = ''
|
||||||
|
mkdir -p $out/nar
|
||||||
|
|
||||||
|
python ${./make-binary-cache.py}
|
||||||
|
|
||||||
|
# These directories must exist, or Nix might try to create them in LocalBinaryCacheStore::init(),
|
||||||
|
# which fails if mounted read-only
|
||||||
|
mkdir $out/realisations
|
||||||
|
mkdir $out/debuginfo
|
||||||
|
mkdir $out/log
|
||||||
|
'';
|
||||||
|
}
|
43
pkgs/build-support/binary-cache/make-binary-cache.py
Normal file
43
pkgs/build-support/binary-cache/make-binary-cache.py
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
with open(os.environ["NIX_ATTRS_JSON_FILE"], "r") as f:
|
||||||
|
closures = json.load(f)["closure"]
|
||||||
|
|
||||||
|
os.chdir(os.environ["out"])
|
||||||
|
|
||||||
|
nixPrefix = os.environ["NIX_STORE"] # Usually /nix/store
|
||||||
|
|
||||||
|
with open("nix-cache-info", "w") as f:
|
||||||
|
f.write("StoreDir: " + nixPrefix + "\n")
|
||||||
|
|
||||||
|
def dropPrefix(path):
|
||||||
|
return path[len(nixPrefix + "/"):]
|
||||||
|
|
||||||
|
for item in closures:
|
||||||
|
narInfoHash = dropPrefix(item["path"]).split("-")[0]
|
||||||
|
|
||||||
|
xzFile = "nar/" + narInfoHash + ".nar.xz"
|
||||||
|
with open(xzFile, "w") as f:
|
||||||
|
subprocess.run("nix-store --dump %s | xz -c" % item["path"], stdout=f, shell=True)
|
||||||
|
|
||||||
|
fileHash = subprocess.run(["nix-hash", "--base32", "--type", "sha256", item["path"]], capture_output=True).stdout.decode().strip()
|
||||||
|
fileSize = os.path.getsize(xzFile)
|
||||||
|
|
||||||
|
# Rename the .nar.xz file to its own hash to match "nix copy" behavior
|
||||||
|
finalXzFile = "nar/" + fileHash + ".nar.xz"
|
||||||
|
os.rename(xzFile, finalXzFile)
|
||||||
|
|
||||||
|
with open(narInfoHash + ".narinfo", "w") as f:
|
||||||
|
f.writelines((x + "\n" for x in [
|
||||||
|
"StorePath: " + item["path"],
|
||||||
|
"URL: " + finalXzFile,
|
||||||
|
"Compression: xz",
|
||||||
|
"FileHash: sha256:" + fileHash,
|
||||||
|
"FileSize: " + str(fileSize),
|
||||||
|
"NarHash: " + item["narHash"],
|
||||||
|
"NarSize: " + str(item["narSize"]),
|
||||||
|
"References: " + " ".join(dropPrefix(ref) for ref in item["references"]),
|
||||||
|
]))
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Unconditionally adding in platform version flags will result in warnings that
|
||||||
|
# will be treated as errors by some packages. Add any missing flags here.
|
||||||
|
|
||||||
|
# There are two things to be configured: the "platform version" (oldest
|
||||||
|
# supported version of macos, ios, etc), and the "sdk version".
|
||||||
|
#
|
||||||
|
# The modern way of configuring these is to use:
|
||||||
|
# -platform_version $platform $platform_version $sdk_version"
|
||||||
|
#
|
||||||
|
# The old way is still supported, and uses flags like:
|
||||||
|
# -${platform}_version_min $platform_version
|
||||||
|
# -sdk_version $sdk_version
|
||||||
|
#
|
||||||
|
# If both styles are specified ld will combine them. If multiple versions are
|
||||||
|
# specified for the same platform, ld will emit an error.
|
||||||
|
#
|
||||||
|
# The following adds flags for whichever properties have not already been
|
||||||
|
# provided.
|
||||||
|
|
||||||
|
havePlatformVersionFlag=
|
||||||
|
haveDarwinSDKVersion=
|
||||||
|
haveDarwinPlatformVersion=
|
||||||
|
|
||||||
|
# Roles will set by add-flags.sh, but add-flags.sh can be skipped when the
|
||||||
|
# cc-wrapper has added the linker flags. Both the cc-wrapper and the binutils
|
||||||
|
# wrapper mangle the same variable (MACOSX_DEPLOYMENT_TARGET), so if roles are
|
||||||
|
# empty due to being run through the cc-wrapper then the mangle here is a no-op
|
||||||
|
# and we still do the right thing.
|
||||||
|
#
|
||||||
|
# To be robust, make sure we always have the correct set of roles.
|
||||||
|
accumulateRoles
|
||||||
|
|
||||||
|
mangleVarSingle @darwinMinVersionVariable@ ${role_suffixes[@]+"${role_suffixes[@]}"}
|
||||||
|
|
||||||
|
n=0
|
||||||
|
nParams=${#params[@]}
|
||||||
|
while (( n < nParams )); do
|
||||||
|
p=${params[n]}
|
||||||
|
case "$p" in
|
||||||
|
# the current platform
|
||||||
|
-@darwinPlatform@_version_min)
|
||||||
|
haveDarwinPlatformVersion=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
# legacy aliases
|
||||||
|
-macosx_version_min|-iphoneos_version_min|-iosmac_version_min|-uikitformac_version_min)
|
||||||
|
haveDarwinPlatformVersion=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
-sdk_version)
|
||||||
|
haveDarwinSDKVersion=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
-platform_version)
|
||||||
|
havePlatformVersionFlag=1
|
||||||
|
|
||||||
|
# If clang can't determine the sdk version it will pass 0.0.0. This
|
||||||
|
# has runtime effects so we override this to use the known sdk
|
||||||
|
# version.
|
||||||
|
if [ "${params[n+3]-}" = 0.0.0 ]; then
|
||||||
|
params[n+3]=@darwinSdkVersion@
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
n=$((n + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
# If the caller has set -platform_version, trust they're doing the right thing.
|
||||||
|
# This will be the typical case for clang in nixpkgs.
|
||||||
|
if [ ! "$havePlatformVersionFlag" ]; then
|
||||||
|
if [ ! "$haveDarwinSDKVersion" ] && [ ! "$haveDarwinPlatformVersion" ]; then
|
||||||
|
# Nothing provided. Use the modern "-platform_version" to set both.
|
||||||
|
extraBefore+=(-platform_version @darwinPlatform@ "${@darwinMinVersionVariable@_@suffixSalt@:-@darwinMinVersion@}" @darwinSdkVersion@)
|
||||||
|
elif [ ! "$haveDarwinSDKVersion" ]; then
|
||||||
|
# Add missing sdk version
|
||||||
|
extraBefore+=(-sdk_version @darwinSdkVersion@)
|
||||||
|
elif [ ! "$haveDarwinPlatformVersion" ]; then
|
||||||
|
# Add missing platform version
|
||||||
|
extraBefore+=(-@darwinPlatform@_version_min "${@darwinMinVersionVariable@_@suffixSalt@:-@darwinMinVersion@}")
|
||||||
|
fi
|
||||||
|
fi
|
37
pkgs/build-support/bintools-wrapper/add-flags.sh
Normal file
37
pkgs/build-support/bintools-wrapper/add-flags.sh
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# See cc-wrapper for comments.
|
||||||
|
var_templates_list=(
|
||||||
|
NIX_IGNORE_LD_THROUGH_GCC
|
||||||
|
NIX_LDFLAGS
|
||||||
|
NIX_LDFLAGS_BEFORE
|
||||||
|
NIX_DYNAMIC_LINKER
|
||||||
|
NIX_LDFLAGS_AFTER
|
||||||
|
NIX_LDFLAGS_HARDEN
|
||||||
|
NIX_HARDENING_ENABLE
|
||||||
|
)
|
||||||
|
var_templates_bool=(
|
||||||
|
NIX_SET_BUILD_ID
|
||||||
|
NIX_DONT_SET_RPATH
|
||||||
|
)
|
||||||
|
|
||||||
|
accumulateRoles
|
||||||
|
|
||||||
|
for var in "${var_templates_list[@]}"; do
|
||||||
|
mangleVarList "$var" ${role_suffixes[@]+"${role_suffixes[@]}"}
|
||||||
|
done
|
||||||
|
for var in "${var_templates_bool[@]}"; do
|
||||||
|
mangleVarBool "$var" ${role_suffixes[@]+"${role_suffixes[@]}"}
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/libc-ldflags ]; then
|
||||||
|
NIX_LDFLAGS_@suffixSalt@+=" $(< @out@/nix-support/libc-ldflags)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$NIX_DYNAMIC_LINKER_@suffixSalt@" ] && [ -e @out@/nix-support/ld-set-dynamic-linker ]; then
|
||||||
|
NIX_DYNAMIC_LINKER_@suffixSalt@="$(< @out@/nix-support/dynamic-linker)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/libc-ldflags-before ]; then
|
||||||
|
NIX_LDFLAGS_BEFORE_@suffixSalt@="$(< @out@/nix-support/libc-ldflags-before) $NIX_LDFLAGS_BEFORE_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export NIX_BINTOOLS_WRAPPER_FLAGS_SET_@suffixSalt@=1
|
62
pkgs/build-support/bintools-wrapper/add-hardening.sh
Normal file
62
pkgs/build-support/bintools-wrapper/add-hardening.sh
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
declare -a hardeningLDFlags=()
|
||||||
|
|
||||||
|
declare -A hardeningEnableMap=()
|
||||||
|
|
||||||
|
# Intentionally word-split in case 'NIX_HARDENING_ENABLE' is defined in Nix. The
|
||||||
|
# array expansion also prevents undefined variables from causing trouble with
|
||||||
|
# `set -u`.
|
||||||
|
for flag in ${NIX_HARDENING_ENABLE_@suffixSalt@-}; do
|
||||||
|
hardeningEnableMap["$flag"]=1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove unsupported flags.
|
||||||
|
for flag in @hardening_unsupported_flags@; do
|
||||||
|
unset -v "hardeningEnableMap[$flag]"
|
||||||
|
done
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||||
|
declare -a allHardeningFlags=(pie relro bindnow)
|
||||||
|
declare -A hardeningDisableMap=()
|
||||||
|
|
||||||
|
# Determine which flags were effectively disabled so we can report below.
|
||||||
|
for flag in "${allHardeningFlags[@]}"; do
|
||||||
|
if [[ -z "${hardeningEnableMap[$flag]-}" ]]; then
|
||||||
|
hardeningDisableMap[$flag]=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf 'HARDENING: disabled flags:' >&2
|
||||||
|
(( "${#hardeningDisableMap[@]}" )) && printf ' %q' "${!hardeningDisableMap[@]}" >&2
|
||||||
|
echo >&2
|
||||||
|
|
||||||
|
if (( "${#hardeningEnableMap[@]}" )); then
|
||||||
|
echo 'HARDENING: Is active (not completely disabled with "all" flag)' >&2;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
for flag in "${!hardeningEnableMap[@]}"; do
|
||||||
|
case $flag in
|
||||||
|
pie)
|
||||||
|
if [[ ! (" ${params[*]} " =~ " -shared " \
|
||||||
|
|| " ${params[*]} " =~ " -static " \
|
||||||
|
|| " ${params[*]} " =~ " -r " \
|
||||||
|
|| " ${params[*]} " =~ " -Ur " \
|
||||||
|
|| " ${params[*]} " =~ " -i ") ]]; then
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling LDFlags -pie >&2; fi
|
||||||
|
hardeningLDFlags+=('-pie')
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
relro)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling relro >&2; fi
|
||||||
|
hardeningLDFlags+=('-z' 'relro')
|
||||||
|
;;
|
||||||
|
bindnow)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling bindnow >&2; fi
|
||||||
|
hardeningLDFlags+=('-z' 'now')
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Ignore unsupported. Checked in Nix that at least *some*
|
||||||
|
# tool supports each flag.
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
49
pkgs/build-support/bintools-wrapper/darwin-install_name_tool-wrapper.sh
Executable file
49
pkgs/build-support/bintools-wrapper/darwin-install_name_tool-wrapper.sh
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
#! @shell@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
set -eu -o pipefail +o posix
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 7 )); then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
source @signingUtils@
|
||||||
|
|
||||||
|
extraAfter=()
|
||||||
|
extraBefore=()
|
||||||
|
params=("$@")
|
||||||
|
|
||||||
|
input=
|
||||||
|
|
||||||
|
pprev=
|
||||||
|
prev=
|
||||||
|
for p in \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
||||||
|
do
|
||||||
|
if [ "$pprev" != "-change" ] && [[ "$prev" != -* ]] && [[ "$p" != -* ]]; then
|
||||||
|
input="$p"
|
||||||
|
fi
|
||||||
|
pprev="$prev"
|
||||||
|
prev="$p"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Optionally print debug info.
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||||
|
# Old bash workaround, see above.
|
||||||
|
echo "extra flags before to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraBefore+"${extraBefore[@]}"} >&2
|
||||||
|
echo "original flags to @prog@:" >&2
|
||||||
|
printf " %q\n" ${params+"${params[@]}"} >&2
|
||||||
|
echo "extra flags after to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraAfter+"${extraAfter[@]}"} >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
@prog@ \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
||||||
|
|
||||||
|
sign "$input"
|
78
pkgs/build-support/bintools-wrapper/darwin-strip-wrapper.sh
Executable file
78
pkgs/build-support/bintools-wrapper/darwin-strip-wrapper.sh
Executable file
|
@ -0,0 +1,78 @@
|
||||||
|
#! @shell@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
set -eu -o pipefail +o posix
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 7 )); then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
source @signingUtils@
|
||||||
|
|
||||||
|
extraAfter=()
|
||||||
|
extraBefore=()
|
||||||
|
params=("$@")
|
||||||
|
|
||||||
|
output=
|
||||||
|
inputs=()
|
||||||
|
|
||||||
|
restAreFiles=
|
||||||
|
prev=
|
||||||
|
for p in \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
||||||
|
do
|
||||||
|
if [ "$restAreFiles" ]; then
|
||||||
|
inputs+=("$p")
|
||||||
|
else
|
||||||
|
case "$prev" in
|
||||||
|
-s|-R|-d|-arch)
|
||||||
|
# Unrelated arguments with values
|
||||||
|
;;
|
||||||
|
-o)
|
||||||
|
# Explicit output
|
||||||
|
output="$p"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Any other orgument either takes no value, or is a file.
|
||||||
|
if [[ "$p" != -* ]]; then
|
||||||
|
inputs+=("$p")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$p" == - ]; then
|
||||||
|
restAreFiles=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
prev="$p"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Optionally print debug info.
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||||
|
# Old bash workaround, see above.
|
||||||
|
echo "extra flags before to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraBefore+"${extraBefore[@]}"} >&2
|
||||||
|
echo "original flags to @prog@:" >&2
|
||||||
|
printf " %q\n" ${params+"${params[@]}"} >&2
|
||||||
|
echo "extra flags after to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraAfter+"${extraAfter[@]}"} >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
@prog@ \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
||||||
|
|
||||||
|
if [ "$output" ]; then
|
||||||
|
# Single explicit output
|
||||||
|
signIfRequired "$output"
|
||||||
|
else
|
||||||
|
# Multiple inputs, rewritten in place
|
||||||
|
for input in "${inputs[@]}"; do
|
||||||
|
signIfRequired "$input"
|
||||||
|
done
|
||||||
|
fi
|
439
pkgs/build-support/bintools-wrapper/default.nix
Normal file
439
pkgs/build-support/bintools-wrapper/default.nix
Normal file
|
@ -0,0 +1,439 @@
|
||||||
|
# The Nixpkgs CC is not directly usable, since it doesn't know where
|
||||||
|
# the C library and standard header files are. Therefore the compiler
|
||||||
|
# produced by that package cannot be installed directly in a user
|
||||||
|
# environment and used from the command line. So we use a wrapper
|
||||||
|
# script that sets up the right environment variables so that the
|
||||||
|
# compiler and the linker just "work".
|
||||||
|
|
||||||
|
{ name ? ""
|
||||||
|
, lib
|
||||||
|
, stdenvNoCC
|
||||||
|
, runtimeShell
|
||||||
|
, bintools ? null, libc ? null, coreutils ? null, gnugrep ? null
|
||||||
|
, netbsd ? null, netbsdCross ? null
|
||||||
|
, sharedLibraryLoader ?
|
||||||
|
if libc == null then
|
||||||
|
null
|
||||||
|
else if stdenvNoCC.targetPlatform.isNetBSD then
|
||||||
|
if !(targetPackages ? netbsdCross) then
|
||||||
|
netbsd.ld_elf_so
|
||||||
|
else if libc != targetPackages.netbsdCross.headers then
|
||||||
|
targetPackages.netbsdCross.ld_elf_so
|
||||||
|
else
|
||||||
|
null
|
||||||
|
else
|
||||||
|
lib.getLib libc
|
||||||
|
, nativeTools, noLibc ? false, nativeLibc, nativePrefix ? ""
|
||||||
|
, propagateDoc ? bintools != null && bintools ? man
|
||||||
|
, extraPackages ? [], extraBuildCommands ? ""
|
||||||
|
, isGNU ? bintools.isGNU or false
|
||||||
|
, isLLVM ? bintools.isLLVM or false
|
||||||
|
, isCCTools ? bintools.isCCTools or false
|
||||||
|
, expand-response-params
|
||||||
|
, targetPackages ? {}
|
||||||
|
, useMacosReexportHack ? false
|
||||||
|
, wrapGas ? false
|
||||||
|
|
||||||
|
# Note: the hardening flags are part of the bintools-wrapper, rather than
|
||||||
|
# the cc-wrapper, because a few of them are handled by the linker.
|
||||||
|
, defaultHardeningFlags ? [
|
||||||
|
"bindnow"
|
||||||
|
"format"
|
||||||
|
"fortify"
|
||||||
|
"fortify3"
|
||||||
|
"pic"
|
||||||
|
"relro"
|
||||||
|
"stackprotector"
|
||||||
|
"strictoverflow"
|
||||||
|
] ++ lib.optional (with stdenvNoCC;
|
||||||
|
# Musl-based platforms will keep "pie", other platforms will not.
|
||||||
|
# If you change this, make sure to update section `{#sec-hardening-in-nixpkgs}`
|
||||||
|
# in the nixpkgs manual to inform users about the defaults.
|
||||||
|
targetPlatform.libc == "musl"
|
||||||
|
# Except when:
|
||||||
|
# - static aarch64, where compilation works, but produces segfaulting dynamically linked binaries.
|
||||||
|
# - static armv7l, where compilation fails.
|
||||||
|
&& !(targetPlatform.isAarch && targetPlatform.isStatic)
|
||||||
|
) "pie"
|
||||||
|
|
||||||
|
# Darwin code signing support utilities
|
||||||
|
, postLinkSignHook ? null, signingUtils ? null
|
||||||
|
}:
|
||||||
|
|
||||||
|
assert nativeTools -> !propagateDoc && nativePrefix != "";
|
||||||
|
assert !nativeTools -> bintools != null && coreutils != null && gnugrep != null;
|
||||||
|
assert !(nativeLibc && noLibc);
|
||||||
|
assert (noLibc || nativeLibc) == (libc == null);
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
attrByPath
|
||||||
|
concatStringsSep
|
||||||
|
getBin
|
||||||
|
getDev
|
||||||
|
getLib
|
||||||
|
getName
|
||||||
|
getVersion
|
||||||
|
hasSuffix
|
||||||
|
optional
|
||||||
|
optionalAttrs
|
||||||
|
optionals
|
||||||
|
optionalString
|
||||||
|
platforms
|
||||||
|
removePrefix
|
||||||
|
replaceStrings
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (stdenvNoCC) hostPlatform targetPlatform;
|
||||||
|
|
||||||
|
# Prefix for binaries. Customarily ends with a dash separator.
|
||||||
|
#
|
||||||
|
# TODO(@Ericson2314) Make unconditional, or optional but always true by
|
||||||
|
# default.
|
||||||
|
targetPrefix = optionalString (targetPlatform != hostPlatform)
|
||||||
|
(targetPlatform.config + "-");
|
||||||
|
|
||||||
|
bintoolsVersion = getVersion bintools;
|
||||||
|
bintoolsName = removePrefix targetPrefix (getName bintools);
|
||||||
|
|
||||||
|
libc_bin = optionalString (libc != null) (getBin libc);
|
||||||
|
libc_dev = optionalString (libc != null) (getDev libc);
|
||||||
|
libc_lib = optionalString (libc != null) (getLib libc);
|
||||||
|
bintools_bin = optionalString (!nativeTools) (getBin bintools);
|
||||||
|
# The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
|
||||||
|
coreutils_bin = optionalString (!nativeTools) (getBin coreutils);
|
||||||
|
|
||||||
|
# See description in cc-wrapper.
|
||||||
|
suffixSalt = replaceStrings ["-" "."] ["_" "_"] targetPlatform.config;
|
||||||
|
|
||||||
|
# The dynamic linker has different names on different platforms. This is a
|
||||||
|
# shell glob that ought to match it.
|
||||||
|
dynamicLinker =
|
||||||
|
/**/ if sharedLibraryLoader == null then ""
|
||||||
|
else if targetPlatform.libc == "musl" then "${sharedLibraryLoader}/lib/ld-musl-*"
|
||||||
|
else if targetPlatform.libc == "uclibc" then "${sharedLibraryLoader}/lib/ld*-uClibc.so.1"
|
||||||
|
else if (targetPlatform.libc == "bionic" && targetPlatform.is32bit) then "/system/bin/linker"
|
||||||
|
else if (targetPlatform.libc == "bionic" && targetPlatform.is64bit) then "/system/bin/linker64"
|
||||||
|
else if targetPlatform.libc == "nblibc" then "${sharedLibraryLoader}/libexec/ld.elf_so"
|
||||||
|
else if targetPlatform.system == "i686-linux" then "${sharedLibraryLoader}/lib/ld-linux.so.2"
|
||||||
|
else if targetPlatform.system == "x86_64-linux" then "${sharedLibraryLoader}/lib/ld-linux-x86-64.so.2"
|
||||||
|
# ELFv1 (.1) or ELFv2 (.2) ABI
|
||||||
|
else if targetPlatform.isPower64 then "${sharedLibraryLoader}/lib/ld64.so.*"
|
||||||
|
# ARM with a wildcard, which can be "" or "-armhf".
|
||||||
|
else if (with targetPlatform; isAarch32 && isLinux) then "${sharedLibraryLoader}/lib/ld-linux*.so.3"
|
||||||
|
else if targetPlatform.system == "aarch64-linux" then "${sharedLibraryLoader}/lib/ld-linux-aarch64.so.1"
|
||||||
|
else if targetPlatform.system == "powerpc-linux" then "${sharedLibraryLoader}/lib/ld.so.1"
|
||||||
|
else if targetPlatform.isMips then "${sharedLibraryLoader}/lib/ld.so.1"
|
||||||
|
# `ld-linux-riscv{32,64}-<abi>.so.1`
|
||||||
|
else if targetPlatform.isRiscV then "${sharedLibraryLoader}/lib/ld-linux-riscv*.so.1"
|
||||||
|
else if targetPlatform.isLoongArch64 then "${sharedLibraryLoader}/lib/ld-linux-loongarch*.so.1"
|
||||||
|
else if targetPlatform.isDarwin then "/usr/lib/dyld"
|
||||||
|
else if targetPlatform.isFreeBSD then "/libexec/ld-elf.so.1"
|
||||||
|
else if hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1"
|
||||||
|
else "";
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
stdenvNoCC.mkDerivation {
|
||||||
|
pname = targetPrefix
|
||||||
|
+ (if name != "" then name else "${bintoolsName}-wrapper");
|
||||||
|
version = optionalString (bintools != null) bintoolsVersion;
|
||||||
|
|
||||||
|
preferLocalBuild = true;
|
||||||
|
|
||||||
|
outputs = [ "out" ] ++ optionals propagateDoc ([ "man" ] ++ optional (bintools ? info) "info");
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
inherit targetPrefix suffixSalt;
|
||||||
|
inherit bintools libc nativeTools nativeLibc nativePrefix isGNU isLLVM;
|
||||||
|
|
||||||
|
emacsBufferSetup = pkgs: ''
|
||||||
|
; We should handle propagation here too
|
||||||
|
(mapc
|
||||||
|
(lambda (arg)
|
||||||
|
(when (file-directory-p (concat arg "/lib"))
|
||||||
|
(setenv "NIX_LDFLAGS_${suffixSalt}" (concat (getenv "NIX_LDFLAGS_${suffixSalt}") " -L" arg "/lib")))
|
||||||
|
(when (file-directory-p (concat arg "/lib64"))
|
||||||
|
(setenv "NIX_LDFLAGS_${suffixSalt}" (concat (getenv "NIX_LDFLAGS_${suffixSalt}") " -L" arg "/lib64"))))
|
||||||
|
'(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)}))
|
||||||
|
'';
|
||||||
|
|
||||||
|
inherit defaultHardeningFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
dontBuild = true;
|
||||||
|
dontConfigure = true;
|
||||||
|
|
||||||
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
|
unpackPhase = ''
|
||||||
|
src=$PWD
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase =
|
||||||
|
''
|
||||||
|
mkdir -p $out/bin $out/nix-support
|
||||||
|
|
||||||
|
wrap() {
|
||||||
|
local dst="$1"
|
||||||
|
local wrapper="$2"
|
||||||
|
export prog="$3"
|
||||||
|
export use_response_file_by_default=${if isCCTools then "1" else "0"}
|
||||||
|
substituteAll "$wrapper" "$out/bin/$dst"
|
||||||
|
chmod +x "$out/bin/$dst"
|
||||||
|
}
|
||||||
|
''
|
||||||
|
|
||||||
|
+ (if nativeTools then ''
|
||||||
|
echo ${nativePrefix} > $out/nix-support/orig-bintools
|
||||||
|
|
||||||
|
ldPath="${nativePrefix}/bin"
|
||||||
|
'' else ''
|
||||||
|
echo $bintools_bin > $out/nix-support/orig-bintools
|
||||||
|
|
||||||
|
ldPath="${bintools_bin}/bin"
|
||||||
|
''
|
||||||
|
|
||||||
|
# Solaris needs an additional ld wrapper.
|
||||||
|
+ optionalString (targetPlatform.isSunOS && nativePrefix != "") ''
|
||||||
|
ldPath="${nativePrefix}/bin"
|
||||||
|
exec="$ldPath/${targetPrefix}ld"
|
||||||
|
wrap ld-solaris ${./ld-solaris-wrapper.sh}
|
||||||
|
'')
|
||||||
|
|
||||||
|
# If we are asked to wrap `gas` and this bintools has it,
|
||||||
|
# then symlink it (`as` will be symlinked next).
|
||||||
|
# This is mainly for the wrapped gnat-bootstrap on x86-64 Darwin,
|
||||||
|
# as it must have both the GNU assembler from cctools (installed as `gas`)
|
||||||
|
# and the Clang integrated assembler (installed as `as`).
|
||||||
|
# See pkgs/os-specific/darwin/binutils/default.nix for details.
|
||||||
|
+ optionalString wrapGas ''
|
||||||
|
if [ -e $ldPath/${targetPrefix}gas ]; then
|
||||||
|
ln -s $ldPath/${targetPrefix}gas $out/bin/${targetPrefix}gas
|
||||||
|
fi
|
||||||
|
''
|
||||||
|
|
||||||
|
# Create symlinks for rest of the binaries.
|
||||||
|
+ ''
|
||||||
|
for binary in objdump objcopy size strings as ar nm gprof dwp c++filt addr2line \
|
||||||
|
ranlib readelf elfedit dlltool dllwrap windmc windres; do
|
||||||
|
if [ -e $ldPath/${targetPrefix}''${binary} ]; then
|
||||||
|
ln -s $ldPath/${targetPrefix}''${binary} $out/bin/${targetPrefix}''${binary}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
'' + (if !useMacosReexportHack then ''
|
||||||
|
if [ -e ''${ld:-$ldPath/${targetPrefix}ld} ]; then
|
||||||
|
wrap ${targetPrefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${targetPrefix}ld}
|
||||||
|
fi
|
||||||
|
'' else ''
|
||||||
|
ldInner="${targetPrefix}ld-reexport-delegate"
|
||||||
|
wrap "$ldInner" ${./macos-sierra-reexport-hack.bash} ''${ld:-$ldPath/${targetPrefix}ld}
|
||||||
|
wrap "${targetPrefix}ld" ${./ld-wrapper.sh} "$out/bin/$ldInner"
|
||||||
|
unset ldInner
|
||||||
|
'') + ''
|
||||||
|
|
||||||
|
for variant in $ldPath/${targetPrefix}ld.*; do
|
||||||
|
basename=$(basename "$variant")
|
||||||
|
wrap $basename ${./ld-wrapper.sh} $variant
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
strictDeps = true;
|
||||||
|
depsTargetTargetPropagated = extraPackages;
|
||||||
|
|
||||||
|
setupHooks = [
|
||||||
|
../setup-hooks/role.bash
|
||||||
|
./setup-hook.sh
|
||||||
|
];
|
||||||
|
|
||||||
|
postFixup =
|
||||||
|
##
|
||||||
|
## General libc support
|
||||||
|
##
|
||||||
|
optionalString (libc != null) (''
|
||||||
|
touch "$out/nix-support/libc-ldflags"
|
||||||
|
echo "-L${libc_lib}${libc.libdir or "/lib"}" >> $out/nix-support/libc-ldflags
|
||||||
|
|
||||||
|
echo "${libc_lib}" > $out/nix-support/orig-libc
|
||||||
|
echo "${libc_dev}" > $out/nix-support/orig-libc-dev
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## Dynamic linker support
|
||||||
|
##
|
||||||
|
+ optionalString (sharedLibraryLoader != null) ''
|
||||||
|
if [[ -z ''${dynamicLinker+x} ]]; then
|
||||||
|
echo "Don't know the name of the dynamic linker for platform '${targetPlatform.config}', so guessing instead." >&2
|
||||||
|
local dynamicLinker="${sharedLibraryLoader}/lib/ld*.so.?"
|
||||||
|
fi
|
||||||
|
''
|
||||||
|
|
||||||
|
# Expand globs to fill array of options
|
||||||
|
+ ''
|
||||||
|
dynamicLinker=($dynamicLinker)
|
||||||
|
|
||||||
|
case ''${#dynamicLinker[@]} in
|
||||||
|
0) echo "No dynamic linker found for platform '${targetPlatform.config}'." >&2;;
|
||||||
|
1) echo "Using dynamic linker: '$dynamicLinker'" >&2;;
|
||||||
|
*) echo "Multiple dynamic linkers found for platform '${targetPlatform.config}'." >&2;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "''${dynamicLinker-}" ]; then
|
||||||
|
echo $dynamicLinker > $out/nix-support/dynamic-linker
|
||||||
|
|
||||||
|
${if targetPlatform.isDarwin then ''
|
||||||
|
printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
|
||||||
|
'' else optionalString (sharedLibraryLoader != null) ''
|
||||||
|
if [ -e ${sharedLibraryLoader}/lib/32/ld-linux.so.2 ]; then
|
||||||
|
echo ${sharedLibraryLoader}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
|
||||||
|
fi
|
||||||
|
touch $out/nix-support/ld-set-dynamic-linker
|
||||||
|
''}
|
||||||
|
fi
|
||||||
|
'')
|
||||||
|
|
||||||
|
##
|
||||||
|
## User env support
|
||||||
|
##
|
||||||
|
|
||||||
|
# Propagate the underling unwrapped bintools so that if you
|
||||||
|
# install the wrapper, you get tools like objdump (same for any
|
||||||
|
# binaries of libc).
|
||||||
|
+ optionalString (!nativeTools) ''
|
||||||
|
printWords ${bintools_bin} ${optionalString (libc != null) libc_bin} > $out/nix-support/propagated-user-env-packages
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## Man page and info support
|
||||||
|
##
|
||||||
|
+ optionalString propagateDoc (''
|
||||||
|
ln -s ${bintools.man} $man
|
||||||
|
'' + optionalString (bintools ? info) ''
|
||||||
|
ln -s ${bintools.info} $info
|
||||||
|
'')
|
||||||
|
|
||||||
|
##
|
||||||
|
## Hardening support
|
||||||
|
##
|
||||||
|
|
||||||
|
# some linkers on some platforms don't support specific -z flags
|
||||||
|
+ ''
|
||||||
|
export hardening_unsupported_flags=""
|
||||||
|
if [[ "$($ldPath/${targetPrefix}ld -z now 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
|
||||||
|
hardening_unsupported_flags+=" bindnow"
|
||||||
|
fi
|
||||||
|
if [[ "$($ldPath/${targetPrefix}ld -z relro 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
|
||||||
|
hardening_unsupported_flags+=" relro"
|
||||||
|
fi
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString hostPlatform.isCygwin ''
|
||||||
|
hardening_unsupported_flags+=" pic"
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString (targetPlatform.isAvr || targetPlatform.isWindows) ''
|
||||||
|
hardening_unsupported_flags+=" relro bindnow"
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString (libc != null && targetPlatform.isAvr) ''
|
||||||
|
for isa in avr5 avr3 avr4 avr6 avr25 avr31 avr35 avr51 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack; do
|
||||||
|
echo "-L${getLib libc}/avr/lib/$isa" >> $out/nix-support/libc-cflags
|
||||||
|
done
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString targetPlatform.isDarwin ''
|
||||||
|
echo "-arch ${targetPlatform.darwinArch}" >> $out/nix-support/libc-ldflags
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## GNU specific extra strip flags
|
||||||
|
##
|
||||||
|
|
||||||
|
# TODO(@sternenseemann): make a generic strip wrapper?
|
||||||
|
+ optionalString (bintools.isGNU or false) ''
|
||||||
|
wrap ${targetPrefix}strip ${./gnu-binutils-strip-wrapper.sh} \
|
||||||
|
"${bintools_bin}/bin/${targetPrefix}strip"
|
||||||
|
''
|
||||||
|
|
||||||
|
###
|
||||||
|
### Remove certain timestamps from final binaries
|
||||||
|
###
|
||||||
|
+ optionalString (targetPlatform.isDarwin && !(bintools.isGNU or false)) ''
|
||||||
|
echo "export ZERO_AR_DATE=1" >> $out/nix-support/setup-hook
|
||||||
|
''
|
||||||
|
|
||||||
|
+ ''
|
||||||
|
for flags in "$out/nix-support"/*flags*; do
|
||||||
|
substituteInPlace "$flags" --replace $'\n' ' '
|
||||||
|
done
|
||||||
|
|
||||||
|
substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh
|
||||||
|
substituteAll ${./add-hardening.sh} $out/nix-support/add-hardening.sh
|
||||||
|
substituteAll ${../wrapper-common/utils.bash} $out/nix-support/utils.bash
|
||||||
|
''
|
||||||
|
|
||||||
|
###
|
||||||
|
### Ensure consistent LC_VERSION_MIN_MACOSX
|
||||||
|
###
|
||||||
|
+ optionalString targetPlatform.isDarwin (
|
||||||
|
let
|
||||||
|
inherit (targetPlatform)
|
||||||
|
darwinPlatform darwinSdkVersion
|
||||||
|
darwinMinVersion darwinMinVersionVariable;
|
||||||
|
in ''
|
||||||
|
export darwinPlatform=${darwinPlatform}
|
||||||
|
export darwinMinVersion=${darwinMinVersion}
|
||||||
|
export darwinSdkVersion=${darwinSdkVersion}
|
||||||
|
export darwinMinVersionVariable=${darwinMinVersionVariable}
|
||||||
|
substituteAll ${./add-darwin-ldflags-before.sh} $out/nix-support/add-local-ldflags-before.sh
|
||||||
|
''
|
||||||
|
)
|
||||||
|
|
||||||
|
##
|
||||||
|
## Code signing on Apple Silicon
|
||||||
|
##
|
||||||
|
+ optionalString (targetPlatform.isDarwin && targetPlatform.isAarch64) ''
|
||||||
|
echo 'source ${postLinkSignHook}' >> $out/nix-support/post-link-hook
|
||||||
|
|
||||||
|
export signingUtils=${signingUtils}
|
||||||
|
|
||||||
|
wrap \
|
||||||
|
${targetPrefix}install_name_tool \
|
||||||
|
${./darwin-install_name_tool-wrapper.sh} \
|
||||||
|
"${bintools_bin}/bin/${targetPrefix}install_name_tool"
|
||||||
|
|
||||||
|
wrap \
|
||||||
|
${targetPrefix}strip ${./darwin-strip-wrapper.sh} \
|
||||||
|
"${bintools_bin}/bin/${targetPrefix}strip"
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## Extra custom steps
|
||||||
|
##
|
||||||
|
+ extraBuildCommands;
|
||||||
|
|
||||||
|
env = {
|
||||||
|
# for substitution in utils.bash
|
||||||
|
# TODO(@sternenseemann): invent something cleaner than passing in "" in case of absence
|
||||||
|
expandResponseParams = "${expand-response-params}/bin/expand-response-params";
|
||||||
|
# TODO(@sternenseemann): rename env var via stdenv rebuild
|
||||||
|
shell = (getBin runtimeShell + runtimeShell.shellPath or "");
|
||||||
|
gnugrep_bin = optionalString (!nativeTools) gnugrep;
|
||||||
|
wrapperName = "BINTOOLS_WRAPPER";
|
||||||
|
inherit dynamicLinker targetPrefix suffixSalt coreutils_bin;
|
||||||
|
inherit bintools_bin libc_bin libc_dev libc_lib;
|
||||||
|
default_hardening_flags_str = builtins.toString defaultHardeningFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
meta =
|
||||||
|
let bintools_ = optionalAttrs (bintools != null) bintools; in
|
||||||
|
(optionalAttrs (bintools_ ? meta) (removeAttrs bintools.meta ["priority"])) //
|
||||||
|
{ description =
|
||||||
|
attrByPath ["meta" "description"] "System binary utilities" bintools_
|
||||||
|
+ " (wrapper script)";
|
||||||
|
priority = 10;
|
||||||
|
} // optionalAttrs useMacosReexportHack {
|
||||||
|
platforms = platforms.darwin;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
#! @shell@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
exec @prog@ --enable-deterministic-archives "$@"
|
29
pkgs/build-support/bintools-wrapper/ld-solaris-wrapper.sh
Normal file
29
pkgs/build-support/bintools-wrapper/ld-solaris-wrapper.sh
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#!@shell@
|
||||||
|
set -eu -o pipefail
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 7 )); then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -a args=("$@")
|
||||||
|
# I've also tried adding -z direct and -z lazyload, but it gave too many problems with C++ exceptions :'(
|
||||||
|
# Also made sure libgcc would not be lazy-loaded, as suggested here: https://www.illumos.org/issues/2534#note-3
|
||||||
|
# but still no success.
|
||||||
|
declare -a argsBefore=(-z ignore) argsAfter=()
|
||||||
|
|
||||||
|
# This loop makes sure all -L arguments are before -l arguments, or ld may complain it cannot find a library.
|
||||||
|
# GNU binutils does not have this problem:
|
||||||
|
# http://stackoverflow.com/questions/5817269/does-the-order-of-l-and-l-options-in-the-gnu-linker-matter
|
||||||
|
while (( $# )); do
|
||||||
|
case "${args[$i]}" in
|
||||||
|
-L) argsBefore+=("$1" "$2"); shift ;;
|
||||||
|
-L?*) argsBefore+=("$1") ;;
|
||||||
|
*) argsAfter+=("$1") ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Trace:
|
||||||
|
set -x
|
||||||
|
exec "@ld@" "${argsBefore[@]}" "${argsAfter[@]}"
|
273
pkgs/build-support/bintools-wrapper/ld-wrapper.sh
Normal file
273
pkgs/build-support/bintools-wrapper/ld-wrapper.sh
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
#! @shell@
|
||||||
|
set -eu -o pipefail +o posix
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 7 )); then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
path_backup="$PATH"
|
||||||
|
|
||||||
|
# phase separation makes this look useless
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [ -n "@coreutils_bin@" ]; then
|
||||||
|
PATH="@coreutils_bin@/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
source @out@/nix-support/utils.bash
|
||||||
|
|
||||||
|
if [ -z "${NIX_BINTOOLS_WRAPPER_FLAGS_SET_@suffixSalt@:-}" ]; then
|
||||||
|
source @out@/nix-support/add-flags.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Optionally filter out paths not refering to the store.
|
||||||
|
expandResponseParams "$@"
|
||||||
|
|
||||||
|
# NIX_LINK_TYPE is set if ld has been called through our cc wrapper. We take
|
||||||
|
# advantage of this to avoid both recalculating it, and also repeating other
|
||||||
|
# processing cc wrapper has already done.
|
||||||
|
if [[ -n "${NIX_LINK_TYPE_@suffixSalt@:-}" ]]; then
|
||||||
|
linkType=$NIX_LINK_TYPE_@suffixSalt@
|
||||||
|
else
|
||||||
|
linkType=$(checkLinkType "${params[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "${NIX_STORE:-}"
|
||||||
|
&& ( -z "$NIX_IGNORE_LD_THROUGH_GCC_@suffixSalt@" || -z "${NIX_LINK_TYPE_@suffixSalt@:-}" ) ]]; then
|
||||||
|
rest=()
|
||||||
|
nParams=${#params[@]}
|
||||||
|
declare -i n=0
|
||||||
|
|
||||||
|
while (( "$n" < "$nParams" )); do
|
||||||
|
p=${params[n]}
|
||||||
|
p2=${params[n+1]:-} # handle `p` being last one
|
||||||
|
if [ "${p:0:3}" = -L/ ] && badPath "${p:2}"; then
|
||||||
|
skip "${p:2}"
|
||||||
|
elif [ "$p" = -L ] && badPath "$p2"; then
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
elif [ "$p" = -rpath ] && badPath "$p2"; then
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
elif [ "$p" = -dynamic-linker ] && badPath "$p2"; then
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
elif [ "$p" = -syslibroot ] && [ $p2 == // ]; then
|
||||||
|
# When gcc is built on darwin --with-build-sysroot=/
|
||||||
|
# produces '-syslibroot //' linker flag. It's a no-op,
|
||||||
|
# which does not introduce impurities.
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
elif [ "${p:0:10}" = /LIBPATH:/ ] && badPath "${p:9}"; then
|
||||||
|
reject "${p:9}"
|
||||||
|
# We need to not match LINK.EXE-style flags like
|
||||||
|
# /NOLOGO or /LIBPATH:/nix/store/foo
|
||||||
|
elif [[ $p =~ ^/[^:]*/ ]] && badPath "$p"; then
|
||||||
|
reject "$p"
|
||||||
|
elif [ "${p:0:9}" = --sysroot ]; then
|
||||||
|
# Our ld is not built with sysroot support (Can we fix that?)
|
||||||
|
:
|
||||||
|
else
|
||||||
|
rest+=("$p")
|
||||||
|
fi
|
||||||
|
n+=1
|
||||||
|
done
|
||||||
|
# Old bash empty array hack
|
||||||
|
params=(${rest+"${rest[@]}"})
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
source @out@/nix-support/add-hardening.sh
|
||||||
|
|
||||||
|
extraAfter=()
|
||||||
|
extraBefore=(${hardeningLDFlags[@]+"${hardeningLDFlags[@]}"})
|
||||||
|
|
||||||
|
if [ -z "${NIX_LINK_TYPE_@suffixSalt@:-}" ]; then
|
||||||
|
extraAfter+=($(filterRpathFlags "$linkType" $NIX_LDFLAGS_@suffixSalt@))
|
||||||
|
extraBefore+=($(filterRpathFlags "$linkType" $NIX_LDFLAGS_BEFORE_@suffixSalt@))
|
||||||
|
|
||||||
|
# By adding dynamic linker to extraBefore we allow the users set their
|
||||||
|
# own dynamic linker as NIX_LD_FLAGS will override earlier set flags
|
||||||
|
if [[ "$linkType" == dynamic && -n "$NIX_DYNAMIC_LINKER_@suffixSalt@" ]]; then
|
||||||
|
extraBefore+=("-dynamic-linker" "$NIX_DYNAMIC_LINKER_@suffixSalt@")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
extraAfter+=($(filterRpathFlags "$linkType" $NIX_LDFLAGS_AFTER_@suffixSalt@))
|
||||||
|
|
||||||
|
# These flags *must not* be pulled up to -Wl, flags, so they can't go in
|
||||||
|
# add-flags.sh. They must always be set, so must not be disabled by
|
||||||
|
# NIX_LDFLAGS_SET.
|
||||||
|
if [ -e @out@/nix-support/add-local-ldflags-before.sh ]; then
|
||||||
|
source @out@/nix-support/add-local-ldflags-before.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Three tasks:
|
||||||
|
#
|
||||||
|
# 1. Find all -L... switches for rpath
|
||||||
|
#
|
||||||
|
# 2. Find relocatable flag for build id.
|
||||||
|
#
|
||||||
|
# 3. Choose 32-bit dynamic linker if needed
|
||||||
|
declare -a libDirs
|
||||||
|
declare -A libs
|
||||||
|
declare -i relocatable=0 link32=0
|
||||||
|
|
||||||
|
linkerOutput="a.out"
|
||||||
|
|
||||||
|
if
|
||||||
|
[ "$NIX_DONT_SET_RPATH_@suffixSalt@" != 1 ] \
|
||||||
|
|| [ "$NIX_SET_BUILD_ID_@suffixSalt@" = 1 ] \
|
||||||
|
|| [ -e @out@/nix-support/dynamic-linker-m32 ]
|
||||||
|
then
|
||||||
|
prev=
|
||||||
|
# Old bash thinks empty arrays are undefined, ugh.
|
||||||
|
for p in \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
||||||
|
do
|
||||||
|
case "$prev" in
|
||||||
|
-L)
|
||||||
|
libDirs+=("$p")
|
||||||
|
;;
|
||||||
|
-l)
|
||||||
|
libs["lib${p}.so"]=1
|
||||||
|
;;
|
||||||
|
-m)
|
||||||
|
# Presumably only the last `-m` flag has any effect.
|
||||||
|
case "$p" in
|
||||||
|
elf_i386) link32=1;;
|
||||||
|
*) link32=0;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
-dynamic-linker | -plugin)
|
||||||
|
# Ignore this argument, or it will match *.so and be added to rpath.
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
case "$p" in
|
||||||
|
-L/*)
|
||||||
|
libDirs+=("${p:2}")
|
||||||
|
;;
|
||||||
|
-l?*)
|
||||||
|
libs["lib${p:2}.so"]=1
|
||||||
|
;;
|
||||||
|
"${NIX_STORE:-}"/*.so | "${NIX_STORE:-}"/*.so.*)
|
||||||
|
# This is a direct reference to a shared library.
|
||||||
|
libDirs+=("${p%/*}")
|
||||||
|
libs["${p##*/}"]=1
|
||||||
|
;;
|
||||||
|
-r | --relocatable | -i)
|
||||||
|
relocatable=1
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
prev="$p"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine linkerOutput
|
||||||
|
prev=
|
||||||
|
for p in \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
||||||
|
do
|
||||||
|
case "$prev" in
|
||||||
|
-o)
|
||||||
|
# Informational for post-link-hook
|
||||||
|
linkerOutput="$p"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
prev="$p"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$link32" == "1" && "$linkType" == dynamic && -e "@out@/nix-support/dynamic-linker-m32" ]]; then
|
||||||
|
# We have an alternate 32-bit linker and we're producing a 32-bit ELF, let's
|
||||||
|
# use it.
|
||||||
|
extraAfter+=(
|
||||||
|
'-dynamic-linker'
|
||||||
|
"$(< @out@/nix-support/dynamic-linker-m32)"
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add all used dynamic libraries to the rpath.
|
||||||
|
if [[ "$NIX_DONT_SET_RPATH_@suffixSalt@" != 1 && "$linkType" != static-pie ]]; then
|
||||||
|
# For each directory in the library search path (-L...),
|
||||||
|
# see if it contains a dynamic library used by a -l... flag. If
|
||||||
|
# so, add the directory to the rpath.
|
||||||
|
# It's important to add the rpath in the order of -L..., so
|
||||||
|
# the link time chosen objects will be those of runtime linking.
|
||||||
|
declare -A rpaths
|
||||||
|
for dir in ${libDirs+"${libDirs[@]}"}; do
|
||||||
|
if [[ "$dir" =~ [/.][/.] ]] && dir2=$(readlink -f "$dir"); then
|
||||||
|
dir="$dir2"
|
||||||
|
fi
|
||||||
|
if [ -n "${rpaths[$dir]:-}" ] || [[ "$dir" != "${NIX_STORE:-}"/* ]]; then
|
||||||
|
# If the path is not in the store, don't add it to the rpath.
|
||||||
|
# This typically happens for libraries in /tmp that are later
|
||||||
|
# copied to $out/lib. If not, we're screwed.
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
for path in "$dir"/*; do
|
||||||
|
file="${path##*/}"
|
||||||
|
if [ "${libs[$file]:-}" ]; then
|
||||||
|
# This library may have been provided by a previous directory,
|
||||||
|
# but if that library file is inside an output of the current
|
||||||
|
# derivation, it can be deleted after this compilation and
|
||||||
|
# should be found in a later directory, so we add all
|
||||||
|
# directories that contain any of the libraries to rpath.
|
||||||
|
rpaths["$dir"]=1
|
||||||
|
extraAfter+=(-rpath "$dir")
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This is outside the DONT_SET_RPATH branch because it's more targeted and we
|
||||||
|
# usually want it (on Darwin) even if DONT_SET_RPATH is set.
|
||||||
|
if [ -n "${NIX_COREFOUNDATION_RPATH:-}" ]; then
|
||||||
|
extraAfter+=(-rpath $NIX_COREFOUNDATION_RPATH)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only add --build-id if this is a final link. FIXME: should build gcc
|
||||||
|
# with --enable-linker-build-id instead?
|
||||||
|
#
|
||||||
|
# Note: `lld` interprets `--build-id` to mean `--build-id=fast`; GNU ld defaults
|
||||||
|
# to SHA1.
|
||||||
|
if [ "$NIX_SET_BUILD_ID_@suffixSalt@" = 1 ] && ! (( "$relocatable" )); then
|
||||||
|
extraAfter+=(--build-id="${NIX_BUILD_ID_STYLE:-sha1}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Optionally print debug info.
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||||
|
# Old bash workaround, see above.
|
||||||
|
echo "extra flags before to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraBefore+"${extraBefore[@]}"} >&2
|
||||||
|
echo "original flags to @prog@:" >&2
|
||||||
|
printf " %q\n" ${params+"${params[@]}"} >&2
|
||||||
|
echo "extra flags after to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraAfter+"${extraAfter[@]}"} >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
PATH="$path_backup"
|
||||||
|
# Old bash workaround, see above.
|
||||||
|
|
||||||
|
if (( "${NIX_LD_USE_RESPONSE_FILE:-@use_response_file_by_default@}" >= 1 )); then
|
||||||
|
@prog@ @<(printf "%q\n" \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"})
|
||||||
|
else
|
||||||
|
@prog@ \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e "@out@/nix-support/post-link-hook" ]; then
|
||||||
|
source @out@/nix-support/post-link-hook
|
||||||
|
fi
|
|
@ -0,0 +1,246 @@
|
||||||
|
#! @shell@
|
||||||
|
|
||||||
|
set -eu -o pipefail
|
||||||
|
|
||||||
|
# For cmd | while read; do ...; done
|
||||||
|
shopt -s lastpipe
|
||||||
|
|
||||||
|
path_backup="$PATH"
|
||||||
|
if [ -n "@coreutils_bin@" ]; then
|
||||||
|
PATH="@coreutils_bin@/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -ri recurThreshold=200
|
||||||
|
declare -i overflowCount=0
|
||||||
|
|
||||||
|
declare -ar origArgs=("$@")
|
||||||
|
|
||||||
|
# Throw away what we won't need
|
||||||
|
declare -a parentArgs=()
|
||||||
|
|
||||||
|
while (( $# )); do
|
||||||
|
case "$1" in
|
||||||
|
-l)
|
||||||
|
echo "cctools LD does not support '-l foo'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
-lazy_library | -reexport_library | -upward_library | -weak_library)
|
||||||
|
overflowCount+=1
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-l* | *.so.* | *.dylib | -lazy-l* | -reexport-l* | -upward-l* | -weak-l*)
|
||||||
|
overflowCount+=1
|
||||||
|
shift 1
|
||||||
|
;;
|
||||||
|
*.a | *.o)
|
||||||
|
shift 1
|
||||||
|
;;
|
||||||
|
-L | -F)
|
||||||
|
# Evidentally ld doesn't like using the child's RPATH, so it still
|
||||||
|
# needs these.
|
||||||
|
parentArgs+=("$1" "$2")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-L?* | -F?*)
|
||||||
|
parentArgs+=("$1")
|
||||||
|
shift 1
|
||||||
|
;;
|
||||||
|
-o)
|
||||||
|
outputName="$2"
|
||||||
|
parentArgs+=("$1" "$2")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-install_name | -dylib_install_name | -dynamic-linker | -plugin)
|
||||||
|
parentArgs+=("$1" "$2")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-rpath)
|
||||||
|
# Only an rpath to the child is needed, which we will add
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ -f "$1" ]]; then
|
||||||
|
# Propabably a non-standard object file like Haskell's
|
||||||
|
# `.dyn_o`. Skip it like other inputs
|
||||||
|
:
|
||||||
|
else
|
||||||
|
parentArgs+=("$1")
|
||||||
|
fi
|
||||||
|
shift 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (( "$overflowCount" <= "$recurThreshold" )); then
|
||||||
|
if [ -n "${NIX_DEBUG:-}" ]; then
|
||||||
|
echo "ld-wrapper: Only ${overflowCount} inputs counted while ${recurThreshold} is the ceiling, linking normally. " >&2
|
||||||
|
fi
|
||||||
|
PATH="$path_backup"
|
||||||
|
exec @prog@ "${origArgs[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if [ -n "${NIX_DEBUG:-}" ]; then
|
||||||
|
echo "ld-wrapper: ${overflowCount} inputs counted when ${recurThreshold} is the ceiling, inspecting further. " >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect the normalized linker input
|
||||||
|
declare -a norm=()
|
||||||
|
|
||||||
|
# Arguments are null-separated
|
||||||
|
@prog@ --dump-normalized-lib-args "${origArgs[@]}" |
|
||||||
|
while IFS= read -r -d '' input; do
|
||||||
|
norm+=("$input")
|
||||||
|
done
|
||||||
|
|
||||||
|
declare -i leafCount=0
|
||||||
|
declare lastLeaf=''
|
||||||
|
declare -a childrenInputs=() trailingInputs=()
|
||||||
|
while (( "${#norm[@]}" )); do
|
||||||
|
case "${norm[0]}" in
|
||||||
|
-lazy_library | -upward_library)
|
||||||
|
# TODO(@Ericson2314): Don't do that, but intersperse children
|
||||||
|
# between such args.
|
||||||
|
echo "ld-wrapper: Warning: Potentially changing link order" >&2
|
||||||
|
trailingInputs+=("${norm[0]}" "${norm[1]}")
|
||||||
|
norm=("${norm[@]:2}")
|
||||||
|
;;
|
||||||
|
-reexport_library | -weak_library)
|
||||||
|
childrenInputs+=("${norm[0]}" "${norm[1]}")
|
||||||
|
if [[ "${norm[1]}" != "$lastLeaf" ]]; then
|
||||||
|
leafCount+=1
|
||||||
|
lastLeaf="${norm[1]}"
|
||||||
|
fi
|
||||||
|
norm=("${norm[@]:2}")
|
||||||
|
;;
|
||||||
|
*.so | *.dylib)
|
||||||
|
childrenInputs+=(-reexport_library "${norm[0]}")
|
||||||
|
if [[ "${norm[0]}" != "$lastLeaf" ]]; then
|
||||||
|
leafCount+=1
|
||||||
|
lastLeaf="${norm[0]}"
|
||||||
|
fi
|
||||||
|
norm=("${norm[@]:1}")
|
||||||
|
;;
|
||||||
|
*.o | *.a)
|
||||||
|
# Don't delegate object files or static libs
|
||||||
|
parentArgs+=("${norm[0]}")
|
||||||
|
norm=("${norm[@]:1}")
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ -f "${norm[0]}" ]]; then
|
||||||
|
# Propabably a non-standard object file. We'll let it by.
|
||||||
|
parentArgs+=("${norm[0]}")
|
||||||
|
norm=("${norm[@]:1}")
|
||||||
|
else
|
||||||
|
echo "ld-wrapper: Internal Error: Invalid normalized argument" >&2
|
||||||
|
exit 255
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (( "$leafCount" <= "$recurThreshold" )); then
|
||||||
|
if [ -n "${NIX_DEBUG:-}" ]; then
|
||||||
|
echo "ld-wrapper: Only ${leafCount} *dynamic* inputs counted while ${recurThreshold} is the ceiling, linking normally. " >&2
|
||||||
|
fi
|
||||||
|
PATH="$path_backup"
|
||||||
|
exec @prog@ "${origArgs[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if [ -n "${NIX_DEBUG:-}" ]; then
|
||||||
|
echo "ld-wrapper: ${leafCount} *dynamic* inputs counted when ${recurThreshold} is the ceiling, delegating to children. " >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -r outputNameLibless=$( \
|
||||||
|
if [[ -z "${outputName:+isUndefined}" ]]; then
|
||||||
|
echo unnamed
|
||||||
|
return 0;
|
||||||
|
fi
|
||||||
|
baseName=$(basename ${outputName})
|
||||||
|
if [[ "$baseName" = lib* ]]; then
|
||||||
|
baseName="${baseName:3}"
|
||||||
|
fi
|
||||||
|
echo "$baseName")
|
||||||
|
|
||||||
|
declare -ra children=(
|
||||||
|
"$outputNameLibless-reexport-delegate-0"
|
||||||
|
"$outputNameLibless-reexport-delegate-1"
|
||||||
|
)
|
||||||
|
|
||||||
|
mkdir -p "$out/lib"
|
||||||
|
|
||||||
|
symbolBloatObject=$outputNameLibless-symbol-hack.o
|
||||||
|
if [[ ! -f $symbolBloatObject ]]; then
|
||||||
|
# `-Q` means use GNU Assembler rather than Clang, avoiding an awkward
|
||||||
|
# dependency cycle.
|
||||||
|
printf '.private_extern _______child_hack_foo\nchild_hack_foo:\n' |
|
||||||
|
PATH="$PATH:@out@/bin" @targetPrefix@as -Q -- -o $symbolBloatObject
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split inputs between children
|
||||||
|
declare -a child0Inputs=() child1Inputs=("${childrenInputs[@]}")
|
||||||
|
let "countFirstChild = $leafCount / 2" || true
|
||||||
|
lastLeaf=''
|
||||||
|
while (( "$countFirstChild" )); do
|
||||||
|
case "${child1Inputs[0]}" in
|
||||||
|
-reexport_library | -weak_library)
|
||||||
|
child0Inputs+=("${child1Inputs[0]}" "${child1Inputs[1]}")
|
||||||
|
if [[ "${child1Inputs[1]}" != "$lastLeaf" ]]; then
|
||||||
|
let countFirstChild-=1 || true
|
||||||
|
lastLeaf="${child1Inputs[1]}"
|
||||||
|
fi
|
||||||
|
child1Inputs=("${child1Inputs[@]:2}")
|
||||||
|
;;
|
||||||
|
*.so | *.dylib)
|
||||||
|
child0Inputs+=(-reexport_library "${child1Inputs[0]}")
|
||||||
|
if [[ "${child1Inputs[0]}" != "$lastLeaf" ]]; then
|
||||||
|
let countFirstChild-=1 || true
|
||||||
|
lastLeaf="${child1Inputs[1]}"
|
||||||
|
fi
|
||||||
|
child1Inputs=("${child1Inputs[@]:2}")
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "ld-wrapper: Internal Error: Invalid delegated input" >&2
|
||||||
|
exit -1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
# First half of libs
|
||||||
|
@out@/bin/@targetPrefix@ld \
|
||||||
|
-macosx_version_min $MACOSX_DEPLOYMENT_TARGET -arch x86_64 -dylib \
|
||||||
|
-o "$out/lib/lib${children[0]}.dylib" \
|
||||||
|
-install_name "$out/lib/lib${children[0]}.dylib" \
|
||||||
|
"$symbolBloatObject" "${child0Inputs[@]}" "${trailingInputs[@]}"
|
||||||
|
|
||||||
|
# Second half of libs
|
||||||
|
@out@/bin/@targetPrefix@ld \
|
||||||
|
-macosx_version_min $MACOSX_DEPLOYMENT_TARGET -arch x86_64 -dylib \
|
||||||
|
-o "$out/lib/lib${children[1]}.dylib" \
|
||||||
|
-install_name "$out/lib/lib${children[1]}.dylib" \
|
||||||
|
"$symbolBloatObject" "${child1Inputs[@]}" "${trailingInputs[@]}"
|
||||||
|
|
||||||
|
parentArgs+=("-L$out/lib" -rpath "$out/lib")
|
||||||
|
if [[ $outputName != *reexport-delegate* ]]; then
|
||||||
|
parentArgs+=("-l${children[0]}" "-l${children[1]}")
|
||||||
|
else
|
||||||
|
parentArgs+=("-reexport-l${children[0]}" "-reexport-l${children[1]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
parentArgs+=("${trailingInputs[@]}")
|
||||||
|
|
||||||
|
if [ -n "${NIX_DEBUG:-}" ]; then
|
||||||
|
echo "flags using delegated children to @prog@:" >&2
|
||||||
|
printf " %q\n" "${parentArgs[@]}" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
PATH="$path_backup"
|
||||||
|
exec @prog@ "${parentArgs[@]}"
|
72
pkgs/build-support/bintools-wrapper/setup-hook.sh
Normal file
72
pkgs/build-support/bintools-wrapper/setup-hook.sh
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# Binutils Wrapper hygiene
|
||||||
|
#
|
||||||
|
# See comments in cc-wrapper's setup hook. This works exactly the same way.
|
||||||
|
|
||||||
|
# Skip setup hook if we're neither a build-time dep, nor, temporarily, doing a
|
||||||
|
# native compile.
|
||||||
|
#
|
||||||
|
# TODO(@Ericson2314): No native exception
|
||||||
|
[[ -z ${strictDeps-} ]] || (( "$hostOffset" < 0 )) || return 0
|
||||||
|
|
||||||
|
bintoolsWrapper_addLDVars () {
|
||||||
|
# See ../setup-hooks/role.bash
|
||||||
|
local role_post
|
||||||
|
getHostRoleEnvHook
|
||||||
|
|
||||||
|
if [[ -d "$1/lib64" && ! -L "$1/lib64" ]]; then
|
||||||
|
export NIX_LDFLAGS${role_post}+=" -L$1/lib64"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d "$1/lib" ]]; then
|
||||||
|
# Don't add the /lib directory if it actually doesn't contain any libraries. For instance,
|
||||||
|
# Python and Haskell packages often only have directories like $out/lib/ghc-8.4.3/ or
|
||||||
|
# $out/lib/python3.6/, so having them in LDFLAGS just makes the linker search unnecessary
|
||||||
|
# directories and bloats the size of the environment variable space.
|
||||||
|
local -a glob=( $1/lib/lib* )
|
||||||
|
if [ "${#glob[*]}" -gt 0 ]; then
|
||||||
|
export NIX_LDFLAGS${role_post}+=" -L$1/lib"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# See ../setup-hooks/role.bash
|
||||||
|
getTargetRole
|
||||||
|
getTargetRoleWrapper
|
||||||
|
|
||||||
|
addEnvHooks "$targetOffset" bintoolsWrapper_addLDVars
|
||||||
|
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [ -n "@bintools_bin@" ]; then
|
||||||
|
addToSearchPath _PATH @bintools_bin@/bin
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [ -n "@libc_bin@" ]; then
|
||||||
|
addToSearchPath _PATH @libc_bin@/bin
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [ -n "@coreutils_bin@" ]; then
|
||||||
|
addToSearchPath _PATH @coreutils_bin@/bin
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Export tool environment variables so various build systems use the right ones.
|
||||||
|
|
||||||
|
export NIX_BINTOOLS${role_post}=@out@
|
||||||
|
|
||||||
|
for cmd in \
|
||||||
|
ar as ld nm objcopy objdump readelf ranlib strip strings size windres
|
||||||
|
do
|
||||||
|
if
|
||||||
|
PATH=$_PATH type -p "@targetPrefix@${cmd}" > /dev/null
|
||||||
|
then
|
||||||
|
export "${cmd^^}${role_post}=@targetPrefix@${cmd}";
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If unset, assume the default hardening flags.
|
||||||
|
: ${NIX_HARDENING_ENABLE="@default_hardening_flags_str@"}
|
||||||
|
export NIX_HARDENING_ENABLE
|
||||||
|
|
||||||
|
# No local scope in sourced file
|
||||||
|
unset -v role_post cmd upper_case
|
294
pkgs/build-support/build-bazel-package/default.nix
Normal file
294
pkgs/build-support/build-bazel-package/default.nix
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
{ stdenv
|
||||||
|
, cacert
|
||||||
|
, lib
|
||||||
|
, writeCBin
|
||||||
|
}:
|
||||||
|
|
||||||
|
args@{
|
||||||
|
name ? "${args.pname}-${args.version}"
|
||||||
|
, bazel
|
||||||
|
, bazelFlags ? []
|
||||||
|
, bazelBuildFlags ? []
|
||||||
|
, bazelTestFlags ? []
|
||||||
|
, bazelRunFlags ? []
|
||||||
|
, runTargetFlags ? []
|
||||||
|
, bazelFetchFlags ? []
|
||||||
|
, bazelTargets ? []
|
||||||
|
, bazelTestTargets ? []
|
||||||
|
, bazelRunTarget ? null
|
||||||
|
, buildAttrs
|
||||||
|
, fetchAttrs
|
||||||
|
|
||||||
|
# Newer versions of Bazel are moving away from built-in rules_cc and instead
|
||||||
|
# allow fetching it as an external dependency in a WORKSPACE file[1]. If
|
||||||
|
# removed in the fixed-output fetch phase, building will fail to download it.
|
||||||
|
# This can be seen e.g. in #73097
|
||||||
|
#
|
||||||
|
# This option allows configuring the removal of rules_cc in cases where a
|
||||||
|
# project depends on it via an external dependency.
|
||||||
|
#
|
||||||
|
# [1]: https://github.com/bazelbuild/rules_cc
|
||||||
|
, removeRulesCC ? true
|
||||||
|
, removeLocalConfigCc ? true
|
||||||
|
, removeLocal ? true
|
||||||
|
|
||||||
|
# Use build --nobuild instead of fetch. This allows fetching the dependencies
|
||||||
|
# required for the build as configured, rather than fetching all the dependencies
|
||||||
|
# which may not work in some situations (e.g. Java code which ends up relying on
|
||||||
|
# Debian-specific /usr/share/java paths, but doesn't in the configured build).
|
||||||
|
, fetchConfigured ? true
|
||||||
|
|
||||||
|
# Don’t add Bazel --copt and --linkopt from NIX_CFLAGS_COMPILE /
|
||||||
|
# NIX_LDFLAGS. This is necessary when using a custom toolchain which
|
||||||
|
# Bazel wants all headers / libraries to come from, like when using
|
||||||
|
# CROSSTOOL. Weirdly, we can still get the flags through the wrapped
|
||||||
|
# compiler.
|
||||||
|
, dontAddBazelOpts ? false
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
fArgs = removeAttrs args [ "buildAttrs" "fetchAttrs" "removeRulesCC" ] // {
|
||||||
|
inherit
|
||||||
|
name
|
||||||
|
bazelFlags
|
||||||
|
bazelBuildFlags
|
||||||
|
bazelTestFlags
|
||||||
|
bazelRunFlags
|
||||||
|
runTargetFlags
|
||||||
|
bazelFetchFlags
|
||||||
|
bazelTargets
|
||||||
|
bazelTestTargets
|
||||||
|
bazelRunTarget
|
||||||
|
dontAddBazelOpts
|
||||||
|
;
|
||||||
|
};
|
||||||
|
fBuildAttrs = fArgs // buildAttrs;
|
||||||
|
fFetchAttrs = fArgs // removeAttrs fetchAttrs [ "sha256" ];
|
||||||
|
bazelCmd = { cmd, additionalFlags, targets, targetRunFlags ? [ ] }:
|
||||||
|
lib.optionalString (targets != [ ]) ''
|
||||||
|
# See footnote called [USER and BAZEL_USE_CPP_ONLY_TOOLCHAIN variables]
|
||||||
|
BAZEL_USE_CPP_ONLY_TOOLCHAIN=1 \
|
||||||
|
USER=homeless-shelter \
|
||||||
|
bazel \
|
||||||
|
--batch \
|
||||||
|
--output_base="$bazelOut" \
|
||||||
|
--output_user_root="$bazelUserRoot" \
|
||||||
|
${cmd} \
|
||||||
|
--curses=no \
|
||||||
|
"''${copts[@]}" \
|
||||||
|
"''${host_copts[@]}" \
|
||||||
|
"''${linkopts[@]}" \
|
||||||
|
"''${host_linkopts[@]}" \
|
||||||
|
$bazelFlags \
|
||||||
|
${lib.strings.concatStringsSep " " additionalFlags} \
|
||||||
|
${lib.strings.concatStringsSep " " targets} \
|
||||||
|
${lib.optionalString (targetRunFlags != []) " -- " + lib.strings.concatStringsSep " " targetRunFlags}
|
||||||
|
'';
|
||||||
|
# we need this to chmod dangling symlinks on darwin, gnu coreutils refuses to do so:
|
||||||
|
# chmod: cannot operate on dangling symlink '$symlink'
|
||||||
|
chmodder = writeCBin "chmodder" ''
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "usage: chmodder file");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (lchmod(argv[1], mode) != 0) {
|
||||||
|
fprintf(stderr, "failed to lchmod '%s': %s", argv[0], strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation (fBuildAttrs // {
|
||||||
|
|
||||||
|
deps = stdenv.mkDerivation (fFetchAttrs // {
|
||||||
|
name = "${name}-deps.tar.gz";
|
||||||
|
|
||||||
|
impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ fFetchAttrs.impureEnvVars or [];
|
||||||
|
|
||||||
|
nativeBuildInputs = fFetchAttrs.nativeBuildInputs or [] ++ [ bazel ];
|
||||||
|
|
||||||
|
preHook = fFetchAttrs.preHook or "" + ''
|
||||||
|
export bazelOut="$(echo ''${NIX_BUILD_TOP}/output | sed -e 's,//,/,g')"
|
||||||
|
export bazelUserRoot="$(echo ''${NIX_BUILD_TOP}/tmp | sed -e 's,//,/,g')"
|
||||||
|
export HOME="$NIX_BUILD_TOP"
|
||||||
|
export USER="nix"
|
||||||
|
# This is needed for git_repository with https remotes
|
||||||
|
export GIT_SSL_CAINFO="${cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||||
|
# This is needed for Bazel fetchers that are themselves programs (e.g.
|
||||||
|
# rules_go using the go toolchain)
|
||||||
|
export SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||||
|
'';
|
||||||
|
|
||||||
|
buildPhase = fFetchAttrs.buildPhase or ''
|
||||||
|
runHook preBuild
|
||||||
|
|
||||||
|
${
|
||||||
|
bazelCmd {
|
||||||
|
cmd = if fetchConfigured then "build --nobuild" else "fetch";
|
||||||
|
additionalFlags = [
|
||||||
|
# We disable multithreading for the fetching phase since it can lead to timeouts with many dependencies/threads:
|
||||||
|
# https://github.com/bazelbuild/bazel/issues/6502
|
||||||
|
"--loading_phase_threads=1"
|
||||||
|
"$bazelFetchFlags"
|
||||||
|
] ++ (if fetchConfigured then ["--jobs" "$NIX_BUILD_CORES"] else []);
|
||||||
|
targets = fFetchAttrs.bazelTargets ++ fFetchAttrs.bazelTestTargets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = fFetchAttrs.installPhase or (''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
# Remove all built in external workspaces, Bazel will recreate them when building
|
||||||
|
rm -rf $bazelOut/external/{bazel_tools,\@bazel_tools.marker}
|
||||||
|
${lib.optionalString removeRulesCC "rm -rf $bazelOut/external/{rules_cc,\\@rules_cc.marker}"}
|
||||||
|
rm -rf $bazelOut/external/{embedded_jdk,\@embedded_jdk.marker}
|
||||||
|
${lib.optionalString removeLocalConfigCc "rm -rf $bazelOut/external/{local_config_cc,\\@local_config_cc.marker}"}
|
||||||
|
${lib.optionalString removeLocal "rm -rf $bazelOut/external/{local_*,\\@local_*.marker}"}
|
||||||
|
|
||||||
|
# Clear markers
|
||||||
|
find $bazelOut/external -name '@*\.marker' -exec sh -c 'echo > {}' \;
|
||||||
|
|
||||||
|
# Remove all vcs files
|
||||||
|
rm -rf $(find $bazelOut/external -type d -name .git)
|
||||||
|
rm -rf $(find $bazelOut/external -type d -name .svn)
|
||||||
|
rm -rf $(find $bazelOut/external -type d -name .hg)
|
||||||
|
|
||||||
|
# Removing top-level symlinks along with their markers.
|
||||||
|
# This is needed because they sometimes point to temporary paths (?).
|
||||||
|
# For example, in Tensorflow-gpu build:
|
||||||
|
# platforms -> NIX_BUILD_TOP/tmp/install/35282f5123611afa742331368e9ae529/_embedded_binaries/platforms
|
||||||
|
find $bazelOut/external -maxdepth 1 -type l | while read symlink; do
|
||||||
|
name="$(basename "$symlink")"
|
||||||
|
rm "$symlink"
|
||||||
|
test -f "$bazelOut/external/@$name.marker" && rm "$bazelOut/external/@$name.marker" || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Patching symlinks to remove build directory reference
|
||||||
|
find $bazelOut/external -type l | while read symlink; do
|
||||||
|
new_target="$(readlink "$symlink" | sed "s,$NIX_BUILD_TOP,NIX_BUILD_TOP,")"
|
||||||
|
rm "$symlink"
|
||||||
|
ln -sf "$new_target" "$symlink"
|
||||||
|
'' + lib.optionalString stdenv.isDarwin ''
|
||||||
|
# on linux symlink permissions cannot be modified, so we modify those on darwin to match the linux ones
|
||||||
|
${chmodder}/bin/chmodder "$symlink"
|
||||||
|
'' + ''
|
||||||
|
done
|
||||||
|
|
||||||
|
echo '${bazel.name}' > $bazelOut/external/.nix-bazel-version
|
||||||
|
|
||||||
|
(cd $bazelOut/ && tar czf $out --sort=name --mtime='@1' --owner=0 --group=0 --numeric-owner external/)
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'');
|
||||||
|
|
||||||
|
dontFixup = true;
|
||||||
|
allowedRequisites = [];
|
||||||
|
|
||||||
|
outputHashAlgo = "sha256";
|
||||||
|
outputHash = fetchAttrs.sha256;
|
||||||
|
});
|
||||||
|
|
||||||
|
nativeBuildInputs = fBuildAttrs.nativeBuildInputs or [] ++ [ (bazel.override { enableNixHacks = true; }) ];
|
||||||
|
|
||||||
|
preHook = fBuildAttrs.preHook or "" + ''
|
||||||
|
export bazelOut="$NIX_BUILD_TOP/output"
|
||||||
|
export bazelUserRoot="$NIX_BUILD_TOP/tmp"
|
||||||
|
export HOME="$NIX_BUILD_TOP"
|
||||||
|
'';
|
||||||
|
|
||||||
|
preConfigure = ''
|
||||||
|
mkdir -p "$bazelOut"
|
||||||
|
|
||||||
|
(cd $bazelOut && tar xfz $deps)
|
||||||
|
|
||||||
|
test "${bazel.name}" = "$(<$bazelOut/external/.nix-bazel-version)" || {
|
||||||
|
echo "fixed output derivation was built for a different bazel version" >&2
|
||||||
|
echo " got: $(<$bazelOut/external/.nix-bazel-version)" >&2
|
||||||
|
echo "expected: ${bazel.name}" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
chmod -R +w $bazelOut
|
||||||
|
find $bazelOut -type l | while read symlink; do
|
||||||
|
if [[ $(readlink "$symlink") == *NIX_BUILD_TOP* ]]; then
|
||||||
|
ln -sf $(readlink "$symlink" | sed "s,NIX_BUILD_TOP,$NIX_BUILD_TOP,") "$symlink"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
'' + fBuildAttrs.preConfigure or "";
|
||||||
|
|
||||||
|
buildPhase = fBuildAttrs.buildPhase or ''
|
||||||
|
runHook preBuild
|
||||||
|
|
||||||
|
# Bazel sandboxes the execution of the tools it invokes, so even though we are
|
||||||
|
# calling the correct nix wrappers, the values of the environment variables
|
||||||
|
# the wrappers are expecting will not be set. So instead of relying on the
|
||||||
|
# wrappers picking them up, pass them in explicitly via `--copt`, `--linkopt`
|
||||||
|
# and related flags.
|
||||||
|
|
||||||
|
copts=()
|
||||||
|
host_copts=()
|
||||||
|
linkopts=()
|
||||||
|
host_linkopts=()
|
||||||
|
if [ -z "''${dontAddBazelOpts:-}" ]; then
|
||||||
|
for flag in $NIX_CFLAGS_COMPILE; do
|
||||||
|
copts+=( "--copt=$flag" )
|
||||||
|
host_copts+=( "--host_copt=$flag" )
|
||||||
|
done
|
||||||
|
for flag in $NIX_CXXSTDLIB_COMPILE; do
|
||||||
|
copts+=( "--copt=$flag" )
|
||||||
|
host_copts+=( "--host_copt=$flag" )
|
||||||
|
done
|
||||||
|
for flag in $NIX_LDFLAGS; do
|
||||||
|
linkopts+=( "--linkopt=-Wl,$flag" )
|
||||||
|
host_linkopts+=( "--host_linkopt=-Wl,$flag" )
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
${
|
||||||
|
bazelCmd {
|
||||||
|
cmd = "test";
|
||||||
|
additionalFlags =
|
||||||
|
["--test_output=errors"] ++ fBuildAttrs.bazelTestFlags ++ ["--jobs" "$NIX_BUILD_CORES"];
|
||||||
|
targets = fBuildAttrs.bazelTestTargets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${
|
||||||
|
bazelCmd {
|
||||||
|
cmd = "build";
|
||||||
|
additionalFlags = fBuildAttrs.bazelBuildFlags ++ ["--jobs" "$NIX_BUILD_CORES"];
|
||||||
|
targets = fBuildAttrs.bazelTargets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${
|
||||||
|
bazelCmd {
|
||||||
|
cmd = "run";
|
||||||
|
additionalFlags = fBuildAttrs.bazelRunFlags ++ [ "--jobs" "$NIX_BUILD_CORES" ];
|
||||||
|
# Bazel run only accepts a single target, but `bazelCmd` expects `targets` to be a list.
|
||||||
|
targets = lib.optionals (fBuildAttrs.bazelRunTarget != null) [ fBuildAttrs.bazelRunTarget ];
|
||||||
|
targetRunFlags = fBuildAttrs.runTargetFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
|
||||||
|
# [USER and BAZEL_USE_CPP_ONLY_TOOLCHAIN variables]:
|
||||||
|
# Bazel computes the default value of output_user_root before parsing the
|
||||||
|
# flag. The computation of the default value involves getting the $USER
|
||||||
|
# from the environment. Code here :
|
||||||
|
# https://github.com/bazelbuild/bazel/blob/9323c57607d37f9c949b60e293b573584906da46/src/main/cpp/startup_options.cc#L123-L124
|
||||||
|
#
|
||||||
|
# On macOS Bazel will use the system installed Xcode or CLT toolchain instead of the one in the PATH unless we pass BAZEL_USE_CPP_ONLY_TOOLCHAIN.
|
266
pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix
Normal file
266
pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, runCommandLocal
|
||||||
|
, buildEnv
|
||||||
|
, writeText
|
||||||
|
, writeShellScriptBin
|
||||||
|
, pkgs
|
||||||
|
, pkgsi686Linux
|
||||||
|
}:
|
||||||
|
|
||||||
|
{ profile ? ""
|
||||||
|
, targetPkgs ? pkgs: []
|
||||||
|
, multiPkgs ? pkgs: []
|
||||||
|
, multiArch ? false # Whether to include 32bit packages
|
||||||
|
, extraBuildCommands ? ""
|
||||||
|
, extraBuildCommandsMulti ? ""
|
||||||
|
, extraOutputsToInstall ? []
|
||||||
|
, ... # for name, or pname+version
|
||||||
|
} @ args:
|
||||||
|
|
||||||
|
# HOWTO:
|
||||||
|
# All packages (most likely programs) returned from targetPkgs will only be
|
||||||
|
# installed once--matching the host's architecture (64bit on x86_64 and 32bit on
|
||||||
|
# x86).
|
||||||
|
#
|
||||||
|
# Packages (most likely libraries) returned from multiPkgs are installed
|
||||||
|
# once on x86 systems and twice on x86_64 systems.
|
||||||
|
# On x86 they are merged with packages from targetPkgs.
|
||||||
|
# On x86_64 they are added to targetPkgs and in addition their 32bit
|
||||||
|
# versions are also installed. The final directory structure looks as
|
||||||
|
# follows:
|
||||||
|
# /lib32 will include 32bit libraries from multiPkgs
|
||||||
|
# /lib64 will include 64bit libraries from multiPkgs and targetPkgs
|
||||||
|
# /lib will link to /lib32
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (stdenv) is64bit;
|
||||||
|
|
||||||
|
name = if (args ? pname && args ? version)
|
||||||
|
then "${args.pname}-${args.version}"
|
||||||
|
else args.name;
|
||||||
|
|
||||||
|
# "use of glibc_multi is only supported on x86_64-linux"
|
||||||
|
isMultiBuild = multiArch && stdenv.system == "x86_64-linux";
|
||||||
|
isTargetBuild = !isMultiBuild;
|
||||||
|
|
||||||
|
# list of packages (usually programs) which match the host's architecture
|
||||||
|
# (which includes stuff from multiPkgs)
|
||||||
|
targetPaths = targetPkgs pkgs ++ (if multiPkgs == null then [] else multiPkgs pkgs);
|
||||||
|
|
||||||
|
# list of packages which are for x86 (only multiPkgs, only for x86_64 hosts)
|
||||||
|
multiPaths = multiPkgs pkgsi686Linux;
|
||||||
|
|
||||||
|
# base packages of the chroot
|
||||||
|
# these match the host's architecture, glibc_multi is used for multilib
|
||||||
|
# builds. glibcLocales must be before glibc or glibc_multi as otherwiese
|
||||||
|
# the wrong LOCALE_ARCHIVE will be used where only C.UTF-8 is available.
|
||||||
|
baseTargetPaths = with pkgs; [
|
||||||
|
glibcLocales
|
||||||
|
(if isMultiBuild then glibc_multi else glibc)
|
||||||
|
(toString gcc.cc.lib)
|
||||||
|
bashInteractiveFHS
|
||||||
|
coreutils
|
||||||
|
less
|
||||||
|
shadow
|
||||||
|
su
|
||||||
|
gawk
|
||||||
|
diffutils
|
||||||
|
findutils
|
||||||
|
gnused
|
||||||
|
gnugrep
|
||||||
|
gnutar
|
||||||
|
gzip
|
||||||
|
bzip2
|
||||||
|
xz
|
||||||
|
];
|
||||||
|
baseMultiPaths = with pkgsi686Linux; [
|
||||||
|
(toString gcc.cc.lib)
|
||||||
|
];
|
||||||
|
|
||||||
|
ldconfig = writeShellScriptBin "ldconfig" ''
|
||||||
|
# due to a glibc bug, 64-bit ldconfig complains about patchelf'd 32-bit libraries, so we use 32-bit ldconfig when we have them
|
||||||
|
exec ${if isMultiBuild then pkgsi686Linux.glibc.bin else pkgs.glibc.bin}/bin/ldconfig -f /etc/ld.so.conf -C /etc/ld.so.cache "$@"
|
||||||
|
'';
|
||||||
|
|
||||||
|
etcProfile = writeText "profile" ''
|
||||||
|
export PS1='${name}-chrootenv:\u@\h:\w\$ '
|
||||||
|
export LOCALE_ARCHIVE='/usr/lib/locale/locale-archive'
|
||||||
|
export LD_LIBRARY_PATH="/run/opengl-driver/lib:/run/opengl-driver-32/lib''${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH"
|
||||||
|
export PATH="/run/wrappers/bin:/usr/bin:/usr/sbin:$PATH"
|
||||||
|
export TZDIR='/etc/zoneinfo'
|
||||||
|
|
||||||
|
# XDG_DATA_DIRS is used by pressure-vessel (steam proton) and vulkan loaders to find the corresponding icd
|
||||||
|
export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/run/opengl-driver/share:/run/opengl-driver-32/share
|
||||||
|
|
||||||
|
# Following XDG spec [1], XDG_DATA_DIRS should default to "/usr/local/share:/usr/share".
|
||||||
|
# In nix, it is commonly set without containing these values, so we add them as fallback.
|
||||||
|
#
|
||||||
|
# [1] <https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>
|
||||||
|
case ":$XDG_DATA_DIRS:" in
|
||||||
|
*:/usr/local/share:*) ;;
|
||||||
|
*) export XDG_DATA_DIRS="$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/usr/local/share" ;;
|
||||||
|
esac
|
||||||
|
case ":$XDG_DATA_DIRS:" in
|
||||||
|
*:/usr/share:*) ;;
|
||||||
|
*) export XDG_DATA_DIRS="$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/usr/share" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Force compilers and other tools to look in default search paths
|
||||||
|
unset NIX_ENFORCE_PURITY
|
||||||
|
export NIX_BINTOOLS_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1
|
||||||
|
export NIX_CC_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1
|
||||||
|
export NIX_CFLAGS_COMPILE='-idirafter /usr/include'
|
||||||
|
export NIX_CFLAGS_LINK='-L/usr/lib -L/usr/lib32'
|
||||||
|
export NIX_LDFLAGS='-L/usr/lib -L/usr/lib32'
|
||||||
|
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
|
||||||
|
export ACLOCAL_PATH=/usr/share/aclocal
|
||||||
|
|
||||||
|
${profile}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Compose /etc for the chroot environment
|
||||||
|
etcPkg = runCommandLocal "${name}-chrootenv-etc" { } ''
|
||||||
|
mkdir -p $out/etc
|
||||||
|
pushd $out/etc
|
||||||
|
|
||||||
|
# environment variables
|
||||||
|
ln -s ${etcProfile} profile
|
||||||
|
|
||||||
|
# symlink /etc/mtab -> /proc/mounts (compat for old userspace progs)
|
||||||
|
ln -s /proc/mounts mtab
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Composes a /usr-like directory structure
|
||||||
|
staticUsrProfileTarget = buildEnv {
|
||||||
|
name = "${name}-usr-target";
|
||||||
|
# ldconfig wrapper must come first so it overrides the original ldconfig
|
||||||
|
paths = [ etcPkg ldconfig ] ++ baseTargetPaths ++ targetPaths;
|
||||||
|
extraOutputsToInstall = [ "out" "lib" "bin" ] ++ extraOutputsToInstall;
|
||||||
|
ignoreCollisions = true;
|
||||||
|
postBuild = ''
|
||||||
|
if [[ -d $out/share/gsettings-schemas/ ]]; then
|
||||||
|
# Recreate the standard schemas directory if its a symlink to make it writable
|
||||||
|
if [[ -L $out/share/glib-2.0 ]]; then
|
||||||
|
target=$(readlink $out/share/glib-2.0)
|
||||||
|
rm $out/share/glib-2.0
|
||||||
|
mkdir $out/share/glib-2.0
|
||||||
|
ln -fs $target/* $out/share/glib-2.0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -L $out/share/glib-2.0/schemas ]]; then
|
||||||
|
target=$(readlink $out/share/glib-2.0/schemas)
|
||||||
|
rm $out/share/glib-2.0/schemas
|
||||||
|
mkdir $out/share/glib-2.0/schemas
|
||||||
|
ln -fs $target/* $out/share/glib-2.0/schemas
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p $out/share/glib-2.0/schemas
|
||||||
|
|
||||||
|
for d in $out/share/gsettings-schemas/*; do
|
||||||
|
# Force symlink, in case there are duplicates
|
||||||
|
ln -fs $d/glib-2.0/schemas/*.xml $out/share/glib-2.0/schemas
|
||||||
|
ln -fs $d/glib-2.0/schemas/*.gschema.override $out/share/glib-2.0/schemas
|
||||||
|
done
|
||||||
|
|
||||||
|
# and compile them
|
||||||
|
${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/glib-2.0/schemas
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
staticUsrProfileMulti = buildEnv {
|
||||||
|
name = "${name}-usr-multi";
|
||||||
|
paths = baseMultiPaths ++ multiPaths;
|
||||||
|
extraOutputsToInstall = [ "out" "lib" ] ++ extraOutputsToInstall;
|
||||||
|
ignoreCollisions = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# setup library paths only for the targeted architecture
|
||||||
|
setupLibDirsTarget = ''
|
||||||
|
# link content of targetPaths
|
||||||
|
cp -rsHf ${staticUsrProfileTarget}/lib lib
|
||||||
|
ln -s lib lib${if is64bit then "64" else "32"}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# setup /lib, /lib32 and /lib64
|
||||||
|
setupLibDirsMulti = ''
|
||||||
|
mkdir -m0755 lib32
|
||||||
|
mkdir -m0755 lib64
|
||||||
|
ln -s lib64 lib
|
||||||
|
|
||||||
|
# copy glibc stuff
|
||||||
|
cp -rsHf ${staticUsrProfileTarget}/lib/32/* lib32/
|
||||||
|
chmod u+w -R lib32/
|
||||||
|
|
||||||
|
# copy content of multiPaths (32bit libs)
|
||||||
|
if [ -d ${staticUsrProfileMulti}/lib ]; then
|
||||||
|
cp -rsHf ${staticUsrProfileMulti}/lib/* lib32/
|
||||||
|
chmod u+w -R lib32/
|
||||||
|
fi
|
||||||
|
|
||||||
|
# copy content of targetPaths (64bit libs)
|
||||||
|
cp -rsHf ${staticUsrProfileTarget}/lib/* lib64/
|
||||||
|
chmod u+w -R lib64/
|
||||||
|
|
||||||
|
# symlink 32-bit ld-linux.so
|
||||||
|
ln -Ls ${staticUsrProfileTarget}/lib/32/ld-linux.so.2 lib/
|
||||||
|
'';
|
||||||
|
|
||||||
|
setupLibDirs = if isTargetBuild
|
||||||
|
then setupLibDirsTarget
|
||||||
|
else setupLibDirsMulti;
|
||||||
|
|
||||||
|
# the target profile is the actual profile that will be used for the chroot
|
||||||
|
setupTargetProfile = ''
|
||||||
|
mkdir -m0755 usr
|
||||||
|
pushd usr
|
||||||
|
|
||||||
|
${setupLibDirs}
|
||||||
|
|
||||||
|
'' + lib.optionalString isMultiBuild ''
|
||||||
|
if [ -d "${staticUsrProfileMulti}/share" ]; then
|
||||||
|
cp -rLf ${staticUsrProfileMulti}/share share
|
||||||
|
fi
|
||||||
|
'' + ''
|
||||||
|
if [ -d "${staticUsrProfileTarget}/share" ]; then
|
||||||
|
if [ -d share ]; then
|
||||||
|
chmod -R 755 share
|
||||||
|
cp -rLTf ${staticUsrProfileTarget}/share share
|
||||||
|
else
|
||||||
|
cp -rsHf ${staticUsrProfileTarget}/share share
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
for i in bin sbin include; do
|
||||||
|
if [ -d "${staticUsrProfileTarget}/$i" ]; then
|
||||||
|
cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
for i in var etc opt; do
|
||||||
|
if [ -d "${staticUsrProfileTarget}/$i" ]; then
|
||||||
|
cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for i in usr/{bin,sbin,lib,lib32,lib64}; do
|
||||||
|
if [ -d "$i" ]; then
|
||||||
|
ln -s "$i"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
popd
|
||||||
|
'';
|
||||||
|
|
||||||
|
in runCommandLocal "${name}-fhs" {
|
||||||
|
passthru = {
|
||||||
|
inherit args baseTargetPaths targetPaths baseMultiPaths ldconfig isMultiBuild;
|
||||||
|
};
|
||||||
|
} ''
|
||||||
|
mkdir -p $out
|
||||||
|
pushd $out
|
||||||
|
|
||||||
|
${setupTargetProfile}
|
||||||
|
${extraBuildCommands}
|
||||||
|
${lib.optionalString isMultiBuild extraBuildCommandsMulti}
|
||||||
|
''
|
289
pkgs/build-support/build-fhsenv-bubblewrap/default.nix
Normal file
289
pkgs/build-support/build-fhsenv-bubblewrap/default.nix
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, callPackage
|
||||||
|
, runCommandLocal
|
||||||
|
, writeShellScript
|
||||||
|
, glibc
|
||||||
|
, pkgsi686Linux
|
||||||
|
, coreutils
|
||||||
|
, bubblewrap
|
||||||
|
}:
|
||||||
|
|
||||||
|
{ runScript ? "bash"
|
||||||
|
, extraInstallCommands ? ""
|
||||||
|
, meta ? {}
|
||||||
|
, passthru ? {}
|
||||||
|
, extraPreBwrapCmds ? ""
|
||||||
|
, extraBwrapArgs ? []
|
||||||
|
, unshareUser ? false
|
||||||
|
, unshareIpc ? false
|
||||||
|
, unsharePid ? false
|
||||||
|
, unshareNet ? false
|
||||||
|
, unshareUts ? false
|
||||||
|
, unshareCgroup ? false
|
||||||
|
, privateTmp ? false
|
||||||
|
, dieWithParent ? true
|
||||||
|
, ...
|
||||||
|
} @ args:
|
||||||
|
|
||||||
|
assert (!args ? pname || !args ? version) -> (args ? name); # You must provide name if pname or version (preferred) is missing.
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
concatLines
|
||||||
|
concatStringsSep
|
||||||
|
escapeShellArgs
|
||||||
|
filter
|
||||||
|
optionalString
|
||||||
|
splitString
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (lib.attrsets) removeAttrs;
|
||||||
|
|
||||||
|
name = args.name or "${args.pname}-${args.version}";
|
||||||
|
executableName = args.pname or args.name;
|
||||||
|
# we don't know which have been supplied, and want to avoid defaulting missing attrs to null. Passed into runCommandLocal
|
||||||
|
nameAttrs = lib.filterAttrs (key: value: builtins.elem key [ "name" "pname" "version" ]) args;
|
||||||
|
|
||||||
|
buildFHSEnv = callPackage ./buildFHSEnv.nix { };
|
||||||
|
|
||||||
|
fhsenv = buildFHSEnv (removeAttrs args [
|
||||||
|
"runScript" "extraInstallCommands" "meta" "passthru" "extraPreBwrapCmds" "extraBwrapArgs" "dieWithParent"
|
||||||
|
"unshareUser" "unshareCgroup" "unshareUts" "unshareNet" "unsharePid" "unshareIpc" "privateTmp"
|
||||||
|
]);
|
||||||
|
|
||||||
|
etcBindEntries = let
|
||||||
|
files = [
|
||||||
|
# NixOS Compatibility
|
||||||
|
"static"
|
||||||
|
"nix" # mainly for nixUnstable users, but also for access to nix/netrc
|
||||||
|
# Shells
|
||||||
|
"shells"
|
||||||
|
"bashrc"
|
||||||
|
"zshenv"
|
||||||
|
"zshrc"
|
||||||
|
"zinputrc"
|
||||||
|
"zprofile"
|
||||||
|
# Users, Groups, NSS
|
||||||
|
"passwd"
|
||||||
|
"group"
|
||||||
|
"shadow"
|
||||||
|
"hosts"
|
||||||
|
"resolv.conf"
|
||||||
|
"nsswitch.conf"
|
||||||
|
# User profiles
|
||||||
|
"profiles"
|
||||||
|
# Sudo & Su
|
||||||
|
"login.defs"
|
||||||
|
"sudoers"
|
||||||
|
"sudoers.d"
|
||||||
|
# Time
|
||||||
|
"localtime"
|
||||||
|
"zoneinfo"
|
||||||
|
# Other Core Stuff
|
||||||
|
"machine-id"
|
||||||
|
"os-release"
|
||||||
|
# PAM
|
||||||
|
"pam.d"
|
||||||
|
# Fonts
|
||||||
|
"fonts"
|
||||||
|
# ALSA
|
||||||
|
"alsa"
|
||||||
|
"asound.conf"
|
||||||
|
# SSL
|
||||||
|
"ssl/certs"
|
||||||
|
"ca-certificates"
|
||||||
|
"pki"
|
||||||
|
];
|
||||||
|
in map (path: "/etc/${path}") files;
|
||||||
|
|
||||||
|
# Create this on the fly instead of linking from /nix
|
||||||
|
# The container might have to modify it and re-run ldconfig if there are
|
||||||
|
# issues running some binary with LD_LIBRARY_PATH
|
||||||
|
createLdConfCache = ''
|
||||||
|
cat > /etc/ld.so.conf <<EOF
|
||||||
|
/lib
|
||||||
|
/lib/x86_64-linux-gnu
|
||||||
|
/lib64
|
||||||
|
/usr/lib
|
||||||
|
/usr/lib/x86_64-linux-gnu
|
||||||
|
/usr/lib64
|
||||||
|
/lib/i386-linux-gnu
|
||||||
|
/lib32
|
||||||
|
/usr/lib/i386-linux-gnu
|
||||||
|
/usr/lib32
|
||||||
|
/run/opengl-driver/lib
|
||||||
|
/run/opengl-driver-32/lib
|
||||||
|
EOF
|
||||||
|
ldconfig &> /dev/null
|
||||||
|
'';
|
||||||
|
init = run: writeShellScript "${name}-init" ''
|
||||||
|
source /etc/profile
|
||||||
|
${createLdConfCache}
|
||||||
|
exec ${run} "$@"
|
||||||
|
'';
|
||||||
|
|
||||||
|
indentLines = str: concatLines (map (s: " " + s) (filter (s: s != "") (splitString "\n" str)));
|
||||||
|
bwrapCmd = { initArgs ? "" }: ''
|
||||||
|
${extraPreBwrapCmds}
|
||||||
|
ignored=(/nix /dev /proc /etc ${optionalString privateTmp "/tmp"})
|
||||||
|
ro_mounts=()
|
||||||
|
symlinks=()
|
||||||
|
etc_ignored=()
|
||||||
|
|
||||||
|
# loop through all entries of root in the fhs environment, except its /etc.
|
||||||
|
for i in ${fhsenv}/*; do
|
||||||
|
path="/''${i##*/}"
|
||||||
|
if [[ $path == '/etc' ]]; then
|
||||||
|
:
|
||||||
|
elif [[ -L $i ]]; then
|
||||||
|
symlinks+=(--symlink "$(${coreutils}/bin/readlink "$i")" "$path")
|
||||||
|
ignored+=("$path")
|
||||||
|
else
|
||||||
|
ro_mounts+=(--ro-bind "$i" "$path")
|
||||||
|
ignored+=("$path")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# loop through the entries of /etc in the fhs environment.
|
||||||
|
if [[ -d ${fhsenv}/etc ]]; then
|
||||||
|
for i in ${fhsenv}/etc/*; do
|
||||||
|
path="/''${i##*/}"
|
||||||
|
# NOTE: we're binding /etc/fonts and /etc/ssl/certs from the host so we
|
||||||
|
# don't want to override it with a path from the FHS environment.
|
||||||
|
if [[ $path == '/fonts' || $path == '/ssl' ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [[ -L $i ]]; then
|
||||||
|
symlinks+=(--symlink "$i" "/etc$path")
|
||||||
|
else
|
||||||
|
ro_mounts+=(--ro-bind "$i" "/etc$path")
|
||||||
|
fi
|
||||||
|
etc_ignored+=("/etc$path")
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# propagate /etc from the actual host if nested
|
||||||
|
if [[ -e /.host-etc ]]; then
|
||||||
|
ro_mounts+=(--ro-bind /.host-etc /.host-etc)
|
||||||
|
else
|
||||||
|
ro_mounts+=(--ro-bind /etc /.host-etc)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# link selected etc entries from the actual root
|
||||||
|
for i in ${escapeShellArgs etcBindEntries}; do
|
||||||
|
if [[ "''${etc_ignored[@]}" =~ "$i" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [[ -e $i ]]; then
|
||||||
|
symlinks+=(--symlink "/.host-etc/''${i#/etc/}" "$i")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
declare -a auto_mounts
|
||||||
|
# loop through all directories in the root
|
||||||
|
for dir in /*; do
|
||||||
|
# if it is a directory and it is not ignored
|
||||||
|
if [[ -d "$dir" ]] && [[ ! "''${ignored[@]}" =~ "$dir" ]]; then
|
||||||
|
# add it to the mount list
|
||||||
|
auto_mounts+=(--bind "$dir" "$dir")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
declare -a x11_args
|
||||||
|
# Always mount a tmpfs on /tmp/.X11-unix
|
||||||
|
# Rationale: https://github.com/flatpak/flatpak/blob/be2de97e862e5ca223da40a895e54e7bf24dbfb9/common/flatpak-run.c#L277
|
||||||
|
x11_args+=(--tmpfs /tmp/.X11-unix)
|
||||||
|
|
||||||
|
# Try to guess X socket path. This doesn't cover _everything_, but it covers some things.
|
||||||
|
if [[ "$DISPLAY" == :* ]]; then
|
||||||
|
display_nr=''${DISPLAY#?}
|
||||||
|
local_socket=/tmp/.X11-unix/X$display_nr
|
||||||
|
x11_args+=(--ro-bind-try "$local_socket" "$local_socket")
|
||||||
|
fi
|
||||||
|
|
||||||
|
${optionalString privateTmp ''
|
||||||
|
# sddm places XAUTHORITY in /tmp
|
||||||
|
if [[ "$XAUTHORITY" == /tmp/* ]]; then
|
||||||
|
x11_args+=(--ro-bind-try "$XAUTHORITY" "$XAUTHORITY")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# dbus-run-session puts the socket in /tmp
|
||||||
|
IFS=";" read -ra addrs <<<"$DBUS_SESSION_BUS_ADDRESS"
|
||||||
|
for addr in "''${addrs[@]}"; do
|
||||||
|
[[ "$addr" == unix:* ]] || continue
|
||||||
|
IFS="," read -ra parts <<<"''${addr#unix:}"
|
||||||
|
for part in "''${parts[@]}"; do
|
||||||
|
printf -v part '%s' "''${part//\\/\\\\}"
|
||||||
|
printf -v part '%b' "''${part//%/\\x}"
|
||||||
|
[[ "$part" == path=/tmp/* ]] || continue
|
||||||
|
x11_args+=(--ro-bind-try "''${part#path=}" "''${part#path=}")
|
||||||
|
done
|
||||||
|
done
|
||||||
|
''}
|
||||||
|
|
||||||
|
cmd=(
|
||||||
|
${bubblewrap}/bin/bwrap
|
||||||
|
--dev-bind /dev /dev
|
||||||
|
--proc /proc
|
||||||
|
--chdir "$(pwd)"
|
||||||
|
${optionalString unshareUser "--unshare-user"}
|
||||||
|
${optionalString unshareIpc "--unshare-ipc"}
|
||||||
|
${optionalString unsharePid "--unshare-pid"}
|
||||||
|
${optionalString unshareNet "--unshare-net"}
|
||||||
|
${optionalString unshareUts "--unshare-uts"}
|
||||||
|
${optionalString unshareCgroup "--unshare-cgroup"}
|
||||||
|
${optionalString dieWithParent "--die-with-parent"}
|
||||||
|
--ro-bind /nix /nix
|
||||||
|
${optionalString privateTmp "--tmpfs /tmp"}
|
||||||
|
# Our glibc will look for the cache in its own path in `/nix/store`.
|
||||||
|
# As such, we need a cache to exist there, because pressure-vessel
|
||||||
|
# depends on the existence of an ld cache. However, adding one
|
||||||
|
# globally proved to be a bad idea (see #100655), the solution we
|
||||||
|
# settled on being mounting one via bwrap.
|
||||||
|
# Also, the cache needs to go to both 32 and 64 bit glibcs, for games
|
||||||
|
# of both architectures to work.
|
||||||
|
--tmpfs ${glibc}/etc \
|
||||||
|
--tmpfs /etc \
|
||||||
|
--symlink /etc/ld.so.conf ${glibc}/etc/ld.so.conf \
|
||||||
|
--symlink /etc/ld.so.cache ${glibc}/etc/ld.so.cache \
|
||||||
|
--ro-bind ${glibc}/etc/rpc ${glibc}/etc/rpc \
|
||||||
|
--remount-ro ${glibc}/etc \
|
||||||
|
'' + optionalString fhsenv.isMultiBuild (indentLines ''
|
||||||
|
--tmpfs ${pkgsi686Linux.glibc}/etc \
|
||||||
|
--symlink /etc/ld.so.conf ${pkgsi686Linux.glibc}/etc/ld.so.conf \
|
||||||
|
--symlink /etc/ld.so.cache ${pkgsi686Linux.glibc}/etc/ld.so.cache \
|
||||||
|
--ro-bind ${pkgsi686Linux.glibc}/etc/rpc ${pkgsi686Linux.glibc}/etc/rpc \
|
||||||
|
--remount-ro ${pkgsi686Linux.glibc}/etc \
|
||||||
|
'') + ''
|
||||||
|
"''${ro_mounts[@]}"
|
||||||
|
"''${symlinks[@]}"
|
||||||
|
"''${auto_mounts[@]}"
|
||||||
|
"''${x11_args[@]}"
|
||||||
|
${concatStringsSep "\n " extraBwrapArgs}
|
||||||
|
${init runScript} ${initArgs}
|
||||||
|
)
|
||||||
|
exec "''${cmd[@]}"
|
||||||
|
'';
|
||||||
|
|
||||||
|
bin = writeShellScript "${name}-bwrap" (bwrapCmd { initArgs = ''"$@"''; });
|
||||||
|
in runCommandLocal name (nameAttrs // {
|
||||||
|
inherit meta;
|
||||||
|
|
||||||
|
passthru = passthru // {
|
||||||
|
env = runCommandLocal "${name}-shell-env" {
|
||||||
|
shellHook = bwrapCmd {};
|
||||||
|
} ''
|
||||||
|
echo >&2 ""
|
||||||
|
echo >&2 "*** User chroot 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
|
||||||
|
echo >&2 ""
|
||||||
|
exit 1
|
||||||
|
'';
|
||||||
|
inherit args fhsenv;
|
||||||
|
};
|
||||||
|
}) ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
ln -s ${bin} $out/bin/${executableName}
|
||||||
|
|
||||||
|
${extraInstallCommands}
|
||||||
|
''
|
16
pkgs/build-support/build-fhsenv-chroot/chrootenv/default.nix
Normal file
16
pkgs/build-support/build-fhsenv-chroot/chrootenv/default.nix
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{ lib, stdenv, meson, ninja, pkg-config, glib }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "chrootenv";
|
||||||
|
src = ./src;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ meson ninja pkg-config ];
|
||||||
|
buildInputs = [ glib ];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Setup mount/user namespace for FHS emulation";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = with maintainers; [ yana ];
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
169
pkgs/build-support/build-fhsenv-chroot/chrootenv/src/chrootenv.c
Normal file
169
pkgs/build-support/build-fhsenv-chroot/chrootenv/src/chrootenv.c
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
|
#define fail(s, err) g_error("%s: %s: %s", __func__, s, g_strerror(err))
|
||||||
|
#define fail_if(expr) \
|
||||||
|
if (expr) \
|
||||||
|
fail(#expr, errno);
|
||||||
|
|
||||||
|
const gchar *bind_blacklist[] = {"bin", "etc", "host", "real-host", "usr", "lib", "lib64", "lib32", "sbin", "opt", NULL};
|
||||||
|
|
||||||
|
int pivot_root(const char *new_root, const char *put_old) {
|
||||||
|
return syscall(SYS_pivot_root, new_root, put_old);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mount_tmpfs(const gchar *target) {
|
||||||
|
fail_if(mount("none", target, "tmpfs", 0, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_mount(const gchar *source, const gchar *target) {
|
||||||
|
fail_if(g_mkdir(target, 0755));
|
||||||
|
fail_if(mount(source, target, NULL, MS_BIND | MS_REC, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *create_tmpdir() {
|
||||||
|
gchar *prefix =
|
||||||
|
g_build_filename(g_get_tmp_dir(), "chrootenvXXXXXX", NULL);
|
||||||
|
fail_if(!g_mkdtemp_full(prefix, 0755));
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pivot_host(const gchar *guest) {
|
||||||
|
g_autofree gchar *point = g_build_filename(guest, "host", NULL);
|
||||||
|
fail_if(g_mkdir(point, 0755));
|
||||||
|
fail_if(pivot_root(guest, point));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_mount_item(const gchar *host, const gchar *guest, const gchar *name) {
|
||||||
|
g_autofree gchar *source = g_build_filename(host, name, NULL);
|
||||||
|
g_autofree gchar *target = g_build_filename(guest, name, NULL);
|
||||||
|
|
||||||
|
if (G_LIKELY(g_file_test(source, G_FILE_TEST_IS_DIR)))
|
||||||
|
bind_mount(source, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind(const gchar *host, const gchar *guest) {
|
||||||
|
mount_tmpfs(guest);
|
||||||
|
|
||||||
|
pivot_host(guest);
|
||||||
|
|
||||||
|
g_autofree gchar *host_dir = g_build_filename("/host", host, NULL);
|
||||||
|
|
||||||
|
g_autoptr(GError) err = NULL;
|
||||||
|
g_autoptr(GDir) dir = g_dir_open(host_dir, 0, &err);
|
||||||
|
|
||||||
|
if (err != NULL)
|
||||||
|
fail("g_dir_open", errno);
|
||||||
|
|
||||||
|
const gchar *item;
|
||||||
|
|
||||||
|
while ((item = g_dir_read_name(dir)))
|
||||||
|
if (!g_strv_contains(bind_blacklist, item))
|
||||||
|
bind_mount_item(host_dir, "/", item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spit(const char *path, char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
FILE *f = g_fopen(path, "w");
|
||||||
|
|
||||||
|
if (f == NULL)
|
||||||
|
fail("g_fopen", errno);
|
||||||
|
|
||||||
|
g_vfprintf(f, fmt, args);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(gint argc, gchar **argv) {
|
||||||
|
const gchar *self = *argv++;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
g_message("%s command [arguments...]", self);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_autofree const gchar *prefix = create_tmpdir();
|
||||||
|
|
||||||
|
pid_t cpid = fork();
|
||||||
|
|
||||||
|
if (cpid < 0)
|
||||||
|
fail("fork", errno);
|
||||||
|
|
||||||
|
else if (cpid == 0) {
|
||||||
|
uid_t uid = getuid();
|
||||||
|
gid_t gid = getgid();
|
||||||
|
|
||||||
|
int namespaces = CLONE_NEWNS;
|
||||||
|
if (uid != 0) {
|
||||||
|
namespaces |= CLONE_NEWUSER;
|
||||||
|
}
|
||||||
|
if (unshare(namespaces) < 0) {
|
||||||
|
int unshare_errno = errno;
|
||||||
|
|
||||||
|
g_message("Requires Linux version >= 3.19 built with CONFIG_USER_NS");
|
||||||
|
if (g_file_test("/proc/sys/kernel/unprivileged_userns_clone",
|
||||||
|
G_FILE_TEST_EXISTS))
|
||||||
|
g_message("Run: sudo sysctl -w kernel.unprivileged_userns_clone=1");
|
||||||
|
|
||||||
|
fail("unshare", unshare_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hide all mounts we do from the parent
|
||||||
|
fail_if(mount(0, "/", 0, MS_SLAVE | MS_REC, 0));
|
||||||
|
|
||||||
|
if (uid != 0) {
|
||||||
|
spit("/proc/self/setgroups", "deny");
|
||||||
|
spit("/proc/self/uid_map", "%d %d 1", uid, uid);
|
||||||
|
spit("/proc/self/gid_map", "%d %d 1", gid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a /host directory, assume this is nested chrootenv and use it as host instead.
|
||||||
|
gboolean nested_host = g_file_test("/host", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
|
||||||
|
g_autofree const gchar *host = nested_host ? "/host" : "/";
|
||||||
|
|
||||||
|
bind(host, prefix);
|
||||||
|
|
||||||
|
// Replace /host by an actual (inner) /host.
|
||||||
|
if (nested_host) {
|
||||||
|
fail_if(g_mkdir("/real-host", 0755));
|
||||||
|
fail_if(mount("/host/host", "/real-host", NULL, MS_BIND | MS_REC, NULL));
|
||||||
|
// For some reason umount("/host") returns EBUSY even immediately after
|
||||||
|
// pivot_root. We detach it at least to keep `/proc/mounts` from blowing
|
||||||
|
// up in nested cases.
|
||||||
|
fail_if(umount2("/host", MNT_DETACH));
|
||||||
|
fail_if(mount("/real-host", "/host", NULL, MS_MOVE, NULL));
|
||||||
|
fail_if(rmdir("/real-host"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_if(chdir("/"));
|
||||||
|
fail_if(execvp(*argv, argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
fail_if(waitpid(cpid, &status, 0) != cpid);
|
||||||
|
fail_if(rmdir(prefix));
|
||||||
|
|
||||||
|
if (WIFEXITED(status))
|
||||||
|
return WEXITSTATUS(status);
|
||||||
|
|
||||||
|
else if (WIFSIGNALED(status))
|
||||||
|
kill(getpid(), WTERMSIG(status));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
project('chrootenv', 'c')
|
||||||
|
|
||||||
|
glib = dependency('glib-2.0')
|
||||||
|
|
||||||
|
executable('chrootenv', 'chrootenv.c', dependencies: [glib], install: true)
|
53
pkgs/build-support/build-fhsenv-chroot/default.nix
Normal file
53
pkgs/build-support/build-fhsenv-chroot/default.nix
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{ lib, callPackage, runCommandLocal, writeScript, stdenv, coreutils }:
|
||||||
|
|
||||||
|
let buildFHSEnv = callPackage ./env.nix { }; in
|
||||||
|
|
||||||
|
args@{ name, version ? null, runScript ? "bash", extraInstallCommands ? "", meta ? {}, passthru ? {}, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
env = buildFHSEnv (removeAttrs args [ "version" "runScript" "extraInstallCommands" "meta" "passthru" ]);
|
||||||
|
|
||||||
|
chrootenv = callPackage ./chrootenv {};
|
||||||
|
|
||||||
|
init = run: writeScript "${name}-init" ''
|
||||||
|
#! ${stdenv.shell}
|
||||||
|
for i in ${env}/* /host/*; do
|
||||||
|
path="/''${i##*/}"
|
||||||
|
[ -e "$path" ] || ${coreutils}/bin/ln -s "$i" "$path"
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -d "$1" ] && [ -r "$1" ] && cd "$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
source /etc/profile
|
||||||
|
exec ${run} "$@"
|
||||||
|
'';
|
||||||
|
|
||||||
|
versionStr = lib.optionalString (version != null) ("-" + version);
|
||||||
|
|
||||||
|
nameAndVersion = name + versionStr;
|
||||||
|
|
||||||
|
in runCommandLocal nameAndVersion {
|
||||||
|
inherit meta;
|
||||||
|
|
||||||
|
passthru = passthru // {
|
||||||
|
env = runCommandLocal "${name}-shell-env" {
|
||||||
|
shellHook = ''
|
||||||
|
exec ${chrootenv}/bin/chrootenv ${init runScript} "$(pwd)"
|
||||||
|
'';
|
||||||
|
} ''
|
||||||
|
echo >&2 ""
|
||||||
|
echo >&2 "*** User chroot 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
|
||||||
|
echo >&2 ""
|
||||||
|
exit 1
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
} ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cat <<EOF >$out/bin/${name}
|
||||||
|
#! ${stdenv.shell}
|
||||||
|
exec ${chrootenv}/bin/chrootenv ${init runScript} "\$(pwd)" "\$@"
|
||||||
|
EOF
|
||||||
|
chmod +x $out/bin/${name}
|
||||||
|
${extraInstallCommands}
|
||||||
|
''
|
259
pkgs/build-support/build-fhsenv-chroot/env.nix
Normal file
259
pkgs/build-support/build-fhsenv-chroot/env.nix
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
{ stdenv, lib, buildEnv, writeText, pkgs, pkgsi686Linux }:
|
||||||
|
|
||||||
|
{ name
|
||||||
|
, profile ? ""
|
||||||
|
, targetPkgs ? pkgs: []
|
||||||
|
, multiPkgs ? pkgs: []
|
||||||
|
, extraBuildCommands ? ""
|
||||||
|
, extraBuildCommandsMulti ? ""
|
||||||
|
, extraOutputsToInstall ? []
|
||||||
|
}:
|
||||||
|
|
||||||
|
# HOWTO:
|
||||||
|
# All packages (most likely programs) returned from targetPkgs will only be
|
||||||
|
# installed once--matching the host's architecture (64bit on x86_64 and 32bit on
|
||||||
|
# x86).
|
||||||
|
#
|
||||||
|
# Packages (most likely libraries) returned from multiPkgs are installed
|
||||||
|
# once on x86 systems and twice on x86_64 systems.
|
||||||
|
# On x86 they are merged with packages from targetPkgs.
|
||||||
|
# On x86_64 they are added to targetPkgs and in addition their 32bit
|
||||||
|
# versions are also installed. The final directory structure looks as
|
||||||
|
# follows:
|
||||||
|
# /lib32 will include 32bit libraries from multiPkgs
|
||||||
|
# /lib64 will include 64bit libraries from multiPkgs and targetPkgs
|
||||||
|
# /lib will link to /lib32
|
||||||
|
|
||||||
|
let
|
||||||
|
is64Bit = stdenv.hostPlatform.parsed.cpu.bits == 64;
|
||||||
|
# multi-lib glibc is only supported on x86_64
|
||||||
|
isMultiBuild = multiPkgs != null && stdenv.hostPlatform.system == "x86_64-linux";
|
||||||
|
isTargetBuild = !isMultiBuild;
|
||||||
|
|
||||||
|
# list of packages (usually programs) which are only be installed for the
|
||||||
|
# host's architecture
|
||||||
|
targetPaths = targetPkgs pkgs ++ (if multiPkgs == null then [] else multiPkgs pkgs);
|
||||||
|
|
||||||
|
# list of packages which are installed for both x86 and x86_64 on x86_64
|
||||||
|
# systems
|
||||||
|
multiPaths = multiPkgs pkgsi686Linux;
|
||||||
|
|
||||||
|
# base packages of the chroot
|
||||||
|
# these match the host's architecture, glibc_multi is used for multilib
|
||||||
|
# builds. glibcLocales must be before glibc or glibc_multi as otherwiese
|
||||||
|
# the wrong LOCALE_ARCHIVE will be used where only C.UTF-8 is available.
|
||||||
|
basePkgs = with pkgs;
|
||||||
|
[ glibcLocales
|
||||||
|
(if isMultiBuild then glibc_multi else glibc)
|
||||||
|
(toString gcc.cc.lib) bashInteractiveFHS coreutils less shadow su
|
||||||
|
gawk diffutils findutils gnused gnugrep
|
||||||
|
gnutar gzip bzip2 xz
|
||||||
|
];
|
||||||
|
baseMultiPkgs = with pkgsi686Linux;
|
||||||
|
[ (toString gcc.cc.lib)
|
||||||
|
];
|
||||||
|
|
||||||
|
etcProfile = writeText "profile" ''
|
||||||
|
export PS1='${name}-chrootenv:\u@\h:\w\$ '
|
||||||
|
export LOCALE_ARCHIVE='/usr/lib/locale/locale-archive'
|
||||||
|
export LD_LIBRARY_PATH="/run/opengl-driver/lib:/run/opengl-driver-32/lib:/usr/lib:/usr/lib32''${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH"
|
||||||
|
export PATH="/run/wrappers/bin:/usr/bin:/usr/sbin:$PATH"
|
||||||
|
export TZDIR='/etc/zoneinfo'
|
||||||
|
|
||||||
|
# XDG_DATA_DIRS is used by pressure-vessel (steam proton) and vulkan loaders to find the corresponding icd
|
||||||
|
export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/run/opengl-driver/share:/run/opengl-driver-32/share
|
||||||
|
|
||||||
|
# Following XDG spec [1], XDG_DATA_DIRS should default to "/usr/local/share:/usr/share".
|
||||||
|
# In nix, it is commonly set without containing these values, so we add them as fallback.
|
||||||
|
#
|
||||||
|
# [1] <https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>
|
||||||
|
case ":$XDG_DATA_DIRS:" in
|
||||||
|
*:/usr/local/share:*) ;;
|
||||||
|
*) export XDG_DATA_DIRS="$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/usr/local/share" ;;
|
||||||
|
esac
|
||||||
|
case ":$XDG_DATA_DIRS:" in
|
||||||
|
*:/usr/share:*) ;;
|
||||||
|
*) export XDG_DATA_DIRS="$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/usr/share" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Force compilers and other tools to look in default search paths
|
||||||
|
unset NIX_ENFORCE_PURITY
|
||||||
|
export NIX_BINTOOLS_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1
|
||||||
|
export NIX_CC_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1
|
||||||
|
export NIX_CFLAGS_COMPILE='-idirafter /usr/include'
|
||||||
|
export NIX_CFLAGS_LINK='-L/usr/lib -L/usr/lib32'
|
||||||
|
export NIX_LDFLAGS='-L/usr/lib -L/usr/lib32'
|
||||||
|
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
|
||||||
|
export ACLOCAL_PATH=/usr/share/aclocal
|
||||||
|
|
||||||
|
${profile}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Compose /etc for the chroot environment
|
||||||
|
etcPkg = stdenv.mkDerivation {
|
||||||
|
name = "${name}-chrootenv-etc";
|
||||||
|
buildCommand = ''
|
||||||
|
mkdir -p $out/etc
|
||||||
|
cd $out/etc
|
||||||
|
|
||||||
|
# environment variables
|
||||||
|
ln -s ${etcProfile} profile
|
||||||
|
|
||||||
|
# compatibility with NixOS
|
||||||
|
ln -s /host/etc/static static
|
||||||
|
|
||||||
|
# symlink nix config
|
||||||
|
ln -s /host/etc/nix nix
|
||||||
|
|
||||||
|
# symlink some NSS stuff
|
||||||
|
ln -s /host/etc/passwd passwd
|
||||||
|
ln -s /host/etc/group group
|
||||||
|
ln -s /host/etc/shadow shadow
|
||||||
|
ln -s /host/etc/hosts hosts
|
||||||
|
ln -s /host/etc/resolv.conf resolv.conf
|
||||||
|
ln -s /host/etc/nsswitch.conf nsswitch.conf
|
||||||
|
|
||||||
|
# symlink user profiles
|
||||||
|
ln -s /host/etc/profiles profiles
|
||||||
|
|
||||||
|
# symlink sudo and su stuff
|
||||||
|
ln -s /host/etc/login.defs login.defs
|
||||||
|
ln -s /host/etc/sudoers sudoers
|
||||||
|
ln -s /host/etc/sudoers.d sudoers.d
|
||||||
|
|
||||||
|
# symlink other core stuff
|
||||||
|
ln -s /host/etc/localtime localtime
|
||||||
|
ln -s /host/etc/zoneinfo zoneinfo
|
||||||
|
ln -s /host/etc/machine-id machine-id
|
||||||
|
ln -s /host/etc/os-release os-release
|
||||||
|
|
||||||
|
# symlink PAM stuff
|
||||||
|
ln -s /host/etc/pam.d pam.d
|
||||||
|
|
||||||
|
# symlink fonts stuff
|
||||||
|
ln -s /host/etc/fonts fonts
|
||||||
|
|
||||||
|
# symlink ALSA stuff
|
||||||
|
ln -s /host/etc/asound.conf asound.conf
|
||||||
|
ln -s /host/etc/alsa alsa
|
||||||
|
|
||||||
|
# symlink SSL certs
|
||||||
|
mkdir -p ssl
|
||||||
|
ln -s /host/etc/ssl/certs ssl/certs
|
||||||
|
|
||||||
|
# symlink /etc/mtab -> /proc/mounts (compat for old userspace progs)
|
||||||
|
ln -s /proc/mounts mtab
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Composes a /usr-like directory structure
|
||||||
|
staticUsrProfileTarget = buildEnv {
|
||||||
|
name = "${name}-usr-target";
|
||||||
|
paths = [ etcPkg ] ++ basePkgs ++ targetPaths;
|
||||||
|
extraOutputsToInstall = [ "out" "lib" "bin" ] ++ extraOutputsToInstall;
|
||||||
|
ignoreCollisions = true;
|
||||||
|
postBuild = ''
|
||||||
|
if [[ -d $out/share/gsettings-schemas/ ]]; then
|
||||||
|
# Recreate the standard schemas directory if its a symlink to make it writable
|
||||||
|
if [[ -L $out/share/glib-2.0 ]]; then
|
||||||
|
target=$(readlink $out/share/glib-2.0)
|
||||||
|
rm $out/share/glib-2.0
|
||||||
|
mkdir $out/share/glib-2.0
|
||||||
|
ln -fs $target/* $out/share/glib-2.0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -L $out/share/glib-2.0/schemas ]]; then
|
||||||
|
target=$(readlink $out/share/glib-2.0/schemas)
|
||||||
|
rm $out/share/glib-2.0/schemas
|
||||||
|
mkdir $out/share/glib-2.0/schemas
|
||||||
|
ln -fs $target/* $out/share/glib-2.0/schemas
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p $out/share/glib-2.0/schemas
|
||||||
|
|
||||||
|
for d in $out/share/gsettings-schemas/*; do
|
||||||
|
# Force symlink, in case there are duplicates
|
||||||
|
ln -fs $d/glib-2.0/schemas/*.xml $out/share/glib-2.0/schemas
|
||||||
|
ln -fs $d/glib-2.0/schemas/*.gschema.override $out/share/glib-2.0/schemas
|
||||||
|
done
|
||||||
|
|
||||||
|
# and compile them
|
||||||
|
${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/glib-2.0/schemas
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
staticUsrProfileMulti = buildEnv {
|
||||||
|
name = "${name}-usr-multi";
|
||||||
|
paths = baseMultiPkgs ++ multiPaths;
|
||||||
|
extraOutputsToInstall = [ "out" "lib" ] ++ extraOutputsToInstall;
|
||||||
|
ignoreCollisions = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# setup library paths only for the targeted architecture
|
||||||
|
setupLibDirs_target = ''
|
||||||
|
# link content of targetPaths
|
||||||
|
cp -rsHf ${staticUsrProfileTarget}/lib lib
|
||||||
|
ln -s lib lib${if is64Bit then "64" else "32"}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# setup /lib, /lib32 and /lib64
|
||||||
|
setupLibDirs_multi = ''
|
||||||
|
mkdir -m0755 lib32
|
||||||
|
mkdir -m0755 lib64
|
||||||
|
ln -s lib64 lib
|
||||||
|
|
||||||
|
# copy glibc stuff
|
||||||
|
cp -rsHf ${staticUsrProfileTarget}/lib/32/* lib32/ && chmod u+w -R lib32/
|
||||||
|
|
||||||
|
# copy content of multiPaths (32bit libs)
|
||||||
|
[ -d ${staticUsrProfileMulti}/lib ] && cp -rsHf ${staticUsrProfileMulti}/lib/* lib32/ && chmod u+w -R lib32/
|
||||||
|
|
||||||
|
# copy content of targetPaths (64bit libs)
|
||||||
|
cp -rsHf ${staticUsrProfileTarget}/lib/* lib64/ && chmod u+w -R lib64/
|
||||||
|
|
||||||
|
# symlink 32-bit ld-linux.so
|
||||||
|
ln -Ls ${staticUsrProfileTarget}/lib/32/ld-linux.so.2 lib/
|
||||||
|
'';
|
||||||
|
|
||||||
|
setupLibDirs = if isTargetBuild then setupLibDirs_target
|
||||||
|
else setupLibDirs_multi;
|
||||||
|
|
||||||
|
# the target profile is the actual profile that will be used for the chroot
|
||||||
|
setupTargetProfile = ''
|
||||||
|
mkdir -m0755 usr
|
||||||
|
cd usr
|
||||||
|
${setupLibDirs}
|
||||||
|
for i in bin sbin share include; do
|
||||||
|
if [ -d "${staticUsrProfileTarget}/$i" ]; then
|
||||||
|
cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
for i in var etc opt; do
|
||||||
|
if [ -d "${staticUsrProfileTarget}/$i" ]; then
|
||||||
|
cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for i in usr/{bin,sbin,lib,lib32,lib64}; do
|
||||||
|
if [ -d "$i" ]; then
|
||||||
|
ln -s "$i"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
in stdenv.mkDerivation {
|
||||||
|
name = "${name}-fhs";
|
||||||
|
buildCommand = ''
|
||||||
|
mkdir -p $out
|
||||||
|
cd $out
|
||||||
|
${setupTargetProfile}
|
||||||
|
cd $out
|
||||||
|
${extraBuildCommands}
|
||||||
|
cd $out
|
||||||
|
${lib.optionalString isMultiBuild extraBuildCommandsMulti}
|
||||||
|
'';
|
||||||
|
preferLocalBuild = true;
|
||||||
|
allowSubstitutes = false;
|
||||||
|
}
|
84
pkgs/build-support/build-graalvm-native-image/default.nix
Normal file
84
pkgs/build-support/build-graalvm-native-image/default.nix
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, glibcLocales
|
||||||
|
# The GraalVM derivation to use
|
||||||
|
, graalvmDrv
|
||||||
|
, removeReferencesTo
|
||||||
|
, executable ? args.pname
|
||||||
|
# JAR used as input for GraalVM derivation, defaults to src
|
||||||
|
, jar ? args.src
|
||||||
|
, dontUnpack ? (jar == args.src)
|
||||||
|
# Default native-image arguments. You probably don't want to set this,
|
||||||
|
# except in special cases. In most cases, use extraNativeBuildArgs instead
|
||||||
|
, nativeImageBuildArgs ? [
|
||||||
|
(lib.optionalString stdenv.isDarwin "-H:-CheckToolchain")
|
||||||
|
(lib.optionalString (stdenv.isLinux && stdenv.isAarch64) "-H:PageSize=64K")
|
||||||
|
"-H:Name=${executable}"
|
||||||
|
"-march=compatibility"
|
||||||
|
"--verbose"
|
||||||
|
]
|
||||||
|
# Extra arguments to be passed to the native-image
|
||||||
|
, extraNativeImageBuildArgs ? [ ]
|
||||||
|
# XMX size of GraalVM during build
|
||||||
|
, graalvmXmx ? "-J-Xmx6g"
|
||||||
|
, meta ? { }
|
||||||
|
, LC_ALL ? "en_US.UTF-8"
|
||||||
|
, ...
|
||||||
|
} @ args:
|
||||||
|
|
||||||
|
let
|
||||||
|
extraArgs = builtins.removeAttrs args [
|
||||||
|
"lib"
|
||||||
|
"stdenv"
|
||||||
|
"glibcLocales"
|
||||||
|
"jar"
|
||||||
|
"dontUnpack"
|
||||||
|
"LC_ALL"
|
||||||
|
"meta"
|
||||||
|
"buildPhase"
|
||||||
|
"nativeBuildInputs"
|
||||||
|
"installPhase"
|
||||||
|
"postInstall"
|
||||||
|
];
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation ({
|
||||||
|
inherit dontUnpack jar;
|
||||||
|
|
||||||
|
env = { inherit LC_ALL; };
|
||||||
|
|
||||||
|
nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ graalvmDrv glibcLocales removeReferencesTo ];
|
||||||
|
|
||||||
|
nativeImageBuildArgs = nativeImageBuildArgs ++ extraNativeImageBuildArgs ++ [ graalvmXmx ];
|
||||||
|
|
||||||
|
buildPhase = args.buildPhase or ''
|
||||||
|
runHook preBuild
|
||||||
|
|
||||||
|
native-image -jar "$jar" $(export -p | sed -n 's/^declare -x \([^=]\+\)=.*$/ -E\1/p' | tr -d \\n) ''${nativeImageBuildArgs[@]}
|
||||||
|
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = args.installPhase or ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
install -Dm755 ${executable} -t $out/bin
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
remove-references-to -t ${graalvmDrv} $out/bin/${executable}
|
||||||
|
${args.postInstall or ""}
|
||||||
|
'';
|
||||||
|
|
||||||
|
disallowedReferences = [ graalvmDrv ];
|
||||||
|
|
||||||
|
passthru = { inherit graalvmDrv; };
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
# default to graalvm's platforms
|
||||||
|
platforms = graalvmDrv.meta.platforms;
|
||||||
|
# default to executable name
|
||||||
|
mainProgram = executable;
|
||||||
|
} // meta;
|
||||||
|
} // extraArgs)
|
88
pkgs/build-support/build-maven.nix
Normal file
88
pkgs/build-support/build-maven.nix
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
{ stdenv, maven, runCommand, writeText, fetchurl, lib, requireFile, linkFarm }:
|
||||||
|
# Takes an info file generated by mvn2nix
|
||||||
|
# (https://github.com/NixOS/mvn2nix-maven-plugin) and builds the maven
|
||||||
|
# project with it.
|
||||||
|
#
|
||||||
|
# repo: A local maven repository with the project's dependencies.
|
||||||
|
#
|
||||||
|
# settings: A settings.xml to pass to maven to use the repo.
|
||||||
|
#
|
||||||
|
# build: A simple build derivation that uses mvn compile and package to build
|
||||||
|
# the project.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# project = pkgs.buildMaven ./project-info.json
|
||||||
|
infoFile:
|
||||||
|
let
|
||||||
|
info = lib.importJSON infoFile;
|
||||||
|
|
||||||
|
dependencies = lib.flatten (map (dep:
|
||||||
|
let
|
||||||
|
inherit (dep) sha1 groupId artifactId version metadata repository-id;
|
||||||
|
versionDir = dep.unresolved-version or version;
|
||||||
|
authenticated = dep.authenticated or false;
|
||||||
|
url = dep.url or "";
|
||||||
|
|
||||||
|
fetch = if (url != "") then
|
||||||
|
((if authenticated then requireFile else fetchurl) {
|
||||||
|
inherit url sha1;
|
||||||
|
})
|
||||||
|
else
|
||||||
|
"";
|
||||||
|
|
||||||
|
fetchMetadata = (if authenticated then requireFile else fetchurl) {
|
||||||
|
inherit (metadata) url sha1;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout = "${
|
||||||
|
builtins.replaceStrings [ "." ] [ "/" ] groupId
|
||||||
|
}/${artifactId}/${versionDir}";
|
||||||
|
in lib.optional (url != "") {
|
||||||
|
layout = "${layout}/${fetch.name}";
|
||||||
|
drv = fetch;
|
||||||
|
} ++ lib.optionals (dep ? metadata) ([{
|
||||||
|
layout = "${layout}/maven-metadata-${repository-id}.xml";
|
||||||
|
drv = fetchMetadata;
|
||||||
|
}] ++ lib.optional (fetch != "") {
|
||||||
|
layout = "${layout}/${
|
||||||
|
builtins.replaceStrings [ version ] [ dep.unresolved-version ]
|
||||||
|
fetch.name
|
||||||
|
}";
|
||||||
|
drv = fetch;
|
||||||
|
})) info.dependencies);
|
||||||
|
|
||||||
|
repo = linkFarm "maven-repository" (lib.forEach dependencies (dependency: {
|
||||||
|
name = dependency.layout;
|
||||||
|
path = dependency.drv;
|
||||||
|
}));
|
||||||
|
|
||||||
|
settings = writeText "settings.xml" ''
|
||||||
|
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
|
||||||
|
http://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||||
|
<localRepository>${repo}</localRepository>
|
||||||
|
</settings>
|
||||||
|
'';
|
||||||
|
|
||||||
|
src = dirOf infoFile;
|
||||||
|
in {
|
||||||
|
inherit repo settings info;
|
||||||
|
|
||||||
|
build = stdenv.mkDerivation {
|
||||||
|
name = "${info.project.artifactId}-${info.project.version}.jar";
|
||||||
|
|
||||||
|
src = builtins.filterSource (path: type:
|
||||||
|
(toString path) != (toString (src + "/target")) && (toString path)
|
||||||
|
!= (toString (src + "/.git"))) src;
|
||||||
|
|
||||||
|
buildInputs = [ maven ];
|
||||||
|
|
||||||
|
buildPhase = "mvn --offline --settings ${settings} compile";
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mvn --offline --settings ${settings} package
|
||||||
|
mv target/*.jar $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
283
pkgs/build-support/buildenv/builder.pl
Executable file
283
pkgs/build-support/buildenv/builder.pl
Executable file
|
@ -0,0 +1,283 @@
|
||||||
|
#! @perl@ -w
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Cwd 'abs_path';
|
||||||
|
use IO::Handle;
|
||||||
|
use File::Path;
|
||||||
|
use File::Basename;
|
||||||
|
use File::Compare;
|
||||||
|
use JSON::PP;
|
||||||
|
|
||||||
|
STDOUT->autoflush(1);
|
||||||
|
|
||||||
|
$SIG{__WARN__} = sub { warn "warning: ", @_ };
|
||||||
|
$SIG{__DIE__} = sub { die "error: ", @_ };
|
||||||
|
|
||||||
|
my $out = $ENV{"out"};
|
||||||
|
my $extraPrefix = $ENV{"extraPrefix"};
|
||||||
|
|
||||||
|
my @pathsToLink = split ' ', $ENV{"pathsToLink"};
|
||||||
|
|
||||||
|
sub isInPathsToLink {
|
||||||
|
my $path = shift;
|
||||||
|
$path = "/" if $path eq "";
|
||||||
|
foreach my $elem (@pathsToLink) {
|
||||||
|
return 1 if
|
||||||
|
$elem eq "/" ||
|
||||||
|
(substr($path, 0, length($elem)) eq $elem
|
||||||
|
&& (($path eq $elem) || (substr($path, length($elem), 1) eq "/")));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns whether a path in one of the linked packages may contain
|
||||||
|
# files in one of the elements of pathsToLink.
|
||||||
|
sub hasPathsToLink {
|
||||||
|
my $path = shift;
|
||||||
|
foreach my $elem (@pathsToLink) {
|
||||||
|
return 1 if
|
||||||
|
$path eq "" ||
|
||||||
|
(substr($elem, 0, length($path)) eq $path
|
||||||
|
&& (($path eq $elem) || (substr($elem, length($path), 1) eq "/")));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Similar to `lib.isStorePath`
|
||||||
|
sub isStorePath {
|
||||||
|
my $path = shift;
|
||||||
|
my $storePath = "@storeDir@";
|
||||||
|
|
||||||
|
return substr($path, 0, 1) eq "/" && dirname($path) eq $storePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
# For each activated package, determine what symlinks to create.
|
||||||
|
|
||||||
|
my %symlinks;
|
||||||
|
|
||||||
|
# Add all pathsToLink and all parent directories.
|
||||||
|
#
|
||||||
|
# For "/a/b/c" that will include
|
||||||
|
# [ "", "/a", "/a/b", "/a/b/c" ]
|
||||||
|
#
|
||||||
|
# That ensures the whole directory tree needed by pathsToLink is
|
||||||
|
# created as directories and not symlinks.
|
||||||
|
$symlinks{""} = ["", 0];
|
||||||
|
for my $p (@pathsToLink) {
|
||||||
|
my @parts = split '/', $p;
|
||||||
|
|
||||||
|
my $cur = "";
|
||||||
|
for my $x (@parts) {
|
||||||
|
$cur = $cur . "/$x";
|
||||||
|
$cur = "" if $cur eq "/";
|
||||||
|
$symlinks{$cur} = ["", 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub findFiles;
|
||||||
|
|
||||||
|
sub findFilesInDir {
|
||||||
|
my ($relName, $target, $ignoreCollisions, $checkCollisionContents, $priority) = @_;
|
||||||
|
|
||||||
|
opendir DIR, "$target" or die "cannot open `$target': $!";
|
||||||
|
my @names = readdir DIR or die;
|
||||||
|
closedir DIR;
|
||||||
|
|
||||||
|
foreach my $name (@names) {
|
||||||
|
next if $name eq "." || $name eq "..";
|
||||||
|
findFiles("$relName/$name", "$target/$name", $name, $ignoreCollisions, $checkCollisionContents, $priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub checkCollision {
|
||||||
|
my ($path1, $path2) = @_;
|
||||||
|
|
||||||
|
if (! -e $path1 || ! -e $path2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $stat1 = (stat($path1))[2];
|
||||||
|
my $stat2 = (stat($path2))[2];
|
||||||
|
|
||||||
|
if ($stat1 != $stat2) {
|
||||||
|
warn "different permissions in `$path1' and `$path2': "
|
||||||
|
. sprintf("%04o", $stat1 & 07777) . " <-> "
|
||||||
|
. sprintf("%04o", $stat2 & 07777);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return compare($path1, $path2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub prependDangling {
|
||||||
|
my $path = shift;
|
||||||
|
return (-l $path && ! -e $path ? "dangling symlink " : "") . "`$path'";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub findFiles {
|
||||||
|
my ($relName, $target, $baseName, $ignoreCollisions, $checkCollisionContents, $priority) = @_;
|
||||||
|
|
||||||
|
# The store path must not be a file
|
||||||
|
if (-f $target && isStorePath $target) {
|
||||||
|
die "The store path $target is a file and can't be merged into an environment using pkgs.buildEnv!";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Urgh, hacky...
|
||||||
|
return if
|
||||||
|
$relName eq "/propagated-build-inputs" ||
|
||||||
|
$relName eq "/nix-support" ||
|
||||||
|
$relName =~ /info\/dir$/ ||
|
||||||
|
( $relName =~ /^\/share\/mime\// && !( $relName =~ /^\/share\/mime\/packages/ ) ) ||
|
||||||
|
$baseName eq "perllocal.pod" ||
|
||||||
|
$baseName eq "log" ||
|
||||||
|
! (hasPathsToLink($relName) || isInPathsToLink($relName));
|
||||||
|
|
||||||
|
my ($oldTarget, $oldPriority) = @{$symlinks{$relName} // [undef, undef]};
|
||||||
|
|
||||||
|
# If target doesn't exist, create it. If it already exists as a
|
||||||
|
# symlink to a file (not a directory) in a lower-priority package,
|
||||||
|
# overwrite it.
|
||||||
|
if (!defined $oldTarget || ($priority < $oldPriority && ($oldTarget ne "" && ! -d $oldTarget))) {
|
||||||
|
# If target is a dangling symlink, emit a warning.
|
||||||
|
if (-l $target && ! -e $target) {
|
||||||
|
my $link = readlink $target;
|
||||||
|
warn "creating dangling symlink `$out$extraPrefix/$relName' -> `$target' -> `$link'\n";
|
||||||
|
}
|
||||||
|
$symlinks{$relName} = [$target, $priority];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# If target already exists and both targets resolves to the same path, skip
|
||||||
|
if (
|
||||||
|
defined $oldTarget && $oldTarget ne "" &&
|
||||||
|
defined abs_path($target) && defined abs_path($oldTarget) &&
|
||||||
|
abs_path($target) eq abs_path($oldTarget)
|
||||||
|
) {
|
||||||
|
# Prefer the target that is not a symlink, if any
|
||||||
|
if (-l $oldTarget && ! -l $target) {
|
||||||
|
$symlinks{$relName} = [$target, $priority];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# If target already exists as a symlink to a file (not a
|
||||||
|
# directory) in a higher-priority package, skip.
|
||||||
|
if (defined $oldTarget && $priority > $oldPriority && $oldTarget ne "" && ! -d $oldTarget) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# If target is supposed to be a directory but it isn't, die with an error message
|
||||||
|
# instead of attempting to recurse into it, only to fail then.
|
||||||
|
# This happens e.g. when pathsToLink contains a non-directory path.
|
||||||
|
if ($oldTarget eq "" && ! -d $target) {
|
||||||
|
die "not a directory: `$target'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
unless (-d $target && ($oldTarget eq "" || -d $oldTarget)) {
|
||||||
|
# Prepend "dangling symlink" to paths if applicable.
|
||||||
|
my $targetRef = prependDangling($target);
|
||||||
|
my $oldTargetRef = prependDangling($oldTarget);
|
||||||
|
|
||||||
|
if ($ignoreCollisions) {
|
||||||
|
warn "collision between $targetRef and $oldTargetRef\n" if $ignoreCollisions == 1;
|
||||||
|
return;
|
||||||
|
} elsif ($checkCollisionContents && checkCollision($oldTarget, $target)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
die "collision between $targetRef and $oldTargetRef\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findFilesInDir($relName, $oldTarget, $ignoreCollisions, $checkCollisionContents, $oldPriority) unless $oldTarget eq "";
|
||||||
|
findFilesInDir($relName, $target, $ignoreCollisions, $checkCollisionContents, $priority);
|
||||||
|
|
||||||
|
$symlinks{$relName} = ["", $priority]; # denotes directory
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my %done;
|
||||||
|
my %postponed;
|
||||||
|
|
||||||
|
sub addPkg {
|
||||||
|
my ($pkgDir, $ignoreCollisions, $checkCollisionContents, $priority) = @_;
|
||||||
|
|
||||||
|
return if (defined $done{$pkgDir});
|
||||||
|
$done{$pkgDir} = 1;
|
||||||
|
|
||||||
|
findFiles("", $pkgDir, "", $ignoreCollisions, $checkCollisionContents, $priority);
|
||||||
|
|
||||||
|
my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages";
|
||||||
|
if (-e $propagatedFN) {
|
||||||
|
open PROP, "<$propagatedFN" or die;
|
||||||
|
my $propagated = <PROP>;
|
||||||
|
close PROP;
|
||||||
|
my @propagated = split ' ', $propagated;
|
||||||
|
foreach my $p (@propagated) {
|
||||||
|
$postponed{$p} = 1 unless defined $done{$p};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read packages list.
|
||||||
|
my $pkgs;
|
||||||
|
|
||||||
|
if (exists $ENV{"pkgsPath"}) {
|
||||||
|
open FILE, $ENV{"pkgsPath"};
|
||||||
|
$pkgs = <FILE>;
|
||||||
|
close FILE;
|
||||||
|
} else {
|
||||||
|
$pkgs = $ENV{"pkgs"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Symlink to the packages that have been installed explicitly by the
|
||||||
|
# user.
|
||||||
|
for my $pkg (@{decode_json $pkgs}) {
|
||||||
|
for my $path (@{$pkg->{paths}}) {
|
||||||
|
addPkg($path,
|
||||||
|
$ENV{"ignoreCollisions"} eq "1",
|
||||||
|
$ENV{"checkCollisionContents"} eq "1",
|
||||||
|
$pkg->{priority})
|
||||||
|
if -e $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Symlink to the packages that have been "propagated" by packages
|
||||||
|
# installed by the user (i.e., package X declares that it wants Y
|
||||||
|
# installed as well). We do these later because they have a lower
|
||||||
|
# priority in case of collisions.
|
||||||
|
my $priorityCounter = 1000; # don't care about collisions
|
||||||
|
while (scalar(keys %postponed) > 0) {
|
||||||
|
my @pkgDirs = keys %postponed;
|
||||||
|
%postponed = ();
|
||||||
|
foreach my $pkgDir (sort @pkgDirs) {
|
||||||
|
addPkg($pkgDir, 2, $ENV{"checkCollisionContents"} eq "1", $priorityCounter++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Create the symlinks.
|
||||||
|
my $nrLinks = 0;
|
||||||
|
foreach my $relName (sort keys %symlinks) {
|
||||||
|
my ($target, $priority) = @{$symlinks{$relName}};
|
||||||
|
my $abs = "$out" . "$extraPrefix" . "/$relName";
|
||||||
|
next unless isInPathsToLink $relName;
|
||||||
|
if ($target eq "") {
|
||||||
|
#print "creating directory $relName\n";
|
||||||
|
mkpath $abs or die "cannot create directory `$abs': $!";
|
||||||
|
} else {
|
||||||
|
#print "creating symlink $relName to $target\n";
|
||||||
|
symlink $target, $abs ||
|
||||||
|
die "error creating link `$abs': $!";
|
||||||
|
$nrLinks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
print STDERR "created $nrLinks symlinks in user environment\n";
|
||||||
|
|
||||||
|
|
||||||
|
my $manifest = $ENV{"manifest"};
|
||||||
|
if ($manifest) {
|
||||||
|
symlink($manifest, "$out/manifest") or die "cannot create manifest";
|
||||||
|
}
|
81
pkgs/build-support/buildenv/default.nix
Normal file
81
pkgs/build-support/buildenv/default.nix
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
# buildEnv creates a tree of symlinks to the specified paths. This is
|
||||||
|
# a fork of the hardcoded buildEnv in the Nix distribution.
|
||||||
|
|
||||||
|
{ buildPackages, runCommand, lib, substituteAll }:
|
||||||
|
|
||||||
|
let
|
||||||
|
builder = substituteAll {
|
||||||
|
src = ./builder.pl;
|
||||||
|
inherit (builtins) storeDir;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
|
||||||
|
lib.makeOverridable
|
||||||
|
({ name
|
||||||
|
|
||||||
|
, # The manifest file (if any). A symlink $out/manifest will be
|
||||||
|
# created to it.
|
||||||
|
manifest ? ""
|
||||||
|
|
||||||
|
, # The paths to symlink.
|
||||||
|
paths
|
||||||
|
|
||||||
|
, # Whether to ignore collisions or abort.
|
||||||
|
ignoreCollisions ? false
|
||||||
|
|
||||||
|
, # If there is a collision, check whether the contents and permissions match
|
||||||
|
# and only if not, throw a collision error.
|
||||||
|
checkCollisionContents ? true
|
||||||
|
|
||||||
|
, # The paths (relative to each element of `paths') that we want to
|
||||||
|
# symlink (e.g., ["/bin"]). Any file not inside any of the
|
||||||
|
# directories in the list is not symlinked.
|
||||||
|
pathsToLink ? ["/"]
|
||||||
|
|
||||||
|
, # The package outputs to include. By default, only the default
|
||||||
|
# output is included.
|
||||||
|
extraOutputsToInstall ? []
|
||||||
|
|
||||||
|
, # Root the result in directory "$out${extraPrefix}", e.g. "/share".
|
||||||
|
extraPrefix ? ""
|
||||||
|
|
||||||
|
, # Shell commands to run after building the symlink tree.
|
||||||
|
postBuild ? ""
|
||||||
|
|
||||||
|
# Additional inputs
|
||||||
|
, nativeBuildInputs ? [] # Handy e.g. if using makeWrapper in `postBuild`.
|
||||||
|
, buildInputs ? []
|
||||||
|
|
||||||
|
, passthru ? {}
|
||||||
|
, meta ? {}
|
||||||
|
}:
|
||||||
|
|
||||||
|
runCommand name
|
||||||
|
rec {
|
||||||
|
inherit manifest ignoreCollisions checkCollisionContents passthru
|
||||||
|
meta pathsToLink extraPrefix postBuild
|
||||||
|
nativeBuildInputs buildInputs;
|
||||||
|
pkgs = builtins.toJSON (map (drv: {
|
||||||
|
paths =
|
||||||
|
# First add the usual output(s): respect if user has chosen explicitly,
|
||||||
|
# and otherwise use `meta.outputsToInstall`. The attribute is guaranteed
|
||||||
|
# to exist in mkDerivation-created cases. The other cases (e.g. runCommand)
|
||||||
|
# aren't expected to have multiple outputs.
|
||||||
|
(if (! drv ? outputSpecified || ! drv.outputSpecified)
|
||||||
|
&& drv.meta.outputsToInstall or null != null
|
||||||
|
then map (outName: drv.${outName}) drv.meta.outputsToInstall
|
||||||
|
else [ drv ])
|
||||||
|
# Add any extra outputs specified by the caller of `buildEnv`.
|
||||||
|
++ lib.filter (p: p!=null)
|
||||||
|
(builtins.map (outName: drv.${outName} or null) extraOutputsToInstall);
|
||||||
|
priority = drv.meta.priority or 5;
|
||||||
|
}) paths);
|
||||||
|
preferLocalBuild = true;
|
||||||
|
allowSubstitutes = false;
|
||||||
|
# XXX: The size is somewhat arbitrary
|
||||||
|
passAsFile = if builtins.stringLength pkgs >= 128*1024 then [ "pkgs" ] else [ ];
|
||||||
|
}
|
||||||
|
''
|
||||||
|
${buildPackages.perl}/bin/perl -w ${builder}
|
||||||
|
eval "$postBuild"
|
||||||
|
'')
|
11
pkgs/build-support/cc-wrapper/add-clang-cc-cflags-before.sh
Normal file
11
pkgs/build-support/cc-wrapper/add-clang-cc-cflags-before.sh
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
needsTarget=true
|
||||||
|
|
||||||
|
for p in "${params[@]}"; do
|
||||||
|
case "$p" in
|
||||||
|
-target | --target=*) needsTarget=false ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if $needsTarget; then
|
||||||
|
extraBefore+=(-target @defaultTarget@ @march@)
|
||||||
|
fi
|
87
pkgs/build-support/cc-wrapper/add-flags.sh
Normal file
87
pkgs/build-support/cc-wrapper/add-flags.sh
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
# N.B. It may be a surprise that the derivation-specific variables are exported,
|
||||||
|
# since this is just sourced by the wrapped binaries---the end consumers. This
|
||||||
|
# is because one wrapper binary may invoke another (e.g. cc invoking ld). In
|
||||||
|
# that case, it is cheaper/better to not repeat this step and let the forked
|
||||||
|
# wrapped binary just inherit the work of the forker's wrapper script.
|
||||||
|
|
||||||
|
var_templates_list=(
|
||||||
|
NIX_CFLAGS_COMPILE
|
||||||
|
NIX_CFLAGS_COMPILE_BEFORE
|
||||||
|
NIX_CFLAGS_LINK
|
||||||
|
NIX_CXXSTDLIB_COMPILE
|
||||||
|
NIX_CXXSTDLIB_LINK
|
||||||
|
NIX_GNATFLAGS_COMPILE
|
||||||
|
)
|
||||||
|
var_templates_bool=(
|
||||||
|
NIX_ENFORCE_NO_NATIVE
|
||||||
|
)
|
||||||
|
|
||||||
|
accumulateRoles
|
||||||
|
|
||||||
|
# We need to mangle names for hygiene, but also take parameters/overrides
|
||||||
|
# from the environment.
|
||||||
|
for var in "${var_templates_list[@]}"; do
|
||||||
|
mangleVarList "$var" ${role_suffixes[@]+"${role_suffixes[@]}"}
|
||||||
|
done
|
||||||
|
for var in "${var_templates_bool[@]}"; do
|
||||||
|
mangleVarBool "$var" ${role_suffixes[@]+"${role_suffixes[@]}"}
|
||||||
|
done
|
||||||
|
|
||||||
|
# `-B@out@/bin' forces cc to use ld-wrapper.sh when calling ld.
|
||||||
|
NIX_CFLAGS_COMPILE_@suffixSalt@="-B@out@/bin/ $NIX_CFLAGS_COMPILE_@suffixSalt@"
|
||||||
|
|
||||||
|
# Export and assign separately in order that a failing $(..) will fail
|
||||||
|
# the script.
|
||||||
|
|
||||||
|
# Currently bootstrap-tools does not split glibc, and gcc files into
|
||||||
|
# separate directories. As a workaround we want resulting cflags to be
|
||||||
|
# ordered as: crt1-cflags libc-cflags cc-cflags. Otherwise we mix crt/libc.so
|
||||||
|
# from different libc as seen in
|
||||||
|
# https://github.com/NixOS/nixpkgs/issues/158042
|
||||||
|
#
|
||||||
|
# Note that below has reverse ordering as we prepend flags one-by-one.
|
||||||
|
# Once bootstrap-tools is split into different directories we can stop
|
||||||
|
# relying on flag ordering below.
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/cc-cflags ]; then
|
||||||
|
NIX_CFLAGS_COMPILE_@suffixSalt@="$(< @out@/nix-support/cc-cflags) $NIX_CFLAGS_COMPILE_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$cInclude" = 1 ]] && [ -e @out@/nix-support/libc-cflags ]; then
|
||||||
|
NIX_CFLAGS_COMPILE_@suffixSalt@="$(< @out@/nix-support/libc-cflags) $NIX_CFLAGS_COMPILE_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/libc-crt1-cflags ]; then
|
||||||
|
NIX_CFLAGS_COMPILE_@suffixSalt@="$(< @out@/nix-support/libc-crt1-cflags) $NIX_CFLAGS_COMPILE_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/libcxx-cxxflags ]; then
|
||||||
|
NIX_CXXSTDLIB_COMPILE_@suffixSalt@+=" $(< @out@/nix-support/libcxx-cxxflags)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/libcxx-ldflags ]; then
|
||||||
|
NIX_CXXSTDLIB_LINK_@suffixSalt@+=" $(< @out@/nix-support/libcxx-ldflags)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/gnat-cflags ]; then
|
||||||
|
NIX_GNATFLAGS_COMPILE_@suffixSalt@="$(< @out@/nix-support/gnat-cflags) $NIX_GNATFLAGS_COMPILE_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/cc-ldflags ]; then
|
||||||
|
NIX_LDFLAGS_@suffixSalt@+=" $(< @out@/nix-support/cc-ldflags)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e @out@/nix-support/cc-cflags-before ]; then
|
||||||
|
NIX_CFLAGS_COMPILE_BEFORE_@suffixSalt@="$(< @out@/nix-support/cc-cflags-before) $NIX_CFLAGS_COMPILE_BEFORE_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only add darwin min version flag if a default darwin min version is set,
|
||||||
|
# which is a signal that we're targetting darwin.
|
||||||
|
if [ "@darwinMinVersion@" ]; then
|
||||||
|
mangleVarSingle @darwinMinVersionVariable@ ${role_suffixes[@]+"${role_suffixes[@]}"}
|
||||||
|
|
||||||
|
NIX_CFLAGS_COMPILE_BEFORE_@suffixSalt@="-m@darwinPlatformForCC@-version-min=${@darwinMinVersionVariable@_@suffixSalt@:-@darwinMinVersion@} $NIX_CFLAGS_COMPILE_BEFORE_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# That way forked processes will not extend these environment variables again.
|
||||||
|
export NIX_CC_WRAPPER_FLAGS_SET_@suffixSalt@=1
|
23
pkgs/build-support/cc-wrapper/add-gnat-extra-flags.sh
Normal file
23
pkgs/build-support/cc-wrapper/add-gnat-extra-flags.sh
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# See add-flags.sh in cc-wrapper for comments.
|
||||||
|
var_templates_list=(
|
||||||
|
NIX_GNATMAKE_CARGS
|
||||||
|
)
|
||||||
|
|
||||||
|
accumulateRoles
|
||||||
|
|
||||||
|
for var in "${var_templates_list[@]}"; do
|
||||||
|
mangleVarList "$var" ${role_suffixes[@]+"${role_suffixes[@]}"}
|
||||||
|
done
|
||||||
|
|
||||||
|
# `-B@out@/bin' forces cc to use wrapped as instead of the system one.
|
||||||
|
NIX_GNATMAKE_CARGS_@suffixSalt@="$NIX_GNATMAKE_CARGS_@suffixSalt@ -B@out@/bin/"
|
||||||
|
|
||||||
|
# Only add darwin min version flag if a default darwin min version is set,
|
||||||
|
# which is a signal that we're targetting darwin.
|
||||||
|
if [ "@darwinMinVersion@" ]; then
|
||||||
|
mangleVarSingle @darwinMinVersionVariable@ ${role_suffixes[@]+"${role_suffixes[@]}"}
|
||||||
|
|
||||||
|
NIX_GNATMAKE_CARGS_@suffixSalt@="-m@darwinPlatformForCC@-version-min=${@darwinMinVersionVariable@_@suffixSalt@:-@darwinMinVersion@} $NIX_GNATMAKE_CARGS_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export NIX_GNAT_WRAPPER_EXTRA_FLAGS_SET_@suffixSalt@=1
|
126
pkgs/build-support/cc-wrapper/add-hardening.sh
Normal file
126
pkgs/build-support/cc-wrapper/add-hardening.sh
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
declare -a hardeningCFlagsAfter=()
|
||||||
|
declare -a hardeningCFlagsBefore=()
|
||||||
|
|
||||||
|
declare -A hardeningEnableMap=()
|
||||||
|
|
||||||
|
# Intentionally word-split in case 'NIX_HARDENING_ENABLE' is defined in Nix. The
|
||||||
|
# array expansion also prevents undefined variables from causing trouble with
|
||||||
|
# `set -u`.
|
||||||
|
for flag in ${NIX_HARDENING_ENABLE_@suffixSalt@-}; do
|
||||||
|
hardeningEnableMap["$flag"]=1
|
||||||
|
done
|
||||||
|
|
||||||
|
# fortify3 implies fortify enablement - make explicit before
|
||||||
|
# we filter unsupported flags because unsupporting fortify3
|
||||||
|
# doesn't mean we should unsupport fortify too
|
||||||
|
if [[ -n "${hardeningEnableMap[fortify3]-}" ]]; then
|
||||||
|
hardeningEnableMap["fortify"]=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove unsupported flags.
|
||||||
|
for flag in @hardening_unsupported_flags@; do
|
||||||
|
unset -v "hardeningEnableMap[$flag]"
|
||||||
|
# fortify being unsupported implies fortify3 is unsupported
|
||||||
|
if [[ "$flag" = 'fortify' ]] ; then
|
||||||
|
unset -v "hardeningEnableMap['fortify3']"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# now make fortify and fortify3 mutually exclusive
|
||||||
|
if [[ -n "${hardeningEnableMap[fortify3]-}" ]]; then
|
||||||
|
unset -v "hardeningEnableMap['fortify']"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||||
|
declare -a allHardeningFlags=(fortify fortify3 stackprotector pie pic strictoverflow format trivialautovarinit zerocallusedregs)
|
||||||
|
declare -A hardeningDisableMap=()
|
||||||
|
|
||||||
|
# Determine which flags were effectively disabled so we can report below.
|
||||||
|
for flag in "${allHardeningFlags[@]}"; do
|
||||||
|
if [[ -z "${hardeningEnableMap[$flag]-}" ]]; then
|
||||||
|
hardeningDisableMap["$flag"]=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf 'HARDENING: disabled flags:' >&2
|
||||||
|
(( "${#hardeningDisableMap[@]}" )) && printf ' %q' "${!hardeningDisableMap[@]}" >&2
|
||||||
|
echo >&2
|
||||||
|
|
||||||
|
if (( "${#hardeningEnableMap[@]}" )); then
|
||||||
|
echo 'HARDENING: Is active (not completely disabled with "all" flag)' >&2;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
for flag in "${!hardeningEnableMap[@]}"; do
|
||||||
|
case $flag in
|
||||||
|
fortify | fortify3)
|
||||||
|
# Use -U_FORTIFY_SOURCE to avoid warnings on toolchains that explicitly
|
||||||
|
# set -D_FORTIFY_SOURCE=0 (like 'clang -fsanitize=address').
|
||||||
|
hardeningCFlagsBefore+=('-O2' '-U_FORTIFY_SOURCE')
|
||||||
|
# Unset any _FORTIFY_SOURCE values the command-line may have set before
|
||||||
|
# enforcing our own value, avoiding (potentially fatal) redefinition
|
||||||
|
# warnings
|
||||||
|
hardeningCFlagsAfter+=('-U_FORTIFY_SOURCE')
|
||||||
|
case $flag in
|
||||||
|
fortify)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling fortify >&2; fi
|
||||||
|
hardeningCFlagsAfter+=('-D_FORTIFY_SOURCE=2')
|
||||||
|
;;
|
||||||
|
fortify3)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling fortify3 >&2; fi
|
||||||
|
hardeningCFlagsAfter+=('-D_FORTIFY_SOURCE=3')
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Ignore unsupported.
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
stackprotector)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling stackprotector >&2; fi
|
||||||
|
hardeningCFlagsBefore+=('-fstack-protector-strong' '--param' 'ssp-buffer-size=4')
|
||||||
|
;;
|
||||||
|
pie)
|
||||||
|
# NB: we do not use `+=` here, because PIE flags must occur before any PIC flags
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling CFlags -fPIE >&2; fi
|
||||||
|
hardeningCFlagsBefore=('-fPIE' "${hardeningCFlagsBefore[@]}")
|
||||||
|
if [[ ! (" ${params[*]} " =~ " -shared " || " ${params[*]} " =~ " -static ") ]]; then
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling LDFlags -pie >&2; fi
|
||||||
|
hardeningCFlagsBefore=('-pie' "${hardeningCFlagsBefore[@]}")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
pic)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling pic >&2; fi
|
||||||
|
hardeningCFlagsBefore+=('-fPIC')
|
||||||
|
;;
|
||||||
|
strictoverflow)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling strictoverflow >&2; fi
|
||||||
|
if (( @isClang@ )); then
|
||||||
|
# In Clang, -fno-strict-overflow only serves to set -fwrapv and is
|
||||||
|
# reported as an unused CLI argument if -fwrapv or -fno-wrapv is set
|
||||||
|
# explicitly, so we side step that by doing the conversion here.
|
||||||
|
#
|
||||||
|
# See: https://github.com/llvm/llvm-project/blob/llvmorg-16.0.6/clang/lib/Driver/ToolChains/Clang.cpp#L6315
|
||||||
|
#
|
||||||
|
hardeningCFlagsBefore+=('-fwrapv')
|
||||||
|
else
|
||||||
|
hardeningCFlagsBefore+=('-fno-strict-overflow')
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
trivialautovarinit)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling trivialautovarinit >&2; fi
|
||||||
|
hardeningCFlagsBefore+=('-ftrivial-auto-var-init=pattern')
|
||||||
|
;;
|
||||||
|
format)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling format >&2; fi
|
||||||
|
hardeningCFlagsBefore+=('-Wformat' '-Wformat-security' '-Werror=format-security')
|
||||||
|
;;
|
||||||
|
zerocallusedregs)
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling zerocallusedregs >&2; fi
|
||||||
|
hardeningCFlagsBefore+=('-fzero-call-used-regs=used-gpr')
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Ignore unsupported. Checked in Nix that at least *some*
|
||||||
|
# tool supports each flag.
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
261
pkgs/build-support/cc-wrapper/cc-wrapper.sh
Normal file
261
pkgs/build-support/cc-wrapper/cc-wrapper.sh
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
#! @shell@
|
||||||
|
set -eu -o pipefail +o posix
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 7 )); then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
path_backup="$PATH"
|
||||||
|
|
||||||
|
# That @-vars are substituted separately from bash evaluation makes
|
||||||
|
# shellcheck think this, and others like it, are useless conditionals.
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [[ -n "@coreutils_bin@" && -n "@gnugrep_bin@" ]]; then
|
||||||
|
PATH="@coreutils_bin@/bin:@gnugrep_bin@/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
source @out@/nix-support/utils.bash
|
||||||
|
|
||||||
|
|
||||||
|
# Parse command line options and set several variables.
|
||||||
|
# For instance, figure out if linker flags should be passed.
|
||||||
|
# GCC prints annoying warnings when they are not needed.
|
||||||
|
dontLink=0
|
||||||
|
nonFlagArgs=0
|
||||||
|
cc1=0
|
||||||
|
# shellcheck disable=SC2193
|
||||||
|
[[ "@prog@" = *++ ]] && isCxx=1 || isCxx=0
|
||||||
|
cxxInclude=1
|
||||||
|
cxxLibrary=1
|
||||||
|
cInclude=1
|
||||||
|
|
||||||
|
expandResponseParams "$@"
|
||||||
|
|
||||||
|
declare -ag positionalArgs=()
|
||||||
|
declare -i n=0
|
||||||
|
nParams=${#params[@]}
|
||||||
|
while (( "$n" < "$nParams" )); do
|
||||||
|
p=${params[n]}
|
||||||
|
p2=${params[n+1]:-} # handle `p` being last one
|
||||||
|
n+=1
|
||||||
|
|
||||||
|
case "$p" in
|
||||||
|
-[cSEM] | -MM) dontLink=1 ;;
|
||||||
|
-cc1) cc1=1 ;;
|
||||||
|
-nostdinc) cInclude=0 cxxInclude=0 ;;
|
||||||
|
-nostdinc++) cxxInclude=0 ;;
|
||||||
|
-nostdlib) cxxLibrary=0 ;;
|
||||||
|
-x*-header) dontLink=1 ;; # both `-x c-header` and `-xc-header` are accepted by clang
|
||||||
|
-xc++*) isCxx=1 ;; # both `-xc++` and `-x c++` are accepted by clang
|
||||||
|
-x)
|
||||||
|
case "$p2" in
|
||||||
|
*-header) dontLink=1 ;;
|
||||||
|
c++*) isCxx=1 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
--) # Everything else is positional args!
|
||||||
|
# See: https://github.com/llvm/llvm-project/commit/ed1d07282cc9d8e4c25d585e03e5c8a1b6f63a74
|
||||||
|
|
||||||
|
# Any positional arg (i.e. any argument after `--`) will be
|
||||||
|
# interpreted as a "non flag" arg:
|
||||||
|
if [[ -v "params[$n]" ]]; then nonFlagArgs=1; fi
|
||||||
|
|
||||||
|
positionalArgs=("${params[@]:$n}")
|
||||||
|
params=("${params[@]:0:$((n - 1))}")
|
||||||
|
break;
|
||||||
|
;;
|
||||||
|
-?*) ;;
|
||||||
|
*) nonFlagArgs=1 ;; # Includes a solitary dash (`-`) which signifies standard input; it is not a flag
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# If we pass a flag like -Wl, then gcc will call the linker unless it
|
||||||
|
# can figure out that it has to do something else (e.g., because of a
|
||||||
|
# "-c" flag). So if no non-flag arguments are given, don't pass any
|
||||||
|
# linker flags. This catches cases like "gcc" (should just print
|
||||||
|
# "gcc: no input files") and "gcc -v" (should print the version).
|
||||||
|
if [ "$nonFlagArgs" = 0 ]; then
|
||||||
|
dontLink=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally filter out paths not refering to the store.
|
||||||
|
if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "$NIX_STORE" ]]; then
|
||||||
|
kept=()
|
||||||
|
nParams=${#params[@]}
|
||||||
|
declare -i n=0
|
||||||
|
while (( "$n" < "$nParams" )); do
|
||||||
|
p=${params[n]}
|
||||||
|
p2=${params[n+1]:-} # handle `p` being last one
|
||||||
|
n+=1
|
||||||
|
|
||||||
|
skipNext=false
|
||||||
|
path=""
|
||||||
|
case "$p" in
|
||||||
|
-[IL]/*) path=${p:2} ;;
|
||||||
|
-[IL] | -isystem) path=$p2 skipNext=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -n $path ]] && badPath "$path"; then
|
||||||
|
skip "$path"
|
||||||
|
$skipNext && n+=1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
kept+=("$p")
|
||||||
|
done
|
||||||
|
# Old bash empty array hack
|
||||||
|
params=(${kept+"${kept[@]}"})
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Flirting with a layer violation here.
|
||||||
|
if [ -z "${NIX_BINTOOLS_WRAPPER_FLAGS_SET_@suffixSalt@:-}" ]; then
|
||||||
|
source @bintools@/nix-support/add-flags.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Put this one second so libc ldflags take priority.
|
||||||
|
if [ -z "${NIX_CC_WRAPPER_FLAGS_SET_@suffixSalt@:-}" ]; then
|
||||||
|
source @out@/nix-support/add-flags.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clear march/mtune=native -- they bring impurity.
|
||||||
|
if [ "$NIX_ENFORCE_NO_NATIVE_@suffixSalt@" = 1 ]; then
|
||||||
|
kept=()
|
||||||
|
# Old bash empty array hack
|
||||||
|
for p in ${params+"${params[@]}"}; do
|
||||||
|
if [[ "$p" = -m*=native ]]; then
|
||||||
|
skip "$p"
|
||||||
|
else
|
||||||
|
kept+=("$p")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Old bash empty array hack
|
||||||
|
params=(${kept+"${kept[@]}"})
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$isCxx" = 1 ]]; then
|
||||||
|
if [[ "$cxxInclude" = 1 ]]; then
|
||||||
|
#
|
||||||
|
# The motivation for this comment is to explain the reason for appending
|
||||||
|
# the C++ stdlib to NIX_CFLAGS_COMPILE, which I initially thought should
|
||||||
|
# change and later realized it shouldn't in:
|
||||||
|
#
|
||||||
|
# https://github.com/NixOS/nixpkgs/pull/185569#issuecomment-1234959249
|
||||||
|
#
|
||||||
|
# NIX_CFLAGS_COMPILE contains dependencies added using "-isystem", and
|
||||||
|
# NIX_CXXSTDLIB_COMPILE adds the C++ stdlib using "-isystem". Appending
|
||||||
|
# NIX_CXXSTDLIB_COMPILE to NIX_CLAGS_COMPILE emulates this part of the
|
||||||
|
# include lookup order from GCC/Clang:
|
||||||
|
#
|
||||||
|
# > 4. Directories specified with -isystem options are scanned in
|
||||||
|
# > left-to-right order.
|
||||||
|
# > 5. Standard system directories are scanned.
|
||||||
|
# > 6. Directories specified with -idirafter options are scanned
|
||||||
|
# > in left-to-right order.
|
||||||
|
#
|
||||||
|
# NIX_CXX_STDLIB_COMPILE acts as the "standard system directories" that
|
||||||
|
# are otherwise missing from CC in nixpkgs, so should be added last.
|
||||||
|
#
|
||||||
|
# This means that the C standard library should never be present inside
|
||||||
|
# NIX_CFLAGS_COMPILE, because it MUST come after the C++ stdlib. It is
|
||||||
|
# added automatically by cc-wrapper later using "-idirafter".
|
||||||
|
#
|
||||||
|
NIX_CFLAGS_COMPILE_@suffixSalt@+=" $NIX_CXXSTDLIB_COMPILE_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
if [[ "$cxxLibrary" = 1 ]]; then
|
||||||
|
NIX_CFLAGS_LINK_@suffixSalt@+=" $NIX_CXXSTDLIB_LINK_@suffixSalt@"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
source @out@/nix-support/add-hardening.sh
|
||||||
|
|
||||||
|
# Add the flags for the C compiler proper.
|
||||||
|
extraAfter=(${hardeningCFlagsAfter[@]+"${hardeningCFlagsAfter[@]}"} $NIX_CFLAGS_COMPILE_@suffixSalt@)
|
||||||
|
extraBefore=(${hardeningCFlagsBefore[@]+"${hardeningCFlagsBefore[@]}"} $NIX_CFLAGS_COMPILE_BEFORE_@suffixSalt@)
|
||||||
|
|
||||||
|
if [ "$dontLink" != 1 ]; then
|
||||||
|
linkType=$(checkLinkType $NIX_LDFLAGS_BEFORE_@suffixSalt@ "${params[@]}" ${NIX_CFLAGS_LINK_@suffixSalt@:-} $NIX_LDFLAGS_@suffixSalt@)
|
||||||
|
|
||||||
|
# Add the flags that should only be passed to the compiler when
|
||||||
|
# linking.
|
||||||
|
extraAfter+=($(filterRpathFlags "$linkType" $NIX_CFLAGS_LINK_@suffixSalt@))
|
||||||
|
|
||||||
|
# Add the flags that should be passed to the linker (and prevent
|
||||||
|
# `ld-wrapper' from adding NIX_LDFLAGS_@suffixSalt@ again).
|
||||||
|
for i in $(filterRpathFlags "$linkType" $NIX_LDFLAGS_BEFORE_@suffixSalt@); do
|
||||||
|
extraBefore+=("-Wl,$i")
|
||||||
|
done
|
||||||
|
if [[ "$linkType" == dynamic && -n "$NIX_DYNAMIC_LINKER_@suffixSalt@" ]]; then
|
||||||
|
extraBefore+=("-Wl,-dynamic-linker=$NIX_DYNAMIC_LINKER_@suffixSalt@")
|
||||||
|
fi
|
||||||
|
for i in $(filterRpathFlags "$linkType" $NIX_LDFLAGS_@suffixSalt@); do
|
||||||
|
if [ "${i:0:3}" = -L/ ]; then
|
||||||
|
extraAfter+=("$i")
|
||||||
|
else
|
||||||
|
extraAfter+=("-Wl,$i")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
export NIX_LINK_TYPE_@suffixSalt@=$linkType
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -e @out@/nix-support/add-local-cc-cflags-before.sh ]]; then
|
||||||
|
source @out@/nix-support/add-local-cc-cflags-before.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# As a very special hack, if the arguments are just `-v', then don't
|
||||||
|
# add anything. This is to prevent `gcc -v' (which normally prints
|
||||||
|
# out the version number and returns exit code 0) from printing out
|
||||||
|
# `No input files specified' and returning exit code 1.
|
||||||
|
if [ "$*" = -v ]; then
|
||||||
|
extraAfter=()
|
||||||
|
extraBefore=()
|
||||||
|
fi
|
||||||
|
|
||||||
|
# clang's -cc1 mode is not compatible with most options
|
||||||
|
# that we would pass. Rather than trying to pass only
|
||||||
|
# options that would work, let's just remove all of them.
|
||||||
|
if [ "$cc1" = 1 ]; then
|
||||||
|
extraAfter=()
|
||||||
|
extraBefore=()
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Finally, if we got any positional args, append them to `extraAfter`
|
||||||
|
# now:
|
||||||
|
if [[ "${#positionalArgs[@]}" -gt 0 ]]; then
|
||||||
|
extraAfter+=(-- "${positionalArgs[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally print debug info.
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||||
|
# Old bash workaround, see ld-wrapper for explanation.
|
||||||
|
echo "extra flags before to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraBefore+"${extraBefore[@]}"} >&2
|
||||||
|
echo "original flags to @prog@:" >&2
|
||||||
|
printf " %q\n" ${params+"${params[@]}"} >&2
|
||||||
|
echo "extra flags after to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraAfter+"${extraAfter[@]}"} >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
PATH="$path_backup"
|
||||||
|
# Old bash workaround, see above.
|
||||||
|
|
||||||
|
# if a cc-wrapper-hook exists, run it.
|
||||||
|
if [[ -e @out@/nix-support/cc-wrapper-hook ]]; then
|
||||||
|
compiler=@prog@
|
||||||
|
source @out@/nix-support/cc-wrapper-hook
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( "${NIX_CC_USE_RESPONSE_FILE:-@use_response_file_by_default@}" >= 1 )); then
|
||||||
|
responseFile=$(mktemp "${TMPDIR:-/tmp}/cc-params.XXXXXX")
|
||||||
|
trap 'rm -f -- "$responseFile"' EXIT
|
||||||
|
printf "%q\n" \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"} > "$responseFile"
|
||||||
|
@prog@ "@$responseFile"
|
||||||
|
else
|
||||||
|
exec @prog@ \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
||||||
|
fi
|
764
pkgs/build-support/cc-wrapper/default.nix
Normal file
764
pkgs/build-support/cc-wrapper/default.nix
Normal file
|
@ -0,0 +1,764 @@
|
||||||
|
# The Nixpkgs CC is not directly usable, since it doesn't know where
|
||||||
|
# the C library and standard header files are. Therefore the compiler
|
||||||
|
# produced by that package cannot be installed directly in a user
|
||||||
|
# environment and used from the command line. So we use a wrapper
|
||||||
|
# script that sets up the right environment variables so that the
|
||||||
|
# compiler and the linker just "work".
|
||||||
|
|
||||||
|
{ name ? ""
|
||||||
|
, lib
|
||||||
|
, stdenvNoCC
|
||||||
|
, runtimeShell
|
||||||
|
, cc ? null, libc ? null, bintools, coreutils ? null
|
||||||
|
, zlib ? null
|
||||||
|
, nativeTools, noLibc ? false, nativeLibc, nativePrefix ? ""
|
||||||
|
, propagateDoc ? cc != null && cc ? man
|
||||||
|
, extraTools ? [], extraPackages ? [], extraBuildCommands ? ""
|
||||||
|
, nixSupport ? {}
|
||||||
|
, isGNU ? false, isClang ? cc.isClang or false, isCcache ? cc.isCcache or false, gnugrep ? null
|
||||||
|
, expand-response-params
|
||||||
|
, libcxx ? null
|
||||||
|
|
||||||
|
# Whether or not to add `-B` and `-L` to `nix-support/cc-{c,ld}flags`
|
||||||
|
, useCcForLibs ?
|
||||||
|
|
||||||
|
# Always add these flags for Clang, because in order to compile (most
|
||||||
|
# software) it needs libraries that are shipped and compiled with gcc.
|
||||||
|
if isClang then true
|
||||||
|
|
||||||
|
# Never add these flags for a build!=host cross-compiler or a host!=target
|
||||||
|
# ("cross-built-native") compiler; currently nixpkgs has a special build
|
||||||
|
# path for these (`crossStageStatic`). Hopefully at some point that build
|
||||||
|
# path will be merged with this one and this conditional will be removed.
|
||||||
|
else if (with stdenvNoCC; buildPlatform != hostPlatform || hostPlatform != targetPlatform) then false
|
||||||
|
|
||||||
|
# Never add these flags when wrapping the bootstrapFiles' compiler; it has a
|
||||||
|
# /usr/-like layout with everything smashed into a single outpath, so it has
|
||||||
|
# no trouble finding its own libraries.
|
||||||
|
else if (cc.passthru.isFromBootstrapFiles or false) then false
|
||||||
|
|
||||||
|
# Add these flags when wrapping `xgcc` (the first compiler that nixpkgs builds)
|
||||||
|
else if (cc.passthru.isXgcc or false) then true
|
||||||
|
|
||||||
|
# Add these flags when wrapping `stdenv.cc`
|
||||||
|
else if (cc.stdenv.cc.cc.passthru.isXgcc or false) then true
|
||||||
|
|
||||||
|
# Do not add these flags in any other situation. This is `false` mainly to
|
||||||
|
# prevent these flags from being added when wrapping *old* versions of gcc
|
||||||
|
# (e.g. `gcc6Stdenv`), since they will cause the old gcc to get `-B` and
|
||||||
|
# `-L` flags pointing at the new gcc's libstdc++ headers. Example failure:
|
||||||
|
# https://hydra.nixos.org/build/213125495
|
||||||
|
else false
|
||||||
|
|
||||||
|
# the derivation at which the `-B` and `-L` flags added by `useCcForLibs` will point
|
||||||
|
, gccForLibs ? if useCcForLibs then cc else null
|
||||||
|
, fortify-headers ? null
|
||||||
|
, includeFortifyHeaders ? null
|
||||||
|
}:
|
||||||
|
|
||||||
|
assert nativeTools -> !propagateDoc && nativePrefix != "";
|
||||||
|
assert !nativeTools -> cc != null && coreutils != null && gnugrep != null;
|
||||||
|
assert !(nativeLibc && noLibc);
|
||||||
|
assert (noLibc || nativeLibc) == (libc == null);
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
attrByPath
|
||||||
|
concatMapStrings
|
||||||
|
concatStringsSep
|
||||||
|
escapeShellArg
|
||||||
|
getBin
|
||||||
|
getDev
|
||||||
|
getLib
|
||||||
|
getName
|
||||||
|
getVersion
|
||||||
|
mapAttrsToList
|
||||||
|
optional
|
||||||
|
optionalAttrs
|
||||||
|
optionals
|
||||||
|
optionalString
|
||||||
|
removePrefix
|
||||||
|
replaceStrings
|
||||||
|
toList
|
||||||
|
versionAtLeast
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (stdenvNoCC) hostPlatform targetPlatform;
|
||||||
|
|
||||||
|
includeFortifyHeaders' = if includeFortifyHeaders != null
|
||||||
|
then includeFortifyHeaders
|
||||||
|
else (targetPlatform.libc == "musl" && isGNU);
|
||||||
|
|
||||||
|
# Prefix for binaries. Customarily ends with a dash separator.
|
||||||
|
#
|
||||||
|
# TODO(@Ericson2314) Make unconditional, or optional but always true by default.
|
||||||
|
targetPrefix = optionalString (targetPlatform != hostPlatform) (targetPlatform.config + "-");
|
||||||
|
|
||||||
|
ccVersion = getVersion cc;
|
||||||
|
ccName = removePrefix targetPrefix (getName cc);
|
||||||
|
|
||||||
|
libc_bin = optionalString (libc != null) (getBin libc);
|
||||||
|
libc_dev = optionalString (libc != null) (getDev libc);
|
||||||
|
libc_lib = optionalString (libc != null) (getLib libc);
|
||||||
|
cc_solib = getLib cc
|
||||||
|
+ optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
|
||||||
|
|
||||||
|
# The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
|
||||||
|
coreutils_bin = optionalString (!nativeTools) (getBin coreutils);
|
||||||
|
|
||||||
|
# The "suffix salt" is a arbitrary string added in the end of env vars
|
||||||
|
# defined by cc-wrapper's hooks so that multiple cc-wrappers can be used
|
||||||
|
# without interfering. For the moment, it is defined as the target triple,
|
||||||
|
# adjusted to be a valid bash identifier. This should be considered an
|
||||||
|
# unstable implementation detail, however.
|
||||||
|
suffixSalt = replaceStrings ["-" "."] ["_" "_"] targetPlatform.config;
|
||||||
|
|
||||||
|
useGccForLibs = useCcForLibs
|
||||||
|
&& libcxx == null
|
||||||
|
&& !targetPlatform.isDarwin
|
||||||
|
&& !(targetPlatform.useLLVM or false)
|
||||||
|
&& !(targetPlatform.useAndroidPrebuilt or false)
|
||||||
|
&& !(targetPlatform.isiOS or false)
|
||||||
|
&& gccForLibs != null;
|
||||||
|
gccForLibs_solib = getLib gccForLibs
|
||||||
|
+ optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
|
||||||
|
|
||||||
|
# Analogously to cc_solib and gccForLibs_solib
|
||||||
|
libcxx_solib = "${getLib libcxx}/lib";
|
||||||
|
|
||||||
|
# The following two functions, `isGccArchSupported` and
|
||||||
|
# `isGccTuneSupported`, only handle those situations where a flag
|
||||||
|
# (`-march` or `-mtune`) is accepted by one compiler but rejected
|
||||||
|
# by another, and both compilers are relevant to nixpkgs. We are
|
||||||
|
# not trying to maintain a complete list of all flags accepted by
|
||||||
|
# all versions of all compilers ever in nixpkgs.
|
||||||
|
#
|
||||||
|
# The two main cases of interest are:
|
||||||
|
#
|
||||||
|
# - One compiler is gcc and the other is clang
|
||||||
|
# - One compiler is pkgs.gcc and the other is bootstrap-files.gcc
|
||||||
|
# -- older compilers (for example bootstrap's GCC 5) fail with
|
||||||
|
# -march=too-modern-cpu
|
||||||
|
|
||||||
|
isGccArchSupported = arch:
|
||||||
|
if targetPlatform.isPower then false else # powerpc does not allow -march=
|
||||||
|
if isGNU then
|
||||||
|
{ # Generic
|
||||||
|
x86-64-v2 = versionAtLeast ccVersion "11.0";
|
||||||
|
x86-64-v3 = versionAtLeast ccVersion "11.0";
|
||||||
|
x86-64-v4 = versionAtLeast ccVersion "11.0";
|
||||||
|
|
||||||
|
# Intel
|
||||||
|
skylake = versionAtLeast ccVersion "6.0";
|
||||||
|
skylake-avx512 = versionAtLeast ccVersion "6.0";
|
||||||
|
cannonlake = versionAtLeast ccVersion "8.0";
|
||||||
|
icelake-client = versionAtLeast ccVersion "8.0";
|
||||||
|
icelake-server = versionAtLeast ccVersion "8.0";
|
||||||
|
cascadelake = versionAtLeast ccVersion "9.0";
|
||||||
|
cooperlake = versionAtLeast ccVersion "10.0";
|
||||||
|
tigerlake = versionAtLeast ccVersion "10.0";
|
||||||
|
knm = versionAtLeast ccVersion "8.0";
|
||||||
|
alderlake = versionAtLeast ccVersion "12.0";
|
||||||
|
|
||||||
|
# AMD
|
||||||
|
znver1 = versionAtLeast ccVersion "6.0";
|
||||||
|
znver2 = versionAtLeast ccVersion "9.0";
|
||||||
|
znver3 = versionAtLeast ccVersion "11.0";
|
||||||
|
znver4 = versionAtLeast ccVersion "13.0";
|
||||||
|
}.${arch} or true
|
||||||
|
else if isClang then
|
||||||
|
{ #Generic
|
||||||
|
x86-64-v2 = versionAtLeast ccVersion "12.0";
|
||||||
|
x86-64-v3 = versionAtLeast ccVersion "12.0";
|
||||||
|
x86-64-v4 = versionAtLeast ccVersion "12.0";
|
||||||
|
|
||||||
|
# Intel
|
||||||
|
cannonlake = versionAtLeast ccVersion "5.0";
|
||||||
|
icelake-client = versionAtLeast ccVersion "7.0";
|
||||||
|
icelake-server = versionAtLeast ccVersion "7.0";
|
||||||
|
knm = versionAtLeast ccVersion "7.0";
|
||||||
|
alderlake = versionAtLeast ccVersion "16.0";
|
||||||
|
|
||||||
|
# AMD
|
||||||
|
znver1 = versionAtLeast ccVersion "4.0";
|
||||||
|
znver2 = versionAtLeast ccVersion "9.0";
|
||||||
|
znver3 = versionAtLeast ccVersion "12.0";
|
||||||
|
znver4 = versionAtLeast ccVersion "16.0";
|
||||||
|
}.${arch} or true
|
||||||
|
else
|
||||||
|
false;
|
||||||
|
|
||||||
|
isGccTuneSupported = tune:
|
||||||
|
# for x86 -mtune= takes the same values as -march, plus two more:
|
||||||
|
if targetPlatform.isx86 then
|
||||||
|
{
|
||||||
|
generic = true;
|
||||||
|
intel = true;
|
||||||
|
}.${tune} or (isGccArchSupported tune)
|
||||||
|
# on arm64, the -mtune= values are specific processors
|
||||||
|
else if targetPlatform.isAarch64 then
|
||||||
|
(if isGNU then
|
||||||
|
{
|
||||||
|
cortex-a53 = versionAtLeast ccVersion "4.8"; # gcc 8c075f
|
||||||
|
cortex-a72 = versionAtLeast ccVersion "5.1"; # gcc d8f70d
|
||||||
|
"cortex-a72.cortex-a53" = versionAtLeast ccVersion "5.1"; # gcc d8f70d
|
||||||
|
}.${tune} or false
|
||||||
|
else if isClang then
|
||||||
|
{
|
||||||
|
cortex-a53 = versionAtLeast ccVersion "3.9"; # llvm dfc5d1
|
||||||
|
}.${tune} or false
|
||||||
|
else false)
|
||||||
|
else if targetPlatform.isPower then
|
||||||
|
# powerpc does not support -march
|
||||||
|
true
|
||||||
|
else if targetPlatform.isMips then
|
||||||
|
# for mips -mtune= takes the same values as -march
|
||||||
|
isGccArchSupported tune
|
||||||
|
else
|
||||||
|
false;
|
||||||
|
|
||||||
|
# Clang does not support as many `-mtune=` values as gcc does;
|
||||||
|
# this function will return the best possible approximation of the
|
||||||
|
# provided `-mtune=` value, or `null` if none exists.
|
||||||
|
#
|
||||||
|
# Note: this function can make use of ccVersion; for example, `if
|
||||||
|
# versionOlder ccVersion "12" then ...`
|
||||||
|
findBestTuneApproximation = tune:
|
||||||
|
let guess = if isClang
|
||||||
|
then {
|
||||||
|
# clang does not tune for big.LITTLE chips
|
||||||
|
"cortex-a72.cortex-a53" = "cortex-a72";
|
||||||
|
}.${tune} or tune
|
||||||
|
else tune;
|
||||||
|
in if isGccTuneSupported guess
|
||||||
|
then guess
|
||||||
|
else null;
|
||||||
|
|
||||||
|
defaultHardeningFlags = bintools.defaultHardeningFlags or [];
|
||||||
|
|
||||||
|
# if cc.hardeningUnsupportedFlagsByTargetPlatform exists, this is
|
||||||
|
# called with the targetPlatform as an argument and
|
||||||
|
# cc.hardeningUnsupportedFlags is completely ignored - the function
|
||||||
|
# is responsible for including the constant hardeningUnsupportedFlags
|
||||||
|
# list however it sees fit.
|
||||||
|
ccHardeningUnsupportedFlags = if cc ? hardeningUnsupportedFlagsByTargetPlatform
|
||||||
|
then cc.hardeningUnsupportedFlagsByTargetPlatform targetPlatform
|
||||||
|
else (cc.hardeningUnsupportedFlags or []);
|
||||||
|
|
||||||
|
darwinPlatformForCC = optionalString targetPlatform.isDarwin (
|
||||||
|
if (targetPlatform.darwinPlatform == "macos" && isGNU) then "macosx"
|
||||||
|
else targetPlatform.darwinPlatform
|
||||||
|
);
|
||||||
|
|
||||||
|
darwinMinVersion = optionalString targetPlatform.isDarwin (
|
||||||
|
targetPlatform.darwinMinVersion
|
||||||
|
);
|
||||||
|
|
||||||
|
darwinMinVersionVariable = optionalString targetPlatform.isDarwin
|
||||||
|
targetPlatform.darwinMinVersionVariable;
|
||||||
|
in
|
||||||
|
|
||||||
|
assert includeFortifyHeaders' -> fortify-headers != null;
|
||||||
|
|
||||||
|
# Ensure bintools matches
|
||||||
|
assert libc_bin == bintools.libc_bin;
|
||||||
|
assert libc_dev == bintools.libc_dev;
|
||||||
|
assert libc_lib == bintools.libc_lib;
|
||||||
|
assert nativeTools == bintools.nativeTools;
|
||||||
|
assert nativeLibc == bintools.nativeLibc;
|
||||||
|
assert nativePrefix == bintools.nativePrefix;
|
||||||
|
|
||||||
|
stdenvNoCC.mkDerivation {
|
||||||
|
pname = targetPrefix
|
||||||
|
+ (if name != "" then name else "${ccName}-wrapper");
|
||||||
|
version = optionalString (cc != null) ccVersion;
|
||||||
|
|
||||||
|
preferLocalBuild = true;
|
||||||
|
|
||||||
|
outputs = [ "out" ] ++ optionals propagateDoc [ "man" "info" ];
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
inherit targetPrefix suffixSalt;
|
||||||
|
# "cc" is the generic name for a C compiler, but there is no one for package
|
||||||
|
# providing the linker and related tools. The two we use now are GNU
|
||||||
|
# Binutils, and Apple's "cctools"; "bintools" as an attempt to find an
|
||||||
|
# unused middle-ground name that evokes both.
|
||||||
|
inherit bintools;
|
||||||
|
inherit cc libc libcxx nativeTools nativeLibc nativePrefix isGNU isClang;
|
||||||
|
|
||||||
|
emacsBufferSetup = pkgs: ''
|
||||||
|
; We should handle propagation here too
|
||||||
|
(mapc
|
||||||
|
(lambda (arg)
|
||||||
|
(when (file-directory-p (concat arg "/include"))
|
||||||
|
(setenv "NIX_CFLAGS_COMPILE_${suffixSalt}" (concat (getenv "NIX_CFLAGS_COMPILE_${suffixSalt}") " -isystem " arg "/include"))))
|
||||||
|
'(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)}))
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Expose expand-response-params we are /actually/ using. In stdenv
|
||||||
|
# bootstrapping, expand-response-params usually comes from an earlier stage,
|
||||||
|
# so it is important to expose this for reference checking.
|
||||||
|
inherit expand-response-params;
|
||||||
|
|
||||||
|
inherit nixSupport;
|
||||||
|
|
||||||
|
inherit defaultHardeningFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
dontBuild = true;
|
||||||
|
dontConfigure = true;
|
||||||
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
|
unpackPhase = ''
|
||||||
|
src=$PWD
|
||||||
|
'';
|
||||||
|
|
||||||
|
wrapper = ./cc-wrapper.sh;
|
||||||
|
|
||||||
|
installPhase =
|
||||||
|
''
|
||||||
|
mkdir -p $out/bin $out/nix-support
|
||||||
|
|
||||||
|
wrap() {
|
||||||
|
local dst="$1"
|
||||||
|
local wrapper="$2"
|
||||||
|
export prog="$3"
|
||||||
|
export use_response_file_by_default=${if isClang && !isCcache then "1" else "0"}
|
||||||
|
substituteAll "$wrapper" "$out/bin/$dst"
|
||||||
|
chmod +x "$out/bin/$dst"
|
||||||
|
}
|
||||||
|
''
|
||||||
|
|
||||||
|
+ (if nativeTools then ''
|
||||||
|
echo ${if targetPlatform.isDarwin then cc else nativePrefix} > $out/nix-support/orig-cc
|
||||||
|
|
||||||
|
ccPath="${if targetPlatform.isDarwin then cc else nativePrefix}/bin"
|
||||||
|
'' else ''
|
||||||
|
echo $cc > $out/nix-support/orig-cc
|
||||||
|
|
||||||
|
ccPath="${cc}/bin"
|
||||||
|
'')
|
||||||
|
|
||||||
|
# Create symlinks to everything in the bintools wrapper.
|
||||||
|
+ ''
|
||||||
|
for bbin in $bintools/bin/*; do
|
||||||
|
mkdir -p "$out/bin"
|
||||||
|
ln -s "$bbin" "$out/bin/$(basename $bbin)"
|
||||||
|
done
|
||||||
|
''
|
||||||
|
|
||||||
|
# We export environment variables pointing to the wrapped nonstandard
|
||||||
|
# cmds, lest some lousy configure script use those to guess compiler
|
||||||
|
# version.
|
||||||
|
+ ''
|
||||||
|
export named_cc=${targetPrefix}cc
|
||||||
|
export named_cxx=${targetPrefix}c++
|
||||||
|
|
||||||
|
if [ -e $ccPath/${targetPrefix}gcc ]; then
|
||||||
|
wrap ${targetPrefix}gcc $wrapper $ccPath/${targetPrefix}gcc
|
||||||
|
ln -s ${targetPrefix}gcc $out/bin/${targetPrefix}cc
|
||||||
|
export named_cc=${targetPrefix}gcc
|
||||||
|
export named_cxx=${targetPrefix}g++
|
||||||
|
elif [ -e $ccPath/clang ]; then
|
||||||
|
wrap ${targetPrefix}clang $wrapper $ccPath/clang
|
||||||
|
ln -s ${targetPrefix}clang $out/bin/${targetPrefix}cc
|
||||||
|
export named_cc=${targetPrefix}clang
|
||||||
|
export named_cxx=${targetPrefix}clang++
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e $ccPath/${targetPrefix}g++ ]; then
|
||||||
|
wrap ${targetPrefix}g++ $wrapper $ccPath/${targetPrefix}g++
|
||||||
|
ln -s ${targetPrefix}g++ $out/bin/${targetPrefix}c++
|
||||||
|
elif [ -e $ccPath/clang++ ]; then
|
||||||
|
wrap ${targetPrefix}clang++ $wrapper $ccPath/clang++
|
||||||
|
ln -s ${targetPrefix}clang++ $out/bin/${targetPrefix}c++
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e $ccPath/${targetPrefix}cpp ]; then
|
||||||
|
wrap ${targetPrefix}cpp $wrapper $ccPath/${targetPrefix}cpp
|
||||||
|
elif [ -e $ccPath/cpp ]; then
|
||||||
|
wrap ${targetPrefix}cpp $wrapper $ccPath/cpp
|
||||||
|
fi
|
||||||
|
''
|
||||||
|
|
||||||
|
# No need to wrap gnat, gnatkr, gnatname or gnatprep; we can just symlink them in
|
||||||
|
+ optionalString cc.langAda or false ''
|
||||||
|
for cmd in gnatbind gnatchop gnatclean gnatlink gnatls gnatmake; do
|
||||||
|
wrap ${targetPrefix}$cmd ${./gnat-wrapper.sh} $ccPath/${targetPrefix}$cmd
|
||||||
|
done
|
||||||
|
|
||||||
|
for cmd in gnat gnatkr gnatname gnatprep; do
|
||||||
|
ln -s $ccPath/${targetPrefix}$cmd $out/bin/${targetPrefix}$cmd
|
||||||
|
done
|
||||||
|
|
||||||
|
# this symlink points to the unwrapped gnat's output "out". It is used by
|
||||||
|
# our custom gprconfig compiler description to find GNAT's ada runtime. See
|
||||||
|
# ../../development/ada-modules/gprbuild/{boot.nix, nixpkgs-gnat.xml}
|
||||||
|
ln -sf ${cc} $out/nix-support/gprconfig-gnat-unwrapped
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString cc.langD or false ''
|
||||||
|
wrap ${targetPrefix}gdc $wrapper $ccPath/${targetPrefix}gdc
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString cc.langFortran or false ''
|
||||||
|
wrap ${targetPrefix}gfortran $wrapper $ccPath/${targetPrefix}gfortran
|
||||||
|
ln -sv ${targetPrefix}gfortran $out/bin/${targetPrefix}g77
|
||||||
|
ln -sv ${targetPrefix}gfortran $out/bin/${targetPrefix}f77
|
||||||
|
export named_fc=${targetPrefix}gfortran
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString cc.langJava or false ''
|
||||||
|
wrap ${targetPrefix}gcj $wrapper $ccPath/${targetPrefix}gcj
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString cc.langGo or false ''
|
||||||
|
wrap ${targetPrefix}gccgo $wrapper $ccPath/${targetPrefix}gccgo
|
||||||
|
wrap ${targetPrefix}go ${./go-wrapper.sh} $ccPath/${targetPrefix}go
|
||||||
|
'';
|
||||||
|
|
||||||
|
strictDeps = true;
|
||||||
|
propagatedBuildInputs = [ bintools ] ++ extraTools ++ optionals cc.langD or cc.langJava or false [ zlib ];
|
||||||
|
depsTargetTargetPropagated = optional (libcxx != null) libcxx ++ extraPackages;
|
||||||
|
|
||||||
|
setupHooks = [
|
||||||
|
../setup-hooks/role.bash
|
||||||
|
] ++ optional (cc.langC or true) ./setup-hook.sh
|
||||||
|
++ optional (cc.langFortran or false) ./fortran-hook.sh
|
||||||
|
++ optional (targetPlatform.isWindows) (stdenvNoCC.mkDerivation {
|
||||||
|
name = "win-dll-hook.sh";
|
||||||
|
dontUnpack = true;
|
||||||
|
installPhase = ''
|
||||||
|
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib" > $out
|
||||||
|
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib64" >> $out
|
||||||
|
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib32" >> $out
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
|
postFixup =
|
||||||
|
# Ensure flags files exists, as some other programs cat them. (That these
|
||||||
|
# are considered an exposed interface is a bit dubious, but fine for now.)
|
||||||
|
''
|
||||||
|
touch "$out/nix-support/cc-cflags"
|
||||||
|
touch "$out/nix-support/cc-ldflags"
|
||||||
|
''
|
||||||
|
|
||||||
|
# Backwards compatibility for packages expecting this file, e.g. with
|
||||||
|
# `$NIX_CC/nix-support/dynamic-linker`.
|
||||||
|
#
|
||||||
|
# TODO(@Ericson2314): Remove this after stable release and force
|
||||||
|
# everyone to refer to bintools-wrapper directly.
|
||||||
|
+ ''
|
||||||
|
if [[ -f "$bintools/nix-support/dynamic-linker" ]]; then
|
||||||
|
ln -s "$bintools/nix-support/dynamic-linker" "$out/nix-support"
|
||||||
|
fi
|
||||||
|
if [[ -f "$bintools/nix-support/dynamic-linker-m32" ]]; then
|
||||||
|
ln -s "$bintools/nix-support/dynamic-linker-m32" "$out/nix-support"
|
||||||
|
fi
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## GCC libs for non-GCC support
|
||||||
|
##
|
||||||
|
+ optionalString (useGccForLibs && isClang) ''
|
||||||
|
|
||||||
|
echo "-B${gccForLibs}/lib/gcc/${targetPlatform.config}/${gccForLibs.version}" >> $out/nix-support/cc-cflags
|
||||||
|
''
|
||||||
|
+ optionalString useGccForLibs ''
|
||||||
|
echo "-L${gccForLibs}/lib/gcc/${targetPlatform.config}/${gccForLibs.version}" >> $out/nix-support/cc-ldflags
|
||||||
|
echo "-L${gccForLibs_solib}/lib" >> $out/nix-support/cc-ldflags
|
||||||
|
''
|
||||||
|
|
||||||
|
# TODO We would like to connect this to `useGccForLibs`, but we cannot yet
|
||||||
|
# because `libcxxStdenv` on linux still needs this. Maybe someday we'll
|
||||||
|
# always set `useLLVM` on Darwin, and maybe also break down `useLLVM` into
|
||||||
|
# fine-grained use flags (libgcc vs compiler-rt, ld.lld vs legacy, libc++
|
||||||
|
# vs libstdc++, etc.) since Darwin isn't `useLLVM` on all counts. (See
|
||||||
|
# https://clang.llvm.org/docs/Toolchain.html for all the axes one might
|
||||||
|
# break `useLLVM` into.)
|
||||||
|
+ optionalString (isClang
|
||||||
|
&& targetPlatform.isLinux
|
||||||
|
&& !(targetPlatform.useAndroidPrebuilt or false)
|
||||||
|
&& !(targetPlatform.useLLVM or false)
|
||||||
|
&& gccForLibs != null) (''
|
||||||
|
echo "--gcc-toolchain=${gccForLibs}" >> $out/nix-support/cc-cflags
|
||||||
|
|
||||||
|
# Pull in 'cc.out' target to get 'libstdc++fs.a'. It should be in
|
||||||
|
# 'cc.lib'. But it's a gcc package bug.
|
||||||
|
# TODO(trofi): remove once gcc is fixed to move libraries to .lib output.
|
||||||
|
echo "-L${gccForLibs}/${optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}"}/lib" >> $out/nix-support/cc-ldflags
|
||||||
|
''
|
||||||
|
# this ensures that when clang passes -lgcc_s to lld (as it does
|
||||||
|
# when building e.g. firefox), lld is able to find libgcc_s.so
|
||||||
|
+ concatMapStrings (libgcc: ''
|
||||||
|
echo "-L${libgcc}/lib" >> $out/nix-support/cc-ldflags
|
||||||
|
'') (toList (gccForLibs.libgcc or [])))
|
||||||
|
|
||||||
|
##
|
||||||
|
## General libc support
|
||||||
|
##
|
||||||
|
|
||||||
|
# The "-B${libc_lib}/lib/" flag is a quick hack to force gcc to link
|
||||||
|
# against the crt1.o from our own glibc, rather than the one in
|
||||||
|
# /usr/lib. (This is only an issue when using an `impure'
|
||||||
|
# compiler/linker, i.e., one that searches /usr/lib and so on.)
|
||||||
|
#
|
||||||
|
# Unfortunately, setting -B appears to override the default search
|
||||||
|
# path. Thus, the gcc-specific "../includes-fixed" directory is
|
||||||
|
# now longer searched and glibc's <limits.h> header fails to
|
||||||
|
# compile, because it uses "#include_next <limits.h>" to find the
|
||||||
|
# limits.h file in ../includes-fixed. To remedy the problem,
|
||||||
|
# another -idirafter is necessary to add that directory again.
|
||||||
|
+ optionalString (libc != null) (''
|
||||||
|
touch "$out/nix-support/libc-cflags"
|
||||||
|
touch "$out/nix-support/libc-ldflags"
|
||||||
|
echo "-B${libc_lib}${libc.libdir or "/lib/"}" >> $out/nix-support/libc-crt1-cflags
|
||||||
|
'' + optionalString (!(cc.langD or false)) ''
|
||||||
|
echo "-idirafter ${libc_dev}${libc.incdir or "/include"}" >> $out/nix-support/libc-cflags
|
||||||
|
'' + optionalString (isGNU && (!(cc.langD or false))) ''
|
||||||
|
for dir in "${cc}"/lib/gcc/*/*/include-fixed; do
|
||||||
|
echo '-idirafter' ''${dir} >> $out/nix-support/libc-cflags
|
||||||
|
done
|
||||||
|
'' + ''
|
||||||
|
|
||||||
|
echo "${libc_lib}" > $out/nix-support/orig-libc
|
||||||
|
echo "${libc_dev}" > $out/nix-support/orig-libc-dev
|
||||||
|
''
|
||||||
|
# fortify-headers is a set of wrapper headers that augment libc
|
||||||
|
# and use #include_next to pass through to libc's true
|
||||||
|
# implementations, so must appear before them in search order.
|
||||||
|
# in theory a correctly placed -idirafter could be used, but in
|
||||||
|
# practice the compiler may have been built with a --with-headers
|
||||||
|
# like option that forces the libc headers before all -idirafter,
|
||||||
|
# hence -isystem here.
|
||||||
|
+ optionalString includeFortifyHeaders' ''
|
||||||
|
echo "-isystem ${fortify-headers}/include" >> $out/nix-support/libc-cflags
|
||||||
|
'')
|
||||||
|
|
||||||
|
##
|
||||||
|
## General libc++ support
|
||||||
|
##
|
||||||
|
|
||||||
|
# We have a libc++ directly, we have one via "smuggled" GCC, or we have one
|
||||||
|
# bundled with the C compiler because it is GCC
|
||||||
|
+ optionalString (libcxx != null || (useGccForLibs && gccForLibs.langCC or false) || (isGNU && cc.langCC or false)) ''
|
||||||
|
touch "$out/nix-support/libcxx-cxxflags"
|
||||||
|
touch "$out/nix-support/libcxx-ldflags"
|
||||||
|
''
|
||||||
|
# Adding -isystem flags should be done only for clang; gcc
|
||||||
|
# already knows how to find its own libstdc++, and adding
|
||||||
|
# additional -isystem flags will confuse gfortran (see
|
||||||
|
# https://github.com/NixOS/nixpkgs/pull/209870#issuecomment-1500550903)
|
||||||
|
+ optionalString (libcxx == null && isClang && (useGccForLibs && gccForLibs.langCC or false)) ''
|
||||||
|
for dir in ${gccForLibs}/include/c++/*; do
|
||||||
|
echo "-isystem $dir" >> $out/nix-support/libcxx-cxxflags
|
||||||
|
done
|
||||||
|
for dir in ${gccForLibs}/include/c++/*/${targetPlatform.config}; do
|
||||||
|
echo "-isystem $dir" >> $out/nix-support/libcxx-cxxflags
|
||||||
|
done
|
||||||
|
''
|
||||||
|
+ optionalString (libcxx.isLLVM or false) ''
|
||||||
|
echo "-isystem ${getDev libcxx}/include/c++/v1" >> $out/nix-support/libcxx-cxxflags
|
||||||
|
echo "-stdlib=libc++" >> $out/nix-support/libcxx-ldflags
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## Initial CFLAGS
|
||||||
|
##
|
||||||
|
|
||||||
|
# GCC shows ${cc_solib}/lib in `gcc -print-search-dirs', but not
|
||||||
|
# ${cc_solib}/lib64 (even though it does actually search there...)..
|
||||||
|
# This confuses libtool. So add it to the compiler tool search
|
||||||
|
# path explicitly.
|
||||||
|
+ optionalString (!nativeTools) ''
|
||||||
|
if [ -e "${cc_solib}/lib64" -a ! -L "${cc_solib}/lib64" ]; then
|
||||||
|
ccLDFlags+=" -L${cc_solib}/lib64"
|
||||||
|
ccCFlags+=" -B${cc_solib}/lib64"
|
||||||
|
fi
|
||||||
|
ccLDFlags+=" -L${cc_solib}/lib"
|
||||||
|
ccCFlags+=" -B${cc_solib}/lib"
|
||||||
|
|
||||||
|
'' + optionalString cc.langAda or false ''
|
||||||
|
touch "$out/nix-support/gnat-cflags"
|
||||||
|
touch "$out/nix-support/gnat-ldflags"
|
||||||
|
basePath=$(echo $cc/lib/*/*/*)
|
||||||
|
ccCFlags+=" -B$basePath -I$basePath/adainclude"
|
||||||
|
gnatCFlags="-I$basePath/adainclude -I$basePath/adalib"
|
||||||
|
|
||||||
|
echo "$gnatCFlags" >> $out/nix-support/gnat-cflags
|
||||||
|
'' + ''
|
||||||
|
echo "$ccLDFlags" >> $out/nix-support/cc-ldflags
|
||||||
|
echo "$ccCFlags" >> $out/nix-support/cc-cflags
|
||||||
|
'' + optionalString (targetPlatform.isDarwin && (libcxx != null) && (cc.isClang or false)) ''
|
||||||
|
echo " -L${libcxx_solib}" >> $out/nix-support/cc-ldflags
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## Man page and info support
|
||||||
|
##
|
||||||
|
+ optionalString propagateDoc ''
|
||||||
|
ln -s ${cc.man} $man
|
||||||
|
ln -s ${cc.info} $info
|
||||||
|
'' + optionalString (cc.langD or cc.langJava or false) ''
|
||||||
|
echo "-B${zlib}${zlib.libdir or "/lib/"}" >> $out/nix-support/libc-cflags
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## Hardening support
|
||||||
|
##
|
||||||
|
+ ''
|
||||||
|
export hardening_unsupported_flags="${concatStringsSep " " ccHardeningUnsupportedFlags}"
|
||||||
|
''
|
||||||
|
|
||||||
|
# Machine flags. These are necessary to support
|
||||||
|
|
||||||
|
# TODO: We should make a way to support miscellaneous machine
|
||||||
|
# flags and other gcc flags as well.
|
||||||
|
|
||||||
|
# Always add -march based on cpu in triple. Sometimes there is a
|
||||||
|
# discrepency (x86_64 vs. x86-64), so we provide an "arch" arg in
|
||||||
|
# that case.
|
||||||
|
#
|
||||||
|
# For clang, this is handled in add-clang-cc-cflags-before.sh
|
||||||
|
|
||||||
|
# TODO: aarch64-darwin has mcpu incompatible with gcc
|
||||||
|
+ optionalString ((targetPlatform ? gcc.arch) && !isClang && !(targetPlatform.isDarwin && targetPlatform.isAarch64) &&
|
||||||
|
isGccArchSupported targetPlatform.gcc.arch) ''
|
||||||
|
echo "-march=${targetPlatform.gcc.arch}" >> $out/nix-support/cc-cflags-before
|
||||||
|
''
|
||||||
|
|
||||||
|
# -mcpu is not very useful, except on PowerPC where it is used
|
||||||
|
# instead of march. On all other platforms you should use mtune
|
||||||
|
# and march instead.
|
||||||
|
# TODO: aarch64-darwin has mcpu incompatible with gcc
|
||||||
|
+ optionalString ((targetPlatform ? gcc.cpu) && (isClang || !(targetPlatform.isDarwin && targetPlatform.isAarch64))) ''
|
||||||
|
echo "-mcpu=${targetPlatform.gcc.cpu}" >> $out/nix-support/cc-cflags-before
|
||||||
|
''
|
||||||
|
|
||||||
|
# -mfloat-abi only matters on arm32 but we set it here
|
||||||
|
# unconditionally just in case. If the abi specifically sets hard
|
||||||
|
# vs. soft floats we use it here.
|
||||||
|
+ optionalString (targetPlatform ? gcc.float-abi) ''
|
||||||
|
echo "-mfloat-abi=${targetPlatform.gcc.float-abi}" >> $out/nix-support/cc-cflags-before
|
||||||
|
''
|
||||||
|
+ optionalString (targetPlatform ? gcc.fpu) ''
|
||||||
|
echo "-mfpu=${targetPlatform.gcc.fpu}" >> $out/nix-support/cc-cflags-before
|
||||||
|
''
|
||||||
|
+ optionalString (targetPlatform ? gcc.mode) ''
|
||||||
|
echo "-mmode=${targetPlatform.gcc.mode}" >> $out/nix-support/cc-cflags-before
|
||||||
|
''
|
||||||
|
+ optionalString (targetPlatform ? gcc.thumb) ''
|
||||||
|
echo "-m${if targetPlatform.gcc.thumb then "thumb" else "arm"}" >> $out/nix-support/cc-cflags-before
|
||||||
|
''
|
||||||
|
+ (let tune = if targetPlatform ? gcc.tune
|
||||||
|
then findBestTuneApproximation targetPlatform.gcc.tune
|
||||||
|
else null;
|
||||||
|
in optionalString (tune != null) ''
|
||||||
|
echo "-mtune=${tune}" >> $out/nix-support/cc-cflags-before
|
||||||
|
'')
|
||||||
|
|
||||||
|
# TODO: categorize these and figure out a better place for them
|
||||||
|
+ optionalString targetPlatform.isWindows ''
|
||||||
|
hardening_unsupported_flags+=" pic"
|
||||||
|
'' + optionalString targetPlatform.isMinGW ''
|
||||||
|
hardening_unsupported_flags+=" stackprotector fortify"
|
||||||
|
'' + optionalString targetPlatform.isAvr ''
|
||||||
|
hardening_unsupported_flags+=" stackprotector pic"
|
||||||
|
'' + optionalString (targetPlatform.libc == "newlib" || targetPlatform.libc == "newlib-nano") ''
|
||||||
|
hardening_unsupported_flags+=" stackprotector fortify pie pic"
|
||||||
|
'' + optionalString (targetPlatform.libc == "musl" && targetPlatform.isx86_32) ''
|
||||||
|
hardening_unsupported_flags+=" stackprotector"
|
||||||
|
'' + optionalString targetPlatform.isNetBSD ''
|
||||||
|
hardening_unsupported_flags+=" stackprotector fortify"
|
||||||
|
'' + optionalString cc.langAda or false ''
|
||||||
|
hardening_unsupported_flags+=" format stackprotector strictoverflow"
|
||||||
|
'' + optionalString cc.langD or false ''
|
||||||
|
hardening_unsupported_flags+=" format"
|
||||||
|
'' + optionalString cc.langFortran or false ''
|
||||||
|
hardening_unsupported_flags+=" format"
|
||||||
|
'' + optionalString targetPlatform.isWasm ''
|
||||||
|
hardening_unsupported_flags+=" stackprotector fortify pie pic"
|
||||||
|
'' + optionalString targetPlatform.isMicroBlaze ''
|
||||||
|
hardening_unsupported_flags+=" stackprotector"
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString (libc != null && targetPlatform.isAvr) ''
|
||||||
|
for isa in avr5 avr3 avr4 avr6 avr25 avr31 avr35 avr51 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack; do
|
||||||
|
echo "-B${getLib libc}/avr/lib/$isa" >> $out/nix-support/libc-crt1-cflags
|
||||||
|
done
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString targetPlatform.isDarwin ''
|
||||||
|
echo "-arch ${targetPlatform.darwinArch}" >> $out/nix-support/cc-cflags
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString targetPlatform.isAndroid ''
|
||||||
|
echo "-D__ANDROID_API__=${targetPlatform.sdkVer}" >> $out/nix-support/cc-cflags
|
||||||
|
''
|
||||||
|
|
||||||
|
# There are a few tools (to name one libstdcxx5) which do not work
|
||||||
|
# well with multi line flags, so make the flags single line again
|
||||||
|
+ ''
|
||||||
|
for flags in "$out/nix-support"/*flags*; do
|
||||||
|
substituteInPlace "$flags" --replace $'\n' ' '
|
||||||
|
done
|
||||||
|
|
||||||
|
substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh
|
||||||
|
substituteAll ${./add-hardening.sh} $out/nix-support/add-hardening.sh
|
||||||
|
substituteAll ${../wrapper-common/utils.bash} $out/nix-support/utils.bash
|
||||||
|
''
|
||||||
|
|
||||||
|
+ optionalString cc.langAda or false ''
|
||||||
|
substituteAll ${./add-gnat-extra-flags.sh} $out/nix-support/add-gnat-extra-flags.sh
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## General Clang support
|
||||||
|
## Needs to go after ^ because the for loop eats \n and makes this file an invalid script
|
||||||
|
##
|
||||||
|
+ optionalString isClang ''
|
||||||
|
# Escape twice: once for this script, once for the one it gets substituted into.
|
||||||
|
export march=${escapeShellArg
|
||||||
|
(optionalString (targetPlatform ? gcc.arch)
|
||||||
|
(escapeShellArg "-march=${targetPlatform.gcc.arch}"))}
|
||||||
|
export defaultTarget=${targetPlatform.config}
|
||||||
|
substituteAll ${./add-clang-cc-cflags-before.sh} $out/nix-support/add-local-cc-cflags-before.sh
|
||||||
|
''
|
||||||
|
|
||||||
|
##
|
||||||
|
## Extra custom steps
|
||||||
|
##
|
||||||
|
+ extraBuildCommands
|
||||||
|
+ concatStringsSep "; "
|
||||||
|
(mapAttrsToList
|
||||||
|
(name: value: "echo ${toString value} >> $out/nix-support/${name}")
|
||||||
|
nixSupport);
|
||||||
|
|
||||||
|
|
||||||
|
env = {
|
||||||
|
inherit isClang;
|
||||||
|
|
||||||
|
# for substitution in utils.bash
|
||||||
|
# TODO(@sternenseemann): invent something cleaner than passing in "" in case of absence
|
||||||
|
expandResponseParams = "${expand-response-params}/bin/expand-response-params";
|
||||||
|
# TODO(@sternenseemann): rename env var via stdenv rebuild
|
||||||
|
shell = getBin runtimeShell + runtimeShell.shellPath or "";
|
||||||
|
gnugrep_bin = optionalString (!nativeTools) gnugrep;
|
||||||
|
# stdenv.cc.cc should not be null and we have nothing better for now.
|
||||||
|
# if the native impure bootstrap is gotten rid of this can become `inherit cc;` again.
|
||||||
|
cc = optionalString (!nativeTools) cc;
|
||||||
|
wrapperName = "CC_WRAPPER";
|
||||||
|
inherit suffixSalt coreutils_bin bintools;
|
||||||
|
inherit libc_bin libc_dev libc_lib;
|
||||||
|
inherit darwinPlatformForCC darwinMinVersion darwinMinVersionVariable;
|
||||||
|
default_hardening_flags_str = builtins.toString defaultHardeningFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
meta =
|
||||||
|
let cc_ = optionalAttrs (cc != null) cc; in
|
||||||
|
(optionalAttrs (cc_ ? meta) (removeAttrs cc.meta ["priority"])) //
|
||||||
|
{ description = attrByPath ["meta" "description"] "System C compiler" cc_ + " (wrapper script)";
|
||||||
|
priority = 10;
|
||||||
|
mainProgram = if name != "" then name else ccName;
|
||||||
|
};
|
||||||
|
}
|
10
pkgs/build-support/cc-wrapper/fortran-hook.sh
Normal file
10
pkgs/build-support/cc-wrapper/fortran-hook.sh
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
getTargetRole
|
||||||
|
getTargetRoleWrapper
|
||||||
|
|
||||||
|
export FC${role_post}=@named_fc@
|
||||||
|
|
||||||
|
# If unset, assume the default hardening flags.
|
||||||
|
: ${NIX_HARDENING_ENABLE="@default_hardening_flags_str@"}
|
||||||
|
export NIX_HARDENING_ENABLE
|
||||||
|
|
||||||
|
unset -v role_post
|
182
pkgs/build-support/cc-wrapper/gnat-wrapper.sh
Normal file
182
pkgs/build-support/cc-wrapper/gnat-wrapper.sh
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
#! @shell@
|
||||||
|
set -eu -o pipefail +o posix
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 7 )); then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
path_backup="$PATH"
|
||||||
|
|
||||||
|
# That @-vars are substituted separately from bash evaluation makes
|
||||||
|
# shellcheck think this, and others like it, are useless conditionals.
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [[ -n "@coreutils_bin@" && -n "@gnugrep_bin@" ]]; then
|
||||||
|
PATH="@coreutils_bin@/bin:@gnugrep_bin@/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cInclude=0
|
||||||
|
|
||||||
|
source @out@/nix-support/utils.bash
|
||||||
|
|
||||||
|
# Flirting with a layer violation here.
|
||||||
|
if [ -z "${NIX_BINTOOLS_WRAPPER_FLAGS_SET_@suffixSalt@:-}" ]; then
|
||||||
|
source @bintools@/nix-support/add-flags.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Put this one second so libc ldflags take priority.
|
||||||
|
if [ -z "${NIX_CC_WRAPPER_FLAGS_SET_@suffixSalt@:-}" ]; then
|
||||||
|
source @out@/nix-support/add-flags.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${NIX_GNAT_WRAPPER_EXTRA_FLAGS_SET_@suffixSalt@:-}" ]; then
|
||||||
|
source @out@/nix-support/add-gnat-extra-flags.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse command line options and set several variables.
|
||||||
|
# For instance, figure out if linker flags should be passed.
|
||||||
|
# GCC prints annoying warnings when they are not needed.
|
||||||
|
dontLink=0
|
||||||
|
nonFlagArgs=0
|
||||||
|
# shellcheck disable=SC2193
|
||||||
|
|
||||||
|
expandResponseParams "$@"
|
||||||
|
declare -i n=0
|
||||||
|
nParams=${#params[@]}
|
||||||
|
while (( "$n" < "$nParams" )); do
|
||||||
|
p=${params[n]}
|
||||||
|
p2=${params[n+1]:-} # handle `p` being last one
|
||||||
|
if [ "$p" = -c ]; then
|
||||||
|
dontLink=1
|
||||||
|
elif [ "$p" = -S ]; then
|
||||||
|
dontLink=1
|
||||||
|
elif [ "$p" = -E ]; then
|
||||||
|
dontLink=1
|
||||||
|
elif [ "$p" = -E ]; then
|
||||||
|
dontLink=1
|
||||||
|
elif [ "$p" = -M ]; then
|
||||||
|
dontLink=1
|
||||||
|
elif [ "$p" = -MM ]; then
|
||||||
|
dontLink=1
|
||||||
|
elif [[ "$p" = -x && "$p2" = *-header ]]; then
|
||||||
|
dontLink=1
|
||||||
|
elif [[ "$p" != -?* ]]; then
|
||||||
|
# A dash alone signifies standard input; it is not a flag
|
||||||
|
nonFlagArgs=1
|
||||||
|
fi
|
||||||
|
n+=1
|
||||||
|
done
|
||||||
|
|
||||||
|
# If we pass a flag like -Wl, then gcc will call the linker unless it
|
||||||
|
# can figure out that it has to do something else (e.g., because of a
|
||||||
|
# "-c" flag). So if no non-flag arguments are given, don't pass any
|
||||||
|
# linker flags. This catches cases like "gcc" (should just print
|
||||||
|
# "gcc: no input files") and "gcc -v" (should print the version).
|
||||||
|
if [ "$nonFlagArgs" = 0 ]; then
|
||||||
|
dontLink=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally filter out paths not refering to the store.
|
||||||
|
if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "$NIX_STORE" ]]; then
|
||||||
|
rest=()
|
||||||
|
nParams=${#params[@]}
|
||||||
|
declare -i n=0
|
||||||
|
while (( "$n" < "$nParams" )); do
|
||||||
|
p=${params[n]}
|
||||||
|
p2=${params[n+1]:-} # handle `p` being last one
|
||||||
|
if [ "${p:0:3}" = -L/ ] && badPath "${p:2}"; then
|
||||||
|
skip "${p:2}"
|
||||||
|
elif [ "$p" = -L ] && badPath "$p2"; then
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
elif [ "${p:0:3}" = -I/ ] && badPath "${p:2}"; then
|
||||||
|
skip "${p:2}"
|
||||||
|
elif [ "$p" = -I ] && badPath "$p2"; then
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
elif [ "${p:0:4}" = -aI/ ] && badPath "${p:3}"; then
|
||||||
|
skip "${p:3}"
|
||||||
|
elif [ "$p" = -aI ] && badPath "$p2"; then
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
elif [ "${p:0:4}" = -aO/ ] && badPath "${p:3}"; then
|
||||||
|
skip "${p:3}"
|
||||||
|
elif [ "$p" = -aO ] && badPath "$p2"; then
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
elif [ "$p" = -isystem ] && badPath "$p2"; then
|
||||||
|
n+=1; skip "$p2"
|
||||||
|
else
|
||||||
|
rest+=("$p")
|
||||||
|
fi
|
||||||
|
n+=1
|
||||||
|
done
|
||||||
|
# Old bash empty array hack
|
||||||
|
params=(${rest+"${rest[@]}"})
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Clear march/mtune=native -- they bring impurity.
|
||||||
|
if [ "$NIX_ENFORCE_NO_NATIVE_@suffixSalt@" = 1 ]; then
|
||||||
|
rest=()
|
||||||
|
# Old bash empty array hack
|
||||||
|
for p in ${params+"${params[@]}"}; do
|
||||||
|
if [[ "$p" = -m*=native ]]; then
|
||||||
|
skip "$p"
|
||||||
|
else
|
||||||
|
rest+=("$p")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Old bash empty array hack
|
||||||
|
params=(${rest+"${rest[@]}"})
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$(basename $0)x" in
|
||||||
|
"gnatbindx")
|
||||||
|
extraBefore=()
|
||||||
|
extraAfter=($NIX_GNATFLAGS_COMPILE_@suffixSalt@)
|
||||||
|
;;
|
||||||
|
"gnatchopx")
|
||||||
|
extraBefore=("--GCC=@out@/bin/gcc")
|
||||||
|
extraAfter=()
|
||||||
|
;;
|
||||||
|
"gnatcleanx")
|
||||||
|
extraBefore=($NIX_GNATFLAGS_COMPILE_@suffixSalt@)
|
||||||
|
extraAfter=()
|
||||||
|
;;
|
||||||
|
"gnatlinkx")
|
||||||
|
extraBefore=()
|
||||||
|
extraAfter=("--GCC=@out@/bin/gcc")
|
||||||
|
;;
|
||||||
|
"gnatlsx")
|
||||||
|
extraBefore=()
|
||||||
|
extraAfter=($NIX_GNATFLAGS_COMPILE_@suffixSalt@)
|
||||||
|
;;
|
||||||
|
"gnatmakex")
|
||||||
|
extraBefore=("--GNATBIND=@out@/bin/gnatbind" "--GNATLINK=@out@/bin/gnatlink")
|
||||||
|
extraAfter=($NIX_GNATFLAGS_COMPILE_@suffixSalt@ -cargs $NIX_GNATMAKE_CARGS_@suffixSalt@)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# As a very special hack, if the arguments are just `-v', then don't
|
||||||
|
# add anything. This is to prevent `gcc -v' (which normally prints
|
||||||
|
# out the version number and returns exit code 0) from printing out
|
||||||
|
# `No input files specified' and returning exit code 1.
|
||||||
|
if [ "$*" = -v ]; then
|
||||||
|
extraAfter=()
|
||||||
|
extraBefore=()
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally print debug info.
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||||
|
# Old bash workaround, see ld-wrapper for explanation.
|
||||||
|
echo "extra flags before to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraBefore+"${extraBefore[@]}"} >&2
|
||||||
|
echo "original flags to @prog@:" >&2
|
||||||
|
printf " %q\n" ${params+"${params[@]}"} >&2
|
||||||
|
echo "extra flags after to @prog@:" >&2
|
||||||
|
printf " %q\n" ${extraAfter+"${extraAfter[@]}"} >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
PATH="$path_backup"
|
||||||
|
# Old bash workaround, see above.
|
||||||
|
exec @prog@ \
|
||||||
|
${extraBefore+"${extraBefore[@]}"} \
|
||||||
|
${params+"${params[@]}"} \
|
||||||
|
${extraAfter+"${extraAfter[@]}"}
|
11
pkgs/build-support/cc-wrapper/go-wrapper.sh
Normal file
11
pkgs/build-support/cc-wrapper/go-wrapper.sh
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#! @shell@
|
||||||
|
set -eu -o pipefail +o posix
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
if (( "${NIX_DEBUG:-0}" >= 7 )); then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
export GCCGO="@out@/bin/gccgo"
|
||||||
|
|
||||||
|
exec @prog@ "$@"
|
118
pkgs/build-support/cc-wrapper/setup-hook.sh
Normal file
118
pkgs/build-support/cc-wrapper/setup-hook.sh
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
# CC Wrapper hygiene
|
||||||
|
#
|
||||||
|
# For at least cross compilation, we need to depend on multiple cc-wrappers at
|
||||||
|
# once---specifically up to one per sort of dependency. This follows from having
|
||||||
|
# different tools targeting different platforms, and different flags for those
|
||||||
|
# tools. For example:
|
||||||
|
#
|
||||||
|
# # Flags for compiling (whether or not linking) C code for the...
|
||||||
|
# NIX_CFLAGS_COMPILE_FOR_BUILD # ...build platform
|
||||||
|
# NIX_CFLAGS_COMPILE # ...host platform
|
||||||
|
# NIX_CFLAGS_COMPILE_FOR_TARGET # ...target platform
|
||||||
|
#
|
||||||
|
# Notice that these platforms are the 3 *relative* to the package using
|
||||||
|
# cc-wrapper, not absolute like `x86_64-pc-linux-gnu`.
|
||||||
|
#
|
||||||
|
# The simplest solution would be to have separate cc-wrappers per (3 intended
|
||||||
|
# use-cases * n absolute concrete platforms). For the use-case axis, we would
|
||||||
|
# @-splice in 'BUILD_' '' 'TARGET_' to use the write environment variables when
|
||||||
|
# building the cc-wrapper, and likewise prefix the binaries' names so they didn't
|
||||||
|
# clobber each other on the PATH. But the need for 3x cc-wrappers, along with
|
||||||
|
# non-standard name prefixes, is annoying and liable to break packages' build
|
||||||
|
# systems.
|
||||||
|
#
|
||||||
|
# Instead, we opt to have just one cc-wrapper per absolute platform. Matching
|
||||||
|
# convention, the binaries' names can just be prefixed with their target
|
||||||
|
# platform. On the other hand, that means packages will depend on not just
|
||||||
|
# multiple cc-wrappers, but the exact same cc-wrapper derivation multiple ways.
|
||||||
|
# That means the exact same cc-wrapper derivation must be able to avoid
|
||||||
|
# conflicting with itself, despite the fact that `setup-hook.sh`, the `addCvars`
|
||||||
|
# function, and `add-flags.sh` are all communicating with each other with
|
||||||
|
# environment variables. Yuck.
|
||||||
|
#
|
||||||
|
# The basic strategy is:
|
||||||
|
#
|
||||||
|
# - Everyone exclusively *adds information* to relative-platform-specific
|
||||||
|
# environment variables, like `NIX_CFLAGS_COMPILE_FOR_TARGET`, to communicate
|
||||||
|
# with the wrapped binaries.
|
||||||
|
#
|
||||||
|
# - The wrapped binaries will exclusively *read* cc-wrapper-derivation-specific
|
||||||
|
# environment variables distinguished with with `suffixSalt`, like
|
||||||
|
# `NIX_CFLAGS_COMPILE_@suffixSalt@`.
|
||||||
|
#
|
||||||
|
# - `add-flags`, beyond its old task of reading extra flags stuck inside the
|
||||||
|
# cc-wrapper derivation, will convert the relative-platform-specific
|
||||||
|
# variables to cc-wrapper-derivation-specific variables. This conversion is
|
||||||
|
# the only time all but one of the cc-wrapper-derivation-specific variables
|
||||||
|
# are set.
|
||||||
|
#
|
||||||
|
# This ensures the flow of information is exclusive from
|
||||||
|
# relative-platform-specific variables to cc-wrapper-derivation-specific
|
||||||
|
# variables. This allows us to support the general case of a many--many relation
|
||||||
|
# between relative platforms and cc-wrapper derivations.
|
||||||
|
#
|
||||||
|
# For more details, read the individual files where the mechanisms used to
|
||||||
|
# accomplish this will be individually documented.
|
||||||
|
|
||||||
|
# Skip setup hook if we're neither a build-time dep, nor, temporarily, doing a
|
||||||
|
# native compile.
|
||||||
|
#
|
||||||
|
# TODO(@Ericson2314): No native exception
|
||||||
|
[[ -z ${strictDeps-} ]] || (( "$hostOffset" < 0 )) || return 0
|
||||||
|
|
||||||
|
# It's fine that any other cc-wrapper will redefine this. Bash functions close
|
||||||
|
# over no state, and there's no @-substitutions within, so any redefined
|
||||||
|
# function is guaranteed to be exactly the same.
|
||||||
|
ccWrapper_addCVars () {
|
||||||
|
# See ../setup-hooks/role.bash
|
||||||
|
local role_post
|
||||||
|
getHostRoleEnvHook
|
||||||
|
|
||||||
|
if [ -d "$1/include" ]; then
|
||||||
|
export NIX_CFLAGS_COMPILE${role_post}+=" -isystem $1/include"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$1/Library/Frameworks" ]; then
|
||||||
|
export NIX_CFLAGS_COMPILE${role_post}+=" -iframework $1/Library/Frameworks"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# See ../setup-hooks/role.bash
|
||||||
|
getTargetRole
|
||||||
|
getTargetRoleWrapper
|
||||||
|
|
||||||
|
# We use the `targetOffset` to choose the right env hook to accumulate the right
|
||||||
|
# sort of deps (those with that offset).
|
||||||
|
addEnvHooks "$targetOffset" ccWrapper_addCVars
|
||||||
|
|
||||||
|
# Note 1: these come *after* $out in the PATH (see setup.sh).
|
||||||
|
# Note 2: phase separation makes this look useless to shellcheck.
|
||||||
|
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [ -n "@cc@" ]; then
|
||||||
|
addToSearchPath _PATH @cc@/bin
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [ -n "@libc_bin@" ]; then
|
||||||
|
addToSearchPath _PATH @libc_bin@/bin
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2157
|
||||||
|
if [ -n "@coreutils_bin@" ]; then
|
||||||
|
addToSearchPath _PATH @coreutils_bin@/bin
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Export tool environment variables so various build systems use the right ones.
|
||||||
|
|
||||||
|
export NIX_CC${role_post}=@out@
|
||||||
|
|
||||||
|
export CC${role_post}=@named_cc@
|
||||||
|
export CXX${role_post}=@named_cxx@
|
||||||
|
|
||||||
|
# If unset, assume the default hardening flags.
|
||||||
|
: ${NIX_HARDENING_ENABLE="@default_hardening_flags_str@"}
|
||||||
|
export NIX_HARDENING_ENABLE
|
||||||
|
|
||||||
|
# No local scope in sourced file
|
||||||
|
unset -v role_post
|
95
pkgs/build-support/checkpoint-build.nix
Normal file
95
pkgs/build-support/checkpoint-build.nix
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{ lib
|
||||||
|
, buildPackages
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
# rudimentary support for cross-compiling
|
||||||
|
# see: https://github.com/NixOS/nixpkgs/pull/279487#discussion_r1444449726
|
||||||
|
inherit (buildPackages)
|
||||||
|
mktemp
|
||||||
|
rsync
|
||||||
|
;
|
||||||
|
in
|
||||||
|
|
||||||
|
rec {
|
||||||
|
/* Prepare a derivation for local builds.
|
||||||
|
*
|
||||||
|
* This function prepares checkpoint builds by storing
|
||||||
|
* the build output and the sources for cross checking.
|
||||||
|
* The build output can be used later to allow checkpoint builds
|
||||||
|
* by passing the derivation output to the `mkCheckpointBuild` function.
|
||||||
|
*
|
||||||
|
* To build a project with checkpoints, follow these steps:
|
||||||
|
* - run `prepareCheckpointBuild` on the desired derivation, e.g.
|
||||||
|
* checkpointArtifacts = prepareCheckpointBuild virtualbox;
|
||||||
|
* - change something you want in the sources of the package,
|
||||||
|
* e.g. using source override:
|
||||||
|
* changedVBox = pkgs.virtuabox.overrideAttrs (old: {
|
||||||
|
* src = path/to/vbox/sources;
|
||||||
|
* };
|
||||||
|
* - use `mkCheckpointBuild changedVBox checkpointArtifacts`
|
||||||
|
* - enjoy shorter build times
|
||||||
|
*/
|
||||||
|
prepareCheckpointBuild = drv: drv.overrideAttrs (old: {
|
||||||
|
outputs = [ "out" ];
|
||||||
|
name = drv.name + "-checkpointArtifacts";
|
||||||
|
# To determine differences between the state of the build directory
|
||||||
|
# from an earlier build and a later one we store the state of the build
|
||||||
|
# directory before build, but after patch phases.
|
||||||
|
# This way, the same derivation can be used multiple times and only changes are detected.
|
||||||
|
# Additionally, removed files are handled correctly in later builds.
|
||||||
|
preBuild = (old.preBuild or "") + ''
|
||||||
|
mkdir -p $out/sources
|
||||||
|
cp -r ./* $out/sources/
|
||||||
|
'';
|
||||||
|
|
||||||
|
# After the build, the build directory is copied again
|
||||||
|
# to get the output files.
|
||||||
|
# We copy the complete build folder, to take care of
|
||||||
|
# build tools that build in the source directory, instead of
|
||||||
|
# having a separate build directory such as the Linux kernel.
|
||||||
|
installPhase = ''
|
||||||
|
runHook preCheckpointInstall
|
||||||
|
mkdir -p $out/outputs
|
||||||
|
cp -r ./* $out/outputs/
|
||||||
|
runHook postCheckpointInstall
|
||||||
|
unset postPhases
|
||||||
|
'';
|
||||||
|
|
||||||
|
dontFixup = true;
|
||||||
|
doInstallCheck = false;
|
||||||
|
doDist = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Build a derivation based on the checkpoint output generated by
|
||||||
|
* the `prepareCheckpointBuild` function.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* let
|
||||||
|
* checkpointArtifacts = prepareCheckpointBuild drv;
|
||||||
|
* in mkCheckpointBuild drv checkpointArtifacts
|
||||||
|
*/
|
||||||
|
mkCheckpointBuild = drv: checkpointArtifacts: drv.overrideAttrs (old: {
|
||||||
|
# The actual checkpoint build phase.
|
||||||
|
# We compare the changed sources from a previous build with the current and create a patch.
|
||||||
|
# Afterwards we clean the build directory and copy the previous output files (including the sources).
|
||||||
|
# The source difference patch is then applied to get the latest changes again to allow short build times.
|
||||||
|
preBuild = (old.preBuild or "") + ''
|
||||||
|
set +e
|
||||||
|
sourceDifferencePatchFile=$(${mktemp}/bin/mktemp)
|
||||||
|
diff -ur ${checkpointArtifacts}/sources ./ > "$sourceDifferencePatchFile"
|
||||||
|
set -e
|
||||||
|
shopt -s dotglob
|
||||||
|
rm -r *
|
||||||
|
${rsync}/bin/rsync \
|
||||||
|
--checksum --times --atimes --chown=$USER:$USER --chmod=+w \
|
||||||
|
-r ${checkpointArtifacts}/outputs/ .
|
||||||
|
patch -p 1 -i "$sourceDifferencePatchFile"
|
||||||
|
rm "$sourceDifferencePatchFile"
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
|
mkCheckpointedBuild = lib.warn
|
||||||
|
"`mkCheckpointedBuild` is deprecated, use `mkCheckpointBuild` instead!"
|
||||||
|
mkCheckpointBuild;
|
||||||
|
}
|
42
pkgs/build-support/closure-info.nix
Normal file
42
pkgs/build-support/closure-info.nix
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# This derivation builds two files containing information about the
|
||||||
|
# closure of 'rootPaths': $out/store-paths contains the paths in the
|
||||||
|
# closure, and $out/registration contains a file suitable for use with
|
||||||
|
# "nix-store --load-db" and "nix-store --register-validity
|
||||||
|
# --hash-given".
|
||||||
|
|
||||||
|
{ stdenv, coreutils, jq }:
|
||||||
|
|
||||||
|
{ rootPaths }:
|
||||||
|
|
||||||
|
assert builtins.langVersion >= 5;
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "closure-info";
|
||||||
|
|
||||||
|
__structuredAttrs = true;
|
||||||
|
|
||||||
|
exportReferencesGraph.closure = rootPaths;
|
||||||
|
|
||||||
|
preferLocalBuild = true;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ coreutils jq ];
|
||||||
|
|
||||||
|
empty = rootPaths == [];
|
||||||
|
|
||||||
|
buildCommand =
|
||||||
|
''
|
||||||
|
out=''${outputs[out]}
|
||||||
|
|
||||||
|
mkdir $out
|
||||||
|
|
||||||
|
if [[ -n "$empty" ]]; then
|
||||||
|
echo 0 > $out/total-nar-size
|
||||||
|
touch $out/registration $out/store-paths
|
||||||
|
else
|
||||||
|
jq -r ".closure | map(.narSize) | add" < "$NIX_ATTRS_JSON_FILE" > $out/total-nar-size
|
||||||
|
jq -r '.closure | map([.path, .narHash, .narSize, "", (.references | length)] + .references) | add | map("\(.)\n") | add' < "$NIX_ATTRS_JSON_FILE" | head -n -1 > $out/registration
|
||||||
|
jq -r '.closure[].path' < "$NIX_ATTRS_JSON_FILE" > $out/store-paths
|
||||||
|
fi
|
||||||
|
|
||||||
|
'';
|
||||||
|
}
|
155
pkgs/build-support/coq/default.nix
Normal file
155
pkgs/build-support/coq/default.nix
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
{ lib, stdenv, coqPackages, coq, which, fetchzip }@args:
|
||||||
|
|
||||||
|
let
|
||||||
|
lib = import ./extra-lib.nix {
|
||||||
|
inherit (args) lib;
|
||||||
|
};
|
||||||
|
|
||||||
|
inherit (lib)
|
||||||
|
concatStringsSep
|
||||||
|
flip
|
||||||
|
foldl
|
||||||
|
isFunction
|
||||||
|
isString
|
||||||
|
optional
|
||||||
|
optionalAttrs
|
||||||
|
optionals
|
||||||
|
optionalString
|
||||||
|
pred
|
||||||
|
remove
|
||||||
|
switch
|
||||||
|
versions
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (lib.attrsets) removeAttrs;
|
||||||
|
inherit (lib.strings) match;
|
||||||
|
|
||||||
|
isGitHubDomain = d: match "^github.*" d != null;
|
||||||
|
isGitLabDomain = d: match "^gitlab.*" d != null;
|
||||||
|
in
|
||||||
|
|
||||||
|
{ pname,
|
||||||
|
version ? null,
|
||||||
|
fetcher ? null,
|
||||||
|
owner ? "coq-community",
|
||||||
|
domain ? "github.com",
|
||||||
|
repo ? pname,
|
||||||
|
defaultVersion ? null,
|
||||||
|
releaseRev ? (v: v),
|
||||||
|
displayVersion ? {},
|
||||||
|
release ? {},
|
||||||
|
buildInputs ? [],
|
||||||
|
nativeBuildInputs ? [],
|
||||||
|
extraBuildInputs ? [],
|
||||||
|
extraNativeBuildInputs ? [],
|
||||||
|
overrideBuildInputs ? [],
|
||||||
|
overrideNativeBuildInputs ? [],
|
||||||
|
namePrefix ? [ "coq" ],
|
||||||
|
enableParallelBuilding ? true,
|
||||||
|
extraInstallFlags ? [],
|
||||||
|
setCOQBIN ? true,
|
||||||
|
mlPlugin ? false,
|
||||||
|
useMelquiondRemake ? null,
|
||||||
|
dropAttrs ? [],
|
||||||
|
keepAttrs ? [],
|
||||||
|
dropDerivationAttrs ? [],
|
||||||
|
useDuneifVersion ? (x: false),
|
||||||
|
useDune ? false,
|
||||||
|
opam-name ? (concatStringsSep "-" (namePrefix ++ [ pname ])),
|
||||||
|
...
|
||||||
|
}@args:
|
||||||
|
let
|
||||||
|
args-to-remove = foldl (flip remove) ([
|
||||||
|
"version" "fetcher" "repo" "owner" "domain" "releaseRev"
|
||||||
|
"displayVersion" "defaultVersion" "useMelquiondRemake"
|
||||||
|
"release"
|
||||||
|
"buildInputs" "nativeBuildInputs"
|
||||||
|
"extraBuildInputs" "extraNativeBuildInputs"
|
||||||
|
"overrideBuildInputs" "overrideNativeBuildInputs"
|
||||||
|
"namePrefix"
|
||||||
|
"meta" "useDuneifVersion" "useDune" "opam-name"
|
||||||
|
"extraInstallFlags" "setCOQBIN" "mlPlugin"
|
||||||
|
"dropAttrs" "dropDerivationAttrs" "keepAttrs" ] ++ dropAttrs) keepAttrs;
|
||||||
|
fetch = import ../coq/meta-fetch/default.nix
|
||||||
|
{ inherit lib stdenv fetchzip; } ({
|
||||||
|
inherit release releaseRev;
|
||||||
|
location = { inherit domain owner repo; };
|
||||||
|
} // optionalAttrs (args?fetcher) {inherit fetcher;});
|
||||||
|
fetched = fetch (if version != null then version else defaultVersion);
|
||||||
|
display-pkg = n: sep: v:
|
||||||
|
let d = displayVersion.${n} or (if sep == "" then ".." else true); in
|
||||||
|
n + optionalString (v != "" && v != null) (switch d [
|
||||||
|
{ case = true; out = sep + v; }
|
||||||
|
{ case = "."; out = sep + versions.major v; }
|
||||||
|
{ case = ".."; out = sep + versions.majorMinor v; }
|
||||||
|
{ case = "..."; out = sep + versions.majorMinorPatch v; }
|
||||||
|
{ case = isFunction; out = optionalString (d v != "") (sep + d v); }
|
||||||
|
{ case = isString; out = optionalString (d != "") (sep + d); }
|
||||||
|
] "") + optionalString (v == null) "-broken";
|
||||||
|
append-version = p: n: p + display-pkg n "" coqPackages.${n}.version + "-";
|
||||||
|
prefix-name = foldl append-version "" namePrefix;
|
||||||
|
useDune = args.useDune or (useDuneifVersion fetched.version);
|
||||||
|
coqlib-flags = switch coq.coq-version [
|
||||||
|
{ case = v: versions.isLe "8.6" v && v != "dev" ;
|
||||||
|
out = [ "COQLIB=$(out)/lib/coq/${coq.coq-version}/" ]; }
|
||||||
|
] [ "COQLIBINSTALL=$(out)/lib/coq/${coq.coq-version}/user-contrib"
|
||||||
|
"COQPLUGININSTALL=$(OCAMLFIND_DESTDIR)" ];
|
||||||
|
docdir-flags = switch coq.coq-version [
|
||||||
|
{ case = v: versions.isLe "8.6" v && v != "dev";
|
||||||
|
out = [ "DOCDIR=$(out)/share/coq/${coq.coq-version}/" ]; }
|
||||||
|
] [ "COQDOCINSTALL=$(out)/share/coq/${coq.coq-version}/user-contrib" ];
|
||||||
|
in
|
||||||
|
|
||||||
|
stdenv.mkDerivation (removeAttrs ({
|
||||||
|
|
||||||
|
name = prefix-name + (display-pkg pname "-" fetched.version);
|
||||||
|
|
||||||
|
inherit (fetched) version src;
|
||||||
|
|
||||||
|
nativeBuildInputs = args.overrideNativeBuildInputs
|
||||||
|
or ([ which ]
|
||||||
|
++ optional useDune coq.ocamlPackages.dune_3
|
||||||
|
++ optionals (useDune || mlPlugin) [ coq.ocamlPackages.ocaml coq.ocamlPackages.findlib ]
|
||||||
|
++ (args.nativeBuildInputs or []) ++ extraNativeBuildInputs);
|
||||||
|
buildInputs = args.overrideBuildInputs
|
||||||
|
or ([ coq ] ++ (args.buildInputs or []) ++ extraBuildInputs);
|
||||||
|
inherit enableParallelBuilding;
|
||||||
|
|
||||||
|
meta = ({ platforms = coq.meta.platforms; } //
|
||||||
|
(switch domain [{
|
||||||
|
case = pred.union isGitHubDomain isGitLabDomain;
|
||||||
|
out = { homepage = "https://${domain}/${owner}/${repo}"; };
|
||||||
|
}] {}) //
|
||||||
|
optionalAttrs (fetched.broken or false) { coqFilter = true; broken = true; }) //
|
||||||
|
(args.meta or {}) ;
|
||||||
|
|
||||||
|
}
|
||||||
|
// (optionalAttrs setCOQBIN { COQBIN = "${coq}/bin/"; })
|
||||||
|
// (optionalAttrs (!args?installPhase && !args?useMelquiondRemake) {
|
||||||
|
installFlags =
|
||||||
|
coqlib-flags ++ docdir-flags ++
|
||||||
|
extraInstallFlags;
|
||||||
|
})
|
||||||
|
// (optionalAttrs useDune {
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
dune build -p ${opam-name} ''${enableParallelBuilding:+-j $NIX_BUILD_CORES}
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
dune install ${opam-name} --prefix=$out
|
||||||
|
mv $out/lib/coq $out/lib/TEMPORARY
|
||||||
|
mkdir $out/lib/coq/
|
||||||
|
mv $out/lib/TEMPORARY $out/lib/coq/${coq.coq-version}
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
// (optionalAttrs (args?useMelquiondRemake) rec {
|
||||||
|
COQUSERCONTRIB = "$out/lib/coq/${coq.coq-version}/user-contrib";
|
||||||
|
preConfigurePhases = "autoconf";
|
||||||
|
configureFlags = [ "--libdir=${COQUSERCONTRIB}/${useMelquiondRemake.logpath or ""}" ];
|
||||||
|
buildPhase = "./remake -j$NIX_BUILD_CORES";
|
||||||
|
installPhase = "./remake install";
|
||||||
|
})
|
||||||
|
// (removeAttrs args args-to-remove)) dropDerivationAttrs)
|
213
pkgs/build-support/coq/extra-lib.nix
Normal file
213
pkgs/build-support/coq/extra-lib.nix
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
all
|
||||||
|
concatStringsSep
|
||||||
|
findFirst
|
||||||
|
flip
|
||||||
|
getAttr
|
||||||
|
head
|
||||||
|
isFunction
|
||||||
|
length
|
||||||
|
recursiveUpdate
|
||||||
|
splitVersion
|
||||||
|
tail
|
||||||
|
take
|
||||||
|
versionAtLeast
|
||||||
|
versionOlder
|
||||||
|
zipListsWith
|
||||||
|
;
|
||||||
|
in
|
||||||
|
recursiveUpdate lib (rec {
|
||||||
|
|
||||||
|
versions =
|
||||||
|
let
|
||||||
|
truncate = n: v: concatStringsSep "." (take n (splitVersion v));
|
||||||
|
opTruncate = op: v0: v: let n = length (splitVersion v0); in
|
||||||
|
op (truncate n v) (truncate n v0);
|
||||||
|
in rec {
|
||||||
|
|
||||||
|
/* Get string of the first n parts of a version string.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
- truncate 2 "1.2.3-stuff"
|
||||||
|
=> "1.2"
|
||||||
|
|
||||||
|
- truncate 4 "1.2.3-stuff"
|
||||||
|
=> "1.2.3.stuff"
|
||||||
|
*/
|
||||||
|
|
||||||
|
inherit truncate;
|
||||||
|
|
||||||
|
/* Get string of the first three parts (major, minor and patch)
|
||||||
|
of a version string.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
majorMinorPatch "1.2.3-stuff"
|
||||||
|
=> "1.2.3"
|
||||||
|
*/
|
||||||
|
majorMinorPatch = truncate 3;
|
||||||
|
|
||||||
|
/* Version comparison predicates,
|
||||||
|
- isGe v0 v <-> v is greater or equal than v0 [*]
|
||||||
|
- isLe v0 v <-> v is lesser or equal than v0 [*]
|
||||||
|
- isGt v0 v <-> v is strictly greater than v0 [*]
|
||||||
|
- isLt v0 v <-> v is strictly lesser than v0 [*]
|
||||||
|
- isEq v0 v <-> v is equal to v0 [*]
|
||||||
|
- range low high v <-> v is between low and high [**]
|
||||||
|
|
||||||
|
[*] truncating v to the same number of digits as v0
|
||||||
|
[**] truncating v to low for the lower bound and high for the upper bound
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- isGe "8.10" "8.10.1"
|
||||||
|
=> true
|
||||||
|
- isLe "8.10" "8.10.1"
|
||||||
|
=> true
|
||||||
|
- isGt "8.10" "8.10.1"
|
||||||
|
=> false
|
||||||
|
- isGt "8.10.0" "8.10.1"
|
||||||
|
=> true
|
||||||
|
- isEq "8.10" "8.10.1"
|
||||||
|
=> true
|
||||||
|
- range "8.10" "8.11" "8.11.1"
|
||||||
|
=> true
|
||||||
|
- range "8.10" "8.11+" "8.11.0"
|
||||||
|
=> false
|
||||||
|
- range "8.10" "8.11+" "8.11+beta1"
|
||||||
|
=> false
|
||||||
|
|
||||||
|
*/
|
||||||
|
isGe = opTruncate versionAtLeast;
|
||||||
|
isGt = opTruncate (flip versionOlder);
|
||||||
|
isLe = opTruncate (flip versionAtLeast);
|
||||||
|
isLt = opTruncate versionOlder;
|
||||||
|
isEq = opTruncate pred.equal;
|
||||||
|
range = low: high: pred.inter (versions.isGe low) (versions.isLe high);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Returns a list of list, splitting it using a predicate.
|
||||||
|
This is analoguous to builtins.split sep list,
|
||||||
|
with a predicate as a separator and a list instead of a string.
|
||||||
|
|
||||||
|
Type: splitList :: (a -> bool) -> [a] -> [[a]]
|
||||||
|
|
||||||
|
Example:
|
||||||
|
splitList (x: x == "x") [ "y" "x" "z" "t" ]
|
||||||
|
=> [ [ "y" ] "x" [ "z" "t" ] ]
|
||||||
|
*/
|
||||||
|
splitList = pred: l: # put in file lists
|
||||||
|
let loop = (vv: v: l: if l == [] then vv ++ [v]
|
||||||
|
else let hd = head l; tl = tail l; in
|
||||||
|
if pred hd then loop (vv ++ [ v hd ]) [] tl else loop vv (v ++ [hd]) tl);
|
||||||
|
in loop [] [] l;
|
||||||
|
|
||||||
|
pred = {
|
||||||
|
/* Predicate intersection, union, and complement */
|
||||||
|
inter = p: q: x: p x && q x;
|
||||||
|
union = p: q: x: p x || q x;
|
||||||
|
compl = p: x: ! p x;
|
||||||
|
true = p: true;
|
||||||
|
false = p: false;
|
||||||
|
|
||||||
|
/* predicate "being equal to y" */
|
||||||
|
equal = y: x: x == y;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Emulate a "switch - case" construct,
|
||||||
|
instead of relying on `if then else if ...` */
|
||||||
|
/* Usage:
|
||||||
|
```nix
|
||||||
|
switch-if [
|
||||||
|
if-clause-1
|
||||||
|
..
|
||||||
|
if-clause-k
|
||||||
|
] default-out
|
||||||
|
```
|
||||||
|
where a if-clause has the form `{ cond = b; out = r; }`
|
||||||
|
the first branch such as `b` is true */
|
||||||
|
|
||||||
|
switch-if = c: d: (findFirst (getAttr "cond") {} c).out or d;
|
||||||
|
|
||||||
|
/* Usage:
|
||||||
|
```nix
|
||||||
|
switch x [
|
||||||
|
simple-clause-1
|
||||||
|
..
|
||||||
|
simple-clause-k
|
||||||
|
] default-out
|
||||||
|
```
|
||||||
|
where a simple-clause has the form `{ case = p; out = r; }`
|
||||||
|
the first branch such as `p x` is true
|
||||||
|
or
|
||||||
|
```nix
|
||||||
|
switch [ x1 .. xn ] [
|
||||||
|
complex-clause-1
|
||||||
|
..
|
||||||
|
complex-clause-k
|
||||||
|
] default-out
|
||||||
|
```
|
||||||
|
where a complex-clause is either a simple-clause
|
||||||
|
or has the form { cases = [ p1 .. pn ]; out = r; }
|
||||||
|
in which case the first branch such as all `pi x` are true
|
||||||
|
|
||||||
|
if the variables p are not functions,
|
||||||
|
they are converted to a equal p
|
||||||
|
if out is missing the default-out is taken */
|
||||||
|
|
||||||
|
switch = var: clauses: default: with pred; let
|
||||||
|
compare = f: if isFunction f then f else equal f;
|
||||||
|
combine = cl: var:
|
||||||
|
if cl?case then compare cl.case var
|
||||||
|
else all (equal true) (zipListsWith compare cl.cases var); in
|
||||||
|
switch-if (map (cl: { cond = combine cl var; inherit (cl) out; }) clauses) default;
|
||||||
|
|
||||||
|
/* Override arguments to mkCoqDerivation for a Coq library.
|
||||||
|
|
||||||
|
This function allows you to easily override arguments to mkCoqDerivation,
|
||||||
|
even when they are not exposed by the Coq library directly.
|
||||||
|
|
||||||
|
Type: overrideCoqDerivation :: AttrSet -> CoqLibraryDerivation -> CoqLibraryDerivation
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
coqPackages.lib.overrideCoqDerivation
|
||||||
|
{
|
||||||
|
defaultVersion = "9999";
|
||||||
|
release."9999".sha256 = "1lq8x86vd3vqqh2yq6hvyagpnhfq5wmk5pg2z0xq7b7dbbbhyfkw";
|
||||||
|
}
|
||||||
|
coqPackages.QuickChick;
|
||||||
|
```
|
||||||
|
|
||||||
|
This example overrides the `defaultVersion` and `release` arguments that
|
||||||
|
are passed to `mkCoqDerivation` in the QuickChick derivation.
|
||||||
|
|
||||||
|
Note that there is a difference between using `.override` on a Coq
|
||||||
|
library vs this `overrideCoqDerivation` function. `.override` allows you
|
||||||
|
to modify arguments to the derivation itself, for instance by passing
|
||||||
|
different versions of dependencies:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
coqPackages.QuickChick.override { ssreflect = my-cool-ssreflect; }
|
||||||
|
```
|
||||||
|
|
||||||
|
whereas `overrideCoqDerivation` allows you to override arguments to the
|
||||||
|
call to `mkCoqDerivation` in the Coq library.
|
||||||
|
|
||||||
|
Note that all Coq libraries in Nixpkgs have a `version` argument for
|
||||||
|
easily using a different version. So if all you want to do is use a
|
||||||
|
different version, and the derivation for the Coq library already has
|
||||||
|
support for the version you want, you likely only need to update the
|
||||||
|
`version` argument on the library derivation. This is done with
|
||||||
|
`.override`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
coqPackages.QuickChick.override { version = "1.4.0"; }
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
overrideCoqDerivation = f: drv: (drv.override (args: {
|
||||||
|
mkCoqDerivation = drv_: (args.mkCoqDerivation drv_).override f;
|
||||||
|
}));
|
||||||
|
})
|
95
pkgs/build-support/coq/meta-fetch/default.nix
Normal file
95
pkgs/build-support/coq/meta-fetch/default.nix
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{ lib, stdenv, fetchzip }@args:
|
||||||
|
|
||||||
|
let
|
||||||
|
lib = import ../extra-lib.nix {
|
||||||
|
inherit (args) lib;
|
||||||
|
};
|
||||||
|
|
||||||
|
inherit (lib)
|
||||||
|
attrNames
|
||||||
|
fakeSha256
|
||||||
|
filter
|
||||||
|
findFirst
|
||||||
|
head
|
||||||
|
isAttrs
|
||||||
|
isPath
|
||||||
|
isString
|
||||||
|
last
|
||||||
|
length
|
||||||
|
optionalAttrs
|
||||||
|
pathExists
|
||||||
|
pred
|
||||||
|
sort
|
||||||
|
switch
|
||||||
|
switch-if
|
||||||
|
versionAtLeast
|
||||||
|
versions
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (lib.strings) match split;
|
||||||
|
|
||||||
|
default-fetcher = {domain ? "github.com", owner ? "", repo, rev, name ? "source", sha256 ? null, ...}@args:
|
||||||
|
let ext = if args?sha256 then "zip" else "tar.gz";
|
||||||
|
fmt = if args?sha256 then "zip" else "tarball";
|
||||||
|
pr = match "^#(.*)$" rev;
|
||||||
|
url = switch-if [
|
||||||
|
{ cond = pr == null && (match "^github.*" domain) != null;
|
||||||
|
out = "https://${domain}/${owner}/${repo}/archive/${rev}.${ext}"; }
|
||||||
|
{ cond = pr != null && (match "^github.*" domain) != null;
|
||||||
|
out = "https://api.${domain}/repos/${owner}/${repo}/${fmt}/pull/${head pr}/head"; }
|
||||||
|
{ cond = pr == null && (match "^gitlab.*" domain) != null;
|
||||||
|
out = "https://${domain}/${owner}/${repo}/-/archive/${rev}/${repo}-${rev}.${ext}"; }
|
||||||
|
{ cond = (match "(www.)?mpi-sws.org" domain) != null;
|
||||||
|
out = "https://www.mpi-sws.org/~${owner}/${repo}/download/${repo}-${rev}.${ext}";}
|
||||||
|
] (throw "meta-fetch: no fetcher found for domain ${domain} on ${rev}");
|
||||||
|
fetch = x: if args?sha256 then fetchzip (x // { inherit sha256; }) else builtins.fetchTarball x;
|
||||||
|
in fetch { inherit url ; };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fetcher ? default-fetcher,
|
||||||
|
location,
|
||||||
|
release ? {},
|
||||||
|
releaseRev ? (v: v),
|
||||||
|
}:
|
||||||
|
let isVersion = x: isString x && match "^/.*" x == null && release?${x};
|
||||||
|
shortVersion = x: if (isString x && match "^/.*" x == null)
|
||||||
|
then findFirst (v: versions.majorMinor v == x) null
|
||||||
|
(sort versionAtLeast (attrNames release))
|
||||||
|
else null;
|
||||||
|
isShortVersion = x: shortVersion x != null;
|
||||||
|
isPathString = x: isString x && match "^/.*" x != null && pathExists x; in
|
||||||
|
arg:
|
||||||
|
switch arg [
|
||||||
|
{ case = isNull; out = { version = "broken"; src = ""; broken = true; }; }
|
||||||
|
{ case = isPathString; out = { version = "dev"; src = arg; }; }
|
||||||
|
{ case = pred.union isVersion isShortVersion;
|
||||||
|
out = let
|
||||||
|
v = if isVersion arg then arg else shortVersion arg;
|
||||||
|
given-sha256 = release.${v}.sha256 or "";
|
||||||
|
sha256 = if given-sha256 == "" then fakeSha256 else given-sha256;
|
||||||
|
rv = release.${v} // { inherit sha256; };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
version = rv.version or v;
|
||||||
|
src = rv.src or fetcher (location // { rev = releaseRev v; } // rv);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{ case = isString;
|
||||||
|
out = let
|
||||||
|
splitted = filter isString (split ":" arg);
|
||||||
|
rev = last splitted;
|
||||||
|
has-owner = length splitted > 1;
|
||||||
|
version = "dev"; in {
|
||||||
|
inherit version;
|
||||||
|
src = fetcher (location // { inherit rev; } //
|
||||||
|
(optionalAttrs has-owner { owner = head splitted; }));
|
||||||
|
}; }
|
||||||
|
{ case = isAttrs;
|
||||||
|
out = {
|
||||||
|
version = arg.version or "dev";
|
||||||
|
src = (arg.fetcher or fetcher) (location // (arg.location or {})); }; }
|
||||||
|
{ case = isPath;
|
||||||
|
out = {
|
||||||
|
version = "dev" ;
|
||||||
|
src = builtins.path {path = arg; name = location.name or "source";}; }; }
|
||||||
|
] (throw "not a valid source description")
|
132
pkgs/build-support/dart/build-dart-application/default.nix
Normal file
132
pkgs/build-support/dart/build-dart-application/default.nix
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, callPackage
|
||||||
|
, runCommand
|
||||||
|
, writeText
|
||||||
|
, pub2nix
|
||||||
|
, dartHooks
|
||||||
|
, makeWrapper
|
||||||
|
, dart
|
||||||
|
, nodejs
|
||||||
|
, darwin
|
||||||
|
, jq
|
||||||
|
, yq
|
||||||
|
}:
|
||||||
|
|
||||||
|
{ src
|
||||||
|
, sourceRoot ? "source"
|
||||||
|
, packageRoot ? (lib.removePrefix "/" (lib.removePrefix "source" sourceRoot))
|
||||||
|
, gitHashes ? { }
|
||||||
|
, sdkSourceBuilders ? { }
|
||||||
|
, customSourceBuilders ? { }
|
||||||
|
|
||||||
|
, sdkSetupScript ? ""
|
||||||
|
, extraPackageConfigSetup ? ""
|
||||||
|
|
||||||
|
# Output type to produce. Can be any kind supported by dart
|
||||||
|
# https://dart.dev/tools/dart-compile#types-of-output
|
||||||
|
# If using jit, you might want to pass some arguments to `dartJitFlags`
|
||||||
|
, dartOutputType ? "exe"
|
||||||
|
, dartCompileCommand ? "dart compile"
|
||||||
|
, dartCompileFlags ? [ ]
|
||||||
|
# These come at the end of the command, useful to pass flags to the jit run
|
||||||
|
, dartJitFlags ? [ ]
|
||||||
|
|
||||||
|
# Attrset of entry point files to build and install.
|
||||||
|
# Where key is the final binary path and value is the source file path
|
||||||
|
# e.g. { "bin/foo" = "bin/main.dart"; }
|
||||||
|
# Set to null to read executables from pubspec.yaml
|
||||||
|
, dartEntryPoints ? null
|
||||||
|
# Used when wrapping aot, jit, kernel, and js builds.
|
||||||
|
# Set to null to disable wrapping.
|
||||||
|
, dartRuntimeCommand ? if dartOutputType == "aot-snapshot" then "${dart}/bin/dartaotruntime"
|
||||||
|
else if (dartOutputType == "jit-snapshot" || dartOutputType == "kernel") then "${dart}/bin/dart"
|
||||||
|
else if dartOutputType == "js" then "${nodejs}/bin/node"
|
||||||
|
else null
|
||||||
|
|
||||||
|
, runtimeDependencies ? [ ]
|
||||||
|
, extraWrapProgramArgs ? ""
|
||||||
|
|
||||||
|
, autoPubspecLock ? null
|
||||||
|
, pubspecLock ? if autoPubspecLock == null then
|
||||||
|
throw "The pubspecLock argument is required. If import-from-derivation is allowed (it isn't in Nixpkgs), you can set autoPubspecLock to the path to a pubspec.lock instead."
|
||||||
|
else
|
||||||
|
assert lib.assertMsg (builtins.pathExists autoPubspecLock) "The pubspec.lock file could not be found!";
|
||||||
|
lib.importJSON (runCommand "${lib.getName args}-pubspec-lock-json" { nativeBuildInputs = [ yq ]; } ''yq . '${autoPubspecLock}' > "$out"'')
|
||||||
|
, ...
|
||||||
|
}@args:
|
||||||
|
|
||||||
|
let
|
||||||
|
generators = callPackage ./generators.nix { inherit dart; } { buildDrvArgs = args; };
|
||||||
|
|
||||||
|
pubspecLockFile = builtins.toJSON pubspecLock;
|
||||||
|
pubspecLockData = pub2nix.readPubspecLock { inherit src packageRoot pubspecLock gitHashes sdkSourceBuilders customSourceBuilders; };
|
||||||
|
packageConfig = generators.linkPackageConfig {
|
||||||
|
packageConfig = pub2nix.generatePackageConfig {
|
||||||
|
pname = if args.pname != null then "${args.pname}-${args.version}" else null;
|
||||||
|
|
||||||
|
dependencies =
|
||||||
|
# Ideally, we'd only include the main dependencies and their transitive
|
||||||
|
# dependencies.
|
||||||
|
#
|
||||||
|
# The pubspec.lock file does not contain information about where
|
||||||
|
# transitive dependencies come from, though, and it would be weird to
|
||||||
|
# include the transitive dependencies of dev and override dependencies
|
||||||
|
# without including the dev and override dependencies themselves.
|
||||||
|
builtins.concatLists (builtins.attrValues pubspecLockData.dependencies);
|
||||||
|
|
||||||
|
inherit (pubspecLockData) dependencySources;
|
||||||
|
};
|
||||||
|
extraSetupCommands = extraPackageConfigSetup;
|
||||||
|
};
|
||||||
|
|
||||||
|
inherit (dartHooks.override { inherit dart; }) dartConfigHook dartBuildHook dartInstallHook dartFixupHook;
|
||||||
|
|
||||||
|
baseDerivation = stdenv.mkDerivation (finalAttrs: (builtins.removeAttrs args [ "gitHashes" "sdkSourceBuilders" "pubspecLock" "customSourceBuilders" ]) // {
|
||||||
|
inherit pubspecLockFile packageConfig sdkSetupScript
|
||||||
|
dartCompileCommand dartOutputType dartRuntimeCommand dartCompileFlags
|
||||||
|
dartJitFlags;
|
||||||
|
|
||||||
|
outputs = [ "out" "pubcache" ] ++ args.outputs or [ ];
|
||||||
|
|
||||||
|
dartEntryPoints =
|
||||||
|
if (dartEntryPoints != null)
|
||||||
|
then writeText "entrypoints.json" (builtins.toJSON dartEntryPoints)
|
||||||
|
else null;
|
||||||
|
|
||||||
|
runtimeDependencies = map lib.getLib runtimeDependencies;
|
||||||
|
|
||||||
|
nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [
|
||||||
|
dart
|
||||||
|
dartConfigHook
|
||||||
|
dartBuildHook
|
||||||
|
dartInstallHook
|
||||||
|
dartFixupHook
|
||||||
|
makeWrapper
|
||||||
|
jq
|
||||||
|
] ++ lib.optionals stdenv.isDarwin [
|
||||||
|
darwin.sigtool
|
||||||
|
] ++
|
||||||
|
# Ensure that we inherit the propagated build inputs from the dependencies.
|
||||||
|
builtins.attrValues pubspecLockData.dependencySources;
|
||||||
|
|
||||||
|
preConfigure = args.preConfigure or "" + ''
|
||||||
|
ln -sf "$pubspecLockFilePath" pubspec.lock
|
||||||
|
'';
|
||||||
|
|
||||||
|
# When stripping, it seems some ELF information is lost and the dart VM cli
|
||||||
|
# runs instead of the expected program. Don't strip if it's an exe output.
|
||||||
|
dontStrip = args.dontStrip or (dartOutputType == "exe");
|
||||||
|
|
||||||
|
passAsFile = [ "pubspecLockFile" ];
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
pubspecLock = pubspecLockData;
|
||||||
|
} // (args.passthru or { });
|
||||||
|
|
||||||
|
meta = (args.meta or { }) // { platforms = args.meta.platforms or dart.meta.platforms; };
|
||||||
|
});
|
||||||
|
in
|
||||||
|
assert !(builtins.isString dartOutputType && dartOutputType != "") ->
|
||||||
|
throw "dartOutputType must be a non-empty string";
|
||||||
|
baseDerivation
|
|
@ -0,0 +1,74 @@
|
||||||
|
{ lib
|
||||||
|
, stdenvNoCC
|
||||||
|
, dart
|
||||||
|
, dartHooks
|
||||||
|
, jq
|
||||||
|
, yq
|
||||||
|
, cacert
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Arguments used in the derivation that builds the Dart package.
|
||||||
|
# Passing these is recommended to ensure that the same steps are made to
|
||||||
|
# prepare the sources in both this derivation and the one that builds the Dart
|
||||||
|
# package.
|
||||||
|
buildDrvArgs ? { }
|
||||||
|
, ...
|
||||||
|
}@args:
|
||||||
|
|
||||||
|
# This is a derivation and setup hook that can be used to fetch dependencies for Dart projects.
|
||||||
|
# It is designed to be placed in the nativeBuildInputs of a derivation that builds a Dart package.
|
||||||
|
# Providing the buildDrvArgs argument is highly recommended.
|
||||||
|
let
|
||||||
|
buildDrvInheritArgNames = [
|
||||||
|
"name"
|
||||||
|
"pname"
|
||||||
|
"version"
|
||||||
|
"src"
|
||||||
|
"sourceRoot"
|
||||||
|
"setSourceRoot"
|
||||||
|
"preUnpack"
|
||||||
|
"unpackPhase"
|
||||||
|
"unpackCmd"
|
||||||
|
"postUnpack"
|
||||||
|
"prePatch"
|
||||||
|
"patchPhase"
|
||||||
|
"patches"
|
||||||
|
"patchFlags"
|
||||||
|
"postPatch"
|
||||||
|
];
|
||||||
|
|
||||||
|
buildDrvInheritArgs = builtins.foldl'
|
||||||
|
(attrs: arg:
|
||||||
|
if buildDrvArgs ? ${arg}
|
||||||
|
then attrs // { ${arg} = buildDrvArgs.${arg}; }
|
||||||
|
else attrs)
|
||||||
|
{ }
|
||||||
|
buildDrvInheritArgNames;
|
||||||
|
|
||||||
|
drvArgs = buildDrvInheritArgs // (removeAttrs args [ "buildDrvArgs" ]);
|
||||||
|
name = (if drvArgs ? name then drvArgs.name else "${drvArgs.pname}-${drvArgs.version}");
|
||||||
|
|
||||||
|
# Adds the root package to a dependency package_config.json file from pub2nix.
|
||||||
|
linkPackageConfig = { packageConfig, extraSetupCommands ? "" }: stdenvNoCC.mkDerivation (drvArgs // {
|
||||||
|
name = "${name}-package-config-with-root.json";
|
||||||
|
|
||||||
|
nativeBuildInputs = drvArgs.nativeBuildInputs or [ ] ++ args.nativeBuildInputs or [ ] ++ [ jq yq ];
|
||||||
|
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
packageName="$(yq --raw-output .name pubspec.yaml)"
|
||||||
|
jq --arg name "$packageName" '.packages |= . + [{ name: $name, rootUri: "../", packageUri: "lib/" }]' '${packageConfig}' > "$out"
|
||||||
|
${extraSetupCommands}
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
linkPackageConfig;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
# Outputs line-separated "${dest}\t${source}"
|
||||||
|
_getDartEntryPoints() {
|
||||||
|
if [ -n "$dartEntryPoints" ]; then
|
||||||
|
@jq@ -r '(to_entries | map(.key + "\t" + .value) | join("\n"))' "$dartEntryPoints"
|
||||||
|
else
|
||||||
|
# The pubspec executables section follows the pattern:
|
||||||
|
# <output-bin-name>: [source-file-name]
|
||||||
|
# Where source-file-name defaults to output-bin-name if omited
|
||||||
|
@yq@ -r '(.executables | to_entries | map("bin/" + .key + "\t" + "bin/" + (.value // .key) + ".dart") | join("\n"))' pubspec.yaml
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
dartBuildHook() {
|
||||||
|
echo "Executing dartBuildHook"
|
||||||
|
|
||||||
|
runHook preBuild
|
||||||
|
|
||||||
|
while IFS=$'\t' read -ra target; do
|
||||||
|
dest="${target[0]}"
|
||||||
|
src="${target[1]}"
|
||||||
|
eval "$dartCompileCommand" "$dartOutputType" \
|
||||||
|
-o "$dest" "${dartCompileFlags[@]}" "$src" "${dartJitFlags[@]}"
|
||||||
|
done < <(_getDartEntryPoints)
|
||||||
|
|
||||||
|
runHook postBuild
|
||||||
|
|
||||||
|
echo "Finished dartBuildHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z "${dontDartBuild-}" ] && [ -z "${buildPhase-}" ]; then
|
||||||
|
buildPhase=dartBuildHook
|
||||||
|
fi
|
|
@ -0,0 +1,70 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
dartConfigHook() {
|
||||||
|
echo "Executing dartConfigHook"
|
||||||
|
|
||||||
|
echo "Setting up SDK"
|
||||||
|
eval "$sdkSetupScript"
|
||||||
|
|
||||||
|
echo "Installing dependencies"
|
||||||
|
mkdir -p .dart_tool
|
||||||
|
cp "$packageConfig" .dart_tool/package_config.json
|
||||||
|
|
||||||
|
packagePath() {
|
||||||
|
jq --raw-output --arg name "$1" '.packages.[] | select(.name == $name) .rootUri | sub("file://"; "")' .dart_tool/package_config.json
|
||||||
|
}
|
||||||
|
|
||||||
|
# Runs a Dart executable from a package with a custom path.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# packageRunCustom <package> [executable] [bin_dir]
|
||||||
|
#
|
||||||
|
# By default, [bin_dir] is "bin", and [executable] is <package>.
|
||||||
|
# i.e. `packageRunCustom build_runner` is equivalent to `packageRunCustom build_runner build_runner bin`, which runs `bin/build_runner.dart` from the build_runner package.
|
||||||
|
packageRunCustom() {
|
||||||
|
local args=()
|
||||||
|
local passthrough=()
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
if [ "$1" != "--" ]; then
|
||||||
|
args+=("$1")
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
shift
|
||||||
|
passthrough=("$@")
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
local name="${args[0]}"
|
||||||
|
local path="${args[1]:-$name}"
|
||||||
|
local prefix="${args[2]:-bin}"
|
||||||
|
|
||||||
|
dart --packages=.dart_tool/package_config.json "$(packagePath "$name")/$prefix/$path.dart" "${passthrough[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Runs a Dart executable from a package.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# packageRun <package> [-e executable] [...]
|
||||||
|
#
|
||||||
|
# To run an executable from an unconventional location, use packageRunCustom.
|
||||||
|
packageRun() {
|
||||||
|
local name="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
local executableName="$name"
|
||||||
|
if [ "$1" = "-e" ]; then
|
||||||
|
shift
|
||||||
|
executableName="$1"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
fileName="$(@yq@ --raw-output --arg name "$executableName" '.executables.[$name] // $name' "$(packagePath "$name")/pubspec.yaml")"
|
||||||
|
packageRunCustom "$name" "$fileName" -- "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Finished dartConfigHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
postConfigureHooks+=(dartConfigHook)
|
|
@ -0,0 +1,35 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
dartFixupHook() {
|
||||||
|
echo "Executing dartFixupHook"
|
||||||
|
|
||||||
|
declare -a wrapProgramArgs
|
||||||
|
|
||||||
|
# Add runtime library dependencies to the LD_LIBRARY_PATH.
|
||||||
|
# For some reason, the RUNPATH of the executable is not used to load dynamic libraries in dart:ffi with DynamicLibrary.open().
|
||||||
|
#
|
||||||
|
# This could alternatively be fixed with patchelf --add-needed, but this would cause all the libraries to be opened immediately,
|
||||||
|
# which is not what application authors expect.
|
||||||
|
APPLICATION_LD_LIBRARY_PATH=""
|
||||||
|
for runtimeDependency in "${runtimeDependencies[@]}"; do
|
||||||
|
addToSearchPath APPLICATION_LD_LIBRARY_PATH "${runtimeDependency}/lib"
|
||||||
|
done
|
||||||
|
if [[ ! -z "$APPLICATION_LD_LIBRARY_PATH" ]]; then
|
||||||
|
wrapProgramArgs+=(--suffix LD_LIBRARY_PATH : \"$APPLICATION_LD_LIBRARY_PATH\")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -z "$extraWrapProgramArgs" ]]; then
|
||||||
|
wrapProgramArgs+=("$extraWrapProgramArgs")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#wrapProgramArgs[@]} -ne 0 ]; then
|
||||||
|
for f in "$out"/bin/*; do
|
||||||
|
echo "Wrapping $f..."
|
||||||
|
eval "wrapProgram \"$f\" ${wrapProgramArgs[@]}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Finished dartFixupHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
postFixupHooks+=(dartFixupHook)
|
|
@ -0,0 +1,43 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
dartInstallHook() {
|
||||||
|
echo "Executing dartInstallHook"
|
||||||
|
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
# Install snapshots and executables.
|
||||||
|
mkdir -p "$out"
|
||||||
|
while IFS=$'\t' read -ra target; do
|
||||||
|
dest="${target[0]}"
|
||||||
|
# Wrap with runtime command, if it's defined
|
||||||
|
if [ -n "$dartRuntimeCommand" ]; then
|
||||||
|
install -D "$dest" "$out/share/$dest"
|
||||||
|
makeWrapper "$dartRuntimeCommand" "$out/$dest" \
|
||||||
|
--add-flags "$out/share/$dest"
|
||||||
|
else
|
||||||
|
install -Dm755 "$dest" "$out/$dest"
|
||||||
|
fi
|
||||||
|
done < <(_getDartEntryPoints)
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
|
||||||
|
echo "Finished dartInstallHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
dartInstallCacheHook() {
|
||||||
|
echo "Executing dartInstallCacheHook"
|
||||||
|
|
||||||
|
# Install the package_config.json file.
|
||||||
|
mkdir -p "$pubcache"
|
||||||
|
cp .dart_tool/package_config.json "$pubcache/package_config.json"
|
||||||
|
|
||||||
|
echo "Finished dartInstallCacheHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z "${dontDartInstall-}" ] && [ -z "${installPhase-}" ]; then
|
||||||
|
installPhase=dartInstallHook
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${dontDartInstallCache-}" ]; then
|
||||||
|
postInstallHooks+=(dartInstallCacheHook)
|
||||||
|
fi
|
|
@ -0,0 +1,20 @@
|
||||||
|
{ lib, makeSetupHook, dart, yq, jq }:
|
||||||
|
|
||||||
|
{
|
||||||
|
dartConfigHook = makeSetupHook {
|
||||||
|
name = "dart-config-hook";
|
||||||
|
substitutions.yq = "${yq}/bin/yq";
|
||||||
|
substitutions.jq = "${jq}/bin/jq";
|
||||||
|
} ./dart-config-hook.sh;
|
||||||
|
dartBuildHook = makeSetupHook {
|
||||||
|
name = "dart-build-hook";
|
||||||
|
substitutions.yq = "${yq}/bin/yq";
|
||||||
|
substitutions.jq = "${jq}/bin/jq";
|
||||||
|
} ./dart-build-hook.sh;
|
||||||
|
dartInstallHook = makeSetupHook {
|
||||||
|
name = "dart-install-hook";
|
||||||
|
} ./dart-install-hook.sh;
|
||||||
|
dartFixupHook = makeSetupHook {
|
||||||
|
name = "dart-fixup-hook";
|
||||||
|
} ./dart-fixup-hook.sh;
|
||||||
|
}
|
6
pkgs/build-support/dart/pub2nix/default.nix
Normal file
6
pkgs/build-support/dart/pub2nix/default.nix
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{ callPackage }:
|
||||||
|
|
||||||
|
{
|
||||||
|
readPubspecLock = callPackage ./pubspec-lock.nix { };
|
||||||
|
generatePackageConfig = callPackage ./package-config.nix { };
|
||||||
|
}
|
68
pkgs/build-support/dart/pub2nix/package-config.nix
Normal file
68
pkgs/build-support/dart/pub2nix/package-config.nix
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
{ lib
|
||||||
|
, runCommand
|
||||||
|
, jq
|
||||||
|
, yq
|
||||||
|
}:
|
||||||
|
|
||||||
|
{ pname ? null
|
||||||
|
|
||||||
|
# A list of dependency package names.
|
||||||
|
, dependencies
|
||||||
|
|
||||||
|
# An attribute set of package names to sources.
|
||||||
|
, dependencySources
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
packages = lib.genAttrs dependencies (dependency: rec {
|
||||||
|
src = dependencySources.${dependency};
|
||||||
|
inherit (src) packageRoot;
|
||||||
|
});
|
||||||
|
in
|
||||||
|
(runCommand "${lib.optionalString (pname != null) "${pname}-"}package-config.json" {
|
||||||
|
inherit packages;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ jq yq ];
|
||||||
|
|
||||||
|
__structuredAttrs = true;
|
||||||
|
}) ''
|
||||||
|
declare -A packageSources
|
||||||
|
declare -A packageRoots
|
||||||
|
while IFS=',' read -r name src packageRoot; do
|
||||||
|
packageSources["$name"]="$src"
|
||||||
|
packageRoots["$name"]="$packageRoot"
|
||||||
|
done < <(jq -r '.packages | to_entries | map("\(.key),\(.value.src),\(.value.packageRoot)") | .[]' "$NIX_ATTRS_JSON_FILE")
|
||||||
|
|
||||||
|
for package in "''${!packageSources[@]}"; do
|
||||||
|
if [ ! -e "''${packageSources["$package"]}/''${packageRoots["$package"]}/pubspec.yaml" ]; then
|
||||||
|
echo >&2 "The package sources for $package are missing. Is the following path inside the source derivation?"
|
||||||
|
echo >&2 "Source path: ''${packageSources["$package"]}/''${packageRoots["$package"]}/pubspec.yaml"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
languageConstraint="$(yq -r .environment.sdk "''${packageSources["$package"]}/''${packageRoots["$package"]}/pubspec.yaml")"
|
||||||
|
if [[ "$languageConstraint" =~ ^[[:space:]]*(\^|>=|>)?[[:space:]]*([[:digit:]]+\.[[:digit:]]+)\.[[:digit:]]+.*$ ]]; then
|
||||||
|
languageVersionJson="\"''${BASH_REMATCH[2]}\""
|
||||||
|
elif [ "$languageConstraint" = 'any' ]; then
|
||||||
|
languageVersionJson='null'
|
||||||
|
else
|
||||||
|
# https://github.com/dart-lang/pub/blob/68dc2f547d0a264955c1fa551fa0a0e158046494/lib/src/language_version.dart#L106C35-L106C35
|
||||||
|
languageVersionJson='"2.7"'
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq --null-input \
|
||||||
|
--arg name "$package" \
|
||||||
|
--arg path "''${packageSources["$package"]}/''${packageRoots["$package"]}" \
|
||||||
|
--argjson languageVersion "$languageVersionJson" \
|
||||||
|
'{
|
||||||
|
name: $name,
|
||||||
|
rootUri: "file://\($path)",
|
||||||
|
packageUri: "lib/",
|
||||||
|
languageVersion: $languageVersion,
|
||||||
|
}'
|
||||||
|
done | jq > "$out" --slurp '{
|
||||||
|
configVersion: 2,
|
||||||
|
generator: "nixpkgs",
|
||||||
|
packages: .,
|
||||||
|
}'
|
||||||
|
''
|
119
pkgs/build-support/dart/pub2nix/pubspec-lock.nix
Normal file
119
pkgs/build-support/dart/pub2nix/pubspec-lock.nix
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
{ lib
|
||||||
|
, callPackage
|
||||||
|
, fetchurl
|
||||||
|
, fetchgit
|
||||||
|
, runCommand
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
# The source directory of the package.
|
||||||
|
src
|
||||||
|
|
||||||
|
# The package subdirectory within src.
|
||||||
|
# Useful if the package references sibling packages with relative paths.
|
||||||
|
, packageRoot ? "."
|
||||||
|
|
||||||
|
# The pubspec.lock file, in attribute set form.
|
||||||
|
, pubspecLock
|
||||||
|
|
||||||
|
# Hashes for Git dependencies.
|
||||||
|
# Pub does not record these itself, so they must be manually provided.
|
||||||
|
, gitHashes ? { }
|
||||||
|
|
||||||
|
# Functions to generate SDK package sources.
|
||||||
|
# The function names should match the SDK names, and the package name is given as an argument.
|
||||||
|
, sdkSourceBuilders ? { }
|
||||||
|
|
||||||
|
# Functions that create custom package source derivations.
|
||||||
|
#
|
||||||
|
# The function names should match the package names, and the package version,
|
||||||
|
# source, and source files are given in an attribute set argument.
|
||||||
|
#
|
||||||
|
# The passthru of the source derivation should be propagated.
|
||||||
|
, customSourceBuilders ? { }
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
dependencyVersions = builtins.mapAttrs (name: details: details.version) pubspecLock.packages;
|
||||||
|
|
||||||
|
dependencyTypes = {
|
||||||
|
"direct main" = "main";
|
||||||
|
"direct dev" = "dev";
|
||||||
|
"direct overridden" = "overridden";
|
||||||
|
"transitive" = "transitive";
|
||||||
|
};
|
||||||
|
|
||||||
|
dependencies = lib.foldlAttrs
|
||||||
|
(dependencies: name: details: dependencies // { ${dependencyTypes.${details.dependency}} = dependencies.${dependencyTypes.${details.dependency}} ++ [ name ]; })
|
||||||
|
(lib.genAttrs (builtins.attrValues dependencyTypes) (dependencyType: [ ]))
|
||||||
|
pubspecLock.packages;
|
||||||
|
|
||||||
|
# fetchTarball fails with "tarball contains an unexpected number of top-level files". This is a workaround.
|
||||||
|
# https://discourse.nixos.org/t/fetchtarball-with-multiple-top-level-directories-fails/20556
|
||||||
|
mkHostedDependencySource = name: details:
|
||||||
|
let
|
||||||
|
archive = fetchurl {
|
||||||
|
name = "pub-${name}-${details.version}.tar.gz";
|
||||||
|
url = "${details.description.url}/packages/${details.description.name}/versions/${details.version}.tar.gz";
|
||||||
|
sha256 = details.description.sha256;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
runCommand "pub-${name}-${details.version}" { passthru.packageRoot = "."; } ''
|
||||||
|
mkdir -p "$out"
|
||||||
|
tar xf '${archive}' -C "$out"
|
||||||
|
'';
|
||||||
|
|
||||||
|
mkGitDependencySource = name: details: (fetchgit {
|
||||||
|
name = "pub-${name}-${details.version}";
|
||||||
|
url = details.description.url;
|
||||||
|
rev = details.description.resolved-ref;
|
||||||
|
hash = gitHashes.${name} or (throw "A Git hash is required for ${name}! Set to an empty string to obtain it.");
|
||||||
|
}).overrideAttrs ({ passthru ? { }, ... }: {
|
||||||
|
passthru = passthru // {
|
||||||
|
packageRoot = details.description.path;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
mkPathDependencySource = name: details:
|
||||||
|
assert lib.assertMsg details.description.relative "Only relative paths are supported - ${name} has an absolue path!";
|
||||||
|
(if lib.isDerivation src then src else (runCommand "pub-${name}-${details.version}" { } ''cp -r '${src}' "$out"'')).overrideAttrs ({ passthru ? { }, ... }: {
|
||||||
|
passthru = passthru // {
|
||||||
|
packageRoot = "${packageRoot}/${details.description.path}";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
mkSdkDependencySource = name: details:
|
||||||
|
(sdkSourceBuilders.${details.description} or (throw "No SDK source builder has been given for ${details.description}!")) name;
|
||||||
|
|
||||||
|
addDependencySourceUtils = dependencySource: details: dependencySource.overrideAttrs ({ passthru, ... }: {
|
||||||
|
passthru = passthru // {
|
||||||
|
inherit (details) version;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
sourceBuilders = callPackage ../../../development/compilers/dart/package-source-builders { } // customSourceBuilders;
|
||||||
|
|
||||||
|
dependencySources = lib.filterAttrs (name: src: src != null) (builtins.mapAttrs
|
||||||
|
(name: details:
|
||||||
|
(sourceBuilders.${name} or ({ src, ... }: src)) {
|
||||||
|
inherit (details) version source;
|
||||||
|
src = ((addDependencySourceUtils (({
|
||||||
|
"hosted" = mkHostedDependencySource;
|
||||||
|
"git" = mkGitDependencySource;
|
||||||
|
"path" = mkPathDependencySource;
|
||||||
|
"sdk" = mkSdkDependencySource;
|
||||||
|
}.${details.source} name) details)) details);
|
||||||
|
})
|
||||||
|
pubspecLock.packages);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
# An attribute set of dependency categories to package name lists.
|
||||||
|
dependencies
|
||||||
|
|
||||||
|
# An attribute set of package names to their versions.
|
||||||
|
dependencyVersions
|
||||||
|
|
||||||
|
# An attribute set of package names to their sources.
|
||||||
|
dependencySources;
|
||||||
|
}
|
55
pkgs/build-support/deterministic-uname/default.nix
Normal file
55
pkgs/build-support/deterministic-uname/default.nix
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# expr and script based on our lsb_release
|
||||||
|
{ stdenv
|
||||||
|
, lib
|
||||||
|
, substituteAll
|
||||||
|
, coreutils
|
||||||
|
, getopt
|
||||||
|
, modDirVersion ? ""
|
||||||
|
}:
|
||||||
|
|
||||||
|
substituteAll {
|
||||||
|
name = "uname";
|
||||||
|
|
||||||
|
src = ./deterministic-uname.sh;
|
||||||
|
|
||||||
|
dir = "bin";
|
||||||
|
isExecutable = true;
|
||||||
|
|
||||||
|
inherit coreutils getopt;
|
||||||
|
|
||||||
|
uSystem = if stdenv.buildPlatform.uname.system != null then stdenv.buildPlatform.uname.system else "unknown";
|
||||||
|
inherit (stdenv.buildPlatform.uname) processor;
|
||||||
|
|
||||||
|
# uname -o
|
||||||
|
# maybe add to lib/systems/default.nix uname attrset
|
||||||
|
# https://github.com/coreutils/coreutils/blob/7fc84d1c0f6b35231b0b4577b70aaa26bf548a7c/src/uname.c#L373-L374
|
||||||
|
# https://stackoverflow.com/questions/61711186/where-does-host-operating-system-in-uname-c-comes-from
|
||||||
|
# https://github.com/coreutils/gnulib/blob/master/m4/host-os.m4
|
||||||
|
operatingSystem =
|
||||||
|
if stdenv.buildPlatform.isLinux
|
||||||
|
then "GNU/Linux"
|
||||||
|
else if stdenv.buildPlatform.isDarwin
|
||||||
|
then "Darwin" # darwin isn't in host-os.m4 so where does this come from?
|
||||||
|
else "unknown";
|
||||||
|
|
||||||
|
# in os-specific/linux module packages
|
||||||
|
# --replace '$(shell uname -r)' "${kernel.modDirVersion}" \
|
||||||
|
# is a common thing to do.
|
||||||
|
modDirVersion = if modDirVersion != "" then modDirVersion else "unknown";
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Print certain system information (hardcoded with lib/system values)";
|
||||||
|
mainProgram = "uname";
|
||||||
|
longDescription = ''
|
||||||
|
This package provides a replacement for `uname` whose output depends only
|
||||||
|
on `stdenv.buildPlatform`. It is meant to be used from within derivations.
|
||||||
|
Many packages' build processes run `uname` at compile time and embed its
|
||||||
|
output into the result of the build. Since `uname` calls into the kernel,
|
||||||
|
and the Nix sandbox currently does not intercept these calls, builds made
|
||||||
|
on different kernels will produce different results.
|
||||||
|
'';
|
||||||
|
license = [ licenses.mit ];
|
||||||
|
maintainers = with maintainers; [ artturin ];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
174
pkgs/build-support/deterministic-uname/deterministic-uname.sh
Normal file
174
pkgs/build-support/deterministic-uname/deterministic-uname.sh
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
#! @shell@
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
show_help() {
|
||||||
|
@coreutils@/bin/cat << EOF
|
||||||
|
Usage: uname [OPTION]...
|
||||||
|
Print certain system information. With no OPTION, same as -s.
|
||||||
|
|
||||||
|
-a, --all print all information, in the following order,
|
||||||
|
except omit -p and -i if unknown:
|
||||||
|
-s, --kernel-name print the kernel name
|
||||||
|
-n, --nodename print the network node hostname
|
||||||
|
-r, --kernel-release print the kernel release
|
||||||
|
-v, --kernel-version print the kernel version
|
||||||
|
-m, --machine print the machine hardware name
|
||||||
|
-p, --processor print the processor type (non-portable)
|
||||||
|
-i, --hardware-platform print the hardware platform (non-portable)
|
||||||
|
-o, --operating-system print the operating system
|
||||||
|
--help display this help and exit
|
||||||
|
--version output version information and exit
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Potential command-line options.
|
||||||
|
version=0
|
||||||
|
all=0
|
||||||
|
|
||||||
|
|
||||||
|
kernel_name=0
|
||||||
|
nodename=0
|
||||||
|
kernel_release=0
|
||||||
|
kernel_version=0
|
||||||
|
machine=0
|
||||||
|
processor=0
|
||||||
|
hardware_platform=0
|
||||||
|
operating_system=0
|
||||||
|
|
||||||
|
# With no OPTION, same as -s.
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
kernel_name=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
@getopt@/bin/getopt --test > /dev/null && rc=$? || rc=$?
|
||||||
|
if [[ $rc -ne 4 ]]; then
|
||||||
|
# This shouldn't happen.
|
||||||
|
echo "Warning: Enhanced getopt not supported, please open an issue in nixpkgs." >&2
|
||||||
|
else
|
||||||
|
# Define all short and long options.
|
||||||
|
SHORT=hvsnrvmpioa
|
||||||
|
LONG=help,version,kernel-name,nodename,kernel-release,kernel-version,machine,processor,hardware-platform,operating-system,all
|
||||||
|
|
||||||
|
# Parse all options.
|
||||||
|
PARSED=`@getopt@/bin/getopt --options $SHORT --longoptions $LONG --name "$0" -- "$@"`
|
||||||
|
|
||||||
|
eval set -- "$PARSED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Process each argument, and set the appropriate flag if we recognize it.
|
||||||
|
while [[ $# -ge 1 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--version)
|
||||||
|
version=1
|
||||||
|
;;
|
||||||
|
-s|--kernel-name)
|
||||||
|
kernel_name=1
|
||||||
|
;;
|
||||||
|
-n|--nodename)
|
||||||
|
nodename=1
|
||||||
|
;;
|
||||||
|
-r|--kernel-release)
|
||||||
|
kernel_release=1
|
||||||
|
;;
|
||||||
|
-v|--kernel-version)
|
||||||
|
kernel_version=1
|
||||||
|
;;
|
||||||
|
-m|--machine)
|
||||||
|
machine=1
|
||||||
|
;;
|
||||||
|
-p|--processor)
|
||||||
|
processor=1
|
||||||
|
;;
|
||||||
|
-i|--hardware-platform)
|
||||||
|
hardware_platform=1
|
||||||
|
;;
|
||||||
|
-o|--operating-system)
|
||||||
|
operating_system=1
|
||||||
|
;;
|
||||||
|
-a|--all)
|
||||||
|
all=1
|
||||||
|
;;
|
||||||
|
--help)
|
||||||
|
show_help
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "uname: unrecognized option '$1'"
|
||||||
|
echo "Type 'uname --help' for a list of available options."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
KERNEL_NAME_VAL=@uSystem@
|
||||||
|
NODENAME_VAL=nixpkgs
|
||||||
|
KERNEL_RELEASE_VAL=@modDirVersion@
|
||||||
|
# #1-NixOS SMP PREEMPT_DYNAMIC Wed Dec 14 10:41:06 UTC 2022
|
||||||
|
KERNEL_VERSION_VAL="#1-NixOS Tue Jan 1 00:00:00 UTC 1980"
|
||||||
|
MACHINE_VAL=@processor@
|
||||||
|
PROCESSOR_VAL=unknown
|
||||||
|
HARDWARE_PLATFORM_VAL=unknown
|
||||||
|
OPERATING_SYSTEM_VAL=@operatingSystem@
|
||||||
|
|
||||||
|
|
||||||
|
if [[ "$version" = "1" ]]; then
|
||||||
|
# in case some script greps for GNU coreutils.
|
||||||
|
echo "uname (GNU coreutils) 9.1"
|
||||||
|
echo "Nixpkgs deterministic-uname"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# output of the real uname from GNU coreutils
|
||||||
|
# Darwin:
|
||||||
|
# Darwin *nodename* 22.1.0 Darwin Kernel Version 22.1.0: Sun Oct 9 20:14:30 PDT 2022; root:xnu-8792.41.9~2/RELEASE_ARM64_T8103 arm64 arm Darwin
|
||||||
|
# NixOS:
|
||||||
|
# Linux *nodename* 6.0.13 #1-NixOS SMP PREEMPT_DYNAMIC Wed Dec 14 10:41:06 UTC 2022 x86_64 GNU/Linux
|
||||||
|
output=()
|
||||||
|
if [[ "$all" = "1" ]]; then
|
||||||
|
output+=("$KERNEL_NAME_VAL" "$NODENAME_VAL" "$KERNEL_RELEASE_VAL" "$KERNEL_VERSION_VAL" "$MACHINE_VAL")
|
||||||
|
# in help: except omit -p and -i if unknown.
|
||||||
|
# output+=($PROCESSOR_VAL $HARDWARE_PLATFORM_VAL)
|
||||||
|
output+=("$OPERATING_SYSTEM_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$kernel_name" = "1" ]]; then
|
||||||
|
output+=("$KERNEL_NAME_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$nodename" = "1" ]]; then
|
||||||
|
output+=("$NODENAME_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$kernel_release" = "1" ]]; then
|
||||||
|
output+=("$KERNEL_RELEASE_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$kernel_version" = "1" ]]; then
|
||||||
|
output+=("$KERNEL_VERSION_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$machine" = "1" ]]; then
|
||||||
|
output+=("$MACHINE_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$processor" = "1" ]]; then
|
||||||
|
output+=("$PROCESSOR_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$hardware_platform" = "1" ]]; then
|
||||||
|
output+=("$HARDWARE_PLATFORM_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$operating_system" = "1" ]]; then
|
||||||
|
output+=("$OPERATING_SYSTEM_VAL")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${output[@]}"
|
25
pkgs/build-support/dhall/directory-to-nix.nix
Normal file
25
pkgs/build-support/dhall/directory-to-nix.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{ dhallPackages, dhallPackageToNix}:
|
||||||
|
|
||||||
|
# `dhallDirectoryToNix is a utility function to take a directory of Dhall files
|
||||||
|
# and read them in as a Nix expression.
|
||||||
|
#
|
||||||
|
# This function is similar to `dhallToNix`, but takes a Nixpkgs Dhall package
|
||||||
|
# as input instead of raw Dhall code.
|
||||||
|
#
|
||||||
|
# Note that this uses "import from derivation" (IFD), meaning that Nix will
|
||||||
|
# perform a build during the evaluation phase if you use this
|
||||||
|
# `dhallDirectoryToNix` utility. It is not possible to use
|
||||||
|
# `dhallDirectoryToNix` in Nixpkgs, since the Nixpkgs Hydra doesn't allow IFD.
|
||||||
|
|
||||||
|
{ src
|
||||||
|
, # The file to import, relative to the src root directory
|
||||||
|
file ? "package.dhall"
|
||||||
|
}@args:
|
||||||
|
|
||||||
|
let
|
||||||
|
generatedPkg = dhallPackages.generateDhallDirectoryPackage args;
|
||||||
|
|
||||||
|
builtPkg = dhallPackages.callPackage generatedPkg { };
|
||||||
|
|
||||||
|
in
|
||||||
|
dhallPackageToNix builtPkg
|
36
pkgs/build-support/dhall/package-to-nix.nix
Normal file
36
pkgs/build-support/dhall/package-to-nix.nix
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
# `dhallPackageToNix` is a utility function to take a Nixpkgs Dhall package
|
||||||
|
# (created with a function like `dhallPackages.buildDhallDirectoryPackage`)
|
||||||
|
# and read it in as a Nix expression.
|
||||||
|
#
|
||||||
|
# This function is similar to `dhallToNix`, but takes a Nixpkgs Dhall package
|
||||||
|
# as input instead of raw Dhall code.
|
||||||
|
#
|
||||||
|
# Note that this uses "import from derivation" (IFD), meaning that Nix will
|
||||||
|
# perform a build during the evaluation phase if you use this
|
||||||
|
# `dhallPackageToNix` utility. It is not possible to use `dhallPackageToNix`
|
||||||
|
# in Nixpkgs, since the Nixpkgs Hydra doesn't allow IFD.
|
||||||
|
|
||||||
|
{ stdenv, dhall-nix }:
|
||||||
|
|
||||||
|
dhallPackage:
|
||||||
|
let
|
||||||
|
drv = stdenv.mkDerivation {
|
||||||
|
name = "dhall-compiled-package.nix";
|
||||||
|
|
||||||
|
buildCommand = ''
|
||||||
|
# Dhall requires that the cache is writable, even if it is never written to.
|
||||||
|
# We copy the cache from the input package to the current directory and
|
||||||
|
# set the cache as writable.
|
||||||
|
cp -r "${dhallPackage}/.cache" ./
|
||||||
|
export XDG_CACHE_HOME=$PWD/.cache
|
||||||
|
chmod -R +w ./.cache
|
||||||
|
|
||||||
|
dhall-to-nix <<< "${dhallPackage}/binary.dhall" > $out
|
||||||
|
'';
|
||||||
|
|
||||||
|
nativeBuildInputs = [ dhall-nix ];
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
import drv
|
38
pkgs/build-support/dhall/to-nix.nix
Normal file
38
pkgs/build-support/dhall/to-nix.nix
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/* `dhallToNix` is a utility function to convert expressions in the Dhall
|
||||||
|
configuration language to their corresponding Nix expressions.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
dhallToNix "{ foo = 1, bar = True }"
|
||||||
|
=> { foo = 1; bar = true; }
|
||||||
|
dhallToNix "λ(x : Bool) → x == False"
|
||||||
|
=> x : x == false
|
||||||
|
dhallToNix "λ(x : Bool) → x == False" false
|
||||||
|
=> true
|
||||||
|
|
||||||
|
See https://hackage.haskell.org/package/dhall-nix/docs/Dhall-Nix.html for
|
||||||
|
a longer tutorial
|
||||||
|
|
||||||
|
Note that this uses "import from derivation", meaning that Nix will perform
|
||||||
|
a build during the evaluation phase if you use this `dhallToNix` utility
|
||||||
|
*/
|
||||||
|
{ stdenv, dhall-nix, writeText }:
|
||||||
|
|
||||||
|
let
|
||||||
|
dhallToNix = code :
|
||||||
|
let
|
||||||
|
file = writeText "dhall-expression" code;
|
||||||
|
|
||||||
|
drv = stdenv.mkDerivation {
|
||||||
|
name = "dhall-compiled.nix";
|
||||||
|
|
||||||
|
buildCommand = ''
|
||||||
|
dhall-to-nix <<< "${file}" > $out
|
||||||
|
'';
|
||||||
|
|
||||||
|
buildInputs = [ dhall-nix ];
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
import drv;
|
||||||
|
in
|
||||||
|
dhallToNix
|
7
pkgs/build-support/dlang/README.md
Normal file
7
pkgs/build-support/dlang/README.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Build support for D
|
||||||
|
|
||||||
|
Build utilities for the D language can be found in this directory.
|
||||||
|
|
||||||
|
### Current maintainers
|
||||||
|
- @TomaSajt
|
||||||
|
- @jtbx
|
124
pkgs/build-support/dlang/builddubpackage/default.nix
Normal file
124
pkgs/build-support/dlang/builddubpackage/default.nix
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
stdenv,
|
||||||
|
fetchurl,
|
||||||
|
linkFarm,
|
||||||
|
dub,
|
||||||
|
ldc,
|
||||||
|
removeReferencesTo,
|
||||||
|
}:
|
||||||
|
|
||||||
|
# See https://nixos.org/manual/nixpkgs/unstable#dlang for more detailed usage information
|
||||||
|
|
||||||
|
{
|
||||||
|
# A lockfile generated by `dub-to-nix` from the source of the package.
|
||||||
|
# Can be either a path to the file, or an attrset already parsed with `lib.importJSON`.
|
||||||
|
dubLock,
|
||||||
|
# The build type to pass to `dub build` as a value for the `--build=` flag.
|
||||||
|
dubBuildType ? "release",
|
||||||
|
# The flags to pass to `dub build` and `dub test`.
|
||||||
|
dubFlags ? [ ],
|
||||||
|
# The flags to pass to `dub build`.
|
||||||
|
dubBuildFlags ? [ ],
|
||||||
|
# The flags to pass to `dub test`.
|
||||||
|
dubTestFlags ? [ ],
|
||||||
|
# The D compiler to be used by `dub`.
|
||||||
|
compiler ? ldc,
|
||||||
|
...
|
||||||
|
}@args:
|
||||||
|
|
||||||
|
let
|
||||||
|
makeDubDep =
|
||||||
|
{
|
||||||
|
pname,
|
||||||
|
version,
|
||||||
|
sha256,
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
inherit pname version;
|
||||||
|
src = fetchurl {
|
||||||
|
name = "dub-${pname}-${version}.zip";
|
||||||
|
url = "mirror://dub/${pname}/${version}.zip";
|
||||||
|
inherit sha256;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
lockJson = if lib.isPath dubLock then lib.importJSON dubLock else dubLock;
|
||||||
|
|
||||||
|
lockedDeps = lib.mapAttrsToList (
|
||||||
|
pname: { version, sha256 }: makeDubDep { inherit pname version sha256; }
|
||||||
|
) lockJson.dependencies;
|
||||||
|
|
||||||
|
# a directory with multiple single element registries
|
||||||
|
# one big directory with all .zip files leads to version parsing errors
|
||||||
|
# when the name of a package is a prefix of the name of another package
|
||||||
|
dubRegistryBase = linkFarm "dub-registry-base" (
|
||||||
|
map (dep: {
|
||||||
|
name = "${dep.pname}/${dep.pname}-${dep.version}.zip";
|
||||||
|
path = dep.src;
|
||||||
|
}) lockedDeps
|
||||||
|
);
|
||||||
|
|
||||||
|
combinedFlags = "--skip-registry=all --compiler=${lib.getExe compiler} ${toString dubFlags}";
|
||||||
|
combinedBuildFlags = "${combinedFlags} --build=${dubBuildType} ${toString dubBuildFlags}";
|
||||||
|
combinedTestFlags = "${combinedFlags} ${toString dubTestFlags}";
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation (
|
||||||
|
builtins.removeAttrs args [ "dubLock" ]
|
||||||
|
// {
|
||||||
|
strictDeps = args.strictDeps or true;
|
||||||
|
|
||||||
|
nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
|
||||||
|
dub
|
||||||
|
compiler
|
||||||
|
removeReferencesTo
|
||||||
|
];
|
||||||
|
|
||||||
|
configurePhase =
|
||||||
|
args.configurePhase or ''
|
||||||
|
runHook preConfigure
|
||||||
|
|
||||||
|
export DUB_HOME="$NIX_BUILD_TOP/.dub"
|
||||||
|
mkdir -p $DUB_HOME
|
||||||
|
|
||||||
|
# register dependencies
|
||||||
|
${lib.concatMapStringsSep "\n" (dep: ''
|
||||||
|
dub fetch ${dep.pname}@${dep.version} --cache=user --skip-registry=standard --registry=file://${dubRegistryBase}/${dep.pname}
|
||||||
|
'') lockedDeps}
|
||||||
|
|
||||||
|
runHook postConfigure
|
||||||
|
'';
|
||||||
|
|
||||||
|
buildPhase =
|
||||||
|
args.buildPhase or ''
|
||||||
|
runHook preBuild
|
||||||
|
|
||||||
|
dub build ${combinedBuildFlags}
|
||||||
|
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
doCheck = args.doCheck or false;
|
||||||
|
|
||||||
|
checkPhase =
|
||||||
|
args.checkPhase or ''
|
||||||
|
runHook preCheck
|
||||||
|
|
||||||
|
dub test ${combinedTestFlags}
|
||||||
|
|
||||||
|
runHook postCheck
|
||||||
|
'';
|
||||||
|
|
||||||
|
preFixup = ''
|
||||||
|
${args.preFixup or ""}
|
||||||
|
|
||||||
|
find "$out" -type f -exec remove-references-to -t ${compiler} '{}' +
|
||||||
|
'';
|
||||||
|
|
||||||
|
disallowedReferences = [ compiler ];
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
platforms = dub.meta.platforms;
|
||||||
|
} // args.meta or { };
|
||||||
|
}
|
||||||
|
)
|
5
pkgs/build-support/dlang/dub-support.nix
Normal file
5
pkgs/build-support/dlang/dub-support.nix
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{ callPackage }:
|
||||||
|
{
|
||||||
|
buildDubPackage = callPackage ./builddubpackage { };
|
||||||
|
dub-to-nix = callPackage ./dub-to-nix { };
|
||||||
|
}
|
19
pkgs/build-support/dlang/dub-to-nix/default.nix
Normal file
19
pkgs/build-support/dlang/dub-to-nix/default.nix
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
runCommand,
|
||||||
|
makeWrapper,
|
||||||
|
python3,
|
||||||
|
nix,
|
||||||
|
}:
|
||||||
|
|
||||||
|
runCommand "dub-to-nix"
|
||||||
|
{
|
||||||
|
nativeBuildInputs = [ makeWrapper ];
|
||||||
|
buildInputs = [ python3 ];
|
||||||
|
}
|
||||||
|
''
|
||||||
|
install -Dm755 ${./dub-to-nix.py} "$out/bin/dub-to-nix"
|
||||||
|
patchShebangs "$out/bin/dub-to-nix"
|
||||||
|
wrapProgram "$out/bin/dub-to-nix" \
|
||||||
|
--prefix PATH : ${lib.makeBinPath [ nix ]}
|
||||||
|
''
|
39
pkgs/build-support/dlang/dub-to-nix/dub-to-nix.py
Normal file
39
pkgs/build-support/dlang/dub-to-nix/dub-to-nix.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def eprint(text: str):
|
||||||
|
print(text, file=sys.stderr)
|
||||||
|
|
||||||
|
if not os.path.exists("dub.selections.json"):
|
||||||
|
eprint("The file `dub.selections.json` does not exist in the current working directory")
|
||||||
|
eprint("run `dub upgrade --annotate` to generate it")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open("dub.selections.json") as f:
|
||||||
|
selectionsJson = json.load(f)
|
||||||
|
|
||||||
|
versionDict: dict[str, str] = selectionsJson["versions"]
|
||||||
|
|
||||||
|
for pname in versionDict:
|
||||||
|
version = versionDict[pname]
|
||||||
|
if version.startswith("~"):
|
||||||
|
eprint(f'Package "{pname}" has a branch-type version "{version}", which doesn\'t point to a fixed version')
|
||||||
|
eprint("You can resolve it by manually changing the required version to a fixed one inside `dub.selections.json`")
|
||||||
|
eprint("When packaging, you might need to create a patch for `dub.sdl` or `dub.json` to accept the changed version")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
lockedDependenciesDict: dict[str, dict[str, str]] = {}
|
||||||
|
|
||||||
|
for pname in versionDict:
|
||||||
|
version = versionDict[pname]
|
||||||
|
eprint(f"Fetching {pname}@{version}")
|
||||||
|
url = f"https://code.dlang.org/packages/{pname}/{version}.zip"
|
||||||
|
command = ["nix-prefetch-url", "--type", "sha256", url]
|
||||||
|
sha256 = subprocess.run(command, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.rstrip()
|
||||||
|
lockedDependenciesDict[pname] = {"version": version, "sha256": sha256}
|
||||||
|
|
||||||
|
print(json.dumps({"dependencies": lockedDependenciesDict}, indent=2))
|
1299
pkgs/build-support/docker/default.nix
Normal file
1299
pkgs/build-support/docker/default.nix
Normal file
File diff suppressed because it is too large
Load diff
40
pkgs/build-support/docker/detjson.py
Normal file
40
pkgs/build-support/docker/detjson.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Deterministic layer json: https://github.com/docker/hub-feedback/issues/488
|
||||||
|
|
||||||
|
import sys
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('UTF8')
|
||||||
|
import json
|
||||||
|
|
||||||
|
# If any of the keys below are equal to a certain value
|
||||||
|
# then we can delete it because it's the default value
|
||||||
|
SAFEDELS = {
|
||||||
|
"Size": 0,
|
||||||
|
"config": {
|
||||||
|
"ExposedPorts": None,
|
||||||
|
"MacAddress": "",
|
||||||
|
"NetworkDisabled": False,
|
||||||
|
"PortSpecs": None,
|
||||||
|
"VolumeDriver": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SAFEDELS["container_config"] = SAFEDELS["config"]
|
||||||
|
|
||||||
|
def makedet(j, safedels):
|
||||||
|
for k,v in safedels.items():
|
||||||
|
if k not in j:
|
||||||
|
continue
|
||||||
|
if type(v) == dict:
|
||||||
|
makedet(j[k], v)
|
||||||
|
elif j[k] == v:
|
||||||
|
del j[k]
|
||||||
|
|
||||||
|
def main():
|
||||||
|
j = json.load(sys.stdin)
|
||||||
|
makedet(j, SAFEDELS)
|
||||||
|
json.dump(j, sys.stdout, sort_keys=True)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
900
pkgs/build-support/docker/examples.nix
Normal file
900
pkgs/build-support/docker/examples.nix
Normal file
|
@ -0,0 +1,900 @@
|
||||||
|
# Examples of using the docker tools to build packages.
|
||||||
|
#
|
||||||
|
# This file defines several docker images. In order to use an image,
|
||||||
|
# build its derivation with `nix-build`, and then load the result with
|
||||||
|
# `docker load`. For example:
|
||||||
|
#
|
||||||
|
# $ nix-build '<nixpkgs>' -A dockerTools.examples.redis
|
||||||
|
# $ docker load < result
|
||||||
|
|
||||||
|
{ pkgs, buildImage, buildLayeredImage, fakeNss, pullImage, shadowSetup, buildImageWithNixDb, pkgsCross, streamNixShellImage }:
|
||||||
|
|
||||||
|
let
|
||||||
|
nixosLib = import ../../../nixos/lib {
|
||||||
|
# Experimental features need testing too, but there's no point in warning
|
||||||
|
# about it, so we enable the feature flag.
|
||||||
|
featureFlags.minimalModules = {};
|
||||||
|
};
|
||||||
|
evalMinimalConfig = module: nixosLib.evalModules { modules = [ module ]; };
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
rec {
|
||||||
|
# 1. basic example
|
||||||
|
bash = buildImage {
|
||||||
|
name = "bash";
|
||||||
|
tag = "latest";
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
paths = [ pkgs.bashInteractive ];
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 2. service example, layered on another image
|
||||||
|
redis = buildImage {
|
||||||
|
name = "redis";
|
||||||
|
tag = "latest";
|
||||||
|
|
||||||
|
# for example's sake, we can layer redis on top of bash or debian
|
||||||
|
fromImage = bash;
|
||||||
|
# fromImage = debian;
|
||||||
|
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
paths = [ pkgs.redis ];
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
runAsRoot = ''
|
||||||
|
mkdir -p /data
|
||||||
|
'';
|
||||||
|
|
||||||
|
config = {
|
||||||
|
Cmd = [ "/bin/redis-server" ];
|
||||||
|
WorkingDir = "/data";
|
||||||
|
Volumes = {
|
||||||
|
"/data" = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 3. another service example
|
||||||
|
nginx = let
|
||||||
|
nginxPort = "80";
|
||||||
|
nginxConf = pkgs.writeText "nginx.conf" ''
|
||||||
|
user nobody nobody;
|
||||||
|
daemon off;
|
||||||
|
error_log /dev/stdout info;
|
||||||
|
pid /dev/null;
|
||||||
|
events {}
|
||||||
|
http {
|
||||||
|
access_log /dev/stdout;
|
||||||
|
server {
|
||||||
|
listen ${nginxPort};
|
||||||
|
index index.html;
|
||||||
|
location / {
|
||||||
|
root ${nginxWebRoot};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
nginxWebRoot = pkgs.writeTextDir "index.html" ''
|
||||||
|
<html><body><h1>Hello from NGINX</h1></body></html>
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
buildLayeredImage {
|
||||||
|
name = "nginx-container";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [
|
||||||
|
fakeNss
|
||||||
|
pkgs.nginx
|
||||||
|
];
|
||||||
|
|
||||||
|
extraCommands = ''
|
||||||
|
mkdir -p tmp/nginx_client_body
|
||||||
|
|
||||||
|
# nginx still tries to read this directory even if error_log
|
||||||
|
# directive is specifying another file :/
|
||||||
|
mkdir -p var/log/nginx
|
||||||
|
'';
|
||||||
|
|
||||||
|
config = {
|
||||||
|
Cmd = [ "nginx" "-c" nginxConf ];
|
||||||
|
ExposedPorts = {
|
||||||
|
"${nginxPort}/tcp" = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 4. example of pulling an image. could be used as a base for other images
|
||||||
|
nixFromDockerHub = pullImage {
|
||||||
|
imageName = "nixos/nix";
|
||||||
|
imageDigest = "sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357";
|
||||||
|
sha256 = "19fw0n3wmddahzr20mhdqv6jkjn1kanh6n2mrr08ai53dr8ph5n7";
|
||||||
|
finalImageTag = "2.2.1";
|
||||||
|
finalImageName = "nix";
|
||||||
|
};
|
||||||
|
# Same example, but re-fetches every time the fetcher implementation changes.
|
||||||
|
# NOTE: Only use this for testing, or you'd be wasting a lot of time, network and space.
|
||||||
|
testNixFromDockerHub = pkgs.testers.invalidateFetcherByDrvHash pullImage {
|
||||||
|
imageName = "nixos/nix";
|
||||||
|
imageDigest = "sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357";
|
||||||
|
sha256 = "19fw0n3wmddahzr20mhdqv6jkjn1kanh6n2mrr08ai53dr8ph5n7";
|
||||||
|
finalImageTag = "2.2.1";
|
||||||
|
finalImageName = "nix";
|
||||||
|
};
|
||||||
|
|
||||||
|
# 5. example of multiple contents, emacs and vi happily coexisting
|
||||||
|
editors = buildImage {
|
||||||
|
name = "editors";
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.bash
|
||||||
|
pkgs.emacs
|
||||||
|
pkgs.vim
|
||||||
|
pkgs.nano
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 6. nix example to play with the container nix store
|
||||||
|
# docker run -it --rm nix nix-store -qR $(nix-build '<nixpkgs>' -A nix)
|
||||||
|
nix = buildImageWithNixDb {
|
||||||
|
name = "nix";
|
||||||
|
tag = "latest";
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [
|
||||||
|
# nix-store uses cat program to display results as specified by
|
||||||
|
# the image env variable NIX_PAGER.
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.nix
|
||||||
|
pkgs.bash
|
||||||
|
];
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
Env = [
|
||||||
|
"NIX_PAGER=cat"
|
||||||
|
# A user is required by nix
|
||||||
|
# https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478
|
||||||
|
"USER=nobody"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 7. example of adding something on top of an image pull by our
|
||||||
|
# dockerTools chain.
|
||||||
|
onTopOfPulledImage = buildImage {
|
||||||
|
name = "onTopOfPulledImage";
|
||||||
|
tag = "latest";
|
||||||
|
fromImage = nixFromDockerHub;
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [ pkgs.hello ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 8. regression test for erroneous use of eval and string expansion.
|
||||||
|
# See issue #34779 and PR #40947 for details.
|
||||||
|
runAsRootExtraCommands = pkgs.dockerTools.buildImage {
|
||||||
|
name = "runAsRootExtraCommands";
|
||||||
|
tag = "latest";
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [ pkgs.coreutils ];
|
||||||
|
};
|
||||||
|
# The parens here are to create problematic bash to embed and eval. In case
|
||||||
|
# this is *embedded* into the script (with nix expansion) the initial quotes
|
||||||
|
# will close the string and the following parens are unexpected
|
||||||
|
runAsRoot = ''echo "(runAsRoot)" > runAsRoot'';
|
||||||
|
extraCommands = ''echo "(extraCommand)" > extraCommands'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# 9. Ensure that setting created to now results in a date which
|
||||||
|
# isn't the epoch + 1
|
||||||
|
unstableDate = pkgs.dockerTools.buildImage {
|
||||||
|
name = "unstable-date";
|
||||||
|
tag = "latest";
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [ pkgs.coreutils ];
|
||||||
|
};
|
||||||
|
created = "now";
|
||||||
|
};
|
||||||
|
|
||||||
|
# 10. Create a layered image
|
||||||
|
layered-image = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "layered-image";
|
||||||
|
tag = "latest";
|
||||||
|
extraCommands = ''echo "(extraCommand)" > extraCommands'';
|
||||||
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
||||||
|
contents = [ pkgs.hello pkgs.bash pkgs.coreutils ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# 11. Create an image on top of a layered image
|
||||||
|
layered-on-top = pkgs.dockerTools.buildImage {
|
||||||
|
name = "layered-on-top";
|
||||||
|
tag = "latest";
|
||||||
|
fromImage = layered-image;
|
||||||
|
extraCommands = ''
|
||||||
|
mkdir ./example-output
|
||||||
|
chmod 777 ./example-output
|
||||||
|
'';
|
||||||
|
config = {
|
||||||
|
Env = [ "PATH=${pkgs.coreutils}/bin/" ];
|
||||||
|
WorkingDir = "/example-output";
|
||||||
|
Cmd = [
|
||||||
|
"${pkgs.bash}/bin/bash" "-c" "echo hello > foo; cat foo"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 12 Create a layered image on top of a layered image
|
||||||
|
layered-on-top-layered = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "layered-on-top-layered";
|
||||||
|
tag = "latest";
|
||||||
|
fromImage = layered-image;
|
||||||
|
extraCommands = ''
|
||||||
|
mkdir ./example-output
|
||||||
|
chmod 777 ./example-output
|
||||||
|
'';
|
||||||
|
config = {
|
||||||
|
Env = [ "PATH=${pkgs.coreutils}/bin/" ];
|
||||||
|
WorkingDir = "/example-output";
|
||||||
|
Cmd = [
|
||||||
|
"${pkgs.bash}/bin/bash" "-c" "echo hello > foo; cat foo"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 13. example of running something as root on top of a parent image
|
||||||
|
# Regression test related to PR #52109
|
||||||
|
runAsRootParentImage = buildImage {
|
||||||
|
name = "runAsRootParentImage";
|
||||||
|
tag = "latest";
|
||||||
|
runAsRoot = "touch /example-file";
|
||||||
|
fromImage = bash;
|
||||||
|
};
|
||||||
|
|
||||||
|
# 14. example of 3 layers images This image is used to verify the
|
||||||
|
# order of layers is correct.
|
||||||
|
# It allows to validate
|
||||||
|
# - the layer of parent are below
|
||||||
|
# - the order of parent layer is preserved at image build time
|
||||||
|
# (this is why there are 3 images)
|
||||||
|
layersOrder = let
|
||||||
|
l1 = pkgs.dockerTools.buildImage {
|
||||||
|
name = "l1";
|
||||||
|
tag = "latest";
|
||||||
|
extraCommands = ''
|
||||||
|
mkdir -p tmp
|
||||||
|
echo layer1 > tmp/layer1
|
||||||
|
echo layer1 > tmp/layer2
|
||||||
|
echo layer1 > tmp/layer3
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
l2 = pkgs.dockerTools.buildImage {
|
||||||
|
name = "l2";
|
||||||
|
fromImage = l1;
|
||||||
|
tag = "latest";
|
||||||
|
extraCommands = ''
|
||||||
|
mkdir -p tmp
|
||||||
|
echo layer2 > tmp/layer2
|
||||||
|
echo layer2 > tmp/layer3
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in pkgs.dockerTools.buildImage {
|
||||||
|
name = "l3";
|
||||||
|
fromImage = l2;
|
||||||
|
tag = "latest";
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [ pkgs.coreutils ];
|
||||||
|
};
|
||||||
|
extraCommands = ''
|
||||||
|
mkdir -p tmp
|
||||||
|
echo layer3 > tmp/layer3
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# 15. Environment variable inheritance.
|
||||||
|
# Child image should inherit parents environment variables,
|
||||||
|
# optionally overriding them.
|
||||||
|
environmentVariablesParent = pkgs.dockerTools.buildImage {
|
||||||
|
name = "parent";
|
||||||
|
tag = "latest";
|
||||||
|
config = {
|
||||||
|
Env = [
|
||||||
|
"FROM_PARENT=true"
|
||||||
|
"LAST_LAYER=parent"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environmentVariables = pkgs.dockerTools.buildImage {
|
||||||
|
name = "child";
|
||||||
|
fromImage = environmentVariablesParent;
|
||||||
|
tag = "latest";
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [ pkgs.coreutils ];
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
Env = [
|
||||||
|
"FROM_CHILD=true"
|
||||||
|
"LAST_LAYER=child"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environmentVariablesLayered = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "child";
|
||||||
|
fromImage = environmentVariablesParent;
|
||||||
|
tag = "latest";
|
||||||
|
contents = [ pkgs.coreutils ];
|
||||||
|
config = {
|
||||||
|
Env = [
|
||||||
|
"FROM_CHILD=true"
|
||||||
|
"LAST_LAYER=child"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 16. Create another layered image, for comparing layers with image 10.
|
||||||
|
another-layered-image = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "another-layered-image";
|
||||||
|
tag = "latest";
|
||||||
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# 17. Create a layered image with only 2 layers
|
||||||
|
two-layered-image = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "two-layered-image";
|
||||||
|
tag = "latest";
|
||||||
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
||||||
|
contents = [ pkgs.bash pkgs.hello ];
|
||||||
|
maxLayers = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
# 18. Create a layered image with more packages than max layers.
|
||||||
|
# coreutils and hello are part of the same layer
|
||||||
|
bulk-layer = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "bulk-layer";
|
||||||
|
tag = "latest";
|
||||||
|
contents = with pkgs; [
|
||||||
|
coreutils hello
|
||||||
|
];
|
||||||
|
maxLayers = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
# 19. Create a layered image with a base image and more packages than max
|
||||||
|
# layers. coreutils and hello are part of the same layer
|
||||||
|
layered-bulk-layer = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "layered-bulk-layer";
|
||||||
|
tag = "latest";
|
||||||
|
fromImage = two-layered-image;
|
||||||
|
contents = with pkgs; [
|
||||||
|
coreutils hello
|
||||||
|
];
|
||||||
|
maxLayers = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
# 20. Create a "layered" image without nix store layers. This is not
|
||||||
|
# recommended, but can be useful for base images in rare cases.
|
||||||
|
no-store-paths = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "no-store-paths";
|
||||||
|
tag = "latest";
|
||||||
|
extraCommands = ''
|
||||||
|
# This removes sharing of busybox and is not recommended. We do this
|
||||||
|
# to make the example suitable as a test case with working binaries.
|
||||||
|
cp -r ${pkgs.pkgsStatic.busybox}/* .
|
||||||
|
|
||||||
|
# This is a "build" dependency that will not appear in the image
|
||||||
|
${pkgs.hello}/bin/hello
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nixLayered = pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||||
|
name = "nix-layered";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [
|
||||||
|
# nix-store uses cat program to display results as specified by
|
||||||
|
# the image env variable NIX_PAGER.
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.nix
|
||||||
|
pkgs.bash
|
||||||
|
];
|
||||||
|
config = {
|
||||||
|
Env = [
|
||||||
|
"NIX_PAGER=cat"
|
||||||
|
# A user is required by nix
|
||||||
|
# https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478
|
||||||
|
"USER=nobody"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 21. Support files in the store on buildLayeredImage
|
||||||
|
# See: https://github.com/NixOS/nixpkgs/pull/91084#issuecomment-653496223
|
||||||
|
filesInStore = pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||||
|
name = "file-in-store";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.nix
|
||||||
|
(pkgs.writeScriptBin "myscript" ''
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
cat ${pkgs.writeText "somefile" "some data"}
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
config = {
|
||||||
|
Cmd = [ "myscript" ];
|
||||||
|
# For some reason 'nix-store --verify' requires this environment variable
|
||||||
|
Env = [ "USER=root" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 22. Ensure that setting created to now results in a date which
|
||||||
|
# isn't the epoch + 1 for layered images.
|
||||||
|
unstableDateLayered = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "unstable-date-layered";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [ pkgs.coreutils ];
|
||||||
|
created = "now";
|
||||||
|
};
|
||||||
|
|
||||||
|
# 23. Ensure that layers are unpacked in the correct order before the
|
||||||
|
# runAsRoot script is executed.
|
||||||
|
layersUnpackOrder =
|
||||||
|
let
|
||||||
|
layerOnTopOf = parent: layerName:
|
||||||
|
pkgs.dockerTools.buildImage {
|
||||||
|
name = "layers-unpack-order-${layerName}";
|
||||||
|
tag = "latest";
|
||||||
|
fromImage = parent;
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [ pkgs.coreutils ];
|
||||||
|
};
|
||||||
|
runAsRoot = ''
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
echo -n "${layerName}" >> /layer-order
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
# When executing the runAsRoot script when building layer C, if layer B is
|
||||||
|
# not unpacked on top of layer A, the contents of /layer-order will not be
|
||||||
|
# "ABC".
|
||||||
|
layerA = layerOnTopOf null "a";
|
||||||
|
layerB = layerOnTopOf layerA "b";
|
||||||
|
layerC = layerOnTopOf layerB "c";
|
||||||
|
in layerC;
|
||||||
|
|
||||||
|
bashUncompressed = pkgs.dockerTools.buildImage {
|
||||||
|
name = "bash-uncompressed";
|
||||||
|
tag = "latest";
|
||||||
|
compressor = "none";
|
||||||
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
||||||
|
copyToRoot = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
|
||||||
|
bashZstdCompressed = pkgs.dockerTools.buildImage {
|
||||||
|
name = "bash-zstd";
|
||||||
|
tag = "latest";
|
||||||
|
compressor = "zstd";
|
||||||
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
||||||
|
copyToRoot = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
|
||||||
|
# buildImage without explicit tag
|
||||||
|
bashNoTag = pkgs.dockerTools.buildImage {
|
||||||
|
name = "bash-no-tag";
|
||||||
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
||||||
|
copyToRoot = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
|
||||||
|
# buildLayeredImage without explicit tag
|
||||||
|
bashNoTagLayered = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "bash-no-tag-layered";
|
||||||
|
contents = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
|
||||||
|
# buildLayeredImage without compression
|
||||||
|
bashLayeredUncompressed = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "bash-layered-uncompressed";
|
||||||
|
tag = "latest";
|
||||||
|
compressor = "none";
|
||||||
|
contents = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
|
||||||
|
# buildLayeredImage with zstd compression
|
||||||
|
bashLayeredZstdCompressed = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "bash-layered-zstd";
|
||||||
|
tag = "latest";
|
||||||
|
compressor = "zstd";
|
||||||
|
contents = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
|
||||||
|
# streamLayeredImage without explicit tag
|
||||||
|
bashNoTagStreamLayered = pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "bash-no-tag-stream-layered";
|
||||||
|
contents = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
|
||||||
|
# buildLayeredImage with non-root user
|
||||||
|
bashLayeredWithUser =
|
||||||
|
let
|
||||||
|
nonRootShadowSetup = { user, uid, gid ? uid }: with pkgs; [
|
||||||
|
(
|
||||||
|
writeTextDir "etc/shadow" ''
|
||||||
|
root:!x:::::::
|
||||||
|
${user}:!:::::::
|
||||||
|
''
|
||||||
|
)
|
||||||
|
(
|
||||||
|
writeTextDir "etc/passwd" ''
|
||||||
|
root:x:0:0::/root:${runtimeShell}
|
||||||
|
${user}:x:${toString uid}:${toString gid}::/home/${user}:
|
||||||
|
''
|
||||||
|
)
|
||||||
|
(
|
||||||
|
writeTextDir "etc/group" ''
|
||||||
|
root:x:0:
|
||||||
|
${user}:x:${toString gid}:
|
||||||
|
''
|
||||||
|
)
|
||||||
|
(
|
||||||
|
writeTextDir "etc/gshadow" ''
|
||||||
|
root:x::
|
||||||
|
${user}:x::
|
||||||
|
''
|
||||||
|
)
|
||||||
|
];
|
||||||
|
in
|
||||||
|
pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "bash-layered-with-user";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [ pkgs.bash pkgs.coreutils ] ++ nonRootShadowSetup { uid = 999; user = "somebody"; };
|
||||||
|
};
|
||||||
|
|
||||||
|
# basic example, with cross compilation
|
||||||
|
cross = let
|
||||||
|
# Cross compile for x86_64 if on aarch64
|
||||||
|
crossPkgs =
|
||||||
|
if pkgs.stdenv.hostPlatform.system == "aarch64-linux" then pkgsCross.gnu64
|
||||||
|
else pkgsCross.aarch64-multiplatform;
|
||||||
|
in crossPkgs.dockerTools.buildImage {
|
||||||
|
name = "hello-cross";
|
||||||
|
tag = "latest";
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-root";
|
||||||
|
pathsToLink = [ "/bin" ];
|
||||||
|
paths = [ crossPkgs.hello ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# layered image where a store path is itself a symlink
|
||||||
|
layeredStoreSymlink =
|
||||||
|
let
|
||||||
|
target = pkgs.writeTextDir "dir/target" "Content doesn't matter.";
|
||||||
|
symlink = pkgs.runCommand "symlink" {} "ln -s ${target} $out";
|
||||||
|
in
|
||||||
|
pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "layeredstoresymlink";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [ pkgs.bash symlink ];
|
||||||
|
} // { passthru = { inherit symlink; }; };
|
||||||
|
|
||||||
|
# image with registry/ prefix
|
||||||
|
prefixedImage = pkgs.dockerTools.buildImage {
|
||||||
|
name = "registry-1.docker.io/image";
|
||||||
|
tag = "latest";
|
||||||
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# layered image with registry/ prefix
|
||||||
|
prefixedLayeredImage = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "registry-1.docker.io/layered-image";
|
||||||
|
tag = "latest";
|
||||||
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# layered image with files owned by a user other than root
|
||||||
|
layeredImageWithFakeRootCommands = pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "layered-image-with-fake-root-commands";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [
|
||||||
|
pkgs.pkgsStatic.busybox
|
||||||
|
];
|
||||||
|
fakeRootCommands = ''
|
||||||
|
mkdir -p ./home/alice
|
||||||
|
chown 1000 ./home/alice
|
||||||
|
ln -s ${pkgs.hello.overrideAttrs (o: {
|
||||||
|
# A unique `hello` to make sure that it isn't included via another mechanism by accident.
|
||||||
|
configureFlags = o.configureFlags or [] ++ [ " --program-prefix=layeredImageWithFakeRootCommands-" ];
|
||||||
|
doCheck = false;
|
||||||
|
})} ./hello
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# tarball consisting of both bash and redis images
|
||||||
|
mergedBashAndRedis = pkgs.dockerTools.mergeImages [
|
||||||
|
bash
|
||||||
|
redis
|
||||||
|
];
|
||||||
|
|
||||||
|
# tarball consisting of bash (without tag) and redis images
|
||||||
|
mergedBashNoTagAndRedis = pkgs.dockerTools.mergeImages [
|
||||||
|
bashNoTag
|
||||||
|
redis
|
||||||
|
];
|
||||||
|
|
||||||
|
# tarball consisting of bash and layered image with different owner of the
|
||||||
|
# /home/alice directory
|
||||||
|
mergedBashFakeRoot = pkgs.dockerTools.mergeImages [
|
||||||
|
bash
|
||||||
|
layeredImageWithFakeRootCommands
|
||||||
|
];
|
||||||
|
|
||||||
|
mergeVaryingCompressor = pkgs.dockerTools.mergeImages [
|
||||||
|
redis
|
||||||
|
bashUncompressed
|
||||||
|
bashZstdCompressed
|
||||||
|
];
|
||||||
|
|
||||||
|
helloOnRoot = pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "hello";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [
|
||||||
|
(pkgs.buildEnv {
|
||||||
|
name = "hello-root";
|
||||||
|
paths = [ pkgs.hello ];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
config.Cmd = [ "hello" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
helloOnRootNoStore = pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "hello";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [
|
||||||
|
(pkgs.buildEnv {
|
||||||
|
name = "hello-root";
|
||||||
|
paths = [ pkgs.hello ];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
config.Cmd = [ "hello" ];
|
||||||
|
includeStorePaths = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
helloOnRootNoStoreFakechroot = pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "hello";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [
|
||||||
|
(pkgs.buildEnv {
|
||||||
|
name = "hello-root";
|
||||||
|
paths = [ pkgs.hello ];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
config.Cmd = [ "hello" ];
|
||||||
|
includeStorePaths = false;
|
||||||
|
enableFakechroot = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
etc =
|
||||||
|
let
|
||||||
|
inherit (pkgs) lib;
|
||||||
|
nixosCore = (evalMinimalConfig ({ config, ... }: {
|
||||||
|
imports = [
|
||||||
|
pkgs.pkgsModule
|
||||||
|
../../../nixos/modules/system/etc/etc.nix
|
||||||
|
];
|
||||||
|
environment.etc."some-config-file" = {
|
||||||
|
text = ''
|
||||||
|
127.0.0.1 localhost
|
||||||
|
::1 localhost
|
||||||
|
'';
|
||||||
|
# For executables:
|
||||||
|
# mode = "0755";
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
in pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "etc";
|
||||||
|
tag = "latest";
|
||||||
|
enableFakechroot = true;
|
||||||
|
fakeRootCommands = ''
|
||||||
|
mkdir -p /etc
|
||||||
|
${nixosCore.config.system.build.etcActivationCommands}
|
||||||
|
'';
|
||||||
|
config.Cmd = pkgs.writeScript "etc-cmd" ''
|
||||||
|
#!${pkgs.busybox}/bin/sh
|
||||||
|
${pkgs.busybox}/bin/cat /etc/some-config-file
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Example export of the bash image
|
||||||
|
exportBash = pkgs.dockerTools.exportImage { fromImage = bash; };
|
||||||
|
|
||||||
|
imageViaFakeChroot = pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "image-via-fake-chroot";
|
||||||
|
tag = "latest";
|
||||||
|
config.Cmd = [ "hello" ];
|
||||||
|
enableFakechroot = true;
|
||||||
|
# Crucially, instead of a relative path, this creates /bin, which is
|
||||||
|
# intercepted by fakechroot.
|
||||||
|
# This functionality is not available on darwin as of 2021.
|
||||||
|
fakeRootCommands = ''
|
||||||
|
mkdir /bin
|
||||||
|
ln -s ${pkgs.hello}/bin/hello /bin/hello
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
build-image-with-path = buildImage {
|
||||||
|
name = "build-image-with-path";
|
||||||
|
tag = "latest";
|
||||||
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
||||||
|
copyToRoot = [ pkgs.bashInteractive ./test-dummy ];
|
||||||
|
};
|
||||||
|
|
||||||
|
layered-image-with-path = pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "layered-image-with-path";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [ pkgs.bashInteractive ./test-dummy ];
|
||||||
|
};
|
||||||
|
|
||||||
|
build-image-with-architecture = buildImage {
|
||||||
|
name = "build-image-with-architecture";
|
||||||
|
tag = "latest";
|
||||||
|
architecture = "arm64";
|
||||||
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
||||||
|
copyToRoot = [ pkgs.bashInteractive ./test-dummy ];
|
||||||
|
};
|
||||||
|
|
||||||
|
layered-image-with-architecture = pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "layered-image-with-architecture";
|
||||||
|
tag = "latest";
|
||||||
|
architecture = "arm64";
|
||||||
|
contents = [ pkgs.bashInteractive ./test-dummy ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# ensure that caCertificates builds
|
||||||
|
image-with-certs = buildImage {
|
||||||
|
name = "image-with-certs";
|
||||||
|
tag = "latest";
|
||||||
|
|
||||||
|
copyToRoot = pkgs.buildEnv {
|
||||||
|
name = "image-with-certs-root";
|
||||||
|
paths = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.dockerTools.caCertificates
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-basic = streamNixShellImage {
|
||||||
|
name = "nix-shell-basic";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.hello;
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-hook = streamNixShellImage {
|
||||||
|
name = "nix-shell-hook";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.mkShell {
|
||||||
|
shellHook = ''
|
||||||
|
echo "This is the shell hook!"
|
||||||
|
exit
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-inputs = streamNixShellImage {
|
||||||
|
name = "nix-shell-inputs";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.mkShell {
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.hello
|
||||||
|
];
|
||||||
|
};
|
||||||
|
command = ''
|
||||||
|
hello
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-pass-as-file = streamNixShellImage {
|
||||||
|
name = "nix-shell-pass-as-file";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.mkShell {
|
||||||
|
str = "this is a string";
|
||||||
|
passAsFile = [ "str" ];
|
||||||
|
};
|
||||||
|
command = ''
|
||||||
|
cat "$strPath"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-run = streamNixShellImage {
|
||||||
|
name = "nix-shell-run";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.mkShell {};
|
||||||
|
run = ''
|
||||||
|
case "$-" in
|
||||||
|
*i*) echo This shell is interactive ;;
|
||||||
|
*) echo This shell is not interactive ;;
|
||||||
|
esac
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-command = streamNixShellImage {
|
||||||
|
name = "nix-shell-command";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.mkShell {};
|
||||||
|
command = ''
|
||||||
|
case "$-" in
|
||||||
|
*i*) echo This shell is interactive ;;
|
||||||
|
*) echo This shell is not interactive ;;
|
||||||
|
esac
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-writable-home = streamNixShellImage {
|
||||||
|
name = "nix-shell-writable-home";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.mkShell {};
|
||||||
|
run = ''
|
||||||
|
if [[ "$HOME" != "$(eval "echo ~$(whoami)")" ]]; then
|
||||||
|
echo "\$HOME ($HOME) is not the same as ~\$(whoami) ($(eval "echo ~$(whoami)"))"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! touch $HOME/test-file; then
|
||||||
|
echo "home directory is not writable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "home directory is writable"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-nonexistent-home = streamNixShellImage {
|
||||||
|
name = "nix-shell-nonexistent-home";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.mkShell {};
|
||||||
|
homeDirectory = "/homeless-shelter";
|
||||||
|
run = ''
|
||||||
|
if [[ "$HOME" != "$(eval "echo ~$(whoami)")" ]]; then
|
||||||
|
echo "\$HOME ($HOME) is not the same as ~\$(whoami) ($(eval "echo ~$(whoami)"))"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if -e $HOME; then
|
||||||
|
echo "home directory exists"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "home directory doesn't exist"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-shell-build-derivation = streamNixShellImage {
|
||||||
|
name = "nix-shell-build-derivation";
|
||||||
|
tag = "latest";
|
||||||
|
drv = pkgs.hello;
|
||||||
|
run = ''
|
||||||
|
buildDerivation
|
||||||
|
$out/bin/hello
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
173
pkgs/build-support/docker/nix-prefetch-docker
Executable file
173
pkgs/build-support/docker/nix-prefetch-docker
Executable file
|
@ -0,0 +1,173 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
set -e -o pipefail
|
||||||
|
|
||||||
|
os=
|
||||||
|
arch=
|
||||||
|
imageName=
|
||||||
|
imageTag=
|
||||||
|
imageDigest=
|
||||||
|
finalImageName=
|
||||||
|
finalImageTag=
|
||||||
|
hashType=$NIX_HASH_ALGO
|
||||||
|
hashFormat=$hashFormat
|
||||||
|
format=nix
|
||||||
|
|
||||||
|
usage(){
|
||||||
|
echo >&2 "syntax: nix-prefetch-docker [options] [IMAGE_NAME [IMAGE_TAG|IMAGE_DIGEST]]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--os os OS to fetch image for
|
||||||
|
--arch linux Arch to fetch image for
|
||||||
|
--image-name name Name of the image to fetch
|
||||||
|
--image-tag tag Image tag
|
||||||
|
--image-digest digest Image digest
|
||||||
|
--final-image-name name Desired name of the image
|
||||||
|
--final-image-tag tag Desired image tag
|
||||||
|
--json Output result in json format instead of nix
|
||||||
|
--quiet Only print the final result
|
||||||
|
"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
get_image_digest(){
|
||||||
|
local imageName=$1
|
||||||
|
local imageTag=$2
|
||||||
|
|
||||||
|
if test -z "$imageTag"; then
|
||||||
|
imageTag="latest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
skopeo --override-os "${os}" --override-arch "${arch}" --insecure-policy --tmpdir=$TMPDIR inspect "docker://$imageName:$imageTag" | jq '.Digest' -r
|
||||||
|
}
|
||||||
|
|
||||||
|
get_name() {
|
||||||
|
local imageName=$1
|
||||||
|
local imageTag=$2
|
||||||
|
|
||||||
|
echo "docker-image-$(echo "$imageName:$imageTag" | tr '/:' '-').tar"
|
||||||
|
}
|
||||||
|
|
||||||
|
argi=0
|
||||||
|
argfun=""
|
||||||
|
for arg; do
|
||||||
|
if test -z "$argfun"; then
|
||||||
|
case $arg in
|
||||||
|
--os) argfun=set_os;;
|
||||||
|
--arch) argfun=set_arch;;
|
||||||
|
--image-name) argfun=set_imageName;;
|
||||||
|
--image-tag) argfun=set_imageTag;;
|
||||||
|
--image-digest) argfun=set_imageDigest;;
|
||||||
|
--final-image-name) argfun=set_finalImageName;;
|
||||||
|
--final-image-tag) argfun=set_finalImageTag;;
|
||||||
|
--quiet) QUIET=true;;
|
||||||
|
--json) format=json;;
|
||||||
|
--help) usage; exit;;
|
||||||
|
*)
|
||||||
|
: $((++argi))
|
||||||
|
case $argi in
|
||||||
|
1) imageName=$arg;;
|
||||||
|
2) [[ $arg == *"sha256"* ]] && imageDigest=$arg || imageTag=$arg;;
|
||||||
|
*) exit 1;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
case $argfun in
|
||||||
|
set_*)
|
||||||
|
var=${argfun#set_}
|
||||||
|
eval $var=$arg
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
argfun=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if test -z "$imageName"; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$os"; then
|
||||||
|
os=linux
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$arch"; then
|
||||||
|
arch=amd64
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$hashType"; then
|
||||||
|
hashType=sha256
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$hashFormat"; then
|
||||||
|
hashFormat=base32
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$finalImageName"; then
|
||||||
|
finalImageName="$imageName"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$finalImageTag"; then
|
||||||
|
if test -z "$imageTag"; then
|
||||||
|
finalImageTag="latest"
|
||||||
|
else
|
||||||
|
finalImageTag="$imageTag"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$imageDigest"; then
|
||||||
|
imageDigest=$(get_image_digest $imageName $imageTag)
|
||||||
|
fi
|
||||||
|
|
||||||
|
sourceUrl="docker://$imageName@$imageDigest"
|
||||||
|
|
||||||
|
tmpPath="$(mktemp -d "${TMPDIR:-/tmp}/skopeo-copy-tmp-XXXXXXXX")"
|
||||||
|
trap "rm -rf \"$tmpPath\"" EXIT
|
||||||
|
|
||||||
|
tmpFile="$tmpPath/$(get_name $finalImageName $finalImageTag)"
|
||||||
|
|
||||||
|
if test -z "$QUIET"; then
|
||||||
|
skopeo --insecure-policy --tmpdir=$TMPDIR --override-os ${os} --override-arch ${arch} copy "$sourceUrl" "docker-archive://$tmpFile:$finalImageName:$finalImageTag" >&2
|
||||||
|
else
|
||||||
|
skopeo --insecure-policy --tmpdir=$TMPDIR --override-os ${os} --override-arch ${arch} copy "$sourceUrl" "docker-archive://$tmpFile:$finalImageName:$finalImageTag" > /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compute the hash.
|
||||||
|
imageHash=$(nix-hash --flat --type $hashType --base32 "$tmpFile")
|
||||||
|
|
||||||
|
# Add the downloaded file to Nix store.
|
||||||
|
finalPath=$(nix-store --add-fixed "$hashType" "$tmpFile")
|
||||||
|
|
||||||
|
if test -z "$QUIET"; then
|
||||||
|
echo "-> ImageName: $imageName" >&2
|
||||||
|
echo "-> ImageDigest: $imageDigest" >&2
|
||||||
|
echo "-> FinalImageName: $finalImageName" >&2
|
||||||
|
echo "-> FinalImageTag: $finalImageTag" >&2
|
||||||
|
echo "-> ImagePath: $finalPath" >&2
|
||||||
|
echo "-> ImageHash: $imageHash" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$format" == "nix" ]; then
|
||||||
|
cat <<EOF
|
||||||
|
{
|
||||||
|
imageName = "$imageName";
|
||||||
|
imageDigest = "$imageDigest";
|
||||||
|
sha256 = "$imageHash";
|
||||||
|
finalImageName = "$finalImageName";
|
||||||
|
finalImageTag = "$finalImageTag";
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
{
|
||||||
|
"imageName": "$imageName",
|
||||||
|
"imageDigest": "$imageDigest",
|
||||||
|
"sha256": "$imageHash",
|
||||||
|
"finalImageName": "$finalImageName",
|
||||||
|
"finalImageTag": "$finalImageTag"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
fi
|
25
pkgs/build-support/docker/nix-prefetch-docker.nix
Normal file
25
pkgs/build-support/docker/nix-prefetch-docker.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{ lib, stdenv, makeWrapper, nix, skopeo, jq }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "nix-prefetch-docker";
|
||||||
|
|
||||||
|
nativeBuildInputs = [ makeWrapper ];
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
install -vD ${./nix-prefetch-docker} $out/bin/$name;
|
||||||
|
wrapProgram $out/bin/$name \
|
||||||
|
--prefix PATH : ${lib.makeBinPath [ nix skopeo jq ]} \
|
||||||
|
--set HOME /homeless-shelter
|
||||||
|
'';
|
||||||
|
|
||||||
|
preferLocalBuild = true;
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Script used to obtain source hashes for dockerTools.pullImage";
|
||||||
|
mainProgram = "nix-prefetch-docker";
|
||||||
|
maintainers = with maintainers; [ offline ];
|
||||||
|
platforms = platforms.unix;
|
||||||
|
};
|
||||||
|
}
|
398
pkgs/build-support/docker/stream_layered_image.py
Normal file
398
pkgs/build-support/docker/stream_layered_image.py
Normal file
|
@ -0,0 +1,398 @@
|
||||||
|
"""
|
||||||
|
This script generates a Docker image from a set of store paths. Uses
|
||||||
|
Docker Image Specification v1.2 as reference [1].
|
||||||
|
|
||||||
|
It expects a JSON file with the following properties and writes the
|
||||||
|
image as an uncompressed tarball to stdout:
|
||||||
|
|
||||||
|
* "architecture", "config", "os", "created", "repo_tag" correspond to
|
||||||
|
the fields with the same name on the image spec [2].
|
||||||
|
* "created" can be "now".
|
||||||
|
* "created" is also used as mtime for files added to the image.
|
||||||
|
* "uid", "gid", "uname", "gname" is the file ownership, for example,
|
||||||
|
0, 0, "root", "root".
|
||||||
|
* "store_layers" is a list of layers in ascending order, where each
|
||||||
|
layer is the list of store paths to include in that layer.
|
||||||
|
|
||||||
|
The main challenge for this script to create the final image in a
|
||||||
|
streaming fashion, without dumping any intermediate data to disk
|
||||||
|
for performance.
|
||||||
|
|
||||||
|
A docker image has each layer contents archived as separate tarballs,
|
||||||
|
and they later all get enveloped into a single big tarball in a
|
||||||
|
content addressed fashion. However, because how "tar" format works,
|
||||||
|
we have to know about the name (which includes the checksum in our
|
||||||
|
case) and the size of the tarball before we can start adding it to the
|
||||||
|
outer tarball. We achieve that by creating the layer tarballs twice;
|
||||||
|
on the first iteration we calculate the file size and the checksum,
|
||||||
|
and on the second one we actually stream the contents. 'add_layer_dir'
|
||||||
|
function does all this.
|
||||||
|
|
||||||
|
[1]: https://github.com/moby/moby/blob/master/image/spec/v1.2.md
|
||||||
|
[2]: https://github.com/moby/moby/blob/4fb59c20a4fb54f944fe170d0ff1d00eb4a24d6f/image/spec/v1.2.md#image-json-field-descriptions
|
||||||
|
""" # noqa: E501
|
||||||
|
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import hashlib
|
||||||
|
import pathlib
|
||||||
|
import tarfile
|
||||||
|
import itertools
|
||||||
|
import threading
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
|
def archive_paths_to(obj, paths, mtime, uid, gid, uname, gname):
|
||||||
|
"""
|
||||||
|
Writes the given store paths as a tar file to the given stream.
|
||||||
|
|
||||||
|
obj: Stream to write to. Should have a 'write' method.
|
||||||
|
paths: List of store paths.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# gettarinfo makes the paths relative, this makes them
|
||||||
|
# absolute again
|
||||||
|
def append_root(ti):
|
||||||
|
ti.name = "/" + ti.name
|
||||||
|
return ti
|
||||||
|
|
||||||
|
def apply_filters(ti):
|
||||||
|
ti.mtime = mtime
|
||||||
|
ti.uid = uid
|
||||||
|
ti.gid = gid
|
||||||
|
ti.uname = uname
|
||||||
|
ti.gname = gname
|
||||||
|
return ti
|
||||||
|
|
||||||
|
def nix_root(ti):
|
||||||
|
ti.mode = 0o0755 # rwxr-xr-x
|
||||||
|
return ti
|
||||||
|
|
||||||
|
def dir(path):
|
||||||
|
ti = tarfile.TarInfo(path)
|
||||||
|
ti.type = tarfile.DIRTYPE
|
||||||
|
return ti
|
||||||
|
|
||||||
|
with tarfile.open(fileobj=obj, mode="w|") as tar:
|
||||||
|
# To be consistent with the docker utilities, we need to have
|
||||||
|
# these directories first when building layer tarballs.
|
||||||
|
tar.addfile(apply_filters(nix_root(dir("/nix"))))
|
||||||
|
tar.addfile(apply_filters(nix_root(dir("/nix/store"))))
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
path = pathlib.Path(path)
|
||||||
|
if path.is_symlink():
|
||||||
|
files = [path]
|
||||||
|
else:
|
||||||
|
files = itertools.chain([path], path.rglob("*"))
|
||||||
|
|
||||||
|
for filename in sorted(files):
|
||||||
|
ti = append_root(tar.gettarinfo(filename))
|
||||||
|
|
||||||
|
# copy hardlinks as regular files
|
||||||
|
if ti.islnk():
|
||||||
|
ti.type = tarfile.REGTYPE
|
||||||
|
ti.linkname = ""
|
||||||
|
ti.size = filename.stat().st_size
|
||||||
|
|
||||||
|
ti = apply_filters(ti)
|
||||||
|
if ti.isfile():
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
tar.addfile(ti, f)
|
||||||
|
else:
|
||||||
|
tar.addfile(ti)
|
||||||
|
|
||||||
|
|
||||||
|
class ExtractChecksum:
|
||||||
|
"""
|
||||||
|
A writable stream which only calculates the final file size and
|
||||||
|
sha256sum, while discarding the actual contents.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._digest = hashlib.sha256()
|
||||||
|
self._size = 0
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
self._digest.update(data)
|
||||||
|
self._size += len(data)
|
||||||
|
|
||||||
|
def extract(self):
|
||||||
|
"""
|
||||||
|
Returns: Hex-encoded sha256sum and size as a tuple.
|
||||||
|
"""
|
||||||
|
return (self._digest.hexdigest(), self._size)
|
||||||
|
|
||||||
|
|
||||||
|
FromImage = namedtuple("FromImage", ["tar", "manifest_json", "image_json"])
|
||||||
|
# Some metadata for a layer
|
||||||
|
LayerInfo = namedtuple("LayerInfo", ["size", "checksum", "path", "paths"])
|
||||||
|
|
||||||
|
|
||||||
|
def load_from_image(from_image_str):
|
||||||
|
"""
|
||||||
|
Loads the given base image, if any.
|
||||||
|
|
||||||
|
from_image_str: Path to the base image archive.
|
||||||
|
|
||||||
|
Returns: A 'FromImage' object with references to the loaded base image,
|
||||||
|
or 'None' if no base image was provided.
|
||||||
|
"""
|
||||||
|
if from_image_str is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
base_tar = tarfile.open(from_image_str)
|
||||||
|
|
||||||
|
manifest_json_tarinfo = base_tar.getmember("manifest.json")
|
||||||
|
with base_tar.extractfile(manifest_json_tarinfo) as f:
|
||||||
|
manifest_json = json.load(f)
|
||||||
|
|
||||||
|
image_json_tarinfo = base_tar.getmember(manifest_json[0]["Config"])
|
||||||
|
with base_tar.extractfile(image_json_tarinfo) as f:
|
||||||
|
image_json = json.load(f)
|
||||||
|
|
||||||
|
return FromImage(base_tar, manifest_json, image_json)
|
||||||
|
|
||||||
|
|
||||||
|
def add_base_layers(tar, from_image):
|
||||||
|
"""
|
||||||
|
Adds the layers from the given base image to the final image.
|
||||||
|
|
||||||
|
tar: 'tarfile.TarFile' object for new layers to be added to.
|
||||||
|
from_image: 'FromImage' object with references to the loaded base image.
|
||||||
|
"""
|
||||||
|
if from_image is None:
|
||||||
|
print("No 'fromImage' provided", file=sys.stderr)
|
||||||
|
return []
|
||||||
|
|
||||||
|
layers = from_image.manifest_json[0]["Layers"]
|
||||||
|
checksums = from_image.image_json["rootfs"]["diff_ids"]
|
||||||
|
layers_checksums = zip(layers, checksums)
|
||||||
|
|
||||||
|
for num, (layer, checksum) in enumerate(layers_checksums, start=1):
|
||||||
|
layer_tarinfo = from_image.tar.getmember(layer)
|
||||||
|
checksum = re.sub(r"^sha256:", "", checksum)
|
||||||
|
|
||||||
|
tar.addfile(layer_tarinfo, from_image.tar.extractfile(layer_tarinfo))
|
||||||
|
path = layer_tarinfo.path
|
||||||
|
size = layer_tarinfo.size
|
||||||
|
|
||||||
|
print("Adding base layer", num, "from", path, file=sys.stderr)
|
||||||
|
yield LayerInfo(size=size, checksum=checksum, path=path, paths=[path])
|
||||||
|
|
||||||
|
from_image.tar.close()
|
||||||
|
|
||||||
|
|
||||||
|
def overlay_base_config(from_image, final_config):
|
||||||
|
"""
|
||||||
|
Overlays the final image 'config' JSON on top of selected defaults from the
|
||||||
|
base image 'config' JSON.
|
||||||
|
|
||||||
|
from_image: 'FromImage' object with references to the loaded base image.
|
||||||
|
final_config: 'dict' object of the final image 'config' JSON.
|
||||||
|
"""
|
||||||
|
if from_image is None:
|
||||||
|
return final_config
|
||||||
|
|
||||||
|
base_config = from_image.image_json["config"]
|
||||||
|
|
||||||
|
# Preserve environment from base image
|
||||||
|
final_env = base_config.get("Env", []) + final_config.get("Env", [])
|
||||||
|
if final_env:
|
||||||
|
# Resolve duplicates (last one wins) and format back as list
|
||||||
|
resolved_env = {entry.split("=", 1)[0]: entry for entry in final_env}
|
||||||
|
final_config["Env"] = list(resolved_env.values())
|
||||||
|
return final_config
|
||||||
|
|
||||||
|
|
||||||
|
def add_layer_dir(tar, paths, store_dir, mtime, uid, gid, uname, gname):
|
||||||
|
"""
|
||||||
|
Appends given store paths to a TarFile object as a new layer.
|
||||||
|
|
||||||
|
tar: 'tarfile.TarFile' object for the new layer to be added to.
|
||||||
|
paths: List of store paths.
|
||||||
|
store_dir: the root directory of the nix store
|
||||||
|
mtime: 'mtime' of the added files and the layer tarball.
|
||||||
|
Should be an integer representing a POSIX time.
|
||||||
|
|
||||||
|
Returns: A 'LayerInfo' object containing some metadata of
|
||||||
|
the layer added.
|
||||||
|
"""
|
||||||
|
|
||||||
|
invalid_paths = [i for i in paths if not i.startswith(store_dir)]
|
||||||
|
assert len(invalid_paths) == 0, \
|
||||||
|
f"Expecting absolute paths from {store_dir}, but got: {invalid_paths}"
|
||||||
|
|
||||||
|
# First, calculate the tarball checksum and the size.
|
||||||
|
extract_checksum = ExtractChecksum()
|
||||||
|
archive_paths_to(
|
||||||
|
extract_checksum,
|
||||||
|
paths,
|
||||||
|
mtime, uid, gid, uname, gname
|
||||||
|
)
|
||||||
|
(checksum, size) = extract_checksum.extract()
|
||||||
|
|
||||||
|
path = f"{checksum}/layer.tar"
|
||||||
|
layer_tarinfo = tarfile.TarInfo(path)
|
||||||
|
layer_tarinfo.size = size
|
||||||
|
layer_tarinfo.mtime = mtime
|
||||||
|
|
||||||
|
# Then actually stream the contents to the outer tarball.
|
||||||
|
read_fd, write_fd = os.pipe()
|
||||||
|
with open(read_fd, "rb") as read, open(write_fd, "wb") as write:
|
||||||
|
def producer():
|
||||||
|
archive_paths_to(
|
||||||
|
write,
|
||||||
|
paths,
|
||||||
|
mtime, uid, gid, uname, gname
|
||||||
|
)
|
||||||
|
write.close()
|
||||||
|
|
||||||
|
# Closing the write end of the fifo also closes the read end,
|
||||||
|
# so we don't need to wait until this thread is finished.
|
||||||
|
#
|
||||||
|
# Any exception from the thread will get printed by the default
|
||||||
|
# exception handler, and the 'addfile' call will fail since it
|
||||||
|
# won't be able to read required amount of bytes.
|
||||||
|
threading.Thread(target=producer).start()
|
||||||
|
tar.addfile(layer_tarinfo, read)
|
||||||
|
|
||||||
|
return LayerInfo(size=size, checksum=checksum, path=path, paths=paths)
|
||||||
|
|
||||||
|
|
||||||
|
def add_customisation_layer(target_tar, customisation_layer, mtime):
|
||||||
|
"""
|
||||||
|
Adds the customisation layer as a new layer. This is layer is structured
|
||||||
|
differently; given store path has the 'layer.tar' and corresponding
|
||||||
|
sha256sum ready.
|
||||||
|
|
||||||
|
tar: 'tarfile.TarFile' object for the new layer to be added to.
|
||||||
|
customisation_layer: Path containing the layer archive.
|
||||||
|
mtime: 'mtime' of the added layer tarball.
|
||||||
|
"""
|
||||||
|
|
||||||
|
checksum_path = os.path.join(customisation_layer, "checksum")
|
||||||
|
with open(checksum_path) as f:
|
||||||
|
checksum = f.read().strip()
|
||||||
|
assert len(checksum) == 64, f"Invalid sha256 at ${checksum_path}."
|
||||||
|
|
||||||
|
layer_path = os.path.join(customisation_layer, "layer.tar")
|
||||||
|
|
||||||
|
path = f"{checksum}/layer.tar"
|
||||||
|
tarinfo = target_tar.gettarinfo(layer_path)
|
||||||
|
tarinfo.name = path
|
||||||
|
tarinfo.mtime = mtime
|
||||||
|
|
||||||
|
with open(layer_path, "rb") as f:
|
||||||
|
target_tar.addfile(tarinfo, f)
|
||||||
|
|
||||||
|
return LayerInfo(
|
||||||
|
size=None,
|
||||||
|
checksum=checksum,
|
||||||
|
path=path,
|
||||||
|
paths=[customisation_layer]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def add_bytes(tar, path, content, mtime):
|
||||||
|
"""
|
||||||
|
Adds a file to the tarball with given path and contents.
|
||||||
|
|
||||||
|
tar: 'tarfile.TarFile' object.
|
||||||
|
path: Path of the file as a string.
|
||||||
|
content: Contents of the file.
|
||||||
|
mtime: 'mtime' of the file. Should be an integer representing a POSIX time.
|
||||||
|
"""
|
||||||
|
assert type(content) is bytes
|
||||||
|
|
||||||
|
ti = tarfile.TarInfo(path)
|
||||||
|
ti.size = len(content)
|
||||||
|
ti.mtime = mtime
|
||||||
|
tar.addfile(ti, io.BytesIO(content))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open(sys.argv[1], "r") as f:
|
||||||
|
conf = json.load(f)
|
||||||
|
|
||||||
|
created = (
|
||||||
|
datetime.now(tz=timezone.utc)
|
||||||
|
if conf["created"] == "now"
|
||||||
|
else datetime.fromisoformat(conf["created"])
|
||||||
|
)
|
||||||
|
mtime = int(created.timestamp())
|
||||||
|
uid = int(conf["uid"])
|
||||||
|
gid = int(conf["gid"])
|
||||||
|
uname = conf["uname"]
|
||||||
|
gname = conf["gname"]
|
||||||
|
store_dir = conf["store_dir"]
|
||||||
|
|
||||||
|
from_image = load_from_image(conf["from_image"])
|
||||||
|
|
||||||
|
with tarfile.open(mode="w|", fileobj=sys.stdout.buffer) as tar:
|
||||||
|
layers = []
|
||||||
|
layers.extend(add_base_layers(tar, from_image))
|
||||||
|
|
||||||
|
start = len(layers) + 1
|
||||||
|
for num, store_layer in enumerate(conf["store_layers"], start=start):
|
||||||
|
print("Creating layer", num, "from paths:", store_layer,
|
||||||
|
file=sys.stderr)
|
||||||
|
info = add_layer_dir(tar, store_layer, store_dir,
|
||||||
|
mtime, uid, gid, uname, gname)
|
||||||
|
layers.append(info)
|
||||||
|
|
||||||
|
print("Creating layer", len(layers) + 1, "with customisation...",
|
||||||
|
file=sys.stderr)
|
||||||
|
layers.append(
|
||||||
|
add_customisation_layer(
|
||||||
|
tar,
|
||||||
|
conf["customisation_layer"],
|
||||||
|
mtime=mtime
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
print("Adding manifests...", file=sys.stderr)
|
||||||
|
|
||||||
|
image_json = {
|
||||||
|
"created": datetime.isoformat(created),
|
||||||
|
"architecture": conf["architecture"],
|
||||||
|
"os": "linux",
|
||||||
|
"config": overlay_base_config(from_image, conf["config"]),
|
||||||
|
"rootfs": {
|
||||||
|
"diff_ids": [f"sha256:{layer.checksum}" for layer in layers],
|
||||||
|
"type": "layers",
|
||||||
|
},
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"created": datetime.isoformat(created),
|
||||||
|
"comment": f"store paths: {layer.paths}"
|
||||||
|
}
|
||||||
|
for layer in layers
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
image_json = json.dumps(image_json, indent=4).encode("utf-8")
|
||||||
|
image_json_checksum = hashlib.sha256(image_json).hexdigest()
|
||||||
|
image_json_path = f"{image_json_checksum}.json"
|
||||||
|
add_bytes(tar, image_json_path, image_json, mtime=mtime)
|
||||||
|
|
||||||
|
manifest_json = [
|
||||||
|
{
|
||||||
|
"Config": image_json_path,
|
||||||
|
"RepoTags": [conf["repo_tag"]],
|
||||||
|
"Layers": [layer.path for layer in layers],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
manifest_json = json.dumps(manifest_json, indent=4).encode("utf-8")
|
||||||
|
add_bytes(tar, "manifest.json", manifest_json, mtime=mtime)
|
||||||
|
|
||||||
|
print("Done.", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
24
pkgs/build-support/docker/tarsum.go
Normal file
24
pkgs/build-support/docker/tarsum.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"github.com/docker/docker/pkg/tarsum"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ts, err := tarsum.NewTarSum(os.Stdin, true, tarsum.Version1)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = io.Copy(ioutil.Discard, ts); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(ts.Sum(nil))
|
||||||
|
}
|
43
pkgs/build-support/docker/tarsum.nix
Normal file
43
pkgs/build-support/docker/tarsum.nix
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{ stdenv, go, docker, nixosTests }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "tarsum";
|
||||||
|
|
||||||
|
nativeBuildInputs = [ go ];
|
||||||
|
disallowedReferences = [ go ];
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
CGO_ENABLED = 0;
|
||||||
|
GOFLAGS = "-trimpath";
|
||||||
|
GO111MODULE = "off";
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
mkdir tarsum
|
||||||
|
cd tarsum
|
||||||
|
cp ${./tarsum.go} tarsum.go
|
||||||
|
export GOPATH=$(pwd)
|
||||||
|
export GOCACHE="$TMPDIR/go-cache"
|
||||||
|
mkdir -p src/github.com/docker/docker/pkg
|
||||||
|
ln -sT ${docker.moby-src}/pkg/tarsum src/github.com/docker/docker/pkg/tarsum
|
||||||
|
go build
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp tarsum $out/bin/
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
tests = {
|
||||||
|
dockerTools = nixosTests.docker-tools;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
meta.platforms = go.meta.platforms;
|
||||||
|
meta.mainProgram = "tarsum";
|
||||||
|
}
|
1
pkgs/build-support/docker/test-dummy/hello.txt
Normal file
1
pkgs/build-support/docker/test-dummy/hello.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Hello there!
|
|
@ -0,0 +1,48 @@
|
||||||
|
{ buildDotnetModule, emptyDirectory, mkNugetDeps, dotnet-sdk }:
|
||||||
|
|
||||||
|
{ pname
|
||||||
|
, version
|
||||||
|
# Name of the nuget package to install, if different from pname
|
||||||
|
, nugetName ? pname
|
||||||
|
# Hash of the nuget package to install, will be given on first build
|
||||||
|
, nugetSha256 ? ""
|
||||||
|
# Additional nuget deps needed by the tool package
|
||||||
|
, nugetDeps ? (_: [])
|
||||||
|
# Executables to wrap into `$out/bin`, same as in `buildDotnetModule`, but with
|
||||||
|
# a default of `pname` instead of null, to avoid auto-wrapping everything
|
||||||
|
, executables ? pname
|
||||||
|
# The dotnet runtime to use, dotnet tools need a full SDK to function
|
||||||
|
, dotnet-runtime ? dotnet-sdk
|
||||||
|
, ...
|
||||||
|
} @ args:
|
||||||
|
|
||||||
|
buildDotnetModule (args // {
|
||||||
|
inherit pname version dotnet-runtime executables;
|
||||||
|
|
||||||
|
src = emptyDirectory;
|
||||||
|
|
||||||
|
nugetDeps = mkNugetDeps {
|
||||||
|
name = pname;
|
||||||
|
nugetDeps = { fetchNuGet }: [
|
||||||
|
(fetchNuGet { pname = nugetName; inherit version; sha256 = nugetSha256; })
|
||||||
|
] ++ (nugetDeps fetchNuGet);
|
||||||
|
};
|
||||||
|
|
||||||
|
projectFile = "";
|
||||||
|
|
||||||
|
useDotnetFromEnv = true;
|
||||||
|
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
dotnet tool install --tool-path $out/lib/${pname} ${nugetName}
|
||||||
|
|
||||||
|
# remove files that contain nix store paths to temp nuget sources we made
|
||||||
|
find $out -name 'project.assets.json' -delete
|
||||||
|
find $out -name '.nupkg.metadata' -delete
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
})
|
323
pkgs/build-support/dotnet/build-dotnet-module/default.nix
Normal file
323
pkgs/build-support/dotnet/build-dotnet-module/default.nix
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
{ lib
|
||||||
|
, stdenvNoCC
|
||||||
|
, callPackage
|
||||||
|
, writeShellScript
|
||||||
|
, srcOnly
|
||||||
|
, linkFarmFromDrvs
|
||||||
|
, symlinkJoin
|
||||||
|
, makeWrapper
|
||||||
|
, dotnetCorePackages
|
||||||
|
, mkNugetSource
|
||||||
|
, mkNugetDeps
|
||||||
|
, nuget-to-nix
|
||||||
|
, cacert
|
||||||
|
, coreutils
|
||||||
|
, runtimeShellPackage
|
||||||
|
}:
|
||||||
|
|
||||||
|
{ name ? "${args.pname}-${args.version}"
|
||||||
|
, pname ? name
|
||||||
|
, enableParallelBuilding ? true
|
||||||
|
, doCheck ? false
|
||||||
|
# Flags to pass to `makeWrapper`. This is done to avoid double wrapping.
|
||||||
|
, makeWrapperArgs ? [ ]
|
||||||
|
|
||||||
|
# Flags to pass to `dotnet restore`.
|
||||||
|
, dotnetRestoreFlags ? [ ]
|
||||||
|
# Flags to pass to `dotnet build`.
|
||||||
|
, dotnetBuildFlags ? [ ]
|
||||||
|
# Flags to pass to `dotnet test`, if running tests is enabled.
|
||||||
|
, dotnetTestFlags ? [ ]
|
||||||
|
# Flags to pass to `dotnet install`.
|
||||||
|
, dotnetInstallFlags ? [ ]
|
||||||
|
# Flags to pass to `dotnet pack`.
|
||||||
|
, dotnetPackFlags ? [ ]
|
||||||
|
# Flags to pass to dotnet in all phases.
|
||||||
|
, dotnetFlags ? [ ]
|
||||||
|
|
||||||
|
# The path to publish the project to. When unset, the directory "$out/lib/$pname" is used.
|
||||||
|
, installPath ? null
|
||||||
|
# The binaries that should get installed to `$out/bin`, relative to `$installPath/`. These get wrapped accordingly.
|
||||||
|
# Unfortunately, dotnet has no method for doing this automatically.
|
||||||
|
# If unset, all executables in the projects root will get installed. This may cause bloat!
|
||||||
|
, executables ? null
|
||||||
|
# Packs a project as a `nupkg`, and installs it to `$out/share`. If set to `true`, the derivation can be used as a dependency for another dotnet project by adding it to `projectReferences`.
|
||||||
|
, packNupkg ? false
|
||||||
|
# The packages project file, which contains instructions on how to compile it. This can be an array of multiple project files as well.
|
||||||
|
, projectFile ? null
|
||||||
|
# The NuGet dependency file. This locks all NuGet dependency versions, as otherwise they cannot be deterministically fetched.
|
||||||
|
# This can be generated by running the `passthru.fetch-deps` script.
|
||||||
|
, nugetDeps ? null
|
||||||
|
# A list of derivations containing nupkg packages for local project references.
|
||||||
|
# Referenced derivations can be built with `buildDotnetModule` with `packNupkg=true` flag.
|
||||||
|
# Since we are sharing them as nugets they must be added to csproj/fsproj files as `PackageReference` as well.
|
||||||
|
# For example, your project has a local dependency:
|
||||||
|
# <ProjectReference Include="../foo/bar.fsproj" />
|
||||||
|
# To enable discovery through `projectReferences` you would need to add a line:
|
||||||
|
# <ProjectReference Include="../foo/bar.fsproj" />
|
||||||
|
# <PackageReference Include="bar" Version="*" Condition=" '$(ContinuousIntegrationBuild)'=='true' "/>
|
||||||
|
, projectReferences ? [ ]
|
||||||
|
# Libraries that need to be available at runtime should be passed through this.
|
||||||
|
# These get wrapped into `LD_LIBRARY_PATH`.
|
||||||
|
, runtimeDeps ? [ ]
|
||||||
|
# The dotnet runtime ID. If null, fetch-deps will gather dependencies for all
|
||||||
|
# platforms in meta.platforms which are supported by the sdk.
|
||||||
|
, runtimeId ? null
|
||||||
|
|
||||||
|
# Tests to disable. This gets passed to `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all frameworks.
|
||||||
|
# See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details for more details.
|
||||||
|
, disabledTests ? [ ]
|
||||||
|
# The project file to run unit tests against. This is usually referenced in the regular project file, but sometimes it needs to be manually set.
|
||||||
|
# It gets restored and build, but not installed. You may need to regenerate your nuget lockfile after setting this.
|
||||||
|
, testProjectFile ? ""
|
||||||
|
|
||||||
|
# The type of build to perform. This is passed to `dotnet` with the `--configuration` flag. Possible values are `Release`, `Debug`, etc.
|
||||||
|
, buildType ? "Release"
|
||||||
|
# If set to true, builds the application as a self-contained - removing the runtime dependency on dotnet
|
||||||
|
, selfContainedBuild ? false
|
||||||
|
# Whether to use an alternative wrapper, that executes the application DLL using the dotnet runtime from the user environment. `dotnet-runtime` is provided as a default in case no .NET is installed
|
||||||
|
# This is useful for .NET tools and applications that may need to run under different .NET runtimes
|
||||||
|
, useDotnetFromEnv ? false
|
||||||
|
# Whether to explicitly enable UseAppHost when building. This is redundant if useDotnetFromEnv is enabledz
|
||||||
|
, useAppHost ? true
|
||||||
|
# The dotnet SDK to use.
|
||||||
|
, dotnet-sdk ? dotnetCorePackages.sdk_6_0
|
||||||
|
# The dotnet runtime to use.
|
||||||
|
, dotnet-runtime ? dotnetCorePackages.runtime_6_0
|
||||||
|
# The dotnet SDK to run tests against. This can differentiate from the SDK compiled against.
|
||||||
|
, dotnet-test-sdk ? dotnet-sdk
|
||||||
|
, ...
|
||||||
|
} @ args:
|
||||||
|
|
||||||
|
let
|
||||||
|
platforms =
|
||||||
|
if args ? meta.platforms
|
||||||
|
then lib.intersectLists args.meta.platforms dotnet-sdk.meta.platforms
|
||||||
|
else dotnet-sdk.meta.platforms;
|
||||||
|
|
||||||
|
inherit (callPackage ./hooks {
|
||||||
|
inherit dotnet-sdk dotnet-test-sdk disabledTests nuget-source dotnet-runtime runtimeDeps buildType;
|
||||||
|
runtimeId =
|
||||||
|
if runtimeId != null
|
||||||
|
then runtimeId
|
||||||
|
else dotnetCorePackages.systemToDotnetRid stdenvNoCC.targetPlatform.system;
|
||||||
|
}) dotnetConfigureHook dotnetBuildHook dotnetCheckHook dotnetInstallHook dotnetFixupHook;
|
||||||
|
|
||||||
|
localDeps =
|
||||||
|
if (projectReferences != [ ])
|
||||||
|
then linkFarmFromDrvs "${name}-project-references" projectReferences
|
||||||
|
else null;
|
||||||
|
|
||||||
|
_nugetDeps =
|
||||||
|
if (nugetDeps != null) then
|
||||||
|
if lib.isDerivation nugetDeps
|
||||||
|
then nugetDeps
|
||||||
|
else mkNugetDeps {
|
||||||
|
inherit name;
|
||||||
|
sourceFile = nugetDeps;
|
||||||
|
}
|
||||||
|
else throw "Defining the `nugetDeps` attribute is required, as to lock the NuGet dependencies. This file can be generated by running the `passthru.fetch-deps` script.";
|
||||||
|
|
||||||
|
# contains the actual package dependencies
|
||||||
|
dependenciesSource = mkNugetSource {
|
||||||
|
name = "${name}-dependencies-source";
|
||||||
|
description = "A Nuget source with the dependencies for ${name}";
|
||||||
|
deps = [ _nugetDeps ] ++ lib.optional (localDeps != null) localDeps;
|
||||||
|
};
|
||||||
|
|
||||||
|
# this contains all the nuget packages that are implicitly referenced by the dotnet
|
||||||
|
# build system. having them as separate deps allows us to avoid having to regenerate
|
||||||
|
# a packages dependencies when the dotnet-sdk version changes
|
||||||
|
sdkDeps = lib.lists.flatten [ dotnet-sdk.packages ];
|
||||||
|
|
||||||
|
sdkSource = let
|
||||||
|
version = dotnet-sdk.version or (lib.concatStringsSep "-" dotnet-sdk.versions);
|
||||||
|
in mkNugetSource {
|
||||||
|
name = "dotnet-sdk-${version}-source";
|
||||||
|
deps = sdkDeps;
|
||||||
|
};
|
||||||
|
|
||||||
|
nuget-source = symlinkJoin {
|
||||||
|
name = "${name}-nuget-source";
|
||||||
|
paths = [ dependenciesSource sdkSource ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nugetDepsFile = _nugetDeps.sourceFile;
|
||||||
|
in
|
||||||
|
stdenvNoCC.mkDerivation (args // {
|
||||||
|
nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
|
||||||
|
dotnetConfigureHook
|
||||||
|
dotnetBuildHook
|
||||||
|
dotnetCheckHook
|
||||||
|
dotnetInstallHook
|
||||||
|
dotnetFixupHook
|
||||||
|
|
||||||
|
cacert
|
||||||
|
makeWrapper
|
||||||
|
dotnet-sdk
|
||||||
|
];
|
||||||
|
|
||||||
|
# Parse the version attr into a format acceptable for the Version msbuild property
|
||||||
|
# The actual version attr is saved in InformationalVersion, which accepts an arbitrary string
|
||||||
|
versionForDotnet = if !(lib.hasAttr "version" args) || args.version == null
|
||||||
|
then null else let
|
||||||
|
components = lib.pipe args.version [
|
||||||
|
lib.splitVersion
|
||||||
|
(lib.filter (x: (lib.strings.match "[0-9]+" x) != null))
|
||||||
|
(lib.filter (x: (lib.toIntBase10 x) < 65535)) # one version component in dotnet has to fit in 16 bits
|
||||||
|
];
|
||||||
|
in if (lib.length components) == 0
|
||||||
|
then null
|
||||||
|
else lib.concatStringsSep "." ((lib.take 4 components)
|
||||||
|
++ (if (lib.length components) < 4
|
||||||
|
then lib.replicate (4 - (lib.length components)) "0"
|
||||||
|
else [ ]));
|
||||||
|
|
||||||
|
makeWrapperArgs = args.makeWrapperArgs or [ ] ++ [
|
||||||
|
"--prefix LD_LIBRARY_PATH : ${dotnet-sdk.icu}/lib"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Stripping breaks the executable
|
||||||
|
dontStrip = args.dontStrip or true;
|
||||||
|
|
||||||
|
# gappsWrapperArgs gets included when wrapping for dotnet, as to avoid double wrapping
|
||||||
|
dontWrapGApps = args.dontWrapGApps or true;
|
||||||
|
|
||||||
|
inherit selfContainedBuild useAppHost useDotnetFromEnv;
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
inherit nuget-source;
|
||||||
|
} // lib.optionalAttrs (!lib.isDerivation nugetDeps) {
|
||||||
|
fetch-deps =
|
||||||
|
let
|
||||||
|
flags = dotnetFlags ++ dotnetRestoreFlags;
|
||||||
|
runtimeIds =
|
||||||
|
if runtimeId != null
|
||||||
|
then [ runtimeId ]
|
||||||
|
else map (system: dotnetCorePackages.systemToDotnetRid system) platforms;
|
||||||
|
defaultDepsFile =
|
||||||
|
# Wire in the nugetDeps file such that running the script with no args
|
||||||
|
# runs it agains the correct deps file by default.
|
||||||
|
# Note that toString is necessary here as it results in the path at
|
||||||
|
# eval time (i.e. to the file in your local Nixpkgs checkout) rather
|
||||||
|
# than the Nix store path of the path after it's been imported.
|
||||||
|
if lib.isPath nugetDepsFile && !lib.hasPrefix "${builtins.storeDir}/" (toString nugetDepsFile)
|
||||||
|
then toString nugetDepsFile
|
||||||
|
else ''$(mktemp -t "${pname}-deps-XXXXXX.nix")'';
|
||||||
|
in
|
||||||
|
writeShellScript "fetch-${pname}-deps" ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
export PATH="${lib.makeBinPath [ coreutils runtimeShellPackage dotnet-sdk (nuget-to-nix.override { inherit dotnet-sdk; }) ]}"
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--keep-sources|-k)
|
||||||
|
keepSources=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--help|-h)
|
||||||
|
echo "usage: $0 [--keep-sources] [--help] <output path>"
|
||||||
|
echo " <output path> The path to write the lockfile to. A temporary file is used if this is not set"
|
||||||
|
echo " --keep-sources Dont remove temporary directories upon exit, useful for debugging"
|
||||||
|
echo " --help Show this help message"
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ''${TMPDIR:-} == /run/user/* ]]; then
|
||||||
|
# /run/user is usually a tmpfs in RAM, which may be too small
|
||||||
|
# to store all downloaded dotnet packages
|
||||||
|
unset TMPDIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
export tmp=$(mktemp -td "deps-${pname}-XXXXXX")
|
||||||
|
HOME=$tmp/home
|
||||||
|
|
||||||
|
exitTrap() {
|
||||||
|
test -n "''${ranTrap-}" && return
|
||||||
|
ranTrap=1
|
||||||
|
|
||||||
|
if test -n "''${keepSources-}"; then
|
||||||
|
echo -e "Path to the source: $tmp/src\nPath to the fake home: $tmp/home"
|
||||||
|
else
|
||||||
|
rm -rf "$tmp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Since mktemp is used this will be empty if the script didnt succesfully complete
|
||||||
|
if ! test -s "$depsFile"; then
|
||||||
|
rm -rf "$depsFile"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trap exitTrap EXIT INT TERM
|
||||||
|
|
||||||
|
dotnetRestore() {
|
||||||
|
local -r project="''${1-}"
|
||||||
|
local -r rid="$2"
|
||||||
|
|
||||||
|
dotnet restore ''${project-} \
|
||||||
|
-p:ContinuousIntegrationBuild=true \
|
||||||
|
-p:Deterministic=true \
|
||||||
|
--packages "$tmp/nuget_pkgs" \
|
||||||
|
--runtime "$rid" \
|
||||||
|
--no-cache \
|
||||||
|
--force \
|
||||||
|
${lib.optionalString (!enableParallelBuilding) "--disable-parallel"} \
|
||||||
|
${lib.optionalString (flags != []) (toString flags)}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare -a projectFiles=( ${toString (lib.toList projectFile)} )
|
||||||
|
declare -a testProjectFiles=( ${toString (lib.toList testProjectFile)} )
|
||||||
|
|
||||||
|
export DOTNET_NOLOGO=1
|
||||||
|
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
|
|
||||||
|
depsFile=$(realpath "''${1:-${defaultDepsFile}}")
|
||||||
|
echo Will write lockfile to "$depsFile"
|
||||||
|
mkdir -p "$tmp/nuget_pkgs"
|
||||||
|
|
||||||
|
storeSrc="${srcOnly args}"
|
||||||
|
src=$tmp/src
|
||||||
|
cp -rT "$storeSrc" "$src"
|
||||||
|
chmod -R +w "$src"
|
||||||
|
|
||||||
|
cd "$src"
|
||||||
|
echo "Restoring project..."
|
||||||
|
|
||||||
|
${dotnet-sdk}/bin/dotnet tool restore
|
||||||
|
cp -r $HOME/.nuget/packages/* $tmp/nuget_pkgs || true
|
||||||
|
|
||||||
|
for rid in "${lib.concatStringsSep "\" \"" runtimeIds}"; do
|
||||||
|
(( ''${#projectFiles[@]} == 0 )) && dotnetRestore "" "$rid"
|
||||||
|
|
||||||
|
for project in ''${projectFiles[@]-} ''${testProjectFiles[@]-}; do
|
||||||
|
dotnetRestore "$project" "$rid"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
# Second copy, makes sure packages restored by ie. paket are included
|
||||||
|
cp -r $HOME/.nuget/packages/* $tmp/nuget_pkgs || true
|
||||||
|
|
||||||
|
echo "Succesfully restored project"
|
||||||
|
|
||||||
|
echo "Writing lockfile..."
|
||||||
|
|
||||||
|
excluded_sources="${lib.concatStringsSep " " sdkDeps}"
|
||||||
|
for excluded_source in ''${excluded_sources[@]}; do
|
||||||
|
ls "$excluded_source" >> "$tmp/excluded_list"
|
||||||
|
done
|
||||||
|
tmpFile="$tmp"/deps.nix
|
||||||
|
echo -e "# This file was automatically generated by passthru.fetch-deps.\n# Please dont edit it manually, your changes might get overwritten!\n" > "$tmpFile"
|
||||||
|
nuget-to-nix "$tmp/nuget_pkgs" "$tmp/excluded_list" >> "$tmpFile"
|
||||||
|
mv "$tmpFile" "$depsFile"
|
||||||
|
echo "Succesfully wrote lockfile to $depsFile"
|
||||||
|
'';
|
||||||
|
} // args.passthru or { };
|
||||||
|
|
||||||
|
meta = (args.meta or { }) // { inherit platforms; };
|
||||||
|
}
|
||||||
|
# ICU tries to unconditionally load files from /usr/share/icu on Darwin, which makes builds fail
|
||||||
|
# in the sandbox, so disable ICU on Darwin. This, as far as I know, shouldn't cause any built packages
|
||||||
|
# to behave differently, just the dotnet build tool.
|
||||||
|
// lib.optionalAttrs stdenvNoCC.isDarwin { DOTNET_SYSTEM_GLOBALIZATION_INVARIANT = 1; })
|
|
@ -0,0 +1,89 @@
|
||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, which
|
||||||
|
, coreutils
|
||||||
|
, zlib
|
||||||
|
, openssl
|
||||||
|
, callPackage
|
||||||
|
, makeSetupHook
|
||||||
|
, makeWrapper
|
||||||
|
, dotnet-sdk
|
||||||
|
, dotnet-test-sdk
|
||||||
|
, disabledTests
|
||||||
|
, nuget-source
|
||||||
|
, dotnet-runtime
|
||||||
|
, runtimeDeps
|
||||||
|
, buildType
|
||||||
|
, runtimeId
|
||||||
|
}:
|
||||||
|
assert (builtins.isString runtimeId);
|
||||||
|
|
||||||
|
let
|
||||||
|
libraryPath = lib.makeLibraryPath runtimeDeps;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
dotnetConfigureHook = callPackage ({ }:
|
||||||
|
makeSetupHook {
|
||||||
|
name = "dotnet-configure-hook";
|
||||||
|
propagatedBuildInputs = [ dotnet-sdk nuget-source ];
|
||||||
|
substitutions = {
|
||||||
|
nugetSource = nuget-source;
|
||||||
|
dynamicLinker = "${stdenv.cc}/nix-support/dynamic-linker";
|
||||||
|
libPath = lib.makeLibraryPath [
|
||||||
|
stdenv.cc.cc.lib
|
||||||
|
stdenv.cc.libc
|
||||||
|
dotnet-sdk.passthru.icu
|
||||||
|
zlib
|
||||||
|
openssl
|
||||||
|
];
|
||||||
|
inherit runtimeId;
|
||||||
|
};
|
||||||
|
} ./dotnet-configure-hook.sh) { };
|
||||||
|
|
||||||
|
dotnetBuildHook = callPackage ({ }:
|
||||||
|
makeSetupHook {
|
||||||
|
name = "dotnet-build-hook";
|
||||||
|
propagatedBuildInputs = [ dotnet-sdk ];
|
||||||
|
substitutions = {
|
||||||
|
inherit buildType runtimeId;
|
||||||
|
};
|
||||||
|
} ./dotnet-build-hook.sh) { };
|
||||||
|
|
||||||
|
dotnetCheckHook = callPackage ({ }:
|
||||||
|
makeSetupHook {
|
||||||
|
name = "dotnet-check-hook";
|
||||||
|
propagatedBuildInputs = [ dotnet-test-sdk ];
|
||||||
|
substitutions = {
|
||||||
|
inherit buildType runtimeId libraryPath;
|
||||||
|
disabledTests = lib.optionalString (disabledTests != [])
|
||||||
|
(let
|
||||||
|
escapedNames = lib.lists.map (n: lib.replaceStrings [","] ["%2C"] n) disabledTests;
|
||||||
|
filters = lib.lists.map (n: "FullyQualifiedName!=${n}") escapedNames;
|
||||||
|
in
|
||||||
|
"${lib.concatStringsSep "&" filters}");
|
||||||
|
};
|
||||||
|
} ./dotnet-check-hook.sh) { };
|
||||||
|
|
||||||
|
dotnetInstallHook = callPackage ({ }:
|
||||||
|
makeSetupHook {
|
||||||
|
name = "dotnet-install-hook";
|
||||||
|
propagatedBuildInputs = [ dotnet-sdk ];
|
||||||
|
substitutions = {
|
||||||
|
inherit buildType runtimeId;
|
||||||
|
};
|
||||||
|
} ./dotnet-install-hook.sh) { };
|
||||||
|
|
||||||
|
dotnetFixupHook = callPackage ({ }:
|
||||||
|
makeSetupHook {
|
||||||
|
name = "dotnet-fixup-hook";
|
||||||
|
propagatedBuildInputs = [ dotnet-runtime ];
|
||||||
|
substitutions = {
|
||||||
|
dotnetRuntime = dotnet-runtime;
|
||||||
|
runtimeDeps = libraryPath;
|
||||||
|
shell = stdenv.shell;
|
||||||
|
which = "${which}/bin/which";
|
||||||
|
dirname = "${coreutils}/bin/dirname";
|
||||||
|
realpath = "${coreutils}/bin/realpath";
|
||||||
|
};
|
||||||
|
} ./dotnet-fixup-hook.sh) { };
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
# inherit arguments from derivation
|
||||||
|
dotnetBuildFlags=( ${dotnetBuildFlags[@]-} )
|
||||||
|
|
||||||
|
dotnetBuildHook() {
|
||||||
|
echo "Executing dotnetBuildHook"
|
||||||
|
|
||||||
|
runHook preBuild
|
||||||
|
|
||||||
|
if [ "${enableParallelBuilding-}" ]; then
|
||||||
|
local -r maxCpuFlag="$NIX_BUILD_CORES"
|
||||||
|
local -r parallelBuildFlag="true"
|
||||||
|
else
|
||||||
|
local -r maxCpuFlag="1"
|
||||||
|
local -r parallelBuildFlag="false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${selfContainedBuild-}" ]; then
|
||||||
|
dotnetBuildFlags+=("-p:SelfContained=true")
|
||||||
|
else
|
||||||
|
dotnetBuildFlags+=("-p:SelfContained=false")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${useAppHost-}" ]; then
|
||||||
|
dotnetBuildFlags+=("-p:UseAppHost=true")
|
||||||
|
fi
|
||||||
|
|
||||||
|
local versionFlags=()
|
||||||
|
if [ "${version-}" ]; then
|
||||||
|
versionFlags+=("-p:InformationalVersion=${version-}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${versionForDotnet-}" ]; then
|
||||||
|
versionFlags+=("-p:Version=${versionForDotnet-}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
dotnetBuild() {
|
||||||
|
local -r project="${1-}"
|
||||||
|
|
||||||
|
runtimeIdFlags=()
|
||||||
|
if [[ "$project" == *.csproj ]] || [ "${selfContainedBuild-}" ]; then
|
||||||
|
runtimeIdFlags+=("--runtime @runtimeId@")
|
||||||
|
fi
|
||||||
|
|
||||||
|
env dotnet build ${project-} \
|
||||||
|
-maxcpucount:$maxCpuFlag \
|
||||||
|
-p:BuildInParallel=$parallelBuildFlag \
|
||||||
|
-p:ContinuousIntegrationBuild=true \
|
||||||
|
-p:Deterministic=true \
|
||||||
|
--configuration "@buildType@" \
|
||||||
|
--no-restore \
|
||||||
|
${versionFlags[@]} \
|
||||||
|
${runtimeIdFlags[@]} \
|
||||||
|
${dotnetBuildFlags[@]} \
|
||||||
|
${dotnetFlags[@]}
|
||||||
|
}
|
||||||
|
|
||||||
|
(( "${#projectFile[@]}" == 0 )) && dotnetBuild
|
||||||
|
|
||||||
|
for project in ${projectFile[@]} ${testProjectFile[@]-}; do
|
||||||
|
dotnetBuild "$project"
|
||||||
|
done
|
||||||
|
|
||||||
|
runHook postBuild
|
||||||
|
|
||||||
|
echo "Finished dotnetBuildHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -z "${dontDotnetBuild-}" && -z "${buildPhase-}" ]]; then
|
||||||
|
buildPhase=dotnetBuildHook
|
||||||
|
fi
|
|
@ -0,0 +1,46 @@
|
||||||
|
# inherit arguments from derivation
|
||||||
|
dotnetTestFlags=( ${dotnetTestFlags[@]-} )
|
||||||
|
|
||||||
|
dotnetCheckHook() {
|
||||||
|
echo "Executing dotnetCheckHook"
|
||||||
|
|
||||||
|
runHook preCheck
|
||||||
|
|
||||||
|
if [ "${disabledTests-}" ]; then
|
||||||
|
local -r disabledTestsFlag="--filter @disabledTests@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${enableParallelBuilding-}" ]; then
|
||||||
|
local -r maxCpuFlag="$NIX_BUILD_CORES"
|
||||||
|
else
|
||||||
|
local -r maxCpuFlag="1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for project in ${testProjectFile[@]-${projectFile[@]}}; do
|
||||||
|
runtimeIdFlags=()
|
||||||
|
if [[ "$project" == *.csproj ]]; then
|
||||||
|
runtimeIdFlags=("--runtime @runtimeId@")
|
||||||
|
fi
|
||||||
|
|
||||||
|
env "LD_LIBRARY_PATH=@libraryPath@" \
|
||||||
|
dotnet test "$project" \
|
||||||
|
-maxcpucount:$maxCpuFlag \
|
||||||
|
-p:ContinuousIntegrationBuild=true \
|
||||||
|
-p:Deterministic=true \
|
||||||
|
--configuration "@buildType@" \
|
||||||
|
--no-build \
|
||||||
|
--logger "console;verbosity=normal" \
|
||||||
|
${disabledTestsFlag-} \
|
||||||
|
${runtimeIdFlags[@]} \
|
||||||
|
"${dotnetTestFlags[@]}" \
|
||||||
|
"${dotnetFlags[@]}"
|
||||||
|
done
|
||||||
|
|
||||||
|
runHook postCheck
|
||||||
|
|
||||||
|
echo "Finished dotnetCheckHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -z "${dontDotnetCheck-}" && -z "${checkPhase-}" ]]; then
|
||||||
|
checkPhase=dotnetCheckHook
|
||||||
|
fi
|
|
@ -0,0 +1,82 @@
|
||||||
|
declare -a projectFile testProjectFile
|
||||||
|
|
||||||
|
# Inherit arguments from derivation
|
||||||
|
dotnetFlags=( ${dotnetFlags[@]-} )
|
||||||
|
dotnetRestoreFlags=( ${dotnetRestoreFlags[@]-} )
|
||||||
|
|
||||||
|
dotnetConfigureHook() {
|
||||||
|
echo "Executing dotnetConfigureHook"
|
||||||
|
|
||||||
|
runHook preConfigure
|
||||||
|
|
||||||
|
if [ -z "${enableParallelBuilding-}" ]; then
|
||||||
|
local -r parallelFlag="--disable-parallel"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dotnetRestore() {
|
||||||
|
local -r project="${1-}"
|
||||||
|
env dotnet restore ${project-} \
|
||||||
|
-p:ContinuousIntegrationBuild=true \
|
||||||
|
-p:Deterministic=true \
|
||||||
|
--runtime "@runtimeId@" \
|
||||||
|
--source "@nugetSource@/lib" \
|
||||||
|
${parallelFlag-} \
|
||||||
|
${dotnetRestoreFlags[@]} \
|
||||||
|
${dotnetFlags[@]}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate a NuGet.config file to make sure everything,
|
||||||
|
# including things like <Sdk /> dependencies, is restored from the proper source
|
||||||
|
cat <<EOF > "./NuGet.config"
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<clear />
|
||||||
|
<add key="nugetSource" value="@nugetSource@/lib" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Patch paket.dependencies and paket.lock (if found) to use the proper source. This ensures
|
||||||
|
# paket restore works correctly
|
||||||
|
# We use + instead of / in sed to avoid problems with slashes
|
||||||
|
find -name paket.dependencies -exec sed -i 's+source .*+source @nugetSource@/lib+g' {} \;
|
||||||
|
find -name paket.lock -exec sed -i 's+remote:.*+remote: @nugetSource@/lib+g' {} \;
|
||||||
|
|
||||||
|
env dotnet tool restore --add-source "@nugetSource@/lib"
|
||||||
|
|
||||||
|
(( "${#projectFile[@]}" == 0 )) && dotnetRestore
|
||||||
|
|
||||||
|
for project in ${projectFile[@]} ${testProjectFile[@]-}; do
|
||||||
|
dotnetRestore "$project"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Fixing up native binaries..."
|
||||||
|
# Find all native binaries and nuget libraries, and fix them up,
|
||||||
|
# by setting the proper interpreter and rpath to some commonly used libraries
|
||||||
|
for binary in $(find "$HOME/.nuget/packages/" -type f -executable); do
|
||||||
|
if patchelf --print-interpreter "$binary" >/dev/null 2>/dev/null; then
|
||||||
|
echo "Found binary: $binary, fixing it up..."
|
||||||
|
patchelf --set-interpreter "$(cat "@dynamicLinker@")" "$binary"
|
||||||
|
|
||||||
|
# This makes sure that if the binary requires some specific runtime dependencies, it can find it.
|
||||||
|
# This fixes dotnet-built binaries like crossgen2
|
||||||
|
patchelf \
|
||||||
|
--add-needed libicui18n.so \
|
||||||
|
--add-needed libicuuc.so \
|
||||||
|
--add-needed libz.so \
|
||||||
|
--add-needed libssl.so \
|
||||||
|
"$binary"
|
||||||
|
|
||||||
|
patchelf --set-rpath "@libPath@" "$binary"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
runHook postConfigure
|
||||||
|
|
||||||
|
echo "Finished dotnetConfigureHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -z "${dontDotnetConfigure-}" && -z "${configurePhase-}" ]]; then
|
||||||
|
configurePhase=dotnetConfigureHook
|
||||||
|
fi
|
|
@ -0,0 +1,57 @@
|
||||||
|
# Inherit arguments from the derivation
|
||||||
|
declare -a derivationMakeWrapperArgs="( ${makeWrapperArgs-} )"
|
||||||
|
makeWrapperArgs=( "${derivationMakeWrapperArgs[@]}" )
|
||||||
|
|
||||||
|
# First argument is the executable you want to wrap,
|
||||||
|
# the second is the destination for the wrapper.
|
||||||
|
wrapDotnetProgram() {
|
||||||
|
local dotnetRootFlags=()
|
||||||
|
|
||||||
|
if [ ! "${selfContainedBuild-}" ]; then
|
||||||
|
if [ "${useDotnetFromEnv-}" ]; then
|
||||||
|
# if dotnet CLI is available, set DOTNET_ROOT based on it. Otherwise set to default .NET runtime
|
||||||
|
dotnetRootFlags+=("--run" 'command -v dotnet &>/dev/null && export DOTNET_ROOT="$(@dirname@ "$(@realpath@ "$(@which@ dotnet)")")" || export DOTNET_ROOT="@dotnetRuntime@"')
|
||||||
|
dotnetRootFlags+=("--suffix" "PATH" ":" "@dotnetRuntime@/bin")
|
||||||
|
else
|
||||||
|
dotnetRootFlags+=("--set" "DOTNET_ROOT" "@dotnetRuntime@")
|
||||||
|
dotnetRootFlags+=("--prefix" "PATH" ":" "@dotnetRuntime@/bin")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
makeWrapper "$1" "$2" \
|
||||||
|
--suffix "LD_LIBRARY_PATH" : "@runtimeDeps@" \
|
||||||
|
"${dotnetRootFlags[@]}" \
|
||||||
|
"${gappsWrapperArgs[@]}" \
|
||||||
|
"${makeWrapperArgs[@]}"
|
||||||
|
|
||||||
|
echo "installed wrapper to "$2""
|
||||||
|
}
|
||||||
|
|
||||||
|
dotnetFixupHook() {
|
||||||
|
echo "Executing dotnetFixupPhase"
|
||||||
|
|
||||||
|
# check if executables is declared (including empty values, in which case we generate no executables)
|
||||||
|
if declare -p executables &>/dev/null; then
|
||||||
|
for executable in ${executables[@]}; do
|
||||||
|
path="${installPath-$out/lib/$pname}/$executable"
|
||||||
|
|
||||||
|
if test -x "$path"; then
|
||||||
|
wrapDotnetProgram "$path" "$out/bin/$(basename "$executable")"
|
||||||
|
else
|
||||||
|
echo "Specified binary \"$executable\" is either not an executable or does not exist!"
|
||||||
|
echo "Looked in $path"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
while IFS= read -d '' executable; do
|
||||||
|
wrapDotnetProgram "$executable" "$out/bin/$(basename "$executable")" \;
|
||||||
|
done < <(find "${installPath-$out/lib/$pname}" ! -name "*.dll" -executable -type f -print0)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Finished dotnetFixupPhase"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -z "${dontDotnetFixup-}" ]]; then
|
||||||
|
preFixupPhases+=" dotnetFixupHook"
|
||||||
|
fi
|
|
@ -0,0 +1,79 @@
|
||||||
|
# inherit arguments from derivation
|
||||||
|
dotnetInstallFlags=( ${dotnetInstallFlags[@]-} )
|
||||||
|
|
||||||
|
dotnetInstallHook() {
|
||||||
|
echo "Executing dotnetInstallHook"
|
||||||
|
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
if [ "${selfContainedBuild-}" ]; then
|
||||||
|
dotnetInstallFlags+=("--self-contained")
|
||||||
|
else
|
||||||
|
dotnetInstallFlags+=("--no-self-contained")
|
||||||
|
# https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained
|
||||||
|
# Trimming is only available for self-contained build, so force disable it here
|
||||||
|
dotnetInstallFlags+=("-p:PublishTrimmed=false")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${useAppHost-}" ]; then
|
||||||
|
dotnetInstallFlags+=("-p:UseAppHost=true")
|
||||||
|
fi
|
||||||
|
|
||||||
|
dotnetPublish() {
|
||||||
|
local -r project="${1-}"
|
||||||
|
|
||||||
|
runtimeIdFlags=()
|
||||||
|
if [[ "$project" == *.csproj ]] || [ "${selfContainedBuild-}" ]; then
|
||||||
|
runtimeIdFlags+=("--runtime @runtimeId@")
|
||||||
|
fi
|
||||||
|
|
||||||
|
env dotnet publish ${project-} \
|
||||||
|
-p:ContinuousIntegrationBuild=true \
|
||||||
|
-p:Deterministic=true \
|
||||||
|
--output "${installPath-$out/lib/$pname}" \
|
||||||
|
--configuration "@buildType@" \
|
||||||
|
--no-build \
|
||||||
|
${runtimeIdFlags[@]} \
|
||||||
|
${dotnetInstallFlags[@]} \
|
||||||
|
${dotnetFlags[@]}
|
||||||
|
}
|
||||||
|
|
||||||
|
dotnetPack() {
|
||||||
|
local -r project="${1-}"
|
||||||
|
env dotnet pack ${project-} \
|
||||||
|
-p:ContinuousIntegrationBuild=true \
|
||||||
|
-p:Deterministic=true \
|
||||||
|
--output "$out/share" \
|
||||||
|
--configuration "@buildType@" \
|
||||||
|
--no-build \
|
||||||
|
--runtime "@runtimeId@" \
|
||||||
|
${dotnetPackFlags[@]} \
|
||||||
|
${dotnetFlags[@]}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( "${#projectFile[@]}" == 0 )); then
|
||||||
|
dotnetPublish
|
||||||
|
else
|
||||||
|
for project in ${projectFile[@]}; do
|
||||||
|
dotnetPublish "$project"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${packNupkg-}" ]]; then
|
||||||
|
if (( "${#projectFile[@]}" == 0 )); then
|
||||||
|
dotnetPack
|
||||||
|
else
|
||||||
|
for project in ${projectFile[@]}; do
|
||||||
|
dotnetPack "$project"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
|
||||||
|
echo "Finished dotnetInstallHook"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -z "${dontDotnetInstall-}" && -z "${installPhase-}" ]]; then
|
||||||
|
installPhase=dotnetInstallHook
|
||||||
|
fi
|
116
pkgs/build-support/dotnet/build-dotnet-package/default.nix
Normal file
116
pkgs/build-support/dotnet/build-dotnet-package/default.nix
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
{ stdenv, lib, makeWrapper, pkg-config, mono, dotnetbuildhelpers }:
|
||||||
|
|
||||||
|
attrsOrig @
|
||||||
|
{ pname
|
||||||
|
, version
|
||||||
|
, nativeBuildInputs ? []
|
||||||
|
, xBuildFiles ? [ ]
|
||||||
|
, xBuildFlags ? [ "/p:Configuration=Release" ]
|
||||||
|
, outputFiles ? [ "bin/Release/*" ]
|
||||||
|
, dllFiles ? [ "*.dll" ]
|
||||||
|
, exeFiles ? [ "*.exe" ]
|
||||||
|
# Additional arguments to pass to the makeWrapper function, which wraps
|
||||||
|
# generated binaries.
|
||||||
|
, makeWrapperArgs ? [ ]
|
||||||
|
, ... }:
|
||||||
|
let
|
||||||
|
arrayToShell = (a: toString (map (lib.escape (lib.stringToCharacters "\\ ';$`()|<>\t") ) a));
|
||||||
|
|
||||||
|
attrs = {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkg-config
|
||||||
|
makeWrapper
|
||||||
|
dotnetbuildhelpers
|
||||||
|
mono
|
||||||
|
] ++ nativeBuildInputs;
|
||||||
|
|
||||||
|
configurePhase = ''
|
||||||
|
runHook preConfigure
|
||||||
|
|
||||||
|
[ -z "''${dontPlacateNuget-}" ] && placate-nuget.sh
|
||||||
|
[ -z "''${dontPlacatePaket-}" ] && placate-paket.sh
|
||||||
|
[ -z "''${dontPatchFSharpTargets-}" ] && patch-fsharp-targets.sh
|
||||||
|
|
||||||
|
runHook postConfigure
|
||||||
|
'';
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
|
||||||
|
echo Building dotNET packages...
|
||||||
|
|
||||||
|
# Probably needs to be moved to fsharp
|
||||||
|
if pkg-config FSharp.Core
|
||||||
|
then
|
||||||
|
export FSharpTargetsPath="$(dirname $(pkg-config FSharp.Core --variable=Libraries))/Microsoft.FSharp.Targets"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ran=""
|
||||||
|
for xBuildFile in ${arrayToShell xBuildFiles} ''${xBuildFilesExtra}
|
||||||
|
do
|
||||||
|
ran="yes"
|
||||||
|
xbuild ${arrayToShell xBuildFlags} ''${xBuildFlagsArray} $xBuildFile
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -z "$ran" ] && xbuild ${arrayToShell xBuildFlags} ''${xBuildFlagsArray}
|
||||||
|
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
dontStrip = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
target="$out/lib/dotnet/${pname}"
|
||||||
|
mkdir -p "$target"
|
||||||
|
|
||||||
|
cp -rv ${arrayToShell outputFiles} "''${outputFilesArray[@]}" "$target"
|
||||||
|
|
||||||
|
if [ -z "''${dontRemoveDuplicatedDlls-}" ]
|
||||||
|
then
|
||||||
|
pushd "$out"
|
||||||
|
remove-duplicated-dlls.sh
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -f
|
||||||
|
for dllPattern in ${arrayToShell dllFiles} ''${dllFilesArray[@]}
|
||||||
|
do
|
||||||
|
set +f
|
||||||
|
for dll in "$target"/$dllPattern
|
||||||
|
do
|
||||||
|
[ -f "$dll" ] || continue
|
||||||
|
if pkg-config $(basename -s .dll "$dll")
|
||||||
|
then
|
||||||
|
echo "$dll already exported by a buildInputs, not re-exporting"
|
||||||
|
else
|
||||||
|
create-pkg-config-for-dll.sh "$out/lib/pkgconfig" "$dll"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
set -f
|
||||||
|
for exePattern in ${arrayToShell exeFiles} ''${exeFilesArray[@]}
|
||||||
|
do
|
||||||
|
set +f
|
||||||
|
for exe in "$target"/$exePattern
|
||||||
|
do
|
||||||
|
[ -f "$exe" ] || continue
|
||||||
|
mkdir -p "$out"/bin
|
||||||
|
commandName="$(basename -s .exe "$(echo "$exe" | tr "[A-Z]" "[a-z]")")"
|
||||||
|
makeWrapper \
|
||||||
|
"${mono}/bin/mono" \
|
||||||
|
"$out"/bin/"$commandName" \
|
||||||
|
--add-flags "\"$exe\"" \
|
||||||
|
''${makeWrapperArgs}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation (attrs // (builtins.removeAttrs attrsOrig [ "nativeBuildInputs" ] ))
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
targetDir="$1"
|
||||||
|
dllFullPath="$2"
|
||||||
|
|
||||||
|
dllVersion="$(monodis --assembly "$dllFullPath" | grep ^Version: | cut -f 2 -d : | xargs)"
|
||||||
|
[ -z "$dllVersion" ] && echo "Defaulting dllVersion to 0.0.0" && dllVersion="0.0.0"
|
||||||
|
dllFileName="$(basename $dllFullPath)"
|
||||||
|
dllRootName="$(basename -s .dll $dllFileName)"
|
||||||
|
targetPcFile="$targetDir"/"$dllRootName".pc
|
||||||
|
|
||||||
|
mkdir -p "$targetDir"
|
||||||
|
|
||||||
|
cat > $targetPcFile << EOF
|
||||||
|
Libraries=$dllFullPath
|
||||||
|
|
||||||
|
Name: $dllRootName
|
||||||
|
Description: $dllRootName
|
||||||
|
Version: $dllVersion
|
||||||
|
Libs: -r:$dllFileName
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Created $targetPcFile"
|
18
pkgs/build-support/dotnet/dotnetbuildhelpers/default.nix
Normal file
18
pkgs/build-support/dotnet/dotnetbuildhelpers/default.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{ runCommand, mono, pkg-config }:
|
||||||
|
runCommand
|
||||||
|
"dotnetbuildhelpers"
|
||||||
|
{ preferLocalBuild = true; }
|
||||||
|
''
|
||||||
|
target="$out/bin"
|
||||||
|
mkdir -p "$target"
|
||||||
|
|
||||||
|
for script in ${./create-pkg-config-for-dll.sh} ${./patch-fsharp-targets.sh} ${./remove-duplicated-dlls.sh} ${./placate-nuget.sh} ${./placate-paket.sh}
|
||||||
|
do
|
||||||
|
scriptName="$(basename "$script" | cut -f 2- -d -)"
|
||||||
|
cp -v "$script" "$target"/"$scriptName"
|
||||||
|
chmod 755 "$target"/"$scriptName"
|
||||||
|
patchShebangs "$target"/"$scriptName"
|
||||||
|
substituteInPlace "$target"/"$scriptName" --replace pkg-config ${pkg-config}/bin/${pkg-config.targetPrefix}pkg-config
|
||||||
|
substituteInPlace "$target"/"$scriptName" --replace monodis ${mono}/bin/monodis
|
||||||
|
done
|
||||||
|
''
|
20
pkgs/build-support/dotnet/dotnetbuildhelpers/patch-fsharp-targets.sh
Executable file
20
pkgs/build-support/dotnet/dotnetbuildhelpers/patch-fsharp-targets.sh
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Some project files look for F# targets in $(FSharpTargetsPath)
|
||||||
|
# so it's a good idea to add something like this to your ~/.bash_profile:
|
||||||
|
|
||||||
|
# export FSharpTargetsPath=$(dirname $(which fsharpc))/../lib/mono/4.0/Microsoft.FSharp.Targets
|
||||||
|
|
||||||
|
# In build scripts, you would add somehting like this:
|
||||||
|
|
||||||
|
# export FSharpTargetsPath="${fsharp}/lib/mono/4.0/Microsoft.FSharp.Targets"
|
||||||
|
|
||||||
|
# However, some project files look for F# targets in the main Mono directory. When that happens
|
||||||
|
# patch the project files using this script so they will look in $(FSharpTargetsPath) instead.
|
||||||
|
|
||||||
|
echo "Patching F# targets in fsproj files..."
|
||||||
|
|
||||||
|
find -iname \*.fsproj -print -exec \
|
||||||
|
sed --in-place=.bak \
|
||||||
|
-e 's,<FSharpTargetsPath>\([^<]*\)</FSharpTargetsPath>,<FSharpTargetsPath Condition="Exists('\'\\1\'')">\1</FSharpTargetsPath>,'g \
|
||||||
|
{} \;
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
echo Placating Nuget in nuget.targets
|
||||||
|
find -iname nuget.targets -print -exec sed --in-place=bak -e 's,mono --runtime[^<]*,true NUGET PLACATED BY buildDotnetPackage,g' {} \;
|
||||||
|
|
||||||
|
echo Just to be sure, replacing Nuget executables by empty files.
|
||||||
|
find . -iname nuget.exe \! -size 0 -exec mv -v {} {}.bak \; -exec touch {} \;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue