WASM and singletons-base

I’m currently trying to build a haskell project which depends on singleton-base. Nevertheless, it fails with error:

wasm32-wasi-cabal build WASM -f WASM
Error: [Cabal-7125]
Failed to build singletons-base-3.4 (which is required by exe:WASM from ICFP2024-0.1.0.0). The failure occurred during the configure step. The exception was:
  /home/dan/.ghc-wasm/.cabal/logs/ghc-9.10.1.20241115/singletons-base-3.4-7143523c8a4505d927c5f8fad794d9ef09d9fff6b3616742b4c0a4219b648544.log: withFile: user error (Error: cabal:
'/nix/store/5hmcdnb69b7mbk2pjwv4fjxx85w5bpgd-wasm32-wasi-ghc-9.10/bin/wasm32-wasi-ghc'
exited with an error:
wasm-ld: error: unable to find library -lHSrts-1.0.2_thr
wasm32-wasi-clang: error: linker command failed with exit code 1 (use -v to
see invocation)
wasm32-wasi-ghc-9.10.1.20241115: `wasm32-wasi-clang' failed in phase `Linker'.
(Exit code: 1

I tried following the miso repo. My cabal.project looks like:

packages:
  .

index-state: 2024-11-15T08:25:42Z

if arch(wasm32)
  -- Required for TemplateHaskell. When using wasm32-wasi-cabal from
  -- ghc-wasm-meta, this is superseded by the global cabal.config.
  shared: True

  -- https://github.com/haskellari/time-compat/issues/37
  -- Older versions of time don't build on WASM.
  constraints: time installed
  allow-newer: time

package aeson
  flags: -ordered-keymap

Whilst my flake.nix is:

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
    flake-parts.url = "github:hercules-ci/flake-parts";
    haskell-flake.url = "github:srid/haskell-flake";
    ghc-wasm.url = "gitlab:haskell-wasm/ghc-wasm-meta?host=gitlab.haskell.org";

  };
  outputs = inputs@{ self, nixpkgs, flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      systems = nixpkgs.lib.systems.flakeExposed;
      imports = [ inputs.haskell-flake.flakeModule];

      perSystem = { self', pkgs, config, ... }:
        let
          stack-wrapped = pkgs.symlinkJoin {
            name = "stack"; # will be available as the usual `stack` in terminal
            paths = [ pkgs.stack ];
            buildInputs = [ pkgs.makeWrapper ];
            postBuild = ''
              wrapProgram $out/bin/stack \
                --add-flags "\
                  --no-nix \
                  --system-ghc \
                  --no-install-ghc \
                "
            '';
          };
        in {

        haskellProjects.default = {
          basePackages = pkgs.haskell.packages.ghc982;
          packages = {
          };
          settings = {
             singletons-base = {
              check = false;
             };
             singletons-base_3_3 = {
              check = false;
             };

             singletons = {
              check = false;
             };

             singletons-th = {
              check = false;
             };
          };
          devShell = {
            hlsCheck.enable = true;
            hoogle = true;
           };
          autoWire = [ "packages" "apps" "checks" ];

        };
        packages.default = self'.packages.ICFP2024;
        devShells.default = pkgs.mkShell {
          name = "haskell-template";
          meta.description = "Haskell development environment";
          inputsFrom = [
            config.haskellProjects.default.outputs.devShell
          ];
          nativeBuildInputs =
            [ inputs.ghc-wasm.packages.${pkgs.system}.all_9_10
              stack-wrapped
              pkgs.hpack
              pkgs.just
              pkgs.nodejs_20
              pkgs.nodePackages.npm
            ];
        };
      };
    };
}

Beside that, my .cabal file passes the following ghc-options to the executable:

ghc-options: -no-hs-main -optl-mexec-model=reactor -optl-Wl,--export=cmain -O2

As far as I know singletons-base does pure operations only. What am I missing?

This is a threaded RTS, unsupported by WASM. Any chance you have ghc-options: -threaded anywhere?

As far as I know no. My package.yaml is:

name:                ICFP2024
version:             0.1.0.0
github:              "githubuser/ICFP2024"
license:             BSD-3-Clause
author:              "Author name here"
maintainer:          "example@example.com"
copyright:           "2024 Author name here"

extra-source-files:
- README.md
- CHANGELOG.md

# Metadata used when publishing your package
# synopsis:            Short description of your package
# category:            Web

# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description:         Please see the README on GitHub at <https://github.com/githubuser/ICFP2024#readme>

dependencies:
  - base >= 4.7 && < 5
  - containers
  - mtl
  - transformers
  - parsec
  - pretty
  - text >= 1.2
  - jsaddle
  - jsaddle-wasm
  - singletons
  - singletons-base
  - singletons-th

flags:
  WASM:
    description: "target WASM architecture"
    manual: true
    default: false


ghc-options:
- -Wall
- -Wcompat
- -Widentities
- -Wincomplete-record-updates
- -Wincomplete-uni-patterns
- -Wmissing-export-lists
- -Wmissing-home-modules
- -Wpartial-fields
- -Wredundant-constraints

library:
  source-dirs: 
    - src

  when:
    condition: flag(WASM)
    cpp-options: -DWASM


executables:
  ICFP2024-exe:
    main:                Main.hs
    source-dirs:         app
    ghc-options:
      - -no-hs-main
      - -optl-mexec-model=reactor
      - -optl-Wl,--export=cmain
      - -O2
      
 
    dependencies:
    - ICFP2024
    when:
      condition: flag(WASM)
      cpp-options: -DWASM
  
  WASM:
    main:                WASM.hs
    source-dirs:         wasm
    ghc-options:
      - -no-hs-main
      - -optl-mexec-model=reactor
      - -optl-Wl,--export=cmain
      - -O2
     

    dependencies:
    - ICFP2024

tests:
  ICFP2024-test:
    main:                Spec.hs
    source-dirs:         test
    dependencies:
    - ICFP2024

Then I generate the .cabal via hpack

It’s because singletons-base uses build-type: Custom, a legacy Cabal feature which is very slowly being phased out and isn’t supported by the Wasm backend. For singletons-base in particular, it looks like it should be possible to just fork and change to build-type: Simple since the custom setup is only used for tests.

Funnily enough, I’ve had this same problem today while building another library. As for why it generates such an inscrutable error, I have no idea (@TerrorJack?). I don’t currently have any other cross-compilers to hand but I seem to remember when targeting ARM that GHC showed something more intuitive in this scenario.

2 Likes

You are right! I totally forgot about the build-type: Custom. Forking solved the issue c:

2 Likes

For what it’s worth, you are not the only person to encounter issues related to singletons-base's custom Setup.hs script, and I’ve wanted to remove it for a very long time. I am hoping to actually do so in time for the next singletons-base Hackage release (see this issue for the specifics).

8 Likes

Sadly, I’ve encountered an obstacle: Hackage currently does not permit uploading packages that require cabal-version: 3.8, but that is a prerequisite to using cabal code generators. See Cannot upload `cabal-version: 3.8` package to Hackage · Issue #1351 · haskell/hackage-server · GitHub. Depending on how difficult it is to fix that on the Hackage side, I may have to put off replacing the custom Setup.hs script until later.

Here’s what happens:

  • cabal attempts to link the custom Setup.hs using the only ghc it knows of: wasm32-wasi-ghc, and tries to link with -threaded
  • wasm32-wasi-ghc doesn’t ship threaded rts yet, hence the error

It’ll take a lot of work to make vanilla cabal support using a separate host-only ghc to build custom Setup.hs and even with that, most custom Setup.hs scripts either do trivial stuff like doctest or do cursed stuff which absolutely doesn’t have cross compilation in mind. So when doing cross compilation, you need to audit your dependencies and strip all custom Setup.hs use sites.

I agree the error message should be improved; there’s #24872: ghc driver should fail loudly when trying to build with -threaded when there's no threaded RTS · Issues · Glasgow Haskell Compiler / GHC · GitLab that I labeled as a newcomer ticket, if anyone wants to give it a try I’m glad to help :slight_smile:

1 Like