Skip to content

Build on Linux/macOS #365

Build on Linux/macOS

Build on Linux/macOS #365

# Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
# Licensed under Apache License Version 2.0
name: Build on Linux/macOS
on:
pull_request:
push:
schedule:
- cron: '0 3 * * 5' # Every Friday at 3am
workflow_dispatch:
# Minimum permissions for security
permissions:
contents: read
jobs:
linux:
name: Build (${{ matrix.cc }}/${{ matrix.make }} on ${{ matrix.runs-on }})
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
include:
- cc: gcc-14
clang_major_version: null
clang_repo_suffix: null
make: make
runs-on: ubuntu-24.04
- cc: clang-18
clang_major_version: 18
clang_repo_suffix: -18
make: bmake
runs-on: ubuntu-22.04
- cc: musl-gcc
clang_major_version: null
clang_repo_suffix: null
make: bmake
runs-on: ubuntu-22.04
- cc: gcc-12
clang_major_version: null
clang_repo_suffix: null
make: make
runs-on: macos-12
- cc: gcc-13
clang_major_version: null
clang_repo_suffix: null
make: bmake
runs-on: macos-12
- cc: clang-15
clang_major_version: 15
clang_repo_suffix: null
make: bsdmake
runs-on: macos-12
steps:
- name: Add Clang/LLVM repositories
if: "${{ runner.os == 'Linux' && contains(matrix.cc, 'clang') }}"
run: |-
set -x
source /etc/os-release
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository "deb http://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}${{ matrix.clang_repo_suffix }} main"
- name: Install build dependencies
if: "${{ runner.os == 'Linux' }}"
run: |-
sudo apt-get update
sudo apt-get install --yes --no-install-recommends \
bmake \
libncurses-dev \
musl-tools \
pkg-config
- name: Install build dependencies
if: "${{ runner.os == 'macOS' }}"
run: |-
brew install \
bmake \
bsdmake \
coreutils
- name: Install build dependency Clang ${{ matrix.clang_major_version }}
if: "${{ runner.os == 'Linux' && contains(matrix.cc, 'clang') }}"
run: |-
sudo apt-get install --yes --no-install-recommends -V \
clang-${{ matrix.clang_major_version }} \
libclang-rt-${{ matrix.clang_major_version }}-dev
- name: Add versioned aliases for Clang ${{ matrix.clang_major_version }}
if: "${{ runner.os == 'macOS' && contains(matrix.cc, 'clang') }}"
run: |-
set -x
sudo ln -s "$(brew --prefix llvm@${{ matrix.clang_major_version }})"/bin/clang /usr/local/bin/clang-${{ matrix.clang_major_version }}
sudo ln -s "$(brew --prefix llvm@${{ matrix.clang_major_version }})"/bin/clang++ /usr/local/bin/clang++-${{ matrix.clang_major_version }}
- name: Checkout Git branch
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Build musl Ncurses
if: "${{ runner.os == 'Linux' && contains(matrix.cc, 'musl') }}"
run: |-
set -x -o pipefail
sudo apt-get remove --yes libncurses-dev # to be sure to not mix them
wget -q https://invisible-island.net/datafiles/release/ncurses.tar.gz
tar xf ncurses.tar.gz
pushd ncurses-*/
configure_args=(
# Redirect everything to musl
CC=musl-gcc
--prefix=/usr
--includedir=/usr/include/x86_64-linux-musl
--libdir=/usr/lib/x86_64-linux-musl
# Enable things we rely on
--enable-pc-files
--enable-shared
--enable-widec
# Disable things we don't need (to speed up CI)
--disable-static
--without-cxx-binding
--without-manpages
--without-progs
--without-tack
--without-tests
)
./configure "${configure_args[@]}"
make -j$(nproc)
sudo make install
popd
rm -Rf ncurses-*/ ncurses.tar.gz
# Mass-fix "#include <x86_64-linux-musl/foo.h>" to "#include <foo.h>"
grep -RlF "<x86_64-linux-musl/" /usr/include/x86_64-linux-musl/ \
| xargs sudo sed 's,<x86_64-linux-musl/,<,' -i
- name: 'Build'
env:
CC: ${{ matrix.cc }}
MAKE: ${{ matrix.make }}
run: |-
set -x
# macOS default linker does not seem to support --as-needed,
# would error out saying "ld: unknown option: --as-needed"
if [[ ${{ runner.os }} = macOS ]]; then
as_needed=
else
as_needed='-Wl,--as-needed'
fi
# musl-gcc does not seem to support linking with sanitizers
if [[ ${{ matrix.cc }} =~ musl ]]; then
sanitizer=
else
# ASan: https://clang.llvm.org/docs/AddressSanitizer.html
# UBSan: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
sanitizer='-fsanitize=address,undefined -fno-sanitize-recover=all'
fi
${MAKE} --version 2>/dev/null || true
CFLAGS="-std=c99 -pedantic -Werror ${sanitizer} -O1" LDFLAGS="${as_needed} ${sanitizer}" ${MAKE}
- name: 'Install'
env:
MAKE: ${{ matrix.make }}
run: |-
set -x -o pipefail
${MAKE} install DESTDIR="${PWD}"/ROOT/
find ROOT/ | sort | xargs ls -ld
- name: 'Uninstall'
env:
MAKE: ${{ matrix.make }}
run: |-
set -x
${MAKE} uninstall DESTDIR="${PWD}"/ROOT/
[[ "$(find ROOT/ -not -type d | tee /dev/stderr)" == '' ]] # i.e. fail CI if leftover files
- name: 'Run UI tests'
run: |-
./recordings/record.sh
rm -Rf recordings/venv/
- name: 'Upload UI test renderings for inspection'
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
with:
name: ttyplot_ui_test_${{ github.sha }}_${{ matrix.runs-on }}_${{ matrix.cc }}_${{ matrix.make }}
path: recordings/actual*
if-no-files-found: error
- name: 'Evaluate UI test results'
run: |-
cat <<"EOF"
################################################################
## If this step FAILS you can get the expected ANSI screenshots
## back in sync with reality by running:
##
## $ ./recordings/get_back_in_sync.sh
##
## More details on the topic can be found in CONTRIBUTING.md .
################################################################
EOF
diff -u recordings/{expected,actual}.txt
rm -f recordings/actual.txt
- name: 'Clean'
env:
MAKE: ${{ matrix.make }}
run: |-
set -x -o pipefail
${MAKE} clean
[[ "$(git ls-files -o | tee /dev/stderr | wc -l)" -eq 0 ]]