reflex-dom icon indicating copy to clipboard operation
reflex-dom copied to clipboard

Build with ghc(js) 9.8.2 + 9.10.1

Open ymeister opened this issue 6 months ago • 10 comments

Needs:

  • https://github.com/reflex-frp/reflex/pull/502
  • https://github.com/reflex-frp/patch/pull/56

For haskell.nix: default.nix:

let deps = {
      "haskell.nix" = builtins.fetchTarball {
        url = "https://github.com/input-output-hk/haskell.nix/archive/d8c50dcaf3d3d589829ee9be9d5dba8279b8cc59.tar.gz";
        sha256 = "0a5hgryz6nszmy67yf1aks399h2aw0nj845518c4prs5c6ns1z7p";
      };
      patch = pkgs.fetchFromGitHub {
        owner = "ymeister";
        repo = "patch";
        rev = "2170c364450d5827a21dbcd817131d5def6e4767";
        sha256 = "0cnk89h3z0xkfa7jyz9ihycvpa0ak8kyslfl7labkwf6qi3qh80s";
      };
      reflex = pkgs.fetchFromGitHub {
        owner = "ymeister";
        repo = "reflex";
        rev = "844d88d10cbf0db8ad8677a9c72f6a10e811c0f4";
        sha256 = "013iaa4b9d18d8cbszrmp7h153yljsg05b28fblkpyra5ss010qh";
      };
    };

    haskellNix = import deps."haskell.nix" {};

    # Import nixpkgs and pass the haskell.nix provided nixpkgsArgs
    pkgs = import
      # haskell.nix provides access to the nixpkgs pins which are used by our CI,
      # hence you will be more likely to get cache hits when using these.
      # But you can also just use your own, e.g. '<nixpkgs>'.
      haskellNix.sources.nixpkgs-unstable
      # These arguments passed to nixpkgs, include some patches and also
      # the haskell.nix functionality itself as an overlay.
      haskellNix.nixpkgsArgs;

    source-repository-packages = packages:
      builtins.zipAttrsWith
        (k: vs:
          if k == "cabalProjectLocal" then pkgs.lib.strings.concatStringsSep "\n" vs
          else builtins.zipAttrsWith (_: pkgs.lib.lists.last) vs
        )
        (pkgs.lib.lists.forEach packages (p:
          let input = builtins.unsafeDiscardStringContext p;
          in {
            inputMap."${input}" = { name = builtins.baseNameOf p; outPath = p; rev = "HEAD"; };
            cabalProjectLocal = ''
              source-repository-package
                type: git
                location: ${input}
                tag: HEAD
            '';
          }
        ));

    import-cabal-project = dir: file:
      let path = dir + "/${file}";
          content = ''
            -- ${path}
            ${builtins.readFile path}
          '';
          lines = pkgs.lib.strings.splitString "\n" content;
      in pkgs.lib.strings.concatStringsSep "\n" (
          pkgs.lib.lists.forEach lines (line:
            if pkgs.lib.strings.hasPrefix "import: " line
            then import-cabal-project dir (pkgs.lib.strings.removePrefix "import: " line)
            else line
          )
      );

    haskellDeps = source-repository-packages [
      deps.reflex
      deps.patch
    ];

    project = pkgs: pkgs.haskell-nix.project {
      src = ./.;

      inherit (haskellDeps) inputMap cabalProjectLocal;
      cabalProject = import-cabal-project ./. "cabal.project";

      shell.withHaddock = if pkgs.stdenv.hostPlatform.isGhcjs then false else true;

      modules = [({ pkgs, lib, ... }: {
        packages.reflex-dom-core.components.tests = {
          gc.buildable = lib.mkForce false;
          hydration.buildable = lib.mkForce false;
          #gc.build-tools = [ pkgs.chromium ];
          #hydration.build-tools = [ pkgs.chromium ];
        };
      })];

      compiler-nix-name = "ghc910";
    };

in {
  ghc = project pkgs;
  ghc-js = project pkgs.pkgsCross.ghcjs;
}

shell.nix:

