Skip to content

Reduce VM size by supporting compilers from 3 last OTP releases #1525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
6 changes: 5 additions & 1 deletion .github/workflows/build-and-test-macos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ jobs:
os: ["macos-13", "macos-14", "macos-15"]
otp: ["24", "25", "26", "27"]

include:
- otp: "24"
cmake_opts_other: "-DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=24 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=24"

steps:
# Setup
- name: "Checkout repo"
Expand Down Expand Up @@ -83,7 +87,7 @@ jobs:
working-directory: build
run: |
export PATH="/usr/local/opt/erlang@${{ matrix.otp }}/bin:/opt/homebrew/opt/erlang@${{ matrix.otp }}/bin:$PATH"
cmake -DAVM_WARNINGS_ARE_ERRORS=ON -G Ninja ..
cmake -DAVM_WARNINGS_ARE_ERRORS=ON ${{ matrix.cmake_opts_other }} -G Ninja ..

- name: "Build: run ninja"
working-directory: build
Expand Down
18 changes: 16 additions & 2 deletions .github/workflows/build-and-test-other.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ jobs:
name: test-modules
path: build_tests

- name: Skip compilation of Erlang code
run: |
sed -e 's|add_subdirectory(libs)|# add_subdirectory(libs)|g' \
-e 's|add_subdirectory(examples)|# add_subdirectory(examples)|g' \
-i CMakeLists.txt
sed -e 's|add_subdirectory(erlang_tests)|# add_subdirectory(erlang_tests)|g' \
-e 's|add_subdirectory(libs/|# add_subdirectory(libs/|g' \
-e 's|add_dependencies(test-erlang erlang_test_modules)|# add_dependencies(test-erlang erlang_test_modules)|g' \
-i tests/CMakeLists.txt

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

