From e205083920b670d055e0b8ed4afa39f3a3d46526 Mon Sep 17 00:00:00 2001 From: t-wallet Date: Tue, 23 Jul 2024 13:34:08 +0200 Subject: [PATCH] Setup repository --- .gitignore | 47 ++++++++++ README.md | 2 + cabal.project | 10 ++ default.nix | 6 ++ nix/aarch64-reloc.patch | 139 ++++++++++++++++++++++++++++ nix/nixpkgs.nix | 47 ++++++++++ nix/sources.json | 102 +++++++++++++++++++++ nix/sources.nix | 198 ++++++++++++++++++++++++++++++++++++++++ release.nix | 4 + shell.nix | 16 ++++ 10 files changed, 571 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 cabal.project create mode 100644 default.nix create mode 100644 nix/aarch64-reloc.patch create mode 100644 nix/nixpkgs.nix create mode 100644 nix/sources.json create mode 100644 nix/sources.nix create mode 100644 release.nix create mode 100644 shell.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7579cca --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +dist/ +build/ +dist-newstyle/ +.stack-work/ +stack.yaml.lock +cabal-dev +/cabal.project.local +.ghc.environment.* +*.o +*.o-boot +*.hi +*.hi-boot +*.po +*.po-boot +*.p_o +*.p_o-boot +*.chi +*.chs.h +*.dyn_o +*.dyn_o-boot +*.dyn_hi +*.dyn_hi-boot +.virtualenv +.hpc +.hsenv +.cabal-sandbox/ +cabal.sandbox.config +cabal.config +*.prof +*.aux +*.hp +*.bin +*.log +*.tar.gz +stack.yaml.lock + +*~ +*.DS_Store + +# IntelliJ +/.idea +*.iml + +# HDL directories often created during development cycle +/vhdl +/verilog +/systemverilog diff --git a/README.md b/README.md new file mode 100644 index 0000000..a1db4aa --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Clash Cores +TODO diff --git a/cabal.project b/cabal.project new file mode 100644 index 0000000..8b3a3a0 --- /dev/null +++ b/cabal.project @@ -0,0 +1,10 @@ +packages: + clash-cores.cabal + +package clash-cores + ghc-options: +RTS -qn4 -A128M -RTS -j4 + +write-ghc-environment-files: always + +-- Eliminates the need for `--enable-tests`, which is needed for HLS. +tests: true diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..febd360 --- /dev/null +++ b/default.nix @@ -0,0 +1,6 @@ +{ nixpkgs ? import ./nix/nixpkgs.nix {} }: + +with nixpkgs.pkgs; +with gitignore; + +haskellPackages.callCabal2nix "clash-cores" (gitignoreSource ./.) {} diff --git a/nix/aarch64-reloc.patch b/nix/aarch64-reloc.patch new file mode 100644 index 0000000..a304a65 --- /dev/null +++ b/nix/aarch64-reloc.patch @@ -0,0 +1,139 @@ +From bd887b9f8a669f2269c4c420a23b64569be351b5 Mon Sep 17 00:00:00 2001 +From: Sylvain Henry +Date: Wed, 19 Jun 2024 16:55:18 +0200 +Subject: [PATCH 1/3] Linker: use m32 allocator for sections when NEED_PLT + (#24432) + +Use M32 allocator to avoid fragmentation when allocating ELF sections. +We already did this when NEED_PLT was undefined. Failing to do this led +to relocations impossible to fulfil (#24432). +--- + rts/linker/Elf.c | 26 ++++++++++++-------------- + 1 file changed, 12 insertions(+), 14 deletions(-) + +diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c +index 9132d9d3973..8168103e4e5 100644 +--- a/rts/linker/Elf.c ++++ b/rts/linker/Elf.c +@@ -863,25 +863,23 @@ ocGetNames_ELF ( ObjectCode* oc ) + + unsigned nstubs = numberOfStubsForSection(oc, i); + unsigned stub_space = STUB_SIZE * nstubs; ++ unsigned full_size = size+stub_space; + +- void * mem = mmapAnonForLinker(size+stub_space); ++ // use M32 allocator to avoid fragmentation and relocations impossible ++ // to fulfil (cf #24432) ++ bool executable = kind == SECTIONKIND_CODE_OR_RODATA; ++ m32_allocator *allocator = executable ? oc->rx_m32 : oc->rw_m32; + +- if( mem == MAP_FAILED ) { +- barf("failed to mmap allocated memory to load section %d. " +- "errno = %d", i, errno); +- } ++ // Correctly align the section. This is particularly important for ++ // the alignment of .rodata.cstNN sections. ++ start = m32_alloc(allocator, full_size, align); ++ if (start == NULL) goto fail; ++ alloc = SECTION_M32; + + /* copy only the image part over; we don't want to copy data + * into the stub part. + */ +- memcpy( mem, oc->image + offset, size ); +- +- alloc = SECTION_MMAP; +- +- mapped_offset = 0; +- mapped_size = roundUpToPage(size+stub_space); +- start = mem; +- mapped_start = mem; ++ memcpy(start, oc->image + offset, size); + #else + if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) { + // already mapped. +@@ -918,7 +916,7 @@ ocGetNames_ELF ( ObjectCode* oc ) + + #if defined(NEED_PLT) + oc->sections[i].info->nstubs = 0; +- oc->sections[i].info->stub_offset = (uint8_t*)mem + size; ++ oc->sections[i].info->stub_offset = (uint8_t*)start + size; + oc->sections[i].info->stub_size = stub_space; + oc->sections[i].info->stubs = NULL; + #else +-- +GitLab + + +From 976ec5d51ab1f185b7d9ba2c15f326f2a4c8828c Mon Sep 17 00:00:00 2001 +From: Sylvain Henry +Date: Thu, 27 Jun 2024 16:40:50 +0200 +Subject: [PATCH 2/3] RTS: allow M32 allocation outside of 4GB range when + assuming -fPIC + +--- + rts/linker/M32Alloc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/rts/linker/M32Alloc.c b/rts/linker/M32Alloc.c +index 17d3d12459c..adff1b22957 100644 +--- a/rts/linker/M32Alloc.c ++++ b/rts/linker/M32Alloc.c +@@ -156,7 +156,10 @@ static bool + is_okay_address(void *p) { + int8_t *here = LINKER_LOAD_BASE; + ssize_t displacement = (int8_t *) p - here; +- return (displacement > -0x7fffffff) && (displacement < 0x7fffffff); ++ // if we assume -fPIC, we don't care where we load code. ++ // But we still want to use the m32 allocator to avoid fragmentation (#24432) ++ return RtsFlags.MiscFlags.linkerAlwaysPic ++ || ((displacement > -0x7fffffff) && (displacement < 0x7fffffff)); + } + + enum m32_page_type { +-- +GitLab + + +From 54de3a80ebac9a782cf0cc91f3a3afcc94615817 Mon Sep 17 00:00:00 2001 +From: Sylvain Henry +Date: Tue, 9 Jul 2024 13:00:08 +0200 +Subject: [PATCH 3/3] Linker: fix stub offset + +Remove unjustified +8 offset that leads to memory corruption (cf +discussion in #24432). +--- + rts/linker/elf_plt.c | 3 +-- + rts/linker/macho/plt.c | 3 +-- + 2 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/rts/linker/elf_plt.c b/rts/linker/elf_plt.c +index 9cd42efff23..5c6ef8ed442 100644 +--- a/rts/linker/elf_plt.c ++++ b/rts/linker/elf_plt.c +@@ -56,8 +56,7 @@ makeStub(Section * section, + s->target = *addr; + s->flags = flags; + s->next = NULL; +- s->addr = (uint8_t *)section->info->stub_offset + 8 +- + STUB_SIZE * section->info->nstubs; ++ s->addr = (uint8_t *)section->info->stub_offset + STUB_SIZE * section->info->nstubs; + + if((*_makeStub)(s)) + return EXIT_FAILURE; +diff --git a/rts/linker/macho/plt.c b/rts/linker/macho/plt.c +index ed005ba447a..6eb94c29cb0 100644 +--- a/rts/linker/macho/plt.c ++++ b/rts/linker/macho/plt.c +@@ -56,8 +56,7 @@ makeStub(Section * section, + s->target = *addr; + s->flags = flags; + s->next = NULL; +- s->addr = (uint8_t *)section->info->stub_offset + 8 +- + STUB_SIZE * section->info->nstubs; ++ s->addr = (uint8_t *)section->info->stub_offset + STUB_SIZE * section->info->nstubs; + + if((*_makeStub)(s)) + return EXIT_FAILURE; +-- +GitLab diff --git a/nix/nixpkgs.nix b/nix/nixpkgs.nix new file mode 100644 index 0000000..884d8a5 --- /dev/null +++ b/nix/nixpkgs.nix @@ -0,0 +1,47 @@ +{ sources ? import ./sources.nix }: + +let + haskell_compiler = "ghc965"; + + overlay = _: pkgs: { + + # Nix tooling + niv = (import sources.niv {}).niv; + gitignore = import sources.gitignore { inherit (pkgs) lib; }; + + haskell = pkgs.haskell // { + compiler = pkgs.haskell.compiler // { + "${haskell_compiler}" = pkgs.haskell.compiler.${haskell_compiler}.overrideAttrs (old: { + # Fix for linking issues: https://gitlab.haskell.org/ghc/ghc/-/issues/24432 + patches = + let isAarch64 = pkgs.stdenv.hostPlatform.system == "aarch64-linux"; + in (old.patches or [ ]) ++ pkgs.lib.optional isAarch64 [ ./aarch64-reloc.patch ]; + }); + }; + }; + + # Haskell overrides + haskellPackages = pkgs.haskell.packages.${haskell_compiler}.override { + overrides = self: super: { + # Add overrides here + circuit-notation = + self.callCabal2nix "circuit-notation" sources.circuit-notation {}; + doctest-parallel = + self.callCabal2nix "doctest-parallel" sources.doctest-parallel {}; + clash-prelude = + self.callCabal2nix "clash-prelude" (sources.clash-compiler + "/clash-prelude") {}; + clash-lib = + self.callCabal2nix "clash-lib" (sources.clash-compiler + "/clash-lib") {}; + clash-ghc = + self.callCabal2nix "clash-ghc" (sources.clash-compiler + "/clash-ghc") {}; + clash-prelude-hedgehog = + self.callCabal2nix "clash-prelude" (sources.clash-compiler + "/clash-prelude-hedgehog") {}; + tasty-hedgehog = + self.callCabal2nix "tasty-hedgehog" sources.tasty-hedgehog {}; + hedgehog = + self.callCabal2nix "hedgehog" (sources.haskell-hedgehog + "/hedgehog") {}; + }; + }; + }; + +in import sources.nixpkgs { overlays = [ overlay ]; } diff --git a/nix/sources.json b/nix/sources.json new file mode 100644 index 0000000..613a609 --- /dev/null +++ b/nix/sources.json @@ -0,0 +1,102 @@ +{ + "clash-compiler": { + "branch": "master", + "description": "Haskell to VHDL/Verilog/SystemVerilog compiler", + "homepage": "https://clash-lang.org/", + "owner": "clash-lang", + "repo": "clash-compiler", + "rev": "aba55fed9f45711c8336935721a43d243f7f78c1", + "sha256": "1hrzp8g189v46qfr9ds7w6w0yj5w8y4im1pa3lf5vjx3z64v26qv", + "type": "tarball", + "url": "https://github.com/clash-lang/clash-compiler/archive/aba55fed9f45711c8336935721a43d243f7f78c1.tar.gz", + "url_template": "https://github.com///archive/.tar.gz", + "version": "1.8.1" + }, + "doctest-parallel": { + "branch": "main", + "description": "Test interactive Haskell examples", + "homepage": null, + "owner": "martijnbastiaan", + "repo": "doctest-parallel", + "rev": "d73df0a2fd58b0b6aba438eb40aa56d30724e42a", + "sha256": "1k88bkwz2crvb6dafcf6y5y6wm0m2qvds57f3b0rx4id7la4qv89", + "type": "tarball", + "url": "https://github.com/martijnbastiaan/doctest-parallel/archive/d73df0a2fd58b0b6aba438eb40aa56d30724e42a.tar.gz", + "url_template": "https://github.com///archive/.tar.gz", + "version": "0.3.1" + }, + "gitignore": { + "branch": "master", + "description": "Nix function for filtering local git sources", + "homepage": "", + "owner": "hercules-ci", + "repo": "gitignore", + "rev": "bff2832ec341cf30acb3a4d3e2e7f1f7b590116a", + "sha256": "0va0janxvmilm67nbl81gdbpppal4aprxzb25gp9pqvf76ahxsci", + "type": "tarball", + "url": "https://github.com/hercules-ci/gitignore/archive/bff2832ec341cf30acb3a4d3e2e7f1f7b590116a.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "haskell-hedgehog": { + "branch": "master", + "description": "Release with confidence, state-of-the-art property testing for Haskell.", + "homepage": "", + "owner": "hedgehogqa", + "repo": "haskell-hedgehog", + "rev": "52c35cabe24de2a1c03e72dde9d04b64f81d1f44", + "sha256": "1f9znljkmrdd4nlfmjfi8kx0fgcysp328rz27099n7bygchpgjr6", + "type": "tarball", + "url": "https://github.com/hedgehogqa/haskell-hedgehog/archive/52c35cabe24de2a1c03e72dde9d04b64f81d1f44.tar.gz", + "url_template": "https://github.com///archive/.tar.gz", + "version": "1.4" + }, + "circuit-notation": { + "branch": "master", + "description": "A plugin for circuit notation", + "homepage": null, + "owner": "cchalmers", + "repo": "circuit-notation", + "rev": "19b386c4aa3ff690758ae089c7754303f3500cc9", + "sha256": "0qz2w6akxj51kq50rbl88bnjyxzd2798a9sn9jj1z2kak7a6kqbg", + "type": "tarball", + "url": "https://github.com/cchalmers/circuit-notation/archive/19b386c4aa3ff690758ae089c7754303f3500cc9.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "niv": { + "branch": "master", + "description": "Easy dependency management for Nix projects", + "homepage": "https://github.com/nmattia/niv", + "owner": "nmattia", + "repo": "niv", + "rev": "723f0eeb969a730db3c30f977c2b66b9dce9fe4a", + "sha256": "0016l7230gd2kdh0g2w573r9a2krqb7x4ifcjhhsn4h1bwap7qr0", + "type": "tarball", + "url": "https://github.com/nmattia/niv/archive/723f0eeb969a730db3c30f977c2b66b9dce9fe4a.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "nixpkgs": { + "branch": "nixpkgs-unstable", + "description": "Nix Packages collection", + "homepage": "", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e2dd4e18cc1c7314e24154331bae07df76eb582f", + "sha256": "19zbxf7rb787jvyrfhl4z9sn3aisd6xvx6ikybbi75ym9sy39jds", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/e2dd4e18cc1c7314e24154331bae07df76eb582f.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "tasty-hedgehog": { + "branch": "master", + "description": "Tasty integration for the Hedgehog property testing library", + "homepage": "", + "owner": "qfpl", + "repo": "tasty-hedgehog", + "rev": "ed07ecef3f6a01572b577b450ba6d58108173125", + "sha256": "1b8y5ibg1ihgf44nyym4g45lwmabymfcjb2nigv93s2fmng9zp6r", + "type": "tarball", + "url": "https://github.com/qfpl/tasty-hedgehog/archive/ed07ecef3f6a01572b577b450ba6d58108173125.tar.gz", + "url_template": "https://github.com///archive/.tar.gz", + "version": "1.4.0.2" + } +} diff --git a/nix/sources.nix b/nix/sources.nix new file mode 100644 index 0000000..fe3dadf --- /dev/null +++ b/nix/sources.nix @@ -0,0 +1,198 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of 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 = + spec.ref or ( + 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`!" + ); + submodules = spec.submodules or false; + submoduleArg = + let + nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0; + emptyArgWithWarning = + if submodules + then + builtins.trace + ( + "The niv input \"${name}\" uses submodules " + + "but your nix's (${builtins.nixVersion}) builtins.fetchGit " + + "does not support them" + ) + { } + else { }; + in + if nixSupportsSubmodules + then { inherit submodules; } + else emptyArgWithWarning; + in + builtins.fetchGit + ({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg); + + 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 = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import { } + else + abort + '' + Please specify either (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 (builtins.match "[a-zA-Z0-9]" c) == null 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 (name != null) { 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 (name != null) { 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 sourcesFile == null 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/release.nix b/release.nix new file mode 100644 index 0000000..6ea6bb8 --- /dev/null +++ b/release.nix @@ -0,0 +1,4 @@ +let + pkgs = import ./nix/nixpkgs.nix { }; +in + pkgs.haskellPackages.callPackage ./default.nix { } diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..1cbac92 --- /dev/null +++ b/shell.nix @@ -0,0 +1,16 @@ +{ nixpkgs ? import ./nix/nixpkgs.nix {} }: +let + inherit (nixpkgs) pkgs; + inherit (pkgs) haskellPackages; + + project = import ./release.nix; +in + +pkgs.stdenv.mkDerivation { + name = "shell"; + buildInputs = project.env.nativeBuildInputs ++ [ + haskellPackages.cabal-install + haskellPackages.haskell-language-server + ]; + LC_ALL = "C.UTF-8"; +}