From e5db6f96518aef74526531736a77afaf404aef20 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Sun, 10 Aug 2025 18:37:53 +0200 Subject: [PATCH] Use atomvm_packbeam instead of built-in C packbeam Signed-off-by: Paul Guyot --- .github/workflows/run-tests-with-beam.yaml | 4 + CMakeModules/BuildElixir.cmake | 18 +- CMakeModules/BuildErlang.cmake | 46 +- CMakeModules/BuildGleam.cmake | 12 +- doc/src/build-instructions.md | 12 +- libs/CMakeLists.txt | 8 +- .../test/main/test_erl_sources/CMakeLists.txt | 2 +- .../rp2/tests/test_erl_sources/CMakeLists.txt | 2 +- tools/packbeam/CMakeLists.txt | 59 +-- tools/packbeam/README.md | 111 ---- tools/packbeam/packbeam.c | 498 ------------------ tools/packbeam/rebar.config | 26 + tools/uf2tool/CMakeLists.txt | 16 +- 13 files changed, 124 insertions(+), 690 deletions(-) delete mode 100644 tools/packbeam/README.md delete mode 100644 tools/packbeam/packbeam.c create mode 100644 tools/packbeam/rebar.config diff --git a/.github/workflows/run-tests-with-beam.yaml b/.github/workflows/run-tests-with-beam.yaml index 41e73a7e6a..fd5c3de45a 100644 --- a/.github/workflows/run-tests-with-beam.yaml +++ b/.github/workflows/run-tests-with-beam.yaml @@ -102,6 +102,10 @@ jobs: with: submodules: 'recursive' + - name: "Git config safe.directory" + if: matrix.container + run: git config --global --add safe.directory /__w/AtomVM/AtomVM + - name: "Switch to archive.debian.org" if: matrix.archive == 'true' run: | diff --git a/CMakeModules/BuildElixir.cmake b/CMakeModules/BuildElixir.cmake index 6cf954e22b..6dcc912e66 100644 --- a/CMakeModules/BuildElixir.cmake +++ b/CMakeModules/BuildElixir.cmake @@ -41,15 +41,15 @@ macro(pack_archive avm_name) ) if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() add_custom_command( OUTPUT ${avm_name}.avm DEPENDS ${avm_name}_beams PackBEAM ${BEAMS} - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -a ${INCLUDE_LINES} ${avm_name}.avm ${BEAMS} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create ${INCLUDE_LINES} ${avm_name}.avm ${BEAMS} COMMENT "Packing archive ${avm_name}.avm" VERBATIM ) @@ -77,9 +77,9 @@ macro(pack_runnable avm_name main) ) if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() foreach(archive_name ${ARGN}) @@ -94,7 +94,7 @@ macro(pack_runnable avm_name main) add_custom_command( OUTPUT ${avm_name}.avm DEPENDS ${avm_name}_main ${ARCHIVE_TARGETS} PackBEAM Elixir.${main}.beam ${ARCHIVES} - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM ${INCLUDE_LINES} ${avm_name}.avm Elixir.${main}.beam ${ARCHIVES} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create -p -s Elixir.${main} ${INCLUDE_LINES} ${avm_name}.avm Elixir.${main}.beam ${ARCHIVES} COMMENT "Packing runnable ${avm_name}.avm" VERBATIM ) @@ -149,9 +149,9 @@ macro(pack_test avm_name main) ) if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() # Set up standard libraries @@ -171,7 +171,7 @@ macro(pack_test avm_name main) add_custom_command( OUTPUT ${avm_name}.avm DEPENDS ${avm_name}_main ${avm_name}_tests ${ARCHIVE_TARGETS} PackBEAM Elixir.${main}.beam ${TEST_BEAMS} ${ARCHIVES} - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM ${INCLUDE_LINES} ${avm_name}.avm Elixir.${main}.beam ${TEST_BEAMS} ${ARCHIVES} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create ${INCLUDE_LINES} ${avm_name}.avm Elixir.${main}.beam ${TEST_BEAMS} ${ARCHIVES} COMMENT "Packing test ${avm_name}.avm" VERBATIM ) diff --git a/CMakeModules/BuildErlang.cmake b/CMakeModules/BuildErlang.cmake index 931b9d9563..90892be8ed 100644 --- a/CMakeModules/BuildErlang.cmake +++ b/CMakeModules/BuildErlang.cmake @@ -41,15 +41,15 @@ macro(pack_archive avm_name) endforeach() if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() add_custom_command( OUTPUT ${avm_name}.avm DEPENDS ${pack_archive_${avm_name}_beams} PackBEAM - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -a ${INCLUDE_LINES} ${avm_name}.avm ${pack_archive_${avm_name}_beams} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create --lib ${INCLUDE_LINES} ${avm_name}.avm ${pack_archive_${avm_name}_beams} COMMENT "Packing archive ${avm_name}.avm" VERBATIM ) @@ -102,15 +102,15 @@ macro(pack_precompiled_archive avm_name) endforeach() if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() add_custom_command( OUTPUT ${avm_name}-${jit_target_arch_variant}.avm DEPENDS ${pack_precompile_archive_${avm_name}_beams} PackBEAM - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -a ${INCLUDE_LINES} ${avm_name}-${jit_target_arch_variant}.avm ${pack_precompile_archive_${avm_name}_beams} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create --lib ${INCLUDE_LINES} ${avm_name}-${jit_target_arch_variant}.avm ${pack_precompile_archive_${avm_name}_beams} COMMENT "Packing archive ${avm_name}-${jit_target_arch_variant}.avm" VERBATIM ) @@ -146,15 +146,15 @@ macro(pack_lib avm_name) endforeach() if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() add_custom_command( OUTPUT ${avm_name}.avm DEPENDS ${pack_lib_${avm_name}_archive_targets} ${pack_lib_${avm_name}_emu_archives} ${pack_lib_${avm_name}_archives} PackBEAM - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -a ${INCLUDE_LINES} ${avm_name}.avm ${pack_lib_${avm_name}_emu_archives} ${pack_lib_${avm_name}_archives} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create --lib ${INCLUDE_LINES} ${avm_name}.avm ${pack_lib_${avm_name}_emu_archives} ${pack_lib_${avm_name}_archives} COMMENT "Packing lib ${avm_name}.avm" VERBATIM ) @@ -173,7 +173,7 @@ macro(pack_lib avm_name) add_custom_command( OUTPUT ${avm_name}-${jit_target_arch_variant}.avm DEPENDS ${pack_lib_${avm_name}_archive_targets} ${pack_lib_${avm_name}_jit_archives_${jit_target_arch_variant}} PackBEAM - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -a ${INCLUDE_LINES} ${avm_name}-${jit_target_arch_variant}.avm ${pack_lib_${avm_name}_jit_archives_${jit_target_arch_variant}} ${pack_lib_${avm_name}_archives} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create --lib ${INCLUDE_LINES} ${avm_name}-${jit_target_arch_variant}.avm ${pack_lib_${avm_name}_jit_archives_${jit_target_arch_variant}} ${pack_lib_${avm_name}_archives} COMMENT "Packing lib ${avm_name}-${jit_target_arch_variant}.avm" VERBATIM ) @@ -281,15 +281,15 @@ macro(pack_runnable avm_name main) endif() if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() add_custom_command( OUTPUT ${avm_name}.avm DEPENDS ${avm_name}_main ${main}.beam ${pack_runnable_${avm_name}_archives} ${pack_runnable_${avm_name}_archive_targets} PackBEAM - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM ${INCLUDE_LINES} ${avm_name}.avm ${main}.beam ${pack_runnable_${avm_name}_archives} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create -s ${main} ${INCLUDE_LINES} ${avm_name}.avm ${main}.beam ${pack_runnable_${avm_name}_archives} COMMENT "Packing runnable ${avm_name}.avm" VERBATIM ) @@ -322,9 +322,9 @@ macro(pack_test test_avm_name) endforeach() if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() add_custom_command( @@ -337,7 +337,7 @@ macro(pack_test test_avm_name) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${test_avm_name}.avm DEPENDS ${pack_test_${test_avm_name}_archive_targets} PackBEAM tests.beam - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM ${INCLUDE_LINES} ${CMAKE_CURRENT_BINARY_DIR}/${test_avm_name}.avm ${CMAKE_CURRENT_BINARY_DIR}/tests.beam ${pack_test_${test_avm_name}_archives} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create ${INCLUDE_LINES} ${CMAKE_CURRENT_BINARY_DIR}/${test_avm_name}.avm ${CMAKE_CURRENT_BINARY_DIR}/tests.beam ${pack_test_${test_avm_name}_archives} COMMENT "Packing runnable ${test_avm_name}.avm" VERBATIM ) @@ -369,15 +369,15 @@ macro(pack_eunit test_avm_name) endforeach() if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() add_custom_command( OUTPUT ${test_avm_name}.avm DEPENDS ${pack_eunit_${test_avm_name}_archive_targets} PackBEAM ${CMAKE_BINARY_DIR}/libs/etest/src/beams/eunit.beam - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM ${INCLUDE_LINES} ${CMAKE_CURRENT_BINARY_DIR}/${test_avm_name}.avm ${CMAKE_BINARY_DIR}/libs/etest/src/beams/eunit.beam ${pack_eunit_${test_avm_name}_archives} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create ${INCLUDE_LINES} ${CMAKE_CURRENT_BINARY_DIR}/${test_avm_name}.avm ${CMAKE_BINARY_DIR}/libs/etest/src/beams/eunit.beam ${pack_eunit_${test_avm_name}_archives} COMMENT "Packing runnable ${test_avm_name}.avm" VERBATIM ) @@ -412,10 +412,16 @@ macro(pack_uf2 avm_name main) set(pack_uf2_${avm_name}_archive_targets ${pack_uf2_${avm_name}_archive_targets} ${archive_name}) endforeach() + if(AVM_RELEASE) + set(INCLUDE_LINES "--remove_lines") + else() + set(INCLUDE_LINES "") + endif() + add_custom_command( OUTPUT ${avm_name}.avm DEPENDS ${avm_name}_main ${main}.beam ${pack_uf2_${avm_name}_archives} ${pack_uf2_${avm_name}_archive_targets} PackBEAM - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM ${avm_name}.avm ${main}.beam ${pack_uf2_${avm_name}_archives} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create ${INCLUDE_LINES} -s ${main} ${avm_name}.avm ${main}.beam ${pack_uf2_${avm_name}_archives} COMMENT "Packing runnable ${avm_name}.avm" VERBATIM ) diff --git a/CMakeModules/BuildGleam.cmake b/CMakeModules/BuildGleam.cmake index 4d3e4b0ada..f63fd98c63 100644 --- a/CMakeModules/BuildGleam.cmake +++ b/CMakeModules/BuildGleam.cmake @@ -28,9 +28,9 @@ macro(pack_gleam_archive avm_name) endforeach() if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() add_custom_command( @@ -39,7 +39,7 @@ macro(pack_gleam_archive avm_name) COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/gleam.toml ${CMAKE_CURRENT_SOURCE_DIR}/manifest.toml ${CMAKE_CURRENT_BINARY_DIR}/ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src COMMAND gleam export erlang-shipment - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -a ${INCLUDE_LINES} ${avm_name}.avm ${BEAMS} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create --lib ${INCLUDE_LINES} ${avm_name}.avm ${BEAMS} COMMENT "Packing gleam archive ${avm_name}.avm" VERBATIM ) @@ -55,9 +55,9 @@ macro(pack_gleam_runnable avm_name main) list(APPEND BEAMS ${CMAKE_CURRENT_BINARY_DIR}/build/prod/erlang/*/ebin/*.beam) if(AVM_RELEASE) - set(INCLUDE_LINES "") + set(INCLUDE_LINES "--remove_lines") else() - set(INCLUDE_LINES "-i") + set(INCLUDE_LINES "") endif() foreach(archive_name ${ARGN}) @@ -75,7 +75,7 @@ macro(pack_gleam_runnable avm_name main) COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/gleam.toml ${CMAKE_CURRENT_SOURCE_DIR}/manifest.toml ${CMAKE_CURRENT_BINARY_DIR}/ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src COMMAND gleam export erlang-shipment - COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM ${INCLUDE_LINES} ${avm_name}.avm ${BEAMS} ${ARCHIVES} + COMMAND ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam create -p -s ${main} ${INCLUDE_LINES} ${avm_name}.avm ${BEAMS} ${ARCHIVES} COMMENT "Packing gleam runnable ${avm_name}.avm" ) diff --git a/doc/src/build-instructions.md b/doc/src/build-instructions.md index 803167c52b..b9cb99d657 100644 --- a/doc/src/build-instructions.md +++ b/doc/src/build-instructions.md @@ -64,7 +64,7 @@ Source code is organized as follows: * `src` Contains the core AtomVM virtual machine source code; * `lib` Contains the Erlang and Elixir core library source code; -* `tools` Contains AtomVM tooling, including the `PackBEAM` executable, as well as build support tooling; +* `tools` Contains build support tooling; * `examples` Contains sample programs for demonstration purposes; * `tests` Contains test code run as part of test qualification; * `doc` Contains documentation source code and content. @@ -73,11 +73,17 @@ The `src` directory is broken up into the core platform-independent AtomVM libra ## External dependencies +### `packbeam` + +AtomVM depends on `packbeam`. It is used to pack beams as well as assets into AtomVM pack format, `.avm`. `packbeam` source code is downloaded automatically by `rebar3` from `hex` mirrors, and it is then escriptized. + +It is possible to use a local copy of `packbeam` source code by setting `PACKBEAM_PATH` variable to a path to a source checkout of [`atomvm_packbeam`](https://github.com/atomvm/atomvm_packbeam) when invoking CMake. + ### `uf2tool` -AtomVM depends on `uf2tool`. It is used to pack both native and Erlang/Elixir/Gleam code for RP2. uf2tool is downloaded automatically by `rebar3` from `hex` mirrors. +AtomVM depends on `uf2tool`. It is used to pack both native and Erlang/Elixir/Gleam code for RP2. `uf2tool` source code is downloaded automatically by `rebar3` from `hex` mirrors. -It is possible to use a local copy of uf2tool by setting `UF2TOOL_PATH` variable to a path to a source checkout of [`uf2tool`](https://github.com/pguyot/uf2tool) when invoking CMake. +It is possible to use a local copy of `uf2tool` source code by setting `UF2TOOL_PATH` variable to a path to a source checkout of [`uf2tool`](https://github.com/pguyot/uf2tool) when invoking CMake. ## Platform Specific Build Instructions diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 2f168baedd..a7173df44d 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -59,25 +59,25 @@ if (Dialyzer_FOUND) OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/estdlib_beams.txt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/estdlib/src/estdlib.avm PackBEAM COMMAND - ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -l ${CMAKE_CURRENT_BINARY_DIR}/estdlib/src/estdlib.avm | sed -e 's|^|${CMAKE_CURRENT_BINARY_DIR}/estdlib/src/beams/|g' > ${CMAKE_CURRENT_BINARY_DIR}/estdlib_beams.txt + ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam list -f bare ${CMAKE_CURRENT_BINARY_DIR}/estdlib/src/estdlib.avm | sed -e 's|^|${CMAKE_CURRENT_BINARY_DIR}/estdlib/src/beams/|g' > ${CMAKE_CURRENT_BINARY_DIR}/estdlib_beams.txt ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/eavmlib_beams.txt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/eavmlib/src/eavmlib.avm PackBEAM COMMAND - ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -l ${CMAKE_CURRENT_BINARY_DIR}/eavmlib/src/eavmlib.avm | sed -e 's|^|${CMAKE_CURRENT_BINARY_DIR}/eavmlib/src/beams/|g' > ${CMAKE_CURRENT_BINARY_DIR}/eavmlib_beams.txt + ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam list -f bare ${CMAKE_CURRENT_BINARY_DIR}/eavmlib/src/eavmlib.avm | sed -e 's|^|${CMAKE_CURRENT_BINARY_DIR}/eavmlib/src/beams/|g' > ${CMAKE_CURRENT_BINARY_DIR}/eavmlib_beams.txt ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/alisp_beams.txt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/alisp/src/alisp.avm PackBEAM COMMAND - ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -l ${CMAKE_CURRENT_BINARY_DIR}/alisp/src/alisp.avm | sed -e 's|^|${CMAKE_CURRENT_BINARY_DIR}/alisp/src/beams/|g' > ${CMAKE_CURRENT_BINARY_DIR}/alisp_beams.txt + ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam list -f bare ${CMAKE_CURRENT_BINARY_DIR}/alisp/src/alisp.avm | sed -e 's|^|${CMAKE_CURRENT_BINARY_DIR}/alisp/src/beams/|g' > ${CMAKE_CURRENT_BINARY_DIR}/alisp_beams.txt ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/jit_beams.txt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/jit/src/jit.avm PackBEAM COMMAND - ${CMAKE_BINARY_DIR}/tools/packbeam/PackBEAM -l ${CMAKE_CURRENT_BINARY_DIR}/jit/src/jit.avm | sed -e 's|^|${CMAKE_CURRENT_BINARY_DIR}/jit/src/beams/|g' | grep -v jit_precompile > ${CMAKE_CURRENT_BINARY_DIR}/jit_beams.txt + ${CMAKE_BINARY_DIR}/tools/packbeam/packbeam list -f bare ${CMAKE_CURRENT_BINARY_DIR}/jit/src/jit.avm | sed -e 's|^|${CMAKE_CURRENT_BINARY_DIR}/jit/src/beams/|g' | grep -v jit_precompile > ${CMAKE_CURRENT_BINARY_DIR}/jit_beams.txt ) set(dialyzer_lists ${CMAKE_CURRENT_BINARY_DIR}/estdlib_beams.txt diff --git a/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt b/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt index 3710f05434..3871982be2 100644 --- a/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt +++ b/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt @@ -112,7 +112,7 @@ endif() add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/esp32_test_modules.avm" - COMMAND HostAtomVM-prefix/src/HostAtomVM-build/tools/packbeam/PackBEAM -i esp32_test_modules.avm + COMMAND HostAtomVM-prefix/src/HostAtomVM-build/tools/packbeam/packbeam create esp32_test_modules.avm HostAtomVM-prefix/src/HostAtomVM-build/libs/atomvmlib.avm ${erlang_test_beams_to_package} DEPENDS diff --git a/src/platforms/rp2/tests/test_erl_sources/CMakeLists.txt b/src/platforms/rp2/tests/test_erl_sources/CMakeLists.txt index 5c6526d5e2..2918a0396d 100644 --- a/src/platforms/rp2/tests/test_erl_sources/CMakeLists.txt +++ b/src/platforms/rp2/tests/test_erl_sources/CMakeLists.txt @@ -75,7 +75,7 @@ endif() add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/rp2_test_modules.avm" - COMMAND HostAtomVM-prefix/src/HostAtomVM-build/tools/packbeam/PackBEAM -i rp2_test_modules.avm + COMMAND HostAtomVM-prefix/src/HostAtomVM-build/tools/packbeam/packbeam create rp2_test_modules.avm HostAtomVM-prefix/src/HostAtomVM-build/libs/${atomvlib_name} ${erlang_test_beams} DEPENDS diff --git a/tools/packbeam/CMakeLists.txt b/tools/packbeam/CMakeLists.txt index 09cc143059..826e77c240 100644 --- a/tools/packbeam/CMakeLists.txt +++ b/tools/packbeam/CMakeLists.txt @@ -1,7 +1,7 @@ # # This file is part of AtomVM. # -# Copyright 2018-2020 Davide Bettio +# Copyright 2025 Paul Guyot # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,41 +21,36 @@ cmake_minimum_required (VERSION 3.13) project (PackBEAM) -set(PACKBEAM_SOURCES - packbeam.c -) +set(PACKBEAM_PATH "" CACHE PATH "Path to PackBEAM source tree. If unset, hex package will be used") -add_executable(PackBEAM ${PACKBEAM_SOURCES}) -target_compile_features(PackBEAM PUBLIC c_std_11) -if(CMAKE_COMPILER_IS_GNUCC) - target_compile_options(PackBEAM PUBLIC -Wall -pedantic -Wextra -ggdb) +if(NOT PACKBEAM_PATH STREQUAL "") + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/_checkouts) + file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/_checkouts/packbeam) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${PACKBEAM_PATH} ${CMAKE_CURRENT_BINARY_DIR}/_checkouts/packbeam) endif() -find_package(ZLIB) -if (ZLIB_FOUND) - target_compile_definitions(PackBEAM PUBLIC WITH_ZLIB) - target_link_libraries(PackBEAM PRIVATE ${ZLIB_LIBRARIES}) -endif (ZLIB_FOUND) - -if((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") OR - (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") OR - (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") OR - (${CMAKE_SYSTEM_NAME} STREQUAL "DragonFly")) - target_include_directories(PackBEAM PRIVATE ../../src/platforms/generic_unix/lib) -else() - message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}") +find_program(REBAR3 rebar3) +if(NOT REBAR3) + message(FATAL_ERROR "rebar3 is required but was not found") endif() -set( - PLATFORM_LIB_SUFFIX - ${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR} + +add_custom_command( + OUTPUT packbeam + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/rebar.config + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rebar.config ${CMAKE_CURRENT_BINARY_DIR}/rebar.config + COMMAND ${REBAR3} escriptize + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/_build/default/bin/packbeam ${CMAKE_CURRENT_BINARY_DIR}/packbeam + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + VERBATIM ) -target_link_libraries(PackBEAM PRIVATE libAtomVM${PLATFORM_LIB_SUFFIX}) -target_include_directories(PackBEAM PUBLIC ../../src/libAtomVM) -target_link_libraries(PackBEAM PRIVATE libAtomVM) +add_custom_target( + PackBEAM ALL + DEPENDS packbeam +) -if (COVERAGE) - include(CodeCoverage) - append_coverage_compiler_flags_to_target(PackBEAM) - append_coverage_linker_flags_to_target(PackBEAM) -endif() +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/packbeam + DESTINATION bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE +) diff --git a/tools/packbeam/README.md b/tools/packbeam/README.md deleted file mode 100644 index ebbf3290ff..0000000000 --- a/tools/packbeam/README.md +++ /dev/null @@ -1,111 +0,0 @@ - - -# `PackBEAM` - -The `PackBEAM` tool is used to pack a collection of BEAM files into a single AtomVM (`.avm`) file, or to list the contents of a previously created AVM file. - -Packing multiple BEAM files into a single AVM file allows you to load multiple BEAM modules into AtomVM, instead of just running a single module. - -Two types of AVM file may be created: - -* Runnable AVM files, suitable for flashing or supplying to the AtomVM command; -* Archive AVM files, which are used to aggregate collections of BEAM files into libraries, for subsequent use when creating runnable AVM files. - -The only difference between runnable and archive AVM files is that the first module in a runnable AVM file contains the exported function `start/0`, which is the initial entry point for the AtomVM program. Archive AVM files do not require a `start/0` entrypoint. - -Archive AVM files are typically used to create AtomVM "libraries", which can then be used as inputs when creating a runnable AVM. - -When creating an AVM file, you must specify: - -* Name name of the output AVM file, first in the list, followed by -* a sequence of compiled BEAM files (as compiled by the `erlc` compiler), or previously created AVM files. - * If you are creating a runnable AVM, the first file in this sequence must either be a BEAM file that contain an exported `start/0` function or an AVM file whose first module contain an exported `start/0` function. - -When listing modules in an AVM file, just specify the AVM file to list its included modules. - -## Usage - - Usage: PackBEAM - Options: - -h Print this help menu. - -l List the contents of an AVM file. - [-a] + Create an AVM file (archive if -a specified). - -## Examples - -Consider the three modules `mail.erl`, `foo.erl`, and `bar.erl`, defined as follows: - -`main.erl`: - - -module(main). - -export([start/0]). - - start() -> - hello:say_hello(world). - -`hello.erl`: - - -module(hello). - -export([say_hello/1]). - - say_hello(Term) -> - greet:say(hello, Term). - -`greet.erl`: - - -module(greet). - -export([say/2]). - - say(Greeting, Entity) -> - erlang:display({Greeting, Entity}). - -You can compile these modules using `erlc`: - - shell$ erlc main.erl hello.erl greet.erl - -And then pack the second two beam files into an archive using the `-a flag` as follows: - - shell$ PackBEAM -a lib.avm hello.beam greet.beam - -This will create the archive AVM `lib.avm`. - -You can list the contents of this AVM via the `-l` flag: - - shell$ PackBEAM -l lib.avm - greet.beam - hello.beam - -Note that this AVM file is not runnable: - - shell$ AtomVM lib.avm - lib.avm cannot be started. - -To create a runnable AVM file, specify the output AVM file, the beam file that contains the `start/0` function, and a sequence of 1 or more BEAM files or AVM files. For example, - - shell$ PackBEAM -a main.avm main.beam lib.avm - -This will create the output file `main.avm`, which you can run through AtomVM, e.g., - - shell$ AtomVM main.avm - {hello,world} - Return value: 3b - -You can list the modules in an AVM file via the `-l` flag: - - shell$ PackBEAM -l main.avm - main.beam * - hello.beam - greet.beam - -The module containing the `start/0` entrypoint will contain an asterisk (`*`). - -## Additional Notes - -* `PackBeam` does not require that BEAM or AVM files have any specific file suffix. You may use any suffix you like, though `.beam` and `.avm` are conventional. -* `PackBeam` makes no effort to find beam files with the `start/0` function, and order them first. In order to create a runnable AVM file, the first input file must be either a BEAM file with an exported `start/0` function, or another AVM file whose first module has an exported `start/0` function. -* `PackBeam` makes no effort the remove duplicates modules that are packed. AtomVM will only use the first module by name in an AVM files, so adding duplicate modules has no effect on the runtime behavior of the output AVM file. -* Because `PackBeam` uses positional arguments when creating AVM files, an attempt to specify a BEAM file (or other non-AVM file) as output, if it already exists, will result in a failure. This is to prevent accidental omission of an output AVM file as the first argument to `PackBeam` when creating AVM files. diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c deleted file mode 100644 index 63f1f726d1..0000000000 --- a/tools/packbeam/packbeam.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * This file is part of AtomVM. - * - * Copyright 2018 Davide Bettio - * - * 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 - */ - -#include -#include -#include -#include -#include -#include - -#ifdef WITH_ZLIB -#include -#endif - -#include "iff.c" -#include "avmpack.h" -#include "mapped_file.h" - -#define LITT_UNCOMPRESSED_SIZE_OFFSET 8 -#define LITT_HEADER_SIZE 12 - -#define END_OF_FILE 0 -#define BEAM_START_FLAG 1 -#define BEAM_CODE_FLAG 2 -#define BUF_SIZE 1024 - -typedef struct FileData { - uint8_t *data; - size_t size; -} FileData; - -static void pad_and_align(FILE *f); -bool are_literals_compressed(const uint8_t *litT); -static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize); -static void add_module_header(FILE *f, const char *module_name, uint32_t flags); -static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); - -static int do_pack(int argc, char **argv, int is_archive, bool include_lines); -static int do_list(int argc, char **argv); - -static void usage3(FILE *out, const char *program, const char *msg) { - if (!IS_NULL_PTR(msg)) { - fprintf(out, "%s\n", msg); - } - fprintf(out, "Usage: %s [-h] [-l] []\n", program); - fprintf(out, " -h Print this help menu.\n"); - fprintf(out, " -i Include file and line information.\n"); - fprintf(out, " -l List the contents of an AVM file.\n"); - fprintf(out, " [-a] + Create an AVM file (archive if -a specified).\n" - ); -} - -static void usage(const char *program) -{ - usage3(stdout, program, NULL); -} - - -int main(int argc, char **argv) -{ - int opt; - - const char *action = "pack"; - int is_archive = 0; - bool include_lines = false; - while ((opt = getopt(argc, argv, "hail")) != -1) { - switch(opt) { - case 'h': - usage(argv[0]); - return EXIT_SUCCESS; - case 'a': - is_archive = 1; - break; - case 'i': - include_lines = true; - break; - case 'l': - action = "list"; - break; - case '?': { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Unknown option: %c", optopt); - usage3(stderr, argv[0], buf); - return EXIT_FAILURE; - } - } - } - - int new_argc = argc - optind; - char **new_argv = argv + optind; - - if (new_argc < 1) { - usage3(stderr, argv[0], "Missing avm file.\n"); - return EXIT_FAILURE; - } - - if (!strcmp(action, "pack")) { - if (new_argc < 2) { - usage3(stderr, argv[0], "Missing options for pack\n"); - return EXIT_FAILURE; - } - return do_pack(new_argc, new_argv, is_archive, include_lines); - } else { - return do_list(new_argc, new_argv); - } -} - -static void assert_fread(void *buffer, size_t size, FILE* file) -{ - size_t r = fread(buffer, sizeof(uint8_t), size, file); - if (r != size) { - fprintf(stderr, "Unable to read, wanted to read %zu bytes, read %zu bytes\n", size, r); - exit(EXIT_FAILURE); - } -} - -static void assert_fwrite(const void *buffer, size_t size, FILE* file) -{ - size_t r = fwrite(buffer, 1, size, file); - if (r != size) { - fprintf(stderr, "Unable to write, wanted to write %zu bytes, wrote %zu bytes\n", size, r); - exit(EXIT_FAILURE); - } -} - -static void *pack_beam_fun(void *accum, const void *section_ptr, uint32_t section_size, const void *beam_ptr, uint32_t flags, const char *section_name) -{ - UNUSED(beam_ptr); - UNUSED(flags); - UNUSED(section_name); - if (accum == NULL) { - return NULL; - } - - FILE *pack = (FILE *)accum; - size_t r = fwrite(section_ptr, sizeof(unsigned char), section_size, pack); - if (r != section_size) { - return NULL; - } - return accum; -} - -FileData read_file_data(FILE *file) -{ - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - fseek(file, 0, SEEK_SET); - uint8_t *data = malloc(size); - if (!data) { - fprintf(stderr, "Unable to allocate %zu bytes\n", size); - exit(EXIT_FAILURE); - } - assert_fread(data, size, file); - - FileData file_data = { - .data = data, - .size = size - }; - return file_data; -} - -static bool is_avm_file(FILE *file) -{ - FileData file_data = read_file_data(file); - bool ret = avmpack_is_valid(file_data.data, file_data.size); - free(file_data.data); - return ret; -} - -static bool is_beam_file(FILE *file) -{ - FileData file_data = read_file_data(file); - bool ret = iff_is_valid_beam(file_data.data); - free(file_data.data); - return ret; -} - -static void validate_pack_options(int argc, char ** argv) -{ - for (int i = 0; i < argc; ++i) { - const char *filename = argv[i]; - FILE *file = fopen(filename, "r"); - if (i == 0) { - if (file && !is_avm_file(file)) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Invalid AVM file: %s", filename); - usage3(stderr, "PackBeam", buf); - exit(EXIT_FAILURE); - } - } else { - if (!file) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "%s does not exist", filename); - usage3(stderr, "PackBeam", buf); - exit(EXIT_FAILURE); - } else if (!is_avm_file(file) && !is_beam_file(file)) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Invalid AVM or BEAM file: %s", filename); - usage3(stderr, "PackBeam", buf); - exit(EXIT_FAILURE); - } - } - } -} - -static int do_pack(int argc, char **argv, int is_archive, bool include_lines) -{ - validate_pack_options(argc, argv); - - FILE *pack = fopen(argv[0], "w"); - if (!pack) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Cannot open output file for writing %s", argv[0]); - perror(buf); - return EXIT_FAILURE; - } - - const unsigned char pack_header[24] = - { - 0x23, 0x21, 0x2f, 0x75, - 0x73, 0x72, 0x2f, 0x62, - 0x69, 0x6e, 0x2f, 0x65, - 0x6e, 0x76, 0x20, 0x41, - 0x74, 0x6f, 0x6d, 0x56, - 0x4d, 0x0a, 0x00, 0x00 - }; - assert_fwrite(pack_header, 24, pack); - - for (int i = 1; i < argc; i++) { - FILE *file = fopen(argv[i], "r"); - if (!file) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Cannot open file %s", argv[i]); - perror(buf); - return EXIT_FAILURE; - } - - fseek(file, 0, SEEK_END); - size_t file_size = ftell(file); - fseek(file, 0, SEEK_SET); - - - uint8_t *file_data = malloc(file_size); - if (!file_data) { - fprintf(stderr, "Unable to allocate %zu bytes\n", file_size); - return EXIT_FAILURE; - } - assert_fread(file_data, file_size, file); - if (avmpack_is_valid(file_data, file_size)) { - void *result = avmpack_fold(pack, file_data, pack_beam_fun); - if (result == NULL) { - free(file_data); - return EXIT_FAILURE; - } - } else { - char *filename = basename(argv[i]); - pack_beam_file(pack, file_data, file_size, filename, !is_archive && i == 1, include_lines); - } - free(file_data); - } - - add_module_header(pack, "end", END_OF_FILE); - fclose(pack); - - return EXIT_SUCCESS; -} - -static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *section_name, int is_entrypoint, bool include_lines) -{ - size_t zero_pos = ftell(pack); - - if (is_entrypoint) { - add_module_header(pack, section_name, BEAM_CODE_FLAG | BEAM_START_FLAG); - } else { - add_module_header(pack, section_name, BEAM_CODE_FLAG); - } - - int written_beam_header_pos = ftell(pack); - const unsigned char beam_header[12] = - { - 0x46, 0x4f, 0x52, 0x31, - 0x00, 0x00, 0x00, 0x00, - 0x42, 0x45, 0x41, 0x4d - }; - assert_fwrite(beam_header, 12, pack); - - unsigned long offsets[MAX_OFFS]; - unsigned long sizes[MAX_SIZES]; - scan_iff(data, size, offsets, sizes); - - if (offsets[AT8U]) { - assert_fwrite(data + offsets[AT8U], sizes[AT8U] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[CODE]) { - assert_fwrite(data + offsets[CODE], sizes[CODE] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[EXPT]) { - assert_fwrite(data + offsets[EXPT], sizes[EXPT] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[LOCT]) { - assert_fwrite(data + offsets[LOCT], sizes[LOCT] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[IMPT]) { - assert_fwrite(data + offsets[IMPT], sizes[IMPT] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[LITU]) { - assert_fwrite(data + offsets[LITU], sizes[LITU] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[FUNT]) { - assert_fwrite(data + offsets[FUNT], sizes[FUNT] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[STRT]) { - assert_fwrite(data + offsets[STRT], sizes[STRT] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[AVMN]) { - assert_fwrite(data + offsets[AVMN], sizes[AVMN] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[TYPE]) { - assert_fwrite(data + offsets[TYPE], sizes[TYPE] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[LINT] && include_lines) { - assert_fwrite(data + offsets[LINT], sizes[LINT] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - if (offsets[LITT]) { - const uint8_t *litt = data + offsets[LITT]; - size_t litt_size = sizes[LITT]; - if (are_literals_compressed(litt)) { - size_t u_size; - void *deflated = uncompress_literals(data + offsets[LITT], litt_size, &u_size); - assert_fwrite("LitU", 4, pack); - uint32_t size_field = ENDIAN_SWAP_32(u_size); - assert_fwrite(&size_field, sizeof(size_field), pack); - assert_fwrite(deflated, u_size, pack); - free(deflated); - } else { - assert_fwrite(data + offsets[LITT], sizes[LITT] + IFF_SECTION_HEADER_SIZE, pack); - pad_and_align(pack); - } - } - - pad_and_align(pack); - - size_t end_of_module_pos = ftell(pack); - - size_t rsize = end_of_module_pos - zero_pos; - uint32_t size_field = ENDIAN_SWAP_32(rsize); - fseek(pack, zero_pos, SEEK_SET); - assert_fwrite(&size_field, sizeof(uint32_t), pack); - fseek(pack, end_of_module_pos, SEEK_SET); - - int beam_written_size = end_of_module_pos - written_beam_header_pos; - uint32_t beam_written_size_field = ENDIAN_SWAP_32(beam_written_size); - fseek(pack, written_beam_header_pos + 4, SEEK_SET); - assert_fwrite(&beam_written_size_field , sizeof(uint32_t), pack); - fseek(pack, end_of_module_pos, SEEK_SET); -} - - -static void *print_section(void *accum, const void *section_ptr, uint32_t section_size, const void *beam_ptr, uint32_t flags, const char *section_name) -{ - UNUSED(section_ptr); - UNUSED(section_size); - UNUSED(beam_ptr); - printf("%s %s\n", section_name, flags & BEAM_START_FLAG ? "*" : ""); - return accum; -} - -static void validate_list_options(const char *filename) -{ - FILE *file = fopen(filename, "r"); - if (!file) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "%s does not exist", filename); - usage3(stderr, "PackBeam", buf); - exit(EXIT_FAILURE); - } else if (!is_avm_file(file)) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Invalid AVM file: %s", filename); - usage3(stderr, "PackBeam", buf); - exit(EXIT_FAILURE); - } -} - -static int do_list(int argc, char **argv) -{ - UNUSED(argc); - validate_list_options(argv[0]); - - MappedFile *mapped_file = mapped_file_open_beam(argv[0]); - if (IS_NULL_PTR(mapped_file)) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Cannot open AVM file %s", argv[0]); - perror(buf); - return EXIT_FAILURE; - } - - int ret = EXIT_SUCCESS; - if (avmpack_is_valid(mapped_file->mapped, mapped_file->size)) { - avmpack_fold(NULL, mapped_file->mapped, print_section); - } else { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "%s is not an AVM file.\n", argv[1]); - usage3(stderr, "PackBeam", buf); - ret = EXIT_FAILURE; - } - mapped_file_close(mapped_file); - - return ret; -} - -bool are_literals_compressed(const uint8_t *litT) -{ - unsigned int required_buf_size = READ_32_ALIGNED(litT + LITT_UNCOMPRESSED_SIZE_OFFSET); - return (required_buf_size != 0); -} - -static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize) -{ - unsigned int required_buf_size = READ_32_ALIGNED(litT + LITT_UNCOMPRESSED_SIZE_OFFSET); - - uint8_t *outBuf = malloc(required_buf_size); - if (!outBuf) { - fprintf(stderr, "Cannot allocate temporary buffer (size = %u)", required_buf_size); - AVM_ABORT(); - } - - z_stream infstream; - infstream.zalloc = Z_NULL; - infstream.zfree = Z_NULL; - infstream.opaque = Z_NULL; - infstream.avail_in = (uInt) (size - IFF_SECTION_HEADER_SIZE); - infstream.next_in = (Bytef *) (litT + LITT_HEADER_SIZE); - infstream.avail_out = (uInt) required_buf_size; - infstream.next_out = (Bytef *) outBuf; - - int ret = inflateInit(&infstream); - if (ret != Z_OK) { - fprintf(stderr, "Failed inflateInit\n"); - AVM_ABORT(); - } - ret = inflate(&infstream, Z_NO_FLUSH); - if (ret != Z_OK) { - fprintf(stderr, "Failed inflate\n"); - AVM_ABORT(); - } - inflateEnd(&infstream); - - *uncompressedSize = required_buf_size; - return outBuf; -} - -static void pad_and_align(FILE *f) -{ - while ((ftell(f) % 4) != 0) { - fputc(0, f); - } -} - -static void add_module_header(FILE *f, const char *module_name, uint32_t flags) -{ - uint32_t size_field = 0; - uint32_t flags_field = ENDIAN_SWAP_32(flags); - uint32_t reserved = 0; - - assert_fwrite(&size_field, sizeof(uint32_t), f); - assert_fwrite(&flags_field, sizeof(uint32_t), f); - assert_fwrite(&reserved, sizeof(uint32_t), f); - assert_fwrite(module_name, strlen(module_name) + 1, f); - pad_and_align(f); -} diff --git a/tools/packbeam/rebar.config b/tools/packbeam/rebar.config new file mode 100644 index 0000000000..34225a57d2 --- /dev/null +++ b/tools/packbeam/rebar.config @@ -0,0 +1,26 @@ +% +% This file is part of AtomVM. +% +% Copyright 2025 Paul Guyot +% +% 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 +% + +{deps, [ + {atomvm_packbeam, "0.8.1"} +]}. +{escript_main_app, atomvm_packbeam}. +{escript_name, packbeam}. +{escript_emu_args, "%%! -escript main packbeam\n"}. diff --git a/tools/uf2tool/CMakeLists.txt b/tools/uf2tool/CMakeLists.txt index edc15429ae..d03e3f62c7 100644 --- a/tools/uf2tool/CMakeLists.txt +++ b/tools/uf2tool/CMakeLists.txt @@ -25,16 +25,22 @@ set(UF2TOOL_PATH "" CACHE PATH "Path to UF2Tool source tree. If unset, hex packa if(NOT UF2TOOL_PATH STREQUAL "") file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/_checkouts) - file(CREATE_LINK ${UF2TOOL_PATH} ${CMAKE_CURRENT_BINARY_DIR}/_checkouts/uf2tool SYMBOLIC) + file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/_checkouts/uf2tool) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${UF2TOOL_PATH} ${CMAKE_CURRENT_BINARY_DIR}/_checkouts/uf2tool) endif() -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/rebar.config - DESTINATION ${CMAKE_CURRENT_BINARY_DIR} -) +find_program(REBAR3 rebar3) +if(NOT REBAR3) + message(FATAL_ERROR "rebar3 is required but was not found") +endif() add_custom_command( OUTPUT uf2tool - COMMAND rebar3 escriptize && cp _build/default/bin/uf2tool . + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/rebar.config + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rebar.config ${CMAKE_CURRENT_BINARY_DIR}/rebar.config + COMMAND ${REBAR3} escriptize + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/_build/default/bin/uf2tool ${CMAKE_CURRENT_BINARY_DIR}/uf2tool + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} VERBATIM )