let projects = import ./default.nix;
    project = projects.ghc;
    pkgs = project.pkgs;
in project.shellFor {
  tools = {
    cabal = "latest";
  };

  buildInputs = with pkgs; [
    nodejs-slim_latest
  ];

  # Sellect cross compilers to include.
  crossPlatforms = ps: with ps; [
    ghcjs # Adds support for `javascript-unknown-ghcjs-cabal build` in the shell
  ];

  shellHook = ''
    function setup_cabal_to_nix {
      cabal_project_drv="$(nix-store -q --references "${project.plan-nix.drvPath}" | grep ".*-cabal.project.drv" - | head -n 1)"
      [ ! -z "$cabal_project_drv" ] && cabal_project_out="$(nix-store -q --outputs "$cabal_project_drv" | head -n 1)"
      [ ! -z "$cabal_project_out" ] && \cp -f "$cabal_project_out" cabal.project.local && chmod u+w cabal.project.local

      if [ -f cabal.project.local ]; then
        mkdir -p .nix
        store_paths="$(cat cabal.project.local | sed -n 's#.*\(/nix/store/.*\)#\1#p')"
        echo "$store_paths" | while read store_path; do
          target=".nix/$(echo "$store_path" | sed -n 's#/nix/store/\(.*\)#\1#p' | sed 's#/#-#g')"
          [ ! -e "$target" ] && cp -rf "$store_path" "$target" && chmod u+w -R "$target"
          sed -i "s#$store_path#$(readlink -f "$target")#g" cabal.project.local
        done
      fi
    }

    setup_cabal_to_nix 1> /dev/null
  '';
}

For nixpkgs:

From patch PR:

