diff options
author | Ben Gamari <ben@smart-cactus.org> | 2021-07-25 15:50:16 -0400 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-09-23 16:00:17 -0400 |
commit | be11120f56ebe7fa28bc362056733b35ae932e1e (patch) | |
tree | 1ed34c5ff5960a986d7cf7b89fa0cf138725fb05 /.gitlab | |
parent | 55112fbfe6d1fad61b27780d3361a330359d48b3 (diff) | |
download | haskell-be11120f56ebe7fa28bc362056733b35ae932e1e.tar.gz |
ci: More surgical use of nix in Darwin builds
Diffstat (limited to '.gitlab')
-rwxr-xr-x | .gitlab/ci.sh | 11 | ||||
-rw-r--r-- | .gitlab/darwin/nix/sources.json | 26 | ||||
-rw-r--r-- | .gitlab/darwin/nix/sources.nix | 174 | ||||
-rw-r--r-- | .gitlab/darwin/toolchain.nix | 102 | ||||
-rw-r--r-- | .gitlab/shell.nix | 92 |
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 ]); -} |