Skip to content

Merge pull request #2268 from pguyot/w16/renode-1.16.1 #7174

Merge pull request #2268 from pguyot/w16/renode-1.16.1

Merge pull request #2268 from pguyot/w16/renode-1.16.1 #7174

#
# Copyright 2017-2022 Davide Bettio <davide@uninstall.it>
#
# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
#
name: Build and Test
on:
push:
paths-ignore:
- 'src/platforms/emscripten/**'
- 'src/platforms/esp32/**'
- 'src/platforms/rp2/**'
- 'src/platforms/stm32/**'
- 'doc/**'
- 'LICENSES/**'
- '*.Md'
- '*.md'
pull_request:
paths-ignore:
- 'src/platforms/emscripten/**'
- 'src/platforms/esp32/**'
- 'src/platforms/rp2/**'
- 'src/platforms/stm32/**'
- 'doc/**'
- 'LICENSES/**'
- '*.Md'
- '*.md'
concurrency:
group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }}
cancel-in-progress: true
env:
DEFAULT_OTP_VERSION: "28"
DEFAULT_ELIXIR_VERSION: "1.19"
DEFAULT_REBAR3_VERSION: "3.25.1"
DEFAULT_GLEAM_VERSION: "1.11.1"
DEFAULT_CFLAGS: "-O3"
DEFAULT_CMAKE_OPTS_OTHER: "-DAVM_WARNINGS_ARE_ERRORS=ON"
jobs:
build-and-test:
runs-on: ${{ matrix.os || 'ubuntu-24.04' }}
container: ${{ matrix.container }}
strategy:
fail-fast: false
matrix:
# Ubuntu 20.04 has gcc from 7 to 10 ("gcc" is gcc-9)
# Ubuntu 22.04 has gcc from 9 to 12 ("gcc" is gcc-11)
# Ubuntu 24.04 has gcc from 9 to 14 ("gcc" is gcc-13)
# Ubuntu 20.04 has clang 10 and 12 to ("clang" is 10)
# Ubuntu 22.04 has clang from 12 to 15 ("clang" is 14)
# Ubuntu 24.04 has clang from 14 to 18 ("clang" is 18)
# We want to test every compiler but don't need to test every OS
# We only test several OTP versions with default compilers for supported OSes (gcc 11, gcc 13, clang 14, clang 18)
cc: ["gcc-11", "gcc-13", "clang-14", "clang-18"]
otp: ["26", "27", "28"]
include:
### gcc
# erlef/setup-beam officially supports ubuntu 22 and 24, we are getting
# warnings for gcc 7 and 8 that require ubuntu 20.
- cc: "gcc-7"
cxx: "g++-7"
compiler_pkgs: "gcc-7 g++-7"
container: "ubuntu:20.04"
cmake_opts_other: " "
- cc: "gcc-8"
cxx: "g++-8"
compiler_pkgs: "gcc-8 g++-8"
container: "ubuntu:20.04"
# from gcc 9 we can use ubuntu 24.
- cc: "gcc-9"
cxx: "g++-9"
compiler_pkgs: "gcc-9 g++-9"
- cc: "gcc-10"
cxx: "g++-10"
compiler_pkgs: "gcc-10 g++-10"
- cc: "gcc-11"
cxx: "g++-11"
compiler_pkgs: "gcc-11 g++-11"
# otp: all
- cc: "gcc-12"
cxx: "g++-12"
compiler_pkgs: "gcc-12 g++-12"
- cc: "gcc-13"
cxx: "g++-13"
compiler_pkgs: "gcc-13 g++-13"
# otp: all
- cc: "gcc-14"
cxx: "g++-14"
compiler_pkgs: "gcc-14 g++-14"
### clang
- cc: "clang-10"
cxx: "clang++-10"
compiler_pkgs: "clang-10"
container: "ubuntu:20.04"
- cc: "clang-11"
cxx: "clang++-11"
compiler_pkgs: "clang-11"
container: "ubuntu:20.04"
# from clang 12 we can use ubuntu 22
- cc: "clang-12"
cxx: "clang++-12"
compiler_pkgs: "clang-12"
os: "ubuntu-22.04"
- cc: "clang-13"
cxx: "clang++-13"
compiler_pkgs: "clang-13"
os: "ubuntu-22.04"
- cc: "clang-14"
cxx: "clang++-14"
compiler_pkgs: "clang-14"
# otp: all
- cc: "clang-15"
cxx: "clang++-15"
compiler_pkgs: "clang-15"
- cc: "clang-16"
cxx: "clang++-16"
compiler_pkgs: "clang-16"
- cc: "clang-17"
cxx: "clang++-17"
compiler_pkgs: "clang-17"
- cc: "clang-18"
cxx: "clang++-18"
compiler_pkgs: "clang-18"
# otp: all
# Additional runs with older elixir
- cc: "cc"
cxx: "c++"
otp: "27"
elixir_version: "1.18"
- cc: "cc"
cxx: "c++"
otp: "27"
elixir_version: "1.17"
- cc: "cc"
cxx: "c++"
otp: "26"
elixir_version: "1.18"
- cc: "cc"
cxx: "c++"
otp: "26"
elixir_version: "1.17"
# Additional run with OTP master and default compiler
- cc: "cc"
cxx: "c++"
otp: "master"
elixir_version: "main"
# Additional latest & -Os compiler builds
- cc: "gcc-14"
cxx: "g++-14"
cflags: "-Os"
compiler_pkgs: "gcc-14 g++-14"
- cc: "clang-18"
cxx: "clang++-18"
cflags: "-Os"
compiler_pkgs: "clang-18"
# Additional build with 32 bits floats
- cc: "cc"
cxx: "c++"
cmake_opts_other: "-DAVM_USE_32BIT_FLOAT=ON -DAVM_WARNINGS_ARE_ERRORS=ON"
# Additional run with comma-decimal locale (de_DE)
- cc: "cc"
cxx: "c++"
locale: "de_DE.UTF-8"
# Additional run with -DAVM_CREATE_STACKTRACES=off
- cc: "cc"
cxx: "c++"
cmake_opts_other: "-DAVM_CREATE_STACKTRACES=off -DAVM_WARNINGS_ARE_ERRORS=ON"
# JIT build
- cc: "cc"
cxx: "c++"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF"
jit_target_arch: "x86_64"
# Additional 32 bits build
- container: "ubuntu:20.04"
cc: "gcc-10"
cxx: "g++-10"
cflags: "-m32 -O3"
cmake_opts_other: "-DAVM_CREATE_STACKTRACES=off -DAVM_WARNINGS_ARE_ERRORS=ON"
arch: "i386"
compiler_pkgs: "gcc-10 g++-10 gcc-10-multilib g++-10-multilib libc6-dev-i386
libc6-dbg:i386 zlib1g-dev:i386 libmbedtls-dev:i386"
# JIT build with OTP-28
- os: "ubuntu-24.04"
cc: "cc"
cxx: "c++"
cflags: ""
otp: "28"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF"
jit_target_arch: "x86_64"
# JIT build with OTP-29.0-rc1
- os: "ubuntu-24.04"
cc: "cc"
cxx: "c++"
cflags: ""
otp: "29.0-rc1"
version_type: "strict"
elixir_version: "1.19.5"
rebar3_version: "3.27.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF"
jit_target_arch: "x86_64"
# JIT + DWARF build (x86_64)
- os: "ubuntu-24.04"
cc: "cc"
cxx: "c++"
cflags: ""
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF"
jit_target_arch: "x86_64"
# arm64 builds
- os: "ubuntu-24.04-arm"
cc: "cc"
cxx: "c++"
- os: "ubuntu-24.04-arm"
cc: "cc"
cxx: "c++"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF"
jit_target_arch: "aarch64"
# JIT + DWARF build (aarch64)
- os: "ubuntu-24.04-arm"
cc: "cc"
cxx: "c++"
cflags: ""
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF"
jit_target_arch: "aarch64"
# armhf builds
- cc: "arm-linux-gnueabihf-gcc"
cxx: "arm-linux-gnueabihf-g++"
# -D_FILE_OFFSET_BITS=64 is required for making atomvm:posix_readdir/1 test work
# otherwise readdir will fail due to 64 bits inode numbers with 32 bit ino_t
cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O3 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64"
cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support"
arch: "armhf"
library-arch: arm-linux-gnueabihf
# JIT armv6m build (Thumb-1 only JIT code)
- cc: "arm-linux-gnueabihf-gcc"
cxx: "arm-linux-gnueabihf-g++"
cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O3 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=armv6m -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support"
arch: "armhf"
library-arch: arm-linux-gnueabihf
jit_target_arch: "armv6m"
# JIT armv6m+thumb2 build (Thumb-2 JIT code)
- cc: "arm-linux-gnueabihf-gcc"
cxx: "arm-linux-gnueabihf-g++"
cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O3 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=armv6m+thumb2 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support"
arch: "armhf"
library-arch: arm-linux-gnueabihf
jit_target_arch: "armv6m+thumb2"
# JIT ARM32 (ARM mode) build
- cc: "arm-linux-gnueabihf-gcc"
cxx: "arm-linux-gnueabihf-g++"
cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O3 -marm -D_FILE_OFFSET_BITS=64"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=arm32 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support"
arch: "armhf"
library-arch: arm-linux-gnueabihf
jit_target_arch: "arm32"
# JIT + DWARF build (armv6m)
- os: "ubuntu-24.04"
cc: "arm-linux-gnueabihf-gcc"
cxx: "arm-linux-gnueabihf-g++"
cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O2 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64"
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=armv6m -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support"
arch: "armhf"
library-arch: arm-linux-gnueabihf
jit_target_arch: "armv6m"
# JIT + DWARF build (armv6m+thumb2)
- os: "ubuntu-24.04"
cc: "arm-linux-gnueabihf-gcc"
cxx: "arm-linux-gnueabihf-g++"
cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O2 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64"
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=armv6m+thumb2 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support"
arch: "armhf"
library-arch: arm-linux-gnueabihf
jit_target_arch: "armv6m+thumb2"
# JIT + DWARF build (arm32)
- os: "ubuntu-24.04"
cc: "arm-linux-gnueabihf-gcc"
cxx: "arm-linux-gnueabihf-g++"
cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O2 -marm -D_FILE_OFFSET_BITS=64"
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=arm32 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support"
arch: "armhf"
library-arch: arm-linux-gnueabihf
jit_target_arch: "arm32"
# s390x build
- cc: "s390x-linux-gnu-gcc"
cxx: "s390x-linux-gnu-g++"
cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/s390x_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-s390x libc6-dbg:s390x zlib1g-dev:s390x libmbedtls-dev:s390x qemu-user qemu-user-binfmt binfmt-support"
arch: "s390x"
library-arch: s390x-linux-gnu
# riscv64 build
- os: "ubuntu-24.04"
cc: "riscv64-linux-gnu-gcc"
cxx: "riscv64-linux-gnu-g++"
cflags: "-O2"
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv64_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-riscv64 libc6-dbg:riscv64 zlib1g-dev:riscv64 libmbedtls-dev:riscv64 qemu-user qemu-user-binfmt binfmt-support"
arch: "riscv64"
library-arch: riscv64-linux-gnu
# riscv64 build + jit
- os: "ubuntu-24.04"
cc: "riscv64-linux-gnu-gcc"
cxx: "riscv64-linux-gnu-g++"
cflags: "-O2"
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=riscv64 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv64_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-riscv64 libc6-dbg:riscv64 zlib1g-dev:riscv64 libmbedtls-dev:riscv64 qemu-user qemu-user-binfmt binfmt-support"
arch: "riscv64"
library-arch: riscv64-linux-gnu
jit_target_arch: "riscv64"
# JIT + DWARF build (riscv64)
- os: "ubuntu-24.04"
cc: "riscv64-linux-gnu-gcc"
cxx: "riscv64-linux-gnu-g++"
cflags: "-O2"
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=riscv64 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv64_toolchain.cmake"
compiler_pkgs: "crossbuild-essential-riscv64 libc6-dbg:riscv64 zlib1g-dev:riscv64 libmbedtls-dev:riscv64 qemu-user qemu-user-binfmt binfmt-support"
arch: "riscv64"
library-arch: riscv64-linux-gnu
jit_target_arch: "riscv64"
# riscv32-ilp32 build
- os: "ubuntu-24.04"
cc: "riscv32-unknown-linux-gnu-gcc"
cxx: "riscv32-unknown-linux-gnu-g++"
cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv32_ilp32_toolchain.cmake"
compiler_pkgs: "qemu-user qemu-user-binfmt binfmt-support"
arch: "riscv32"
library-arch: riscv32-linux-gnu-ilp32
# riscv32-ilp32 build + jit
- os: "ubuntu-24.04"
cc: "riscv32-unknown-linux-gnu-gcc"
cxx: "riscv32-unknown-linux-gnu-g++"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=riscv32 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv32_ilp32_toolchain.cmake"
compiler_pkgs: "qemu-user qemu-user-binfmt binfmt-support"
arch: "riscv32"
library-arch: riscv32-linux-gnu-ilp32
jit_target_arch: "riscv32"
# libsodium enabled build
- os: "ubuntu-24.04"
cc: "cc"
cxx: "c++"
cflags: ""
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_USE_LIBSODIUM=ON"
compiler_pkgs: "libsodium-dev"
# JIT + DWARF build (riscv32)
- os: "ubuntu-24.04"
cc: "riscv32-unknown-linux-gnu-gcc"
cxx: "riscv32-unknown-linux-gnu-g++"
cflags: "-O2"
otp: "28"
elixir_version: "1.17"
rebar3_version: "3.24.0"
cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=riscv32 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv32_ilp32_toolchain.cmake"
compiler_pkgs: "qemu-user qemu-user-binfmt binfmt-support"
arch: "riscv32"
library-arch: riscv32-linux-gnu-ilp32
jit_target_arch: "riscv32"
env:
ImageOS: ${{ matrix.container == 'ubuntu:20.04' && 'ubuntu20' || matrix.os == 'ubuntu-20.04' && 'ubuntu20' || matrix.os == 'ubuntu-22.04' && 'ubuntu22' || matrix.os == 'ubuntu-24.04' && 'ubuntu24' || 'ubuntu24' }}
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
CFLAGS: ${{ matrix.cflags }}
CXXFLAGS: ${{ matrix.cflags }}
DEBIAN_FRONTEND: noninteractive
TZ: "Etc/UTC"
steps:
# Setup
- name: "Set CFLAGS"
run: |
if [ $"CFLAGS" = "" ]; then
echo "CFLAGS=$DEFAULT_CFLAGS" >> $GITHUB_ENV
echo "CXXFLAGS=$DEFAULT_CFLAGS" >> $GITHUB_ENV
fi
- name: "Install deps for containers"
if: matrix.container != ''
run: apt-get update && apt-get install -y --no-install-recommends sudo unzip git tzdata
- name: "Add i386 architecture"
if: matrix.arch == 'i386'
run: sudo dpkg --add-architecture i386
- name: "Setup cross compilation architecture"
if: matrix.library-arch != '' && matrix.library-arch != 'riscv32-linux-gnu-ilp32'
run: |
# Replace Azure mirrors with official Ubuntu repositories
sudo sed -i 's|azure\.||g' /etc/apt/sources.list
sudo sed -i 's|azure\.||g' /etc/apt/sources.list.d/*.list 2>/dev/null || true
# Handle new DEB822 format
if [ -f /etc/apt/apt-mirrors.txt ]; then
sudo sed -i 's|azure\.||g' /etc/apt/apt-mirrors.txt
fi
sudo dpkg --add-architecture ${{ matrix.arch }}
cat > ${RUNNER_TEMP}/cross-compile-sources.list <<EOF
deb [arch=${{ matrix.arch }}] http://ports.ubuntu.com/ noble main restricted
deb [arch=${{ matrix.arch }}] http://ports.ubuntu.com/ noble-updates main restricted
deb [arch=${{ matrix.arch }}] http://ports.ubuntu.com/ noble universe
deb [arch=${{ matrix.arch }}] http://ports.ubuntu.com/ noble-updates universe
deb [arch=${{ matrix.arch }}] http://ports.ubuntu.com/ noble multiverse
deb [arch=${{ matrix.arch }}] http://ports.ubuntu.com/ noble-updates multiverse
deb [arch=${{ matrix.arch }}] http://ports.ubuntu.com/ noble-backports main restricted universe multiverse
EOF
sudo mv ${RUNNER_TEMP}/cross-compile-sources.list /etc/apt/sources.list.d/
sudo sed -i '/Types: deb/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources
cat > ${RUNNER_TEMP}/${{ matrix.arch }}_toolchain.cmake <<EOF
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_C_LIBRARY_ARCHITECTURE ${{ matrix.library-arch }})
set(ZLIB_LIBRARY /usr/lib/${{ matrix.library-arch }}/libz.so)
set(MBEDTLS_ROOT_DIR /usr)
set(MBEDTLS_LIBRARIES_DIR /usr/lib/${{ matrix.library-arch }})
EOF
- name: "Setup cross compilation architecture (riscv32)"
if: matrix.library-arch == 'riscv32-linux-gnu-ilp32'
run: |
sudo dpkg --add-architecture ${{ matrix.arch }}
# Download toolchain and libraries from release
gh release download riscv-toolchain-2025.10.18 \
-R pguyot/crossbuild-essential-riscv32 \
--pattern 'riscv32-gnu-toolchain-ilp32_2025.10.18_amd64.deb' \
--pattern 'libc6-ilp32_2.39-0ubuntu1_riscv32.deb' \
--pattern 'libc6-dev-ilp32_2.39-0ubuntu1_riscv32.deb' \
--pattern 'libc6-dbg-ilp32_2.39-0ubuntu1_riscv32.deb' \
--pattern 'zlib1g-ilp32_1.3.1-0ubuntu1_riscv32.deb' \
--pattern 'zlib1g-dev-ilp32_1.3.1-0ubuntu1_riscv32.deb' \
--pattern 'libmbedcrypto7-ilp32_2.28.8-0ubuntu1_riscv32.deb' \
--pattern 'libmbedtls-dev-ilp32_2.28.8-0ubuntu1_riscv32.deb' \
--pattern 'libmbedtls14-ilp32_2.28.8-0ubuntu1_riscv32.deb' \
--pattern 'libmbedx509-1-ilp32_2.28.8-0ubuntu1_riscv32.deb'
# Install the toolchain
sudo dpkg -i riscv32-gnu-toolchain-ilp32_2025.10.18_amd64.deb
# Add to PATH for all subsequent steps
echo "/opt/riscv32-ilp32/bin" >> $GITHUB_PATH
# Install the libs
sudo dpkg -i libc6-ilp32_2.39-0ubuntu1_riscv32.deb
sudo dpkg -i libc6-dev-ilp32_2.39-0ubuntu1_riscv32.deb
sudo dpkg -i libc6-dbg-ilp32_2.39-0ubuntu1_riscv32.deb
sudo dpkg -i zlib1g-ilp32_1.3.1-0ubuntu1_riscv32.deb
sudo dpkg -i zlib1g-dev-ilp32_1.3.1-0ubuntu1_riscv32.deb
# Install mbedtls runtime packages first (in dependency order)
sudo dpkg -i libmbedcrypto7-ilp32_2.28.8-0ubuntu1_riscv32.deb
sudo dpkg -i libmbedx509-1-ilp32_2.28.8-0ubuntu1_riscv32.deb
sudo dpkg -i libmbedtls14-ilp32_2.28.8-0ubuntu1_riscv32.deb
# Then install the dev package
sudo dpkg -i libmbedtls-dev-ilp32_2.28.8-0ubuntu1_riscv32.deb
sudo sed -i '/Types: deb/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources
cat > ${RUNNER_TEMP}/riscv32_ilp32_toolchain.cmake <<'EOF'
# Toolchain file for RISC-V32 ILP32 (RV32-IMAC) cross-compilation
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR riscv32)
set(CMAKE_C_LIBRARY_ARCHITECTURE riscv32-linux-gnu-ilp32)
# Specify the cross compiler
set(CMAKE_C_COMPILER riscv32-unknown-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER riscv32-unknown-linux-gnu-g++)
# Specify the target architecture
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=rv32imac -mabi=ilp32" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=rv32imac -mabi=ilp32" CACHE STRING "" FORCE)
# Set up paths for cross-compiled libraries
set(ZLIB_LIBRARY /usr/lib/riscv32-linux-gnu-ilp32/libz.so CACHE FILEPATH "")
set(ZLIB_INCLUDE_DIR /usr/include/riscv32-linux-gnu CACHE PATH "")
set(ZLIB_FOUND TRUE CACHE BOOL "")
# MbedTLS configuration
set(MBEDTLS_ROOT_DIR /usr)
set(MBEDTLS_LIBRARIES_DIR /usr/lib/riscv32-linux-gnu-ilp32)
# Add cross-compilation include path to compiler flags
include_directories(SYSTEM /usr/include/riscv32-linux-gnu)
# Search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Search for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
EOF
# Set up qemu-user binfmt to find libraries
sudo ln -s /opt/riscv32-ilp32/sysroot/lib/ld-linux-riscv32-ilp32.so.1 /lib/ld-linux-riscv32-ilp32.so.1
sudo mkdir -p /usr/gnemul
sudo ln -s /opt/riscv32-ilp32/sysroot /usr/gnemul/qemu-riscv32
# Copy cross-compiled libraries to sysroot for qemu-user
sudo cp /usr/lib/${{ matrix.library-arch }}/libz.so.1* /opt/riscv32-ilp32/sysroot/lib/
sudo cp /usr/lib/${{ matrix.library-arch }}/libmbedtls.so.14 /opt/riscv32-ilp32/sysroot/lib/
sudo cp /usr/lib/${{ matrix.library-arch }}/libmbedcrypto.so.7 /opt/riscv32-ilp32/sysroot/lib/
sudo cp /usr/lib/${{ matrix.library-arch }}/libmbedx509.so.1 /opt/riscv32-ilp32/sysroot/lib/
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "APT update"
run: sudo apt update -y
- name: "Install deps"
if: matrix.container != ''
run: sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen valgrind libmbedtls-dev socat
- name: "Install deps"
if: matrix.container == ''
run: |
sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen libmbedtls-dev libc6-dbg socat
# Get a more recent valgrind
sudo snap install valgrind --classic
- name: "Checkout repo"
uses: actions/checkout@v4
with:
submodules: 'recursive'
# There is no working arm64 binary for gleam
# https://github.com/erlef/setup-beam/issues/398
- uses: erlef/setup-beam@v1
if: matrix.os != 'ubuntu-24.04-arm'
with:
version-type: ${{ matrix.version_type || 'loose' }}
otp-version: ${{ matrix.otp || env.DEFAULT_OTP_VERSION }}
elixir-version: ${{ matrix.elixir_version || env.DEFAULT_ELIXIR_VERSION }}
rebar3-version: ${{ matrix.rebar3_version || env.DEFAULT_REBAR3_VERSION }}
gleam-version: ${{ matrix.gleam_version || env.DEFAULT_GLEAM_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://repo.hex.pm
https://cdn.jsdelivr.net/hex
- uses: erlef/setup-beam@v1
if: matrix.os == 'ubuntu-24.04-arm'
with:
version-type: ${{ matrix.version_type || 'loose' }}
otp-version: ${{ matrix.otp || env.DEFAULT_OTP_VERSION }}
elixir-version: ${{ matrix.elixir_version || env.DEFAULT_ELIXIR_VERSION }}
rebar3-version: ${{ matrix.rebar3_version || env.DEFAULT_REBAR3_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://repo.hex.pm
https://cdn.jsdelivr.net/hex
# Builder info
- name: "System info"
run: |
echo "**uname:**"
uname -a
echo "**libc version:**"
ldd --version
echo "**C Compiler version:**"
$CC --version
$CXX --version
echo "**CFLAGS:**"
echo $CFLAGS
echo "**Linker version:**"
ld --version
echo "**CMake version:**"
cmake --version
echo "**OTP version:**"
cat $(dirname $(which erlc))/../releases/RELEASES || true
- name: "Setup locale"
if: matrix.locale != ''
run: |
echo "${{ matrix.locale }} UTF-8" | sudo tee -a /etc/locale.gen
sudo locale-gen
echo "LC_NUMERIC=${{ matrix.locale }}" >> $GITHUB_ENV
# Build
- name: "Build: create build dir"
run: mkdir build
- uses: actions/cache@v4
id: cache
with:
path: 'build/tests/**/*.beam'
key: ${{ matrix.otp || env.DEFAULT_OTP_VERSION }}-${{ hashFiles('**/build-and-test.yaml', 'tests/**/*.erl', 'tests/**/*.hrl', 'tests/**/*.ex') }}-${{ matrix.jit_target_arch || 'nojit' }}-${{ contains(matrix.cmake_opts_other, 'AVM_DISABLE_JIT_DWARF=OFF') && 'dwarf' || 'nodwarf' }}
- name: "Build: run cmake"
working-directory: build
run: |
cmake ${{ matrix.cmake_opts_fp }} ${{ matrix.cmake_opts_smp }} ${{ matrix.cmake_opts_other || env.DEFAULT_CMAKE_OPTS_OTHER }} ..
# git clone will use more recent timestamps than cached beam files
# touch them so we can benefit from the cache and avoid costly beam file rebuild.
find . -name '*.beam' -exec touch {} \;
- name: "Build: run make"
working-directory: build
run: make -j3
- name: "Build: run dialyzer"
working-directory: build
run: make dialyzer
# Test
- name: "Test: test-erlang with valgrind"
if: matrix.library-arch == ''
timeout-minutes: 30
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./tests/test-erlang -s prime_smp
- name: "Test: test-erlang"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
./tests/test-erlang -s prime_smp
- name: "Test: test-enif with valgrind"
if: matrix.library-arch == ''
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./tests/test-enif
- name: "Test: test-enif"
working-directory: build
run: |
ulimit -c unlimited
./tests/test-enif
- name: "Test: test-heap with valgrind"
if: matrix.library-arch == ''
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./tests/test-heap
- name: "Test: test-heap"
working-directory: build
run: |
ulimit -c unlimited
./tests/test-heap
- name: "Test: test-jit_stream_flash with valgrind"
if: matrix.library-arch == ''
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./tests/test-jit_stream_flash
- name: "Test: test-jit_stream_flash"
working-directory: build
run: |
ulimit -c unlimited
./tests/test-jit_stream_flash
- name: "Test: test-mailbox with valgrind"
if: matrix.library-arch == ''
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./tests/test-mailbox
- name: "Test: test-mailbox"
working-directory: build
run: |
ulimit -c unlimited
./tests/test-mailbox
- name: "Test: test-structs with valgrind"
if: matrix.library-arch == ''
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./tests/test-structs
- name: "Test: test-structs"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
./tests/test-structs
- name: "Test: test_etest.avm with valgrind"
if: matrix.library-arch == ''
timeout-minutes: 5
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/etest/test_etest.avm
- name: "Test: test_etest.avm"
timeout-minutes: 5
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM ./tests/libs/etest/test_etest.avm
- name: "Test: test_estdlib.avm with valgrind"
if: matrix.library-arch == ''
timeout-minutes: 30
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm
- name: "Test: test_estdlib.avm"
timeout-minutes: 20
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm
- name: "Test: test_eavmlib.avm with valgrind"
if: matrix.library-arch == ''
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm
- name: "Test: test_eavmlib.avm"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm
- name: "Test: test_jit.avm with valgrind"
if: matrix.library-arch == ''
timeout-minutes: 60
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./src/AtomVM tests/libs/jit/test_jit.avm
- name: "Test: test_jit.avm"
timeout-minutes: 60
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM tests/libs/jit/test_jit.avm
- name: "Test: test_alisp.avm with valgrind"
if: matrix.library-arch == ''
timeout-minutes: 20
working-directory: build
run: |
ulimit -c unlimited
valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/alisp/test_alisp.avm
- name: "Test: test_alisp.avm"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM ./tests/libs/alisp/test_alisp.avm
- name: "Test: Tests.avm (Elixir) with valgrind"
if: matrix.library-arch == ''
timeout-minutes: 20
working-directory: build
run: |
ulimit -c unlimited
if command -v elixirc >/dev/null 2>&1 && command -v elixir >/dev/null 2>&1
then
valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/exavmlib/Tests.avm
else
echo "Elixir not installed, skipping Elixir tests"
fi
- name: "Test: Tests.avm (Elixir)"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
if command -v elixirc >/dev/null 2>&1 && command -v elixir >/dev/null 2>&1
then
./src/AtomVM ./tests/libs/exavmlib/Tests.avm
else
echo "Elixir not installed, skipping Elixir tests"
fi
- name: "Install and smoke test"
working-directory: build
run: |
ulimit -c unlimited
sudo PATH=${PATH} make install
atomvm examples/erlang/hello_world.avm
atomvm -v
atomvm -h
- name: "Run coredumpctl info"
if: ${{ failure() }}
run: |
# Wait until systemd-coredump finished
while ps x | grep -cE 'systemd-[c]oredump'; do
echo systemd-coredump is still running
sleep 1
done
# info works on all versions of ubuntu
coredumpctl info || true
# The following only works on recent versions of ubuntu
coredumpctl debug --debugger-arguments="-batch -ex 'info all-registers'" || true
coredumpctl debug --debugger-arguments="-batch -ex 'info threads'" || true
coredumpctl debug --debugger-arguments="-batch -ex 'thread apply all bt full'" || true
coredumpctl debug --debugger-arguments='-batch -ex "display /10i $pc"' || true
coredumpctl dump -o core.dump || true
if [ -e core.dump ]; then
mkdir core
mv core.dump core/
cp build/src/AtomVM core/
cp build/tests/test-* core/
fi
- name: "Upload any dumped core"
uses: actions/upload-artifact@v4
if: ${{ failure() }}
with:
name: core-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.otp || env.DEFAULT_OTP_VERSION }}-${{ github.run_id }}-${{ github.run_attempt }}
path: |
core/*
retention-days: 5