Expand Down Expand Up @@ -159,13 +169,17 @@ jobs:
mkdir -p build &&
cd build &&
cmake .. ${{ matrix.cmake_opts }} &&
mkdir -p tests/erlang_tests/code_load/beams/ &&
cp ../build_tests/tests/erlang_tests/*.beam tests/erlang_tests/ &&
cp ../build_tests/tests/erlang_tests/code_load/*.{avm,beam,hrl} tests/erlang_tests/code_load/ &&
mkdir -p tests/erlang_tests/code_load/beams/ &&
cp ../build_tests/tests/erlang_tests/code_load/beams/*.beam tests/erlang_tests/code_load/beams/ &&
mkdir -p tests/libs/etest/ &&
cp ../build_tests/tests/libs/etest/*.avm tests/libs/etest/ &&
cp ../build_tests/tests/libs/estdlib/*.avm tests/libs/estdlib/ &&
mkdir -p tests/libs/estdlib/ &&
cp ../build_tests/tests/libs/estdlib/*.avm tests/libs/estdlib/ &&
mkdir -p tests/libs/eavmlib/ &&
cp ../build_tests/tests/libs/eavmlib/*.avm tests/libs/eavmlib/ &&
mkdir -p tests/libs/alisp/ &&
cp ../build_tests/tests/libs/alisp/*.avm tests/libs/alisp/ &&
make AtomVM &&
make test-erlang &&
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ jobs:
elixir_version: "1.7"
rebar3_version: "3.15.2"
compiler_pkgs: "g++"
cmake_opts_other: "-DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=21 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=21"

- container: "ubuntu:20.04"
cc: "cc"
Expand All @@ -213,6 +214,7 @@ jobs:
elixir_version: "1.8"
rebar3_version: "3.18.0"
compiler_pkgs: "g++"
cmake_opts_other: "-DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=22 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=22"

- container: "ubuntu:20.04"
cc: "cc"
Expand All @@ -222,6 +224,7 @@ jobs:
elixir_version: "1.11"
rebar3_version: "3.20.0"
compiler_pkgs: "g++"
cmake_opts_other: "-DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=23 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=23"

- container: "ubuntu:20.04"
cc: "cc"
Expand All @@ -231,6 +234,7 @@ jobs:
elixir_version: "1.14"
rebar3_version: "3.23.0"
compiler_pkgs: "g++"
cmake_opts_other: "-DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=24 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=24"

- os: "ubuntu-24.04"
cc: "cc"
Expand Down Expand Up @@ -281,9 +285,9 @@ jobs:
cc: "gcc-10"
cxx: "g++-10"
cflags: "-m32 -O3"
otp: "23"
elixir_version: "1.11"
rebar3_version: "3.20.0"
otp: "27"
elixir_version: "1.17"
rebar3_version: "3.24.0"
# Use Werror so we get an error with 32 bit specific warnings
cmake_opts_other: "-DAVM_CREATE_STACKTRACES=off -DAVM_WARNINGS_ARE_ERRORS=ON"
arch: "i386"
Expand Down
21 changes: 17 additions & 4 deletions .github/workflows/esp32-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ jobs:
idf-version: 'v5.0.7'
- esp-idf-target: "esp32c3"
idf-version: 'v5.1.5'

# ESP-IDF 5.0.7 and 5.1.5 containers are based on Ubuntu focal which has Erlang/OTP 22
# ESP-IDF 5.2.3 and 5.3.2 containers are based on Ubuntu jammy which has Erlang/OTP 24
include:
- idf-version: 'v5.0.7'
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=22 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=22
- idf-version: 'v5.1.5'
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=22 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=22
- idf-version: 'v5.2.3'
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=24 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=24
- idf-version: 'v5.3.2'
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=24 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=24

steps:
- name: Checkout repo
uses: actions/checkout@v4
Expand Down Expand Up @@ -170,8 +183,8 @@ jobs:
echo "CONFIG_ESP_WIFI_RX_IRAM_OPT=n" >> sdkconfig.defaults
. $IDF_PATH/export.sh
export IDF_TARGET=${{matrix.esp-idf-target}}
idf.py set-target ${{matrix.esp-idf-target}}
idf.py build
idf.py ${{matrix.cmake_opts}} set-target ${{matrix.esp-idf-target}}
idf.py ${{matrix.cmake_opts}} build

- name: Run ESP32 tests using qemu with memory checks build
working-directory: ./src/platforms/esp32/test/
Expand All @@ -191,8 +204,8 @@ jobs:
. $IDF_PATH/export.sh
export IDF_TARGET=${{matrix.esp-idf-target}}
export PATH=${PATH}:${HOME}/.cache/rebar3/bin
idf.py set-target ${{matrix.esp-idf-target}}
idf.py build
idf.py ${{matrix.cmake_opts}} set-target ${{matrix.esp-idf-target}}
idf.py ${{matrix.cmake_opts}} build

- name: Run ESP32 tests using qemu
working-directory: ./src/platforms/esp32/test/
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/run-tests-with-beam.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,45 +43,55 @@ jobs:
- os: "ubuntu-24.04"
test_erlang_opts: "-s prime_smp"
container: erlang:21
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=21 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=21

- os: "ubuntu-24.04"
test_erlang_opts: "-s prime_smp"
container: erlang:22
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=22 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=22

- os: "ubuntu-24.04"
test_erlang_opts: "-s prime_smp"
container: erlang:23
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=23 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=23

- os: "ubuntu-24.04"
test_erlang_opts: "-s prime_smp"
container: erlang:24
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=24 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=24

- os: "ubuntu-24.04"
test_erlang_opts: "-s prime_smp"
container: erlang:25
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=25 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=25

- os: "ubuntu-24.04"
test_erlang_opts: "-s prime_smp"
otp: "26"
container: erlang:26
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=26 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=26

- os: "ubuntu-24.04"
test_erlang_opts: "-s prime_smp"
otp: "27"
container: erlang:27
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=27 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=27

# This is ARM64
- os: "macos-14"
otp: "25"
path_prefix: "/opt/homebrew/opt/erlang@25/bin:"
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=25 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=25

- os: "macos-14"
otp: "26"
path_prefix: "/opt/homebrew/opt/erlang@26/bin:"
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=26 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=26

- os: "macos-14"
otp: "27"
path_prefix: "/opt/homebrew/opt/erlang@27/bin:"
cmake_opts: -DAVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION=27 -DAVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION=27
steps:
# Setup
- name: "Checkout repo"
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ option(AVM_RELEASE "Build an AtomVM release" OFF)
option(AVM_CREATE_STACKTRACES "Create stacktraces" ON)
option(AVM_BUILD_RUNTIME_ONLY "Only build the AtomVM runtime" OFF)
option(COVERAGE "Build for code coverage" OFF)
set(AVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION "25" CACHE STRING "Minimum supported OTP Release for Erlang compiler")
set(AVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION "28" CACHE STRING "Maximum supported OTP Release for Erlang compiler")

if((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") OR
(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") OR
Expand Down
13 changes: 6 additions & 7 deletions CMakeModules/FindElixir.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@
# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
#

find_program(ELIXIRC_PATH elixirc)
find_program(ELIXIRC_EXECUTABLE elixirc)

if (ELIXIRC_PATH)
message("Found Elixir")
set(Elixir_FOUND TRUE)
elseif(Elixir_FIND_REQUIRED)
message(FATAL_ERROR "Elixir compiler not found")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Elixir
FOUND_VAR Elixir_FOUND
REQUIRED_VARS ELIXIRC_EXECUTABLE
)
72 changes: 72 additions & 0 deletions CMakeModules/FindErlang.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#
# This file is part of AtomVM.
#
# Copyright 2025 Paul Guyot <pguyot@kallisys.net>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
#

cmake_minimum_required(VERSION 3.13)

find_program(ERLC_EXECUTABLE erlc)
find_program(ERL_EXECUTABLE erl)

if (ERLC_EXECUTABLE AND ERL_EXECUTABLE)
execute_process(COMMAND erl -eval "io:put_chars(erlang:system_info(otp_release))." -s init stop -noshell OUTPUT_VARIABLE Erlang_VERSION)
endif()

include(FindPackageHandleStandardArgs)

if (CMAKE_VERSION VERSION_LESS 3.19)
# Handle version range ourselves
if (Erlang_FIND_VERSION AND ERL_EXECUTABLE)
string(REPLACE "..." ";" Erlang_FIND_VERSION_LIST ${Erlang_FIND_VERSION})
list(LENGTH Erlang_FIND_VERSION_LIST Erlang_FIND_VERSION_LIST_LEN)
if (Erlang_FIND_VERSION_LIST_LEN EQUAL 1)
find_package_handle_standard_args(Erlang
FOUND_VAR Erlang_FOUND
REQUIRED_VARS ERLC_EXECUTABLE ERL_EXECUTABLE
VERSION_VAR Erlang_VERSION
)
elseif(${Erlang_FIND_VERSION_LIST_LEN} EQUAL 2)
list(GET Erlang_FIND_VERSION_LIST 0 Erlang_FIND_VERSION_MIN)
list(GET Erlang_FIND_VERSION_LIST 1 Erlang_FIND_VERSION_MAX)
if (${Erlang_VERSION} LESS Erlang_FIND_VERSION_MIN)
message(FATAL_ERROR "-- Found Erlang: ${ERL_EXECUTABLE} but OTP Release ${Erlang_VERSION} is less than required ${Erlang_FIND_VERSION_MIN}")
endif()
if (${Erlang_VERSION} GREATER Erlang_FIND_VERSION_MAX)
message(FATAL_ERROR "-- Found Erlang: ${ERL_EXECUTABLE} but OTP Release ${Erlang_VERSION} is greater than supported ${Erlang_FIND_VERSION_MAX}")
endif()
find_package_handle_standard_args(Erlang
FOUND_VAR Erlang_FOUND
REQUIRED_VARS ERLC_EXECUTABLE ERL_EXECUTABLE
)
else()
message(FATAL_ERROR "-- Found Erlang: ${ERL_EXECUTABLE} but version range syntax is incorrect ${Erlang_FIND_VERSION}")
endif()
else()
find_package_handle_standard_args(Erlang
FOUND_VAR Erlang_FOUND
REQUIRED_VARS ERLC_EXECUTABLE ERL_EXECUTABLE
)
endif()
else()
find_package_handle_standard_args(Erlang
FOUND_VAR Erlang_FOUND
HANDLE_VERSION_RANGE
REQUIRED_VARS ERLC_EXECUTABLE ERL_EXECUTABLE
VERSION_VAR Erlang_VERSION
)
endif()
3 changes: 3 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ if (Gleam_FOUND)
else()
message(WARNING "-- gleam not found, skipping Gleam examples")
endif()

# Ensure erlang version is compatible with VM
find_package(Erlang ${AVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION}...${AVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION} REQUIRED)
5 changes: 4 additions & 1 deletion libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
#

cmake_minimum_required (VERSION 3.12)
cmake_minimum_required (VERSION 3.13)
project(libs)

add_subdirectory(estdlib/src)
Expand Down Expand Up @@ -65,6 +65,9 @@ else()
message("Dialyzer was not found -- skipping PLT build")
endif()

# Ensure erlang version is compatible with VM
find_package(Erlang ${AVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION}...${AVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION} REQUIRED)

install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/atomvmlib.avm
DESTINATION lib/atomvm
Expand Down
6 changes: 6 additions & 0 deletions src/libAtomVM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ endif()
if (ADVANCED_TRACING)
target_compile_definitions(libAtomVM PUBLIC ENABLE_ADVANCED_TRACE)
endif()
if (AVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION)
target_compile_definitions(libAtomVM PUBLIC MINIMUM_OTP_COMPILER_VERSION=${AVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION})
endif()
if (AVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION)
target_compile_definitions(libAtomVM PUBLIC MAXIMUM_OTP_COMPILER_VERSION=${AVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION})
endif()

target_link_libraries(libAtomVM PUBLIC m)
include(CheckCSourceCompiles)
Expand Down
10 changes: 7 additions & 3 deletions src/libAtomVM/opcodesswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@

// These constants can be used to reduce the size of the VM for a specific
// range of compiler versions
#define MINIMUM_OTP_COMPILER_VERSION 21
#define MAXIMUM_OTP_COMPILER_VERSION 26
#ifndef MINIMUM_OTP_COMPILER_VERSION
#define MINIMUM_OTP_COMPILER_VERSION 25
#endif
#ifndef MAXIMUM_OTP_COMPILER_VERSION
#define MAXIMUM_OTP_COMPILER_VERSION 28
#endif

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -5071,7 +5075,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
break;
}

#if MINIMUM_OTP_COMPILER_VERSION <= 24
#if MINIMUM_OTP_COMPILER_VERSION <= 25
case OP_BS_TEST_UNIT: {
uint32_t fail;
DECODE_LABEL(fail, pc)
Expand Down
2 changes: 2 additions & 0 deletions src/platforms/emscripten/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ endif ()
option(AVM_DISABLE_SMP "Disable SMP." OFF)
option(AVM_USE_32BIT_FLOAT "Use 32 bit floats." OFF)
option(AVM_VERBOSE_ABORT "Print module and line number on VM abort" OFF)
set(AVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION "25" CACHE STRING "Minimum supported OTP Release for Erlang compiler")
set(AVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION "28" CACHE STRING "Maximum supported OTP Release for Erlang compiler")

set(
PLATFORM_LIB_SUFFIX
Expand Down
5 changes: 5 additions & 0 deletions src/platforms/esp32/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ set(AVM_SELECT_IN_TASK ON)

project(atomvm-esp32-test)

# Ensure erlang version is compatible with VM
set(AVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION "25" CACHE STRING "Minimum supported OTP Release for Erlang compiler")
set(AVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION "28" CACHE STRING "Maximum supported OTP Release for Erlang compiler")
find_package(Erlang ${AVM_MINIMUM_OTP_RELEASE_COMPILER_VERSION}...${AVM_MAXIMUM_OTP_RELEASE_COMPILER_VERSION} REQUIRED)

# esp-idf does not use compile_feature but instead sets version in
# c_compile_options
# Ensure project is compiled with at least C11
Expand Down
Loading
Loading