When building on ghc js, requires single-core building (https://gitlab.haskell.org/ghc/ghc/-/issues/25083#note_578275).

For nix:

patch = haskellLib.overrideCabal (drv: { enableParallelBuilding = false; }) super.patch;

Fix os-string (https://github.com/NixOS/nixpkgs/pull/332123):

os-string = null;

To build a project depending on reflex-dom using haskell.nix: default.nix:

let deps = {
      "haskell.nix" = builtins.fetchTarball {
        url = "https://github.com/input-output-hk/haskell.nix/archive/d8c50dcaf3d3d589829ee9be9d5dba8279b8cc59.tar.gz";
        sha256 = "0a5hgryz6nszmy67yf1aks399h2aw0nj845518c4prs5c6ns1z7p";
      };
      patch = pkgs.fetchFromGitHub {
        owner = "ymeister";
        repo = "patch";
        rev = "2170c364450d5827a21dbcd817131d5def6e4767";
        sha256 = "0cnk89h3z0xkfa7jyz9ihycvpa0ak8kyslfl7labkwf6qi3qh80s";
      };
      reflex = pkgs.fetchFromGitHub {
        owner = "ymeister";
        repo = "reflex";
        rev = "844d88d10cbf0db8ad8677a9c72f6a10e811c0f4";
        sha256 = "013iaa4b9d18d8cbszrmp7h153yljsg05b28fblkpyra5ss010qh";
      };
      reflex-dom = pkgs.fetchFromGitHub {
        owner = "ymeister";
        repo = "reflex-dom";
        rev = "ede863e98247deb8268f15d663292eb8a714437b";
        sha256 = "1z51gxc77nmnw6ylzkmyqizb4xhnvl6971wi0anm78i81n5aw495";
      };
    };

    haskellNix = import deps."haskell.nix" {};

    # Import nixpkgs and pass the haskell.nix provided nixpkgsArgs
    pkgs = import
      # haskell.nix provides access to the nixpkgs pins which are used by our CI,
      # hence you will be more likely to get cache hits when using these.
      # But you can also just use your own, e.g. '<nixpkgs>'.
      haskellNix.sources.nixpkgs-unstable
      # These arguments passed to nixpkgs, include some patches and also
      # the haskell.nix functionality itself as an overlay.
      haskellNix.nixpkgsArgs;

    source-repository-packages = packages:
      builtins.zipAttrsWith
        (k: vs:
          if k == "cabalProjectLocal" then pkgs.lib.strings.concatStringsSep "\n" vs
          else builtins.zipAttrsWith (_: pkgs.lib.lists.last) vs
        )
        (pkgs.lib.lists.forEach packages (p:
          let input = builtins.unsafeDiscardStringContext p;
          in {
            inputMap."${input}" = { name = builtins.baseNameOf p; outPath = p; rev = "HEAD"; };
            cabalProjectLocal = ''
              source-repository-package
                type: git
                location: ${input}
                tag: HEAD
            '';
          }
        ));

    import-cabal-project = dir: file:
      let path = dir + "/${file}";
          content = ''
            -- ${path}
            ${builtins.readFile path}
          '';
          lines = pkgs.lib.strings.splitString "\n" content;
      in pkgs.lib.strings.concatStringsSep "\n" (
          pkgs.lib.lists.forEach lines (line:
            if pkgs.lib.strings.hasPrefix "import: " line
            then import-cabal-project dir (pkgs.lib.strings.removePrefix "import: " line)
            else line
          )
      );

    haskellDeps = source-repository-packages [
      (deps.reflex-dom + "/reflex-dom")
      (deps.reflex-dom + "/reflex-dom-core")
      deps.reflex
      deps.patch
    ];

    project = pkgs: pkgs.haskell-nix.project {
      src = ./.;

      inherit (haskellDeps) inputMap;
      cabalProject = import-cabal-project ./. "cabal.project";
      cabalProjectLocal = ''
        ${import-cabal-project deps.reflex-dom "cabal.dependencies.project"}

        ${haskellDeps.cabalProjectLocal}

        if arch(javascript)
          extra-packages: ghci
      '';

      shell.withHaddock = if pkgs.stdenv.hostPlatform.isGhcjs then false else true;

      modules = [({ pkgs, lib, ... }: {
        packages.reflex-dom-core.components.tests = {
          gc.buildable = lib.mkForce false;
          hydration.buildable = lib.mkForce false;
          #gc.build-tools = [ pkgs.chromium ];
          #hydration.build-tools = [ pkgs.chromium ];
        };
      })];

      compiler-nix-name = "ghc910";
    };

in {
  ghc = project pkgs;
  ghc-js = project pkgs.pkgsCross.ghcjs;
}

shell.nix:

let projects = import ./default.nix;
    project = projects.ghc;
    pkgs = project.pkgs;
in project.shellFor {
  tools = {
    cabal = "latest";
  };

  buildInputs = with pkgs; [
    nodejs-slim_latest
  ];

  # Sellect cross compilers to include.
  crossPlatforms = ps: with ps; [
    ghcjs # Adds support for `javascript-unknown-ghcjs-cabal build` in the shell
  ];

  shellHook = ''
    function setup_cabal_to_nix {
      cabal_project_drv="$(nix-store -q --references "${project.plan-nix.drvPath}" | grep ".*-cabal.project.drv" - | head -n 1)"
      [ ! -z "$cabal_project_drv" ] && cabal_project_out="$(nix-store -q --outputs "$cabal_project_drv" | head -n 1)"
      [ ! -z "$cabal_project_out" ] && \cp -f "$cabal_project_out" cabal.project.local && chmod u+w cabal.project.local

      if [ -f cabal.project.local ]; then
        mkdir -p .nix
        store_paths="$(cat cabal.project.local | sed -n 's#.*\(/nix/store/.*\)#\1#p')"
        echo "$store_paths" | while read store_path; do
          target=".nix/$(echo "$store_path" | sed -n 's#/nix/store/\(.*\)#\1#p' | sed 's#/#-#g')"
          [ ! -e "$target" ] && cp -rf "$store_path" "$target" && chmod u+w -R "$target"
          sed -i "s#$store_path#$(readlink -f "$target")#g" cabal.project.local
        done
      fi
    }

    setup_cabal_to_nix 1> /dev/null
  '';
}

ymeister avatar Aug 06 '24 02:08 ymeister