Skip to content

Instantly share code, notes, and snippets.

@supermario
Last active November 7, 2022 20:14
Show Gist options
  • Save supermario/3deeaa98396189e541a7532a66334f61 to your computer and use it in GitHub Desktop.
Save supermario/3deeaa98396189e541a7532a66334f61 to your computer and use it in GitHub Desktop.
Elm Architecture Support

A summary of the Elm architectures/compilation/installation/usage matrix state of affairs.

Terms

I've picked the following of the synonyms that get used interchangeably:

  • x86_64: x64, amd64
  • arm64: aarch64
  • macos: macosx, darwin
  • win: windows

For reference:

Context

Problem aspect 1: npm/elm installer

The npm/elm installer package was not intended for normal installs, but appears to have regardless become used as a way to specify an Elm dependency especially on projects, packages and tooling using npm.

A particular source of problems is with Javascript bundlers, i.e:

Because npm/elm explicitly adds support for os,arch pairs, it thus becomes the defacto arbiter of os/arch support source for projects that rely on it as a dependency.

There is currently no standard way to override the Elm binary pulled in by npm/elm, i.e. with an ELM_COMPILER ENV var or otherwise. Individual packages/tools that consume Elm npm would have to each implement a mechanism to do this.

Some folks have had success by manually replacing the binary in ./node_modules/elm/bin/elm after an npm install.

Problem aspect 2: Rise in arm64 architecture usage

ARM based processors are increasingly prevalent in both "desktop" devices and cloud computing.

  • Amazon Web Services launched ARM-based EC2 A1 instances in late 2018, offering cost savings + improved performance compared to other instance types.
  • Apple Silicon M-series chipsets (Nov 2020 onwards), Apple completely moving away from Intel x86 chips.
    • Has the side-effect that developers with new Macbooks who use docker, which runs as linux-arm64 on macos-arm64 chips, run into problem 1.
  • Cloud CI pipelines are starting to show arm64 support, i.e. GitHub Actions: Self-hosted runners now support Apple M1 hardware
  • .NET 4.8.1 added arm64 support (Aug 2022). Possible we'll start to see more win-arm64 demand in future on Windows 11+.

Given Elm is written in Haskell, the availability of an *-arm64 binary is dependent on GHC's support for arm64 builds, which has evolved since Nov 2020 and is now feasible on both macos and linux.

Related meta issue: #2007 - What are use-cases for more binaries? (32-bit and ARM)

Current support by architecture, install method and usage

GHC Official Binary Static build Elm npm Elm npm in Docker
macos-x86_64 βœ… βœ… ❓ βœ… βœ…
macos-arm64 🟠 1 ❌πŸ§ͺ ❓ 🟠 2 ❌ 3
linux-x86_64 βœ… βœ… βœ… βœ… βœ…
linux-arm64 βœ… ❌πŸ§ͺ ❌4 ❌ ❌
win-x86_64 βœ… βœ… βœ… ❌
win-arm64 ❓
  1. GHC has two backends: NCG (native code generator), and LLVM

    • GHC 8.10.5+ only supports macos-arm64 builds using the new LLVM backend (equivalent performance, significant increase in Haskell compile times)
    • GHC 9.2.1+ apparently supports both the faster NCG and LLVM backends for macos-arm64
      • Need to try stack build with system GHC as latest LTS is only 9.0.2 so uses LLVM
  2. A workaround was added in elm/compiler#2156 - Allow M1 users to continue to install elm via our npm package which relies on the Elm npm installer serving macos-x86_64 binaries to both x86_64 and arm64 platforms.

    • This workaround has an implicit dependency on the user additionally installing Rosetta 2, a macos-arm64 based x86_64 emulator.
      • This was an okay-ish assumption initially as developers with early M-series Macbook's simply installed Rosetta to get software covergage when arm64 builds were generally unavailable.
      • But it's now been 2 years since macos-arm64 was released, and we're starting to see users choosing to not install Rosetta because they don't need it.
      • So IMO this workaround has now become a 'hack', thus increasingly causing issues for folks installing Elm or tooling relying on the Elm npm package on macos-arm64.
    • Related issues:
  3. Docker on macos-arm64 will use a linux-arm64 engine, hence why Elm install via npm fails as there is no linux_arm64 mapping in the Elm npm package.

  4. GLIBC isn't suitable for linux static builds, but building under Alpine with MUSL (the x86 solution) doesn't yet work for Alpine as no official GHC/Cabal/Stack builds exist for alpine-arm64.

Suggestions

  • We work on an official macos-arm64 build and fix the hack in Elm npm

    • Stops aarch-mixing confusion, removes implicit dependency on Rosetta
    • The Homebrew binary could be offered as a quick interim fix
  • We work on an official linux-arm64 build and add support to Elm npm

    • Enables linux-arm64 usage and fixes Docker on macos-arm64 problems.
  • We update the npm/elm package to use optionalDependencies (@lydell is on this)

πŸ§ͺ Actions

Work underway to get official builds for *-arm64 platforms:

  • macos-arm64

    • Working with GHC 9.0.2 via stack: commit
      $ file `which elmx`
      /Users/mario/.local/bin/elmx: Mach-O 64-bit executable arm64
      $ ls -alh `which elm-dev`
      -rwxr-xr-x  1 mario  staff    87M  5 Nov 11:05 /Users/mario/.local/bin/elmx
      
      • The same x86_64 build is 17M so definitely some build size issue to hunt down.
    • 🚧 Direct cabal based build for 9.0.2
    • 🚧 Direct cabal based build for 9.2.*
    • 🚧 Direct cabal based build for 9.4.*
    • Notes:
      • Homebrew is offering a macos-arm64 build of Elm, however it is even larger (92M), possibly related to LLVM. See further below for other unofficial binaries.
  • linux-arm64:

    • Dynamic build working on MacOS arm64 system via docker: commit
    • 🚧 Static build on Alpine
      • GHC/Cabal/Stack don't have alpine-arm64 builds unfortunately
    • Notes:

CI limitations

  • Github CI does not yet support macos-arm64 nor linux-arm64 runtimes on Github runners, we'd have to look at setting up self-hosted runners.

Related issues

  • Linux has some library upgrade issues with libtinfo5 / ncurses5-compat. These have been resolved in other Haskell projects by building with MUSL instead of GCC. Might be worth looking into that simultaneously. More info TBC.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment