Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/actions/setup-haskell/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Setup Haskell
description: |
This action sets up a Haskell environment for use in actions by
adding the GHC and Cabal binaries to the PATH. It also caches
the GHC and Cabal installations to speed up subsequent runs.

inputs:
ghc-version:
description: |
The version of GHC to install.
required: false
default: "8.10.7"

cabal-version:
description: |
The version of Cabal to install.
required: false
default: "latest"

cabal-project-dir:
description: |
The working directory for the action.
required: false
default: "waspc"

runs:
using: composite

steps:
- uses: haskell-actions/setup@v2
id: setup-haskell
with:
ghc-version: ${{ inputs.ghc-version }}
cabal-version: ${{ inputs.cabal-version }}

- name: Verify Haskell setup
shell: bash
run: |
ghc --version
cabal --version

# Based on the official recipe for Cabal caching:
# https://github.com/actions/cache/blob/v4.2.3/examples.md#haskell---cabal
- name: Cache Cabal dependencies
uses: actions/cache@v4
with:
# There are two extra directories that are commonly cache, that we've
# decided not to cache:
#
# - `./dist-newstyle`: Our internal code builds quite fast, and changes
# often enough that a cache would need to be invalidated on every run, and
# make our caching story much more complex.
#
# - `~/.cabal/packages`: This is a local cache of the package index. While
# it could be useful, we build in heterogeneous environments and it is
# not always in the same paths. From testing, in packages with a frozen
# `index-state` like ours, the build will just download a single ~4kb file.
# So it is not worth the complexity of caching.
#
# We do cache the Cabal store, which is where the actual built packages
# are stored, as it is the most expensive part of the build, and easily
# reusable.
path: |
${{ steps.setup-haskell.outputs.cabal-store }}
key: |
cabal-${{ inputs.cabal-project-dir }}-${{ runner.os }}-${{ runner.arch }}-${{ inputs.ghc-version }}-${{ hashFiles('${{ inputs.cabal-project-dir }}/*.cabal', '${{ inputs.cabal-project-dir }}/*.project', '${{ inputs.cabal-project-dir }}/*.project.freeze') }}
restore-keys: |
cabal-${{ inputs.cabal-project-dir }}-${{ runner.os }}-${{ runner.arch }}-${{ inputs.ghc-version }}-
36 changes: 0 additions & 36 deletions .github/actions/setup-haskell/action.yml

This file was deleted.

2 changes: 0 additions & 2 deletions .github/workflows/check-formatting.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ jobs:
- uses: actions/checkout@v4

- uses: ./.github/actions/setup-haskell
with:
cabal-project: dev-tool.project
Comment on lines -40 to -41
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover from previous version of the action


- working-directory: waspc
run: ./run ormolu:check
174 changes: 174 additions & 0 deletions .github/workflows/waspc-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
name: Build wasp-cli binaries for multiple platforms

# We never trigger this workflow directly.
# We can call it manually (workflow_dispatch) or from other workflows (workflow_call).
on:
workflow_dispatch:
inputs:
ghc-version:
description: "GHC version to use"
default: "8.10.7"
required: false
node-version:
description: "Node.js version to use"
default: "22"
required: false
workflow_call:
inputs:
ghc-version:
description: "GHC version to use"
default: "8.10.7"
type: string
required: false
node-version:
description: "Node.js version to use"
default: "22"
type: string
required: false

jobs:
build:
strategy:
fail-fast: false

matrix:
# == Why such a big, heterogeneous list? ==
# This is a bit of mish-mash of different platforms and architectures,
# so we need to build some of these directly in the runners, and some in
# containers. Each environment is a different OS and needs different
# dependencies.
#
# When possible, we build inside containers so we are not affected when
# GitHub updates the runners or deprecates old ones. When we build inside
# containers, the runner is only used to host the container, and all the
# steps are run inside the container and not the host (like a Dockerfile).
env:
- name: linux-x86_64
runner: ubuntu-latest
# We use an old Ubuntu version so we can link to a low `glibc` version.
# `glibc` is backwards-compatible but not forwards-compatible, so it
# is a good idea to use the oldest version we reasonably can. Otherwise,
# the wasp binary would possibly not work on the system using an older
# glibc than what it was built with (e.g. an older Ubuntu version).
container: ubuntu:20.04
static: false
install-deps: |
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
# GHCup dependencies (https://www.haskell.org/ghcup/install/#version-2004-2010)
apt-get install -y build-essential curl libffi-dev libffi7 libgmp-dev libgmp10 libncurses-dev libncurses5 libtinfo5
# Cabal dependencies
apt-get install -y zlib1g-dev

# TODO: Add a Linux ARM64 build once we update the GHC version (#1446)
# GHC 8.10.7 does not support ARM64 on Linux yet

- name: linux-x86_64-static
runner: ubuntu-latest
# actions/setup-node does not work in alpine.
# https://github.com/actions/setup-node/issues/1293
# To work around this, we use the alpine variant of the official node
# image, which already has a working Node.js version installed.
container: node:${{ inputs.node-version }}-alpine
skip-node-install: true
static: true
install-deps: |
apk update
# GHCup dependencies (https://www.haskell.org/ghcup/install/#linux-alpine)
apk add binutils-gold curl gcc g++ gmp-dev libc-dev libffi-dev make musl-dev ncurses-dev perl pkgconfig tar xz
# `./run` script dependencies
apk add bash
# Cabal dependencies
apk add zlib-dev zlib-static

- name: darwin-x86_64
runner: macos-13 # Latest image still based on Intel architecture that can be used for free

# macOS's syscalls are private and change between versions, so we
# can't statically link the binary. However, on macOS programs link
# to `libSystem`, which is quite stable between releases, so we're
# fine depending on it.
static: false

- name: darwin-aarch64
runner: macos-latest # Latest macOS images are already Apple Silicon-based
static: false # Check the comment above for why we can't statically link on macOS
install-deps: |
# We need to install llvm@13 for building on Apple Silicon (prebuilt libraries
# are only available for x86_64). The llvm@13 formula is not available in
# Homebrew by default, but we can edit it and comment out the `disable!` line.
curl -fsSL https://raw.githubusercontent.com/Homebrew/homebrew-core/74572f47ce6a2463c19d7fa164ab9fb8c91bbe61/Formula/l/llvm%4013.rb > /tmp/llvm@13.rb
sed -i '' 's/disable!/# disable!/' /tmp/llvm@13.rb
brew install --formula /tmp/llvm@13.rb
brew link --force llvm@13

runs-on: ${{ matrix.env.runner }}
container: ${{ matrix.env.container }}

steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: ${{ matrix.env.install-deps }}

- uses: ./.github/actions/setup-haskell
with:
ghc-version: ${{ inputs.ghc-version }}

- uses: actions/setup-node@v4
if: ${{ !matrix.env.skip-node-install }}
with:
node-version: ${{ inputs.node-version }}

- name: Build and package
working-directory: waspc
env:
LC_ALL: C.UTF-8 # In some Docker containers the LOCALE is not UTF-8 by default
run: |
./run build:all${{ matrix.env.static && ':static' || '' }}
mkdir -p artifacts
./tools/make_binary_package.sh "artifacts/wasp-${{ matrix.env.name }}.tar.gz"

- uses: actions/upload-artifact@v4
with:
path: ./waspc/artifacts/*
name: wasp-${{ matrix.env.name }}
if-no-files-found: error

build-universal:
needs: build
runs-on: macos-latest
steps:
- name: Download macOS binaries
uses: actions/download-artifact@v4
with:
pattern: wasp-darwin-*

- name: Unpack, create universal binary and pack
run: |
set -ex # Fail on error and print each command

input_arch=(
darwin-x86_64
darwin-aarch64
)

# Extract each architecture
for arch in "${input_arch[@]}"; do
mkdir "arch-$arch"
tar -xzf "wasp-${arch}.tar.gz" -C "arch-$arch"
done

mkdir universal
# Create the universal binary
lipo -create arch-*/wasp-bin -output universal/wasp-bin
# Copy the data folder too
cp -R "arch-${input_arch[0]}/data" universal/

# Pack back up
tar -czf wasp-darwin-universal.tar.gz -C universal .

- uses: actions/upload-artifact@v4
with:
name: wasp-darwin-universal
path: ./wasp-darwin-universal.tar.gz
10 changes: 8 additions & 2 deletions waspc/run
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ WASP_PACKAGES_COMPILE="${SCRIPT_DIR}/tools/install_packages_to_data_dir.sh"
BUILD_HS_CMD="cabal build all"
BUILD_HS_FULL_CMD="cabal build all --enable-tests --enable-benchmarks"
BUILD_ALL_CMD="$WASP_PACKAGES_COMPILE && $BUILD_HS_CMD"
BUILD_ALL_STATIC_CMD="$WASP_PACKAGES_COMPILE && $BUILD_HS_CMD --enable-executable-static"

INSTALL_CMD="$WASP_PACKAGES_COMPILE && cabal install --overwrite-policy=always"

Expand Down Expand Up @@ -56,8 +57,8 @@ ORMOLU_CHECK_CMD="$ORMOLU_BASE_CMD --mode check "'$'"(git ls-files '*.hs' '*.hs-
ORMOLU_FORMAT_CMD="$ORMOLU_BASE_CMD --mode inplace "'$'"(git ls-files '*.hs' '*.hs-boot')"

echo_and_eval() {
echo -e $"${LIGHT_CYAN}Running:${DEFAULT_COLOR}" $1 "\n"
eval $1
echo -e $"${LIGHT_CYAN}Running:${DEFAULT_COLOR}" "$1" "\n"
eval "$1"
}

echo_bold() { echo -e $"${BOLD}${1}${RESET}"; }
Expand All @@ -78,6 +79,8 @@ print_usage() {
"Builds the Haskell project."
print_usage_cmd "build:all" \
"Builds the Haskell project + all sub-projects (i.e. TS packages)."
print_usage_cmd "build:all:static" \
"Builds the Haskell project statically + all sub-projects (i.e. TS packages). Only useful for release builds. Needs to be run on a musl-based Linux distribution (e.g. Alpine)."
print_usage_cmd "build:packages" \
"Builds the TypeScript projects under packages/."
echo ""
Expand Down Expand Up @@ -139,6 +142,9 @@ case $COMMAND in
build:all)
echo_and_eval "$BUILD_ALL_CMD"
;;
build:all:static)
echo_and_eval "$BUILD_ALL_STATIC_CMD"
;;
build:packages)
echo_and_eval "$WASP_PACKAGES_COMPILE"
;;
Expand Down
Loading