summaryrefslogtreecommitdiff
path: root/.gitlab
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2021-07-25 15:50:16 -0400
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-09-23 16:00:17 -0400
commitbe11120f56ebe7fa28bc362056733b35ae932e1e (patch)
tree1ed34c5ff5960a986d7cf7b89fa0cf138725fb05 /.gitlab
parent55112fbfe6d1fad61b27780d3361a330359d48b3 (diff)
downloadhaskell-be11120f56ebe7fa28bc362056733b35ae932e1e.tar.gz
ci: More surgical use of nix in Darwin builds
Diffstat (limited to '.gitlab')
-rwxr-xr-x.gitlab/ci.sh11
-rw-r--r--.gitlab/darwin/nix/sources.json26
-rw-r--r--.gitlab/darwin/nix/sources.nix174
-rw-r--r--.gitlab/darwin/toolchain.nix102
-rw-r--r--.gitlab/shell.nix92
5 files changed, 306 insertions, 99 deletions
diff --git a/.gitlab/ci.sh b/.gitlab/ci.sh
index 85fd59cd59..18e63b33bd 100755
--- a/.gitlab/ci.sh
+++ b/.gitlab/ci.sh
@@ -180,17 +180,14 @@ function show_tool() {
function set_toolchain_paths() {
needs_toolchain="1"
case "$(uname -m)-$(uname)" in
+ # Linux toolchains are included in the Docker image
*-Linux) needs_toolchain="" ;;
+ # Darwin toolchains are provided via .gitlab/darwin/toolchain.nix
+ *-Darwin) needs_toolchain="" ;;
*) ;;
esac
- if [[ -n "${IN_NIX_SHELL:-}" ]]; then
- needs_toolchain=""
- GHC="$(which ghc)"
- CABAL="$(which cabal)"
- HAPPY="$(which happy)"
- ALEX="$(which alex)"
- elif [[ -n "$needs_toolchain" ]]; then
+ if [[ -n "$needs_toolchain" ]]; then
# These are populated by setup_toolchain
GHC="$toolchain/bin/ghc$exe"
CABAL="$toolchain/bin/cabal$exe"
diff --git a/.gitlab/darwin/nix/sources.json b/.gitlab/darwin/nix/sources.json
new file mode 100644
index 0000000000..a6ff5dc415
--- /dev/null
+++ b/.gitlab/darwin/nix/sources.json
@@ -0,0 +1,26 @@
+{
+ "niv": {
+ "branch": "master",
+ "description": "Easy dependency management for Nix projects",
+ "homepage": "https://github.com/nmattia/niv",
+ "owner": "nmattia",
+ "repo": "niv",
+ "rev": "e0ca65c81a2d7a4d82a189f1e23a48d59ad42070",
+ "sha256": "1pq9nh1d8nn3xvbdny8fafzw87mj7gsmp6pxkdl65w2g18rmcmzx",
+ "type": "tarball",
+ "url": "https://github.com/nmattia/niv/archive/e0ca65c81a2d7a4d82a189f1e23a48d59ad42070.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ },
+ "nixpkgs": {
+ "branch": "wip/ghc-8.10.7-darwin",
+ "description": "Nix Packages collection",
+ "homepage": "",
+ "owner": "bgamari",
+ "repo": "nixpkgs",
+ "rev": "37c60356e3f83c708a78a96fdd914b5ffc1f551c",
+ "sha256": "0i5j7nwk4ky0fg4agla3aznadpxz0jyrdwp2q92hyxidra987syn",
+ "type": "tarball",
+ "url": "https://github.com/bgamari/nixpkgs/archive/37c60356e3f83c708a78a96fdd914b5ffc1f551c.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ }
+}
diff --git a/.gitlab/darwin/nix/sources.nix b/.gitlab/darwin/nix/sources.nix
new file mode 100644
index 0000000000..1938409ddd
--- /dev/null
+++ b/.gitlab/darwin/nix/sources.nix
@@ -0,0 +1,174 @@
+# This file has been generated by Niv.
+
+let
+
+ #
+ # The fetchers. fetch_<type> fetches specs of type <type>.
+ #
+
+ fetch_file = pkgs: name: spec:
+ let
+ name' = sanitizeName name + "-src";
+ in
+ if spec.builtin or true then
+ builtins_fetchurl { inherit (spec) url sha256; name = name'; }
+ else
+ pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
+
+ fetch_tarball = pkgs: name: spec:
+ let
+ name' = sanitizeName name + "-src";
+ in
+ if spec.builtin or true then
+ builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
+ else
+ pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
+
+ fetch_git = name: spec:
+ let
+ ref =
+ if spec ? ref then spec.ref else
+ if spec ? branch then "refs/heads/${spec.branch}" else
+ if spec ? tag then "refs/tags/${spec.tag}" else
+ abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
+ in
+ builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
+
+ fetch_local = spec: spec.path;
+
+ fetch_builtin-tarball = name: throw
+ ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
+ $ niv modify ${name} -a type=tarball -a builtin=true'';
+
+ fetch_builtin-url = name: throw
+ ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
+ $ niv modify ${name} -a type=file -a builtin=true'';
+
+ #
+ # Various helpers
+ #
+
+ # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
+ sanitizeName = name:
+ (
+ concatMapStrings (s: if builtins.isList s then "-" else s)
+ (
+ builtins.split "[^[:alnum:]+._?=-]+"
+ ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
+ )
+ );
+
+ # The set of packages used when specs are fetched using non-builtins.
+ mkPkgs = sources: system:
+ let
+ sourcesNixpkgs =
+ import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
+ hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
+ hasThisAsNixpkgsPath = <nixpkgs> == ./.;
+ in
+ if builtins.hasAttr "nixpkgs" sources
+ then sourcesNixpkgs
+ else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
+ import <nixpkgs> {}
+ else
+ abort
+ ''
+ Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
+ add a package called "nixpkgs" to your sources.json.
+ '';
+
+ # The actual fetching function.
+ fetch = pkgs: name: spec:
+
+ if ! builtins.hasAttr "type" spec then
+ abort "ERROR: niv spec ${name} does not have a 'type' attribute"
+ else if spec.type == "file" then fetch_file pkgs name spec
+ else if spec.type == "tarball" then fetch_tarball pkgs name spec
+ else if spec.type == "git" then fetch_git name spec
+ else if spec.type == "local" then fetch_local spec
+ else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
+ else if spec.type == "builtin-url" then fetch_builtin-url name
+ else
+ abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
+
+ # If the environment variable NIV_OVERRIDE_${name} is set, then use
+ # the path directly as opposed to the fetched source.
+ replace = name: drv:
+ let
+ saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
+ ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
+ in
+ if ersatz == "" then drv else
+ # this turns the string into an actual Nix path (for both absolute and
+ # relative paths)
+ if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
+
+ # Ports of functions for older nix versions
+
+ # a Nix version of mapAttrs if the built-in doesn't exist
+ mapAttrs = builtins.mapAttrs or (
+ f: set: with builtins;
+ listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
+ );
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
+ range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
+ stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
+ stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
+ concatMapStrings = f: list: concatStrings (map f list);
+ concatStrings = builtins.concatStringsSep "";
+
+ # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
+ optionalAttrs = cond: as: if cond then as else {};
+
+ # fetchTarball version that is compatible between all the versions of Nix
+ builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
+ let
+ inherit (builtins) lessThan nixVersion fetchTarball;
+ in
+ if lessThan nixVersion "1.12" then
+ fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
+ else
+ fetchTarball attrs;
+
+ # fetchurl version that is compatible between all the versions of Nix
+ builtins_fetchurl = { url, name ? null, sha256 }@attrs:
+ let
+ inherit (builtins) lessThan nixVersion fetchurl;
+ in
+ if lessThan nixVersion "1.12" then
+ fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
+ else
+ fetchurl attrs;
+
+ # Create the final "sources" from the config
+ mkSources = config:
+ mapAttrs (
+ name: spec:
+ if builtins.hasAttr "outPath" spec
+ then abort
+ "The values in sources.json should not have an 'outPath' attribute"
+ else
+ spec // { outPath = replace name (fetch config.pkgs name spec); }
+ ) config.sources;
+
+ # The "config" used by the fetchers
+ mkConfig =
+ { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
+ , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
+ , system ? builtins.currentSystem
+ , pkgs ? mkPkgs sources system
+ }: rec {
+ # The sources, i.e. the attribute set of spec name to spec
+ inherit sources;
+
+ # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
+ inherit pkgs;
+ };
+
+in
+mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
diff --git a/.gitlab/darwin/toolchain.nix b/.gitlab/darwin/toolchain.nix
new file mode 100644
index 0000000000..1042b76c18
--- /dev/null
+++ b/.gitlab/darwin/toolchain.nix
@@ -0,0 +1,102 @@
+{ system }:
+
+let
+ sources = import ./nix/sources.nix;
+ nixpkgsSrc = sources.nixpkgs;
+ pkgs = import nixpkgsSrc { inherit system; };
+in
+
+let
+ hsPkgs = pkgs.haskellPackages;
+ alex = hsPkgs.alex;
+ happy = hsPkgs.happy;
+ targetTriple = pkgs.stdenv.targetPlatform.config;
+
+ ghc = pkgs.stdenv.mkDerivation rec {
+ version = "8.10.7";
+ name = "ghc";
+ src =
+ let
+ bindists = {
+ aarch64-darwin = {
+ url = "https://downloads.haskell.org/ghc/${version}/ghc-${version}-aarch64-apple-darwin.tar.xz";
+ sha256 = "sha256:075skdnsa072088a8jfkqac7pphkgzlgqpspb8xa7ljzqg1ryinw";
+ };
+ x86_64-darwin = {
+ url = "https://downloads.haskell.org/ghc/${version}/ghc-${version}-x86_64-apple-darwin.tar.xz";
+ sha256 = "sha256:0ir02gjyb4l073z4gs3f1zjkx04n14dp7a5z4cqzbj9qqgwv0z98";
+ };
+ };
+ in pkgs.fetchurl bindists.${pkgs.stdenv.hostPlatform.system};
+ configureFlags = [
+ "CC=/usr/bin/clang"
+ "CLANG=/usr/bin/clang"
+ "LLC=${llvm}/bin/llc"
+ "OPT=${llvm}/bin/opt"
+ "CONF_CC_OPTS_STAGE2=--target=${targetTriple}"
+ "CONF_CXX_OPTS_STAGE2=--target=${targetTriple}"
+ "CONF_GCC_LINKER_OPTS_STAGE2=--target=${targetTriple}"
+ ];
+ buildPhase = "true";
+
+ # N.B. Work around #20253.
+ nativeBuildInputs = [ pkgs.gnused ];
+ postInstallPhase = ''
+ settings="$out/lib/ghc-${version}/settings"
+ sed -i -e "s%\"llc\"%\"${llvm}/bin/llc\"%" $settings
+ sed -i -e "s%\"opt\"%\"${llvm}/bin/opt\"%" $settings
+ sed -i -e "s%\"clang\"%\"/usr/bin/clang\"%" $settings
+ sed -i -e 's%("C compiler command", "")%("C compiler command", "/usr/bin/clang")%' $settings
+ sed -i -e 's%("C compiler flags", "")%("C compiler flags", "--target=${targetTriple}")%' $settings
+ sed -i -e 's%("C++ compiler flags", "")%("C++ compiler flags", "--target=${targetTriple}")%' $settings
+ sed -i -e 's%("C compiler link flags", "")%("C compiler link flags", "--target=${targetTriple}")%' $settings
+ '';
+
+ # Sanity check: verify that we can compile hello world.
+ doInstallCheck = true;
+ installCheckPhase = ''
+ unset DYLD_LIBRARY_PATH
+ $out/bin/ghc --info
+ cd $TMP
+ mkdir test-ghc; cd test-ghc
+ cat > main.hs << EOF
+ {-# LANGUAGE TemplateHaskell #-}
+ module Main where
+ main = putStrLn \$([|"yes"|])
+ EOF
+ $out/bin/ghc --make -v3 main.hs || exit 1
+ echo compilation ok
+ [ $(./main) == "yes" ]
+ '';
+ };
+
+ ourtexlive = with pkgs;
+ texlive.combine {
+ inherit (texlive)
+ scheme-medium collection-xetex fncychap titlesec tabulary varwidth
+ framed capt-of wrapfig needspace dejavu-otf helvetic upquote;
+ };
+ fonts = with pkgs; makeFontsConf { fontDirectories = [ dejavu_fonts ]; };
+
+ llvm = pkgs.llvm_11;
+in
+pkgs.writeTextFile {
+ name = "toolchain";
+ text = ''
+ export PATH
+ PATH="${pkgs.autoconf}/bin:$PATH"
+ PATH="${pkgs.automake}/bin:$PATH"
+ PATH="${pkgs.coreutils}/bin:$PATH"
+ export FONTCONFIG_FILE=${fonts}
+ export XELATEX="${ourtexlive}/bin/xelatex"
+ export MAKEINDEX="${ourtexlive}/bin/makeindex"
+ export HAPPY="${happy}/bin/happy"
+ export ALEX="${alex}/bin/alex"
+ export GHC="${ghc}/bin/ghc"
+ export LLC="${llvm}/bin/llc"
+ export OPT="${llvm}/bin/opt"
+ export SPHINXBUILD="${pkgs.python3Packages.sphinx}/bin/sphinx-build"
+ export CABAL_INSTALL="${pkgs.cabal-install}/bin/cabal"
+ export CABAL="$CABAL_INSTALL"
+ '';
+}
diff --git a/.gitlab/shell.nix b/.gitlab/shell.nix
deleted file mode 100644
index 1ded62d982..0000000000
--- a/.gitlab/shell.nix
+++ /dev/null
@@ -1,92 +0,0 @@
-{ system ? "aarch64-darwin"
-#, nixpkgs ? fetchTarball https://github.com/angerman/nixpkgs/archive/257cb120334.tar.gz #apple-silicon.tar.gz
-, pkgs ? import <nixpkgs> { inherit system; }
-, compiler ? if system == "aarch64-darwin" then "ghc8103Binary" else "ghc8103"
-}: pkgs.mkShell {
- # this prevents nix from trying to write the env-vars file.
- # we can't really, as NIX_BUILD_TOP/env-vars is not set.
- noDumpEnvVars=1;
-
- # stop polluting LDFLAGS with -liconv
- dontAddExtraLibs = true;
-
- # we need to inject ncurses into --with-curses-libraries.
- # the real fix is to teach terminfo to use libcurses on macOS.
- # CONFIGURE_ARGS = "--with-intree-gmp --with-curses-libraries=${pkgs.ncurses.out}/lib";
- CONFIGURE_ARGS = "--with-intree-gmp";
-
- # magic speedup pony :facepalm:
- #
- # nix has the ugly habbit of duplicating ld flags more than necessary. This
- # somewhat consolidates this.
- shellHook = ''
- echo $NIX_LDFLAGS
- export NIX_LDFLAGS=$(for a in $NIX_LDFLAGS; do echo $a; done |sort|uniq|xargs)
- export NIX_LDFLAGS_FOR_TARGET=$(for a in $NIX_LDFLAGS_FOR_TARGET; do echo $a; done |sort|uniq|xargs)
- export NIX_LDFLAGS_FOR_TARGET=$(comm -3 <(for l in $NIX_LDFLAGS_FOR_TARGET; do echo $l; done) <(for l in $NIX_LDFLAGS; do echo $l; done))
-
-
- # Impurity hack for GHC releases.
- #################################
- # We don't want binary releases to depend on nix, thus we'll need to make sure we don't leak in references.
- # GHC externally depends only on iconv and curses. However we can't force a specific curses library for
- # the terminfo package, as such we'll need to make sure we only look in the system path for the curses library
- # and not pick up the tinfo from the nix provided ncurses package.
- #
- # We also need to force us to use the systems COREFOUNDATION, not the one that nix builds. Again this is impure,
- # but it will allow us to have proper binary distributions.
- #
- # do not use nixpkgs provided core foundation
- export NIX_COREFOUNDATION_RPATH=/System/Library/Frameworks
- # drop curses from the LDFLAGS, we really want the system ones, not the nix ones.
- export NIX_LDFLAGS=$(for lib in $NIX_LDFLAGS; do case "$lib" in *curses*);; *) echo -n "$lib ";; esac; done;)
- export NIX_CFLAGS_COMPILE+=" -Wno-nullability-completeness -Wno-availability -Wno-expansion-to-defined -Wno-builtin-requires-header -Wno-unused-command-line-argument"
-
- # unconditionally add the MacOSX.sdk and TargetConditional.h
- export NIX_CFLAGS_COMPILE+=" -isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include"
- export NIX_LDFLAGS="-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib $NIX_LDFLAGS"
-
- export MACOSX_DEPLOYMENT_TARGET=10.7
-
- '';
-
- nativeBuildInputs = (with pkgs; [
- # This needs to come *before* ghc,
- # otherwise we migth end up with the clang from
- # the bootstrap GHC in PATH with higher priority.
- clang_11
- llvm_11
-
- haskell.compiler.${compiler}
- haskell.packages.${compiler}.cabal-install
- haskell.packages.${compiler}.alex
- haskell.packages.${compiler}.happy # _1_19_12 is needed for older GHCs.
-
- automake
- autoconf
- m4
-
- gmp
- zlib.out
- zlib.dev
- glibcLocales
- # locale doesn't build yet :-/
- # locale
-
- git
-
- python3
- # python3Full
- # python3Packages.sphinx
- perl
-
- which
- wget
- file
-
- xz
- xlibs.lndir
-
- cacert ])
- ++ (with pkgs.darwin.apple_sdk.frameworks; [ Foundation Security ]);
-}