How can I get the GHC with JS backend enabled?

GHC supposedly has the JS and Wasm backend now, but it’s not possible to use it as a cross compiler yet. It’s necessary to build the GHC instance with specific backend enabled by default.

I’m trying to create an environment that has both the “normal” GHC that targets the host platform, as well as the one that targets JavaScript.

While investigating this, I’ve noticed that there’s some mention of the JavaScript back-end in the nixpkgs GHC definition, and it seems like the targetPlatform.isGhcjs is related to the building of a JS backend enabled GHC.

From what I understand, that flag is set by the current system, or by choosing pkgsCross.ghcjs. I’ve tried picking the compiler version from there, but I get a following error message:

string '"x86_64-linux"' is not equal to string '"javascript-ghcjs"'

Now, I feel like I’ve perhaps misunderstood the pkgsCross purpose, as it seems like that is supposed to give me a GHC built on my host platform to run on the JavaScript “machine”. Which… is not what I really want I guess.

Anyway. I’m stuck on this and can’t figure it out, here’s what I currently have in my flake:

{
  description = "Haskell JS stuff";

  inputs =
  {
    nixpkgs.url = "github:nixos/nixpkgs";
    # ghcjs.url = "git+https://gitlab.haskell.org/ghc/ghc.nix";
  };

  outputs = { self , nixpkgs }:
  let
    pkgs = import nixpkgs { system = "x86_64-linux"; };
    ckgs = import nixpkgs { system = "javascript-unknown-ghcjs"; crossSystem = { config = "x86_64-linux"; }; };

    ghc = pkgs.haskell.compiler.ghc9101;
    ghc-js = ckgs.pkgsCross.ghcjs.haskell.compiler.ghc9101;
  in
    {
      devShells.x86_64-linux.default = with pkgs; mkShell
      {
        packages = [ ghc-js cabal-install ghcid ];
      };
    };
}

The ckgs and the ghc-js stuff is just my last ditch attempt at getting the GHC with a JS back-end enabled.

1 Like

I am not at all experienced at cross compilation stuff, but I think crossSystem sets both the host platform and the target platform, and what you want is to set just the target platform to ghcjs and leave the host platform equal to the build platform.

Instead of setting the system via the Nixpkgs argument, maybe something like this (completely untested, this might be entirely the wrong approach too)?

haskell.compiler.ghc9101.override {
  stdenv = stdenv.override {
    targetPlatform = lib.system.examples.ghcjs;
  };
}

It seems like that was on the right track, it just needed a bit “richer” targetPlatform than what was offered by the lib.system.examples.ghcjs, so I’ve used the one from the pkgsCross.ghcjs :slight_smile:

It’s building now, so hopefully something will come of it. I’ll keep this thread updated for anyone interested and report back once it’s done.

{
  description = "Haskell JS stuff";

  inputs =
  {
    nixpkgs.url = "github:nixos/nixpkgs";
  };

  outputs = { self , nixpkgs }:
  {
    devShells.x86_64-linux.default = with import nixpkgs { system = "x86_64-linux"; }; with pkgs;
    let
      ghc = haskell.compiler.ghc9101;
      ghc-js = haskell.compiler.ghc9101.override
      {
        stdenv = stdenv.override { targetPlatform = pkgsCross.ghcjs.stdenv.targetPlatform; };
      };
    in
      mkShell
      {
        packages = [ ghc-js cabal-install ghcid ];
      };
  };
}
1 Like

This appears to be working. I haven’t compiled anything yet, but invoking the GHCwith --print-target-platform results in javascript-unknown-ghcjs.

Do note that it seems like if we change the default platform settings the derivation will output a differently named binary. Instead of a “clean” ghc we get javascript-unknown-ghcjs-ghc. Which is convenient, because I don’t have to tweak the derivations further in order to be able to have both the native GHC and the JS enabled GHC simultaneously.

I’ve added a ghcjs alias for convenience:

{
  description = "A pristine single page web app example written in Haskell.";

  inputs =
  {
    nixpkgs.url = "github:nixos/nixpkgs";
  };

  outputs = { self , nixpkgs }:
  {
    devShells.x86_64-linux.default = with import nixpkgs { system = "x86_64-linux"; }; with pkgs;
    let
      ghc = haskell.compiler.ghc9101;
      ghc-js = haskell.compiler.ghc9101.override
      {
        stdenv = stdenv.override { targetPlatform = pkgsCross.ghcjs.stdenv.targetPlatform; };
      };
    in
      mkShell
      {
        packages = [ ghc ghc-js cabal-install ghcid hello ];
        shellHook = "alias ghcjs=javascript-unknown-ghcjs-ghc";
      };
  };
}