Merge pull request #3641 from vintagepc/build-with-cmake
Build the firmware with cmake
This commit is contained in:
commit
d8c9c4450f
|
|
@ -2,8 +2,11 @@
|
|||
/.settings
|
||||
/.project
|
||||
/.cproject
|
||||
/.vscode
|
||||
|
||||
#cmake
|
||||
/build/
|
||||
/build_gen/
|
||||
.dependencies
|
||||
# Temporary configuration
|
||||
/Firmware/Configuration_prusa.h
|
||||
|
||||
|
|
@ -24,3 +27,4 @@ __pycache__
|
|||
# Generated files
|
||||
/build-env/
|
||||
/Firmware/Doc/
|
||||
compile_commands.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
[
|
||||
{
|
||||
"name": "Local_avr-gcc-none-eabi",
|
||||
"toolchainFile": "${workspaceFolder}/cmake/LocalAvrGcc.cmake",
|
||||
"cmakeSettings": {
|
||||
"CMAKE_MAKE_PROGRAM": "${workspaceFolder}/.dependencies/ninja-1.10.2/ninja"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
buildType:
|
||||
default: debug
|
||||
choices:
|
||||
debug:
|
||||
short: Debug
|
||||
long: Emit debug information
|
||||
buildType: Debug
|
||||
release:
|
||||
short: Release
|
||||
long: Optimize generated code
|
||||
buildType: Release
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"cmake.configureOnOpen": true,
|
||||
"cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json",
|
||||
"cmake.cmakePath": "${workspaceFolder}/.dependencies/cmake-3.22.5/bin/cmake",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.associations": {
|
||||
"xlocale": "cpp"
|
||||
}
|
||||
}
|
||||
512
CMakeLists.txt
512
CMakeLists.txt
|
|
@ -1,23 +1,499 @@
|
|||
cmake_minimum_required(VERSION 3.1)
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(cmake/Utilities.cmake)
|
||||
include(cmake/GetGitRevisionDescription.cmake)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
SET(PROJECT_VERSION_SUFFIX
|
||||
"<auto>"
|
||||
CACHE
|
||||
STRING
|
||||
"Full version suffix to be shown on the info screen in settings (e.g. full_version=4.0.3-BETA+1035.PR111.B4, suffix=-BETA+1035.PR111.B4). Defaults to '+<commit sha>.<dirty?>.<debug?>' if set to '<auto>'."
|
||||
)
|
||||
SET(PROJECT_VERSION_SUFFIX_SHORT
|
||||
"<auto>"
|
||||
CACHE
|
||||
STRING
|
||||
"Short version suffix to be shown on splash screen. Defaults to '+<BUILD_NUMBER>' if set to '<auto>'."
|
||||
)
|
||||
SET(BUILD_NUMBER
|
||||
""
|
||||
CACHE STRING "Build number of the firmware. Resolved automatically if not specified."
|
||||
)
|
||||
|
||||
project(cmake_test)
|
||||
|
||||
# Prepare "Catch" library for other executables
|
||||
set(CATCH_INCLUDE_DIR Catch2)
|
||||
add_library(Catch INTERFACE)
|
||||
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
|
||||
INCLUDE(cmake/ProjectVersion.cmake)
|
||||
resolve_version_variables()
|
||||
|
||||
# Make test executable
|
||||
set(TEST_SOURCES
|
||||
Tests/tests.cpp
|
||||
Tests/Example_test.cpp
|
||||
Tests/Timer_test.cpp
|
||||
Tests/AutoDeplete_test.cpp
|
||||
Tests/PrusaStatistics_test.cpp
|
||||
Firmware/Timer.cpp
|
||||
|
||||
SET(PROJECT_VERSION_FLAVOUR "" CACHE STRING "Firmware flavour to build - DEBUG, DEVEL, APLHA, BETA or RC")
|
||||
SET(PROJECT_VERSION_FLAVOUR_REVISION "" CACHE STRING "Firmware flavour version, e.g. 1 for RC1, etc")
|
||||
|
||||
|
||||
IF( NOT PROJECT_VERSION_FLAVOUR STREQUAL "")
|
||||
SET(PROJECT_VERSION "${PROJECT_VERSION}-${PROJECT_VERSION_FLAVOUR}")
|
||||
add_compile_definitions(FW_FLAVOR=${PROJECT_VERSION_FLAVOUR})
|
||||
IF( NOT PROJECT_VERSION_FLAVOUR_REVISION STREQUAL "")
|
||||
SET(PROJECT_VERSION "${PROJECT_VERSION}${PROJECT_VERSION_FLAVOUR_REVISION}")
|
||||
add_compile_definitions(FW_FLAVERSION=${PROJECT_VERSION_FLAVOUR_REVISION})
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
# Inform user about the resolved settings
|
||||
MESSAGE(STATUS "Project version: ${PROJECT_VERSION}")
|
||||
MESSAGE(
|
||||
STATUS "Project version with short suffix: ${PROJECT_VERSION}${PROJECT_VERSION_SUFFIX_SHORT}"
|
||||
)
|
||||
|
||||
SET(FN_PREFIX "FW${PROJECT_VERSION}${PROJECT_VERSION_SUFFIX_SHORT}")
|
||||
|
||||
MESSAGE(WARNING "
|
||||
***************** YOUR ATTENTION PLEASE *****************
|
||||
CMake support is experimental. There is no guarantee at this time. If you have problems you are encouraged to fall back to the tried-and-true methods.
|
||||
*********************** THANK YOU **********************
|
||||
We now return to your regularly scheduled Firmware Build."
|
||||
)
|
||||
add_executable(tests ${TEST_SOURCES})
|
||||
target_include_directories(tests PRIVATE Tests)
|
||||
target_link_libraries(tests Catch)
|
||||
|
||||
OPTION(SECONDARY_LANGUAGES "Secondary language support in the firmware" ON)
|
||||
|
||||
SET(MAIN_LANGUAGES cs de es fr it pl CACHE STRING "The list of 'main' languages to be included, in the correct order")
|
||||
SET(COMMUNITY_LANGUAGES nl ro hu hr sk sv no CACHE STRING "The list of community languages to be included, in the correct order")
|
||||
SET(SELECTED_LANGUAGES ${MAIN_LANGUAGES} ${COMMUNITY_LANGUAGES})
|
||||
|
||||
get_dependency_directory(prusa3dboards PRUSA_BOARDS_DIR)
|
||||
project(Prusa-Firmware)
|
||||
|
||||
FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/Firmware/config.h MAX_SIZE_LINE REGEX "^#define \+LANG_SIZE_RESERVED \+")
|
||||
STRING(REGEX MATCH "0x[0-9]+" MAX_SIZE_HEX "${MAX_SIZE_LINE}")
|
||||
math(EXPR LANG_MAX_SIZE "${MAX_SIZE_HEX}" OUTPUT_FORMAT DECIMAL)
|
||||
message("Language maximum size (from config.h): ${LANG_MAX_SIZE} bytes")
|
||||
|
||||
set (LANG_BIN_MAX 249856) # Ditto, this in xflash_layout.h but needs invocation of the preprocessor... :-/
|
||||
|
||||
get_recommended_gcc_version(RECOMMENDED_TOOLCHAIN_VERSION)
|
||||
if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL
|
||||
${RECOMMENDED_TOOLCHAIN_VERSION}
|
||||
)
|
||||
message(WARNING "Recommended AVR toolchain is ${RECOMMENDED_TOOLCHAIN_VERSION}"
|
||||
", but you have ${CMAKE_CXX_COMPILER_VERSION}"
|
||||
)
|
||||
|
||||
elseif(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
message(
|
||||
WARNING
|
||||
"Recommended compiler for host tools and unittests is GCC, you have ${CMAKE_CXX_COMPILER_ID}."
|
||||
)
|
||||
endif()
|
||||
|
||||
# append custom C/C++ flags
|
||||
if(CUSTOM_COMPILE_OPTIONS)
|
||||
string(REPLACE " " ";" CUSTOM_COMPILE_OPTIONS "${CUSTOM_COMPILE_OPTIONS}")
|
||||
add_compile_options(${CUSTOM_COMPILE_OPTIONS})
|
||||
endif()
|
||||
|
||||
#
|
||||
# Global Compiler & Linker Configuration
|
||||
#
|
||||
|
||||
# include symbols
|
||||
add_compile_options(-g)
|
||||
|
||||
#
|
||||
# Firmware - get file lists.
|
||||
#
|
||||
SET(FW_SOURCES
|
||||
adc.cpp
|
||||
backlight.cpp
|
||||
BlinkM.cpp
|
||||
bootapp.c
|
||||
cardreader.cpp
|
||||
cmdqueue.cpp
|
||||
Configuration.cpp
|
||||
ConfigurationStore.cpp
|
||||
conv2str.cpp
|
||||
Dcodes.cpp
|
||||
eeprom.cpp
|
||||
fancheck.cpp
|
||||
Filament_sensor.cpp
|
||||
first_lay_cal.cpp
|
||||
heatbed_pwm.cpp
|
||||
la10compat.cpp
|
||||
language.c
|
||||
lcd.cpp
|
||||
Marlin_main.cpp
|
||||
MarlinSerial.cpp
|
||||
menu.cpp
|
||||
mesh_bed_calibration.cpp
|
||||
mesh_bed_leveling.cpp
|
||||
messages.cpp
|
||||
mmu2.cpp
|
||||
mmu2_crc.cpp
|
||||
mmu2_error_converter.cpp
|
||||
mmu2_fsensor.cpp
|
||||
mmu2_log.cpp
|
||||
mmu2_power.cpp
|
||||
mmu2_progress_converter.cpp
|
||||
mmu2_protocol.cpp
|
||||
mmu2_protocol_logic.cpp
|
||||
mmu2_reporting.cpp
|
||||
mmu2_serial.cpp
|
||||
motion_control.cpp
|
||||
optiboot_xflash.cpp
|
||||
pat9125.cpp
|
||||
planner.cpp
|
||||
Prusa_farm.cpp
|
||||
qr_solve.cpp
|
||||
rbuf.c
|
||||
Sd2Card.cpp
|
||||
SdBaseFile.cpp
|
||||
SdFatUtil.cpp
|
||||
SdFile.cpp
|
||||
SdVolume.cpp
|
||||
Servo.cpp
|
||||
sm4.c
|
||||
sound.cpp
|
||||
speed_lookuptable.cpp
|
||||
spi.c
|
||||
SpoolJoin.cpp
|
||||
stepper.cpp
|
||||
swi2c.c
|
||||
swspi.cpp
|
||||
Tcodes.cpp
|
||||
temperature.cpp
|
||||
timer02.c
|
||||
Timer.cpp
|
||||
tmc2130.cpp
|
||||
tone04.c
|
||||
twi.cpp
|
||||
uart2.c
|
||||
ultralcd.cpp
|
||||
util.cpp
|
||||
vector_3.cpp
|
||||
xflash.c
|
||||
xflash_dump.cpp
|
||||
xyzcal.cpp
|
||||
)
|
||||
list(TRANSFORM FW_SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/Firmware/)
|
||||
|
||||
foreach(_FILE ${FW_SOURCES})
|
||||
get_filename_component(_BASE ${_FILE} NAME)
|
||||
set_property(SOURCE ${_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS "-frandom-seed=${_BASE}.o")
|
||||
endforeach()
|
||||
|
||||
|
||||
set(AVR_SOURCES
|
||||
wiring_digital.c
|
||||
WInterrupts.c
|
||||
wiring_pulse.c
|
||||
hooks.c
|
||||
wiring.c
|
||||
wiring_analog.c
|
||||
wiring_shift.c
|
||||
CDC.cpp
|
||||
PluggableUSB.cpp
|
||||
HardwareSerial.cpp
|
||||
HardwareSerial0.cpp
|
||||
HardwareSerial1.cpp
|
||||
HardwareSerial3.cpp
|
||||
IPAddress.cpp
|
||||
HardwareSerial2.cpp
|
||||
Print.cpp
|
||||
Stream.cpp
|
||||
Tone.cpp
|
||||
USBCore.cpp
|
||||
WMath.cpp
|
||||
WString.cpp
|
||||
abi.cpp
|
||||
main.cpp
|
||||
# new.cpp # What happened to this? it was removed in 1.0.5-1 to 1.0.5.2?
|
||||
)
|
||||
list(TRANSFORM AVR_SOURCES PREPEND ${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/)
|
||||
|
||||
foreach(_FILE ${AVR_SOURCES})
|
||||
get_filename_component(_BASE ${_FILE} NAME)
|
||||
set_property(SOURCE ${_FILE} APPEND_STRING PROPERTY COMPILE_FLAGS "-frandom-seed=core/${_BASE}.o")
|
||||
endforeach()
|
||||
|
||||
# optimizations
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_options(-Og)
|
||||
else()
|
||||
add_compile_options(-Os)
|
||||
endif()
|
||||
|
||||
# mcu related settings
|
||||
set(MCU_FLAGS -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_PRUSA_EINSY_RAMBO -DARDUINO_ARCH_AVR)
|
||||
add_compile_options(${MCU_FLAGS})
|
||||
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-threadsafe-statics>)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
|
||||
add_compile_options(-Wall -Wextra -Wno-expansion-to-defined -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects)
|
||||
|
||||
# split and gc sections
|
||||
add_link_options(-Os -g -flto -Wl,--gc-sections -mmcu=atmega2560 -Wl,-u,vfprintf -lprintf_flt -lm )
|
||||
|
||||
# Create this target before we apply the GC options
|
||||
add_library(avr_core STATIC ${AVR_SOURCES})
|
||||
target_include_directories(avr_core PRIVATE
|
||||
${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/
|
||||
${PRUSA_BOARDS_DIR}/variants/prusa_einsy_rambo/
|
||||
)
|
||||
|
||||
|
||||
|
||||
# disable exceptions and related metadata
|
||||
add_compile_options(-fno-unwind-tables)
|
||||
add_link_options(-Wl,--defsym,__exidx_start=0,--defsym,__exidx_end=0)
|
||||
else()
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_options(-O0)
|
||||
else()
|
||||
add_compile_options(-O2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# enable all warnings (well, not all, but some)
|
||||
add_compile_options(-Wsign-compare)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C>:-std=gnu11>)
|
||||
|
||||
# support _DEBUG macro (some code uses to recognize debug builds)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_definitions(_DEBUG)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
# Setup language resources:
|
||||
# file(GLOB LANG_VARIANTS RELATIVE ${PROJECT_SOURCE_DIR}/lang/po ${PROJECT_SOURCE_DIR}/lang/po/Firmware_??.po)
|
||||
# string(REPLACE "Firmware_" "" LANG_VARIANTS "${LANG_VARIANTS}")
|
||||
# string(REPLACE ".po" "" LANG_VARIANTS "${LANG_VARIANTS}")
|
||||
# list(SORT LANG_VARIANTS)
|
||||
# message("Languages found: ${LANG_VARIANTS}")
|
||||
|
||||
|
||||
# Meta target to build absolutely everything
|
||||
add_custom_target(ALL_FIRMWARE)
|
||||
add_custom_target(ALL_ENGLISH)
|
||||
add_custom_target(ALL_MULTILANG)
|
||||
add_dependencies(ALL_FIRMWARE ALL_ENGLISH ALL_MULTILANG)
|
||||
|
||||
function(add_base_binary variant_name)
|
||||
add_executable(${variant_name} ${FW_SOURCES} ${FW_HEADERS} ${VARIANT_CFG_FILE})
|
||||
|
||||
set_target_properties(${variant_name} PROPERTIES CXX_STANDARD 17)
|
||||
|
||||
target_include_directories(${variant_name} PRIVATE
|
||||
${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/
|
||||
${PRUSA_BOARDS_DIR}/variants/prusa_einsy_rambo/
|
||||
${VARIANT_CFG_DIR} # Include the header for this variant.
|
||||
${CMAKE_SOURCE_DIR}/Firmware
|
||||
)
|
||||
|
||||
target_link_libraries(${variant_name} avr_core)
|
||||
|
||||
# # configure linker script
|
||||
set(LINKER_SCRIPT ${PRUSA_BOARDS_DIR}/ldscripts/avr6.xn)
|
||||
target_link_options(${variant_name} PUBLIC -Wl,-T,${LINKER_SCRIPT})
|
||||
|
||||
# limit the text section to 248K (256K - 8k reserved for the bootloader)
|
||||
target_link_options(${variant_name} PUBLIC -Wl,--defsym=__TEXT_REGION_LENGTH__=248K)
|
||||
|
||||
# generate firmware.bin file
|
||||
objcopy(${variant_name} "ihex" ".hex")
|
||||
|
||||
# produce ASM listing. Note we also specify the .map as a byproduct so it gets cleaned
|
||||
# because link_options doesn't have a "generated outputs" feature.
|
||||
add_custom_command(
|
||||
TARGET ${variant_name} POST_BUILD COMMAND ${CMAKE_OBJDUMP} -CSd ${variant_name} > ${variant_name}.asm
|
||||
BYPRODUCTS ${variant_name}.asm ${variant_name}.map
|
||||
)
|
||||
|
||||
# inform about the firmware's size in terminal
|
||||
add_custom_command(
|
||||
TARGET ${variant_name} POST_BUILD COMMAND ${CMAKE_SIZE_UTIL} -C --mcu=atmega2560 ${variant_name}
|
||||
)
|
||||
report_size(${variant_name})
|
||||
|
||||
# generate linker map file
|
||||
target_link_options(${variant_name} PUBLIC -Wl,-Map=${CMAKE_CURRENT_BINARY_DIR}/${variant_name}.map)
|
||||
|
||||
target_compile_definitions(${variant_name} PRIVATE
|
||||
CMAKE_LANG_CONTROL
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(fw_add_variant variant_name)
|
||||
|
||||
# Create the Configuration_Prusa.h for this variant so it can be #included.
|
||||
set(VARIANT_CFG_DIR "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
set(VARIANT_CFG_FILE "${VARIANT_CFG_DIR}/Configuration_prusa.h")
|
||||
add_custom_command(OUTPUT ${VARIANT_CFG_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Firmware/variants/${variant_name}.h ${VARIANT_CFG_FILE}
|
||||
COMMENT "Generating Configuration_prusa.h for ${variant_name}"
|
||||
BYPRODUCTS ${VARIANT_CFG_DIR}
|
||||
)
|
||||
STRING(REPLACE "1_75mm_" "" variant_name "${variant_name}")
|
||||
STRING(REPLACE "-E3Dv6full" "" variant_name "${variant_name}")
|
||||
|
||||
SET(FW_EN "${variant_name}_EN-only")
|
||||
SET(FW_MULTI "${variant_name}_Multilang")
|
||||
|
||||
add_base_binary(${FW_EN})
|
||||
# target_compile_options(${variant_name} PRIVATE) # turn this on for lolz -Wdouble-promotion)
|
||||
|
||||
target_compile_definitions(${FW_EN} PUBLIC LANG_MODE=0)
|
||||
add_custom_command(
|
||||
TARGET ${FW_EN}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${CMAKE_CURRENT_BINARY_DIR}/${FW_EN} ${CMAKE_BINARY_DIR}/${FN_PREFIX}-${FW_EN}.hex
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/${FN_PREFIX}-${FW_EN}.hex
|
||||
COMMENT "Generating ${variant_name} hex"
|
||||
)
|
||||
add_dependencies(ALL_ENGLISH "${FW_EN}")
|
||||
|
||||
if (NOT SECONDARY_LANGUAGES)
|
||||
return() #Done, if no languages there's nothing else to do.
|
||||
else()
|
||||
add_base_binary(${FW_MULTI})
|
||||
target_compile_definitions(${FW_MULTI} PUBLIC LANG_MODE=1)
|
||||
endif()
|
||||
|
||||
#Construct language map
|
||||
set(LANG_TMP_DIR ${CMAKE_BINARY_DIR}/${variant_name}/lang)
|
||||
set(LANG_MAP ${LANG_TMP_DIR}/${variant_name}_lang.map)
|
||||
set(LANG_FWBIN ${CMAKE_CURRENT_BINARY_DIR}/${variant_name}.bin)
|
||||
set(LANG_FINAL_BIN ${LANG_TMP_DIR}/${variant_name}_lang.bin)
|
||||
set(LANG_FINAL_HEX ${LANG_TMP_DIR}/${variant_name}_lang.hex)
|
||||
|
||||
add_custom_command(OUTPUT ${LANG_FWBIN}
|
||||
COMMAND "${CMAKE_OBJCOPY}" -I ihex -O binary ${CMAKE_CURRENT_BINARY_DIR}/${variant_name}_Multilang.hex ${LANG_FWBIN}
|
||||
DEPENDS ${FW_MULTI}
|
||||
)
|
||||
add_custom_command(OUTPUT ${LANG_MAP}
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/lang/lang-map.py "${FW_MULTI}" "${LANG_FWBIN}" > "${LANG_MAP}"
|
||||
DEPENDS ${LANG_FWBIN}
|
||||
)
|
||||
|
||||
set(LANG_BINS "")
|
||||
|
||||
foreach (LANG IN LISTS SELECTED_LANGUAGES)
|
||||
set(LANG_BIN ${LANG_TMP_DIR}/${variant_name}_${LANG}.bin)
|
||||
|
||||
set(PO_FILE "${CMAKE_SOURCE_DIR}/lang/po/Firmware_${LANG}.po")
|
||||
add_custom_command(OUTPUT ${LANG_BIN}
|
||||
# COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/lang/lang-check.py --no-warning --map "${LANG_MAP}" "${PO_FILE}"
|
||||
# COMMAND ${CMAKE_COMMAND} -E echo "Building lang_${LANG}.bin"
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/lang/lang-build.py ${LANG_MAP} ${PO_FILE} ${LANG_BIN}
|
||||
# Check bin size:
|
||||
COMMAND ${CMAKE_COMMAND} -DLANG_MAX_SIZE=${LANG_MAX_SIZE}
|
||||
-DLANG_FILE=${LANG_BIN}
|
||||
-P ${PROJECT_CMAKE_DIR}/Check_lang_size.cmake
|
||||
DEPENDS ${LANG_MAP}
|
||||
COMMENT "Generating ${variant_name}_${LANG}.bin from .po"
|
||||
)
|
||||
LIST(APPEND LANG_BINS ${LANG_BIN})
|
||||
|
||||
endforeach()
|
||||
string(FIND ${variant_name} "MK3" HAS_XFLASH)
|
||||
if (${HAS_XFLASH} GREATER_EQUAL 0)
|
||||
add_custom_command( OUTPUT ${LANG_FINAL_BIN}
|
||||
COMMAND ${CMAKE_COMMAND} -E cat ${LANG_BINS} > ${LANG_FINAL_BIN}
|
||||
DEPENDS ${LANG_BINS}
|
||||
COMMENT "Merging language binaries"
|
||||
)
|
||||
add_custom_command( OUTPUT ${LANG_FINAL_BIN}
|
||||
COMMAND ${CMAKE_COMMAND} -DLANG_MAX_SIZE=${LANG_BIN_MAX}
|
||||
-DLANG_FILE=${LANG_FINAL_BIN}
|
||||
-P ${PROJECT_CMAKE_DIR}/Check_final_lang_bin_size.cmake
|
||||
APPEND
|
||||
)
|
||||
add_custom_command( OUTPUT ${LANG_FINAL_HEX}
|
||||
COMMAND ${CMAKE_OBJCOPY} -I binary -O ihex ${LANG_FINAL_BIN} ${LANG_FINAL_HEX}
|
||||
DEPENDS ${LANG_FINAL_BIN}
|
||||
COMMENT "Generating Hex for language data"
|
||||
)
|
||||
set(LANG_HEX ${CMAKE_BINARY_DIR}/${FN_PREFIX}-${variant_name}-Languages.hex)
|
||||
|
||||
add_custom_target(${variant_name}-language-hex
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${FW_MULTI}.hex ${LANG_HEX}
|
||||
COMMAND ${CMAKE_COMMAND} -E cat ${LANG_FINAL_HEX} >> ${LANG_HEX}
|
||||
COMMENT "Generating final ${variant_name}-Languages.hex"
|
||||
BYPRODUCTS ${LANG_HEX}
|
||||
DEPENDS ${LANG_FINAL_HEX}
|
||||
)
|
||||
add_dependencies(ALL_MULTILANG ${variant_name}-language-hex)
|
||||
else()
|
||||
set (ALL_VARIANT_HEXES "")
|
||||
# Non-xflash, e.g. MK2.5
|
||||
foreach(LANG IN LISTS SELECTED_LANGUAGES)
|
||||
SET(LANG_HEX_FN ${variant_name}-en_${LANG})
|
||||
SET(LANG_HEX ${CMAKE_BINARY_DIR}/${FN_PREFIX}-${LANG_HEX_FN}.hex)
|
||||
SET(LANG_BIN ${LANG_TMP_DIR}/${variant_name}_${LANG}.bin)
|
||||
SET(LANG_FWBIN_TMP ${LANG_TMP_DIR}/${variant_name}-en_${LANG}.bin)
|
||||
|
||||
#Intermediate 2-lang bin
|
||||
add_custom_command(OUTPUT ${LANG_FWBIN_TMP}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LANG_FWBIN} ${LANG_FWBIN_TMP}
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/lang/lang-patchsec.py ${FW_MULTI} ${LANG_BIN} ${LANG_FWBIN_TMP}
|
||||
DEPENDS ${LANG_FWBIN} ${LANG_BIN}
|
||||
COMMENT "Generating ${variant_name}-en_${LANG}.bin"
|
||||
)
|
||||
|
||||
#Final hex:
|
||||
add_custom_target(${LANG_HEX_FN}
|
||||
COMMAND ${CMAKE_OBJCOPY} -I binary -O ihex ${LANG_FWBIN_TMP} ${LANG_HEX}
|
||||
BYPRODUCTS ${LANG_HEX}
|
||||
DEPENDS ${LANG_FWBIN_TMP}
|
||||
COMMENT "Creating ${LANG_HEX_FN}.hex"
|
||||
)
|
||||
LIST(APPEND ALL_VARIANT_HEXES ${LANG_HEX_FN})
|
||||
endforeach()
|
||||
add_custom_target("${variant_name}-All-Languages"
|
||||
DEPENDS ${ALL_VARIANT_HEXES}
|
||||
)
|
||||
add_dependencies(ALL_MULTILANG "${variant_name}-All-Languages")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
|
||||
file(GLOB FW_VARIANTS RELATIVE ${PROJECT_SOURCE_DIR}/Firmware/variants ${PROJECT_SOURCE_DIR}/Firmware/variants/*.h)
|
||||
foreach(THIS_VAR IN LISTS FW_VARIANTS)
|
||||
string(REPLACE ".h" "" TRIMMED_NAME "${THIS_VAR}")
|
||||
message("Variant added: ${TRIMMED_NAME}")
|
||||
string(REPLACE "-E3Dv6full" "" DIR_NAME "${TRIMMED_NAME}")
|
||||
string(REPLACE "1_75mm_" "" DIR_NAME "${DIR_NAME}")
|
||||
# Generate a file in a subfolder so that we can organize things a little more neatly in VS code
|
||||
FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build_gen/${DIR_NAME})
|
||||
FILE(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build_gen/${DIR_NAME}/CMakeLists.txt "project(${DIR_NAME})\nfw_add_variant(${TRIMMED_NAME})")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/build_gen/${DIR_NAME})
|
||||
#fw_add_variant(${TRIMMED_NAME})
|
||||
endforeach(THIS_VAR IN LISTS FW_VARIANTS)
|
||||
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
# do not build the firmware by default (tests are the focus if not crosscompiling)
|
||||
project(cmake_test)
|
||||
|
||||
# Prepare "Catch" library for other executables
|
||||
set(CATCH_INCLUDE_DIR Catch2)
|
||||
add_library(Catch INTERFACE)
|
||||
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
|
||||
|
||||
# Make test executable
|
||||
set(TEST_SOURCES
|
||||
Tests/tests.cpp
|
||||
Tests/Example_test.cpp
|
||||
Tests/Timer_test.cpp
|
||||
Tests/AutoDeplete_test.cpp
|
||||
Tests/PrusaStatistics_test.cpp
|
||||
Firmware/Timer.cpp
|
||||
Firmware/AutoDeplete.cpp
|
||||
)
|
||||
add_executable(tests ${TEST_SOURCES})
|
||||
target_include_directories(tests PRIVATE Tests)
|
||||
target_link_libraries(tests Catch)
|
||||
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -60,9 +60,13 @@
|
|||
#define TMC2130_SPCR SPI_SPCR(TMC2130_SPI_RATE, 1, 1, 1, 0)
|
||||
#define TMC2130_SPSR SPI_SPSR(TMC2130_SPI_RATE)
|
||||
|
||||
// This is set by the cmake build to be able to take control of
|
||||
// the language flag, without breaking existing build mechanisms.
|
||||
#ifndef CMAKE_LANG_CONTROL
|
||||
//LANG - Multi-language support
|
||||
//#define LANG_MODE 0 // primary language only
|
||||
#define LANG_MODE 1 // sec. language support
|
||||
#endif
|
||||
|
||||
#define LANG_SIZE_RESERVED 0x3500 // reserved space for secondary language (13568 bytes).
|
||||
// 0x3D00 Maximum 15616 bytes as it depends on xflash_layout.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
cmake_minimum_required(VERSION 3.18)
|
||||
FILE(SIZE ${LANG_FILE} FILE_SIZE)
|
||||
get_filename_component(FILE_BASE ${LANG_FILE} NAME)
|
||||
MATH(EXPR PADDED_SIZE "((${FILE_SIZE}+4096-1) / 4096 * 4096 )")
|
||||
message(STATUS "${FILE_BASE} raw size ${FILE_SIZE} bytes (${PADDED_SIZE} b padded)")
|
||||
if(${PADDED_SIZE} GREATER ${LANG_MAX_SIZE})
|
||||
message(FATAL_ERROR "Language file ${FILE_BASE} (${PADDED_SIZE}b) exceeds maximum allowed size of ${LANG_MAX_SIZE} bytes - Aborting!")
|
||||
else()
|
||||
MATH(EXPR SIZE_PCT "( ${PADDED_SIZE} * 100) / ${LANG_MAX_SIZE} " )
|
||||
message(STATUS "Language file ${FILE_BASE} is ${PADDED_SIZE} bytes, ${SIZE_PCT}% of allowed space - OK")
|
||||
endif()
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
cmake_minimum_required(VERSION 3.18)
|
||||
FILE(SIZE ${LANG_FILE} FILE_SIZE)
|
||||
get_filename_component(FILE_BASE ${LANG_FILE} NAME)
|
||||
if(${FILE_SIZE} GREATER ${LANG_MAX_SIZE})
|
||||
message(FATAL_ERROR "Language file ${FILE_BASE} (${FILE_SIZE}b) exceeds maximum allowed size of ${LANG_MAX_SIZE} bytes - Aborting!")
|
||||
else()
|
||||
MATH(EXPR SIZE_PCT "( ${FILE_SIZE} * 100) / ${LANG_MAX_SIZE} " )
|
||||
message(STATUS "Language file ${FILE_BASE} is ${FILE_SIZE} bytes, ${SIZE_PCT}% of allowed space - OK")
|
||||
endif()
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
# * Returns a version string from Git
|
||||
#
|
||||
# These functions force a re-configure on each git commit so that you can trust the values of the
|
||||
# variables in your build system.
|
||||
#
|
||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the refspec and sha hash of the current head revision
|
||||
#
|
||||
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe on the source tree, and adjusting the output so that it tests
|
||||
# false if an error occurs.
|
||||
#
|
||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe --exact-match on the source tree, and adjusting the output so
|
||||
# that it tests false if there was no exact matching tag.
|
||||
#
|
||||
# git_local_changes(<var>)
|
||||
#
|
||||
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. Uses the return code of
|
||||
# "git diff-index --quiet HEAD --". Does not regard untracked files.
|
||||
#
|
||||
# git_count_parent_commits(<var>)
|
||||
#
|
||||
# Returns number of commits preceeding current commit -1 if git rev-list --count HEAD failed or
|
||||
# "GIT-NOTFOUND" if git executable was not found or "HEAD-HASH-NOTFOUND" if head hash was not found.
|
||||
# I don't know if get_git_head_revision() must be called internally or not, as reason of calling it
|
||||
# is not clear for me also in git_local_changes().
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author: 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010. Distributed under the Boost Software License, Version
|
||||
# 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__get_git_revision_description)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_revision_description YES)
|
||||
|
||||
# We must run the following at "include" time, not at function call time, to find the path to this
|
||||
# module rather than the path to a calling list file
|
||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar)
|
||||
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_refspecvar}
|
||||
"GITDIR-NOTFOUND"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
set(${_hashvar}
|
||||
"GITDIR-NOTFOUND"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
endwhile()
|
||||
# check if this is a submodule
|
||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
endif()
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if(NOT EXISTS "${GIT_DATA}")
|
||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||
return()
|
||||
endif()
|
||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
configure_file(
|
||||
"${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" "${GIT_DATA}/grabRef.cmake" @ONLY
|
||||
)
|
||||
include("${GIT_DATA}/grabRef.cmake")
|
||||
|
||||
set(${_refspecvar}
|
||||
"${HEAD_REF}"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
set(${_hashvar}
|
||||
"${HEAD_HASH}"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var}
|
||||
"GIT-NOTFOUND"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var}
|
||||
"HEAD-HASH-NOTFOUND"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO sanitize if((${ARGN}" MATCHES "&&") OR (ARGN MATCHES "||") OR (ARGN MATCHES "\\;"))
|
||||
# message("Please report the following error to the project!") message(FATAL_ERROR "Looks like
|
||||
# someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") endif()
|
||||
|
||||
# message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" describe ${hash} ${ARGN}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var}
|
||||
"${out}"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(git_get_exact_tag _var)
|
||||
git_describe(out --exact-match ${ARGN})
|
||||
set(${_var}
|
||||
"${out}"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(git_local_changes _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var}
|
||||
"GIT-NOTFOUND"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var}
|
||||
"HEAD-HASH-NOTFOUND"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(res EQUAL 0)
|
||||
set(${_var}
|
||||
"CLEAN"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
else()
|
||||
set(${_var}
|
||||
"DIRTY"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(git_count_parent_commits _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var}
|
||||
"GIT-NOTFOUND"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var}
|
||||
"HEAD-HASH-NOTFOUND"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" rev-list --count HEAD
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(res EQUAL 0)
|
||||
set(${_var}
|
||||
"${out}"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
else()
|
||||
set(${_var}
|
||||
"-1"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# Internal file for GetGitRevisionDescription.cmake
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author: 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010. Distributed under the Boost Software License, Version
|
||||
# 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set(HEAD_HASH)
|
||||
|
||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if(HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if(NOT HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
get_filename_component(PROJECT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||
include("${PROJECT_CMAKE_DIR}/Utilities.cmake")
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR avr)
|
||||
set(CMAKE_CROSSCOMPILING 1)
|
||||
get_dependency_directory("avr-gcc" AVR_TOOLCHAIN_DIR)
|
||||
message( "tc dir is ${AVR_TOOLCHAIN_DIR}")
|
||||
#
|
||||
# Utilities
|
||||
|
||||
if(MINGW
|
||||
OR CYGWIN
|
||||
OR WIN32
|
||||
)
|
||||
set(UTIL_SEARCH_CMD where)
|
||||
set(EXECUTABLE_SUFFIX ".exe")
|
||||
elseif(UNIX OR APPLE)
|
||||
set(UTIL_SEARCH_CMD which)
|
||||
set(EXECUTABLE_SUFFIX "")
|
||||
endif()
|
||||
|
||||
set(TOOLCHAIN_PREFIX avr-)
|
||||
|
||||
#
|
||||
# Looking up the toolchain
|
||||
#
|
||||
|
||||
if(AVR_TOOLCHAIN_DIR)
|
||||
# using toolchain set by AvrGcc.cmake (locked version)
|
||||
set(BINUTILS_PATH "${AVR_TOOLCHAIN_DIR}/bin")
|
||||
else()
|
||||
# search for ANY avr-gcc toolchain
|
||||
execute_process(
|
||||
COMMAND ${UTIL_SEARCH_CMD} ${TOOLCHAIN_PREFIX}gcc
|
||||
OUTPUT_VARIABLE AVR_GCC_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE FIND_RESULT
|
||||
)
|
||||
# found?
|
||||
if(NOT "${FIND_RESULT}" STREQUAL "0")
|
||||
message(FATAL_ERROR "avr-gcc not found")
|
||||
endif()
|
||||
get_filename_component(BINUTILS_PATH "${AVR_GCC_PATH}" DIRECTORY)
|
||||
get_filename_component(AVR_TOOLCHAIN_DIR ${BINUTILS_PATH} DIRECTORY)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Setup CMake
|
||||
#
|
||||
|
||||
# Without that flag CMake is not able to pass test compilation check
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
|
||||
set(CMAKE_C_COMPILER
|
||||
"${BINUTILS_PATH}/${TOOLCHAIN_PREFIX}gcc${EXECUTABLE_SUFFIX}"
|
||||
CACHE FILEPATH "" FORCE
|
||||
)
|
||||
set(CMAKE_ASM_COMPILER
|
||||
"${BINUTILS_PATH}/${TOOLCHAIN_PREFIX}gcc${EXECUTABLE_SUFFIX}"
|
||||
CACHE FILEPATH "" FORCE
|
||||
)
|
||||
set(CMAKE_CXX_COMPILER
|
||||
"${BINUTILS_PATH}/${TOOLCHAIN_PREFIX}g++${EXECUTABLE_SUFFIX}"
|
||||
CACHE FILEPATH "" FORCE
|
||||
)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_INIT
|
||||
""
|
||||
CACHE STRING "" FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_ASM_COMPILE_OBJECT
|
||||
"<CMAKE_ASM_COMPILER> <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>"
|
||||
CACHE STRING "" FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_AR
|
||||
"${BINUTILS_PATH}/${TOOLCHAIN_PREFIX}gcc-ar${EXECUTABLE_SUFFIX}"
|
||||
CACHE FILEPATH "ar" FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_RANLIB
|
||||
"${BINUTILS_PATH}/${TOOLCHAIN_PREFIX}gcc-ranlib${EXECUTABLE_SUFFIX}"
|
||||
CACHE FILEPATH "ranlib" FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_OBJCOPY
|
||||
"${BINUTILS_PATH}/${TOOLCHAIN_PREFIX}objcopy${EXECUTABLE_SUFFIX}"
|
||||
CACHE INTERNAL "objcopy tool"
|
||||
)
|
||||
set(CMAKE_OBJDUMP
|
||||
"${BINUTILS_PATH}/${TOOLCHAIN_PREFIX}objdump${EXECUTABLE_SUFFIX}"
|
||||
CACHE INTERNAL "objdump tool"
|
||||
)
|
||||
set(CMAKE_SIZE_UTIL
|
||||
"${BINUTILS_PATH}/${TOOLCHAIN_PREFIX}size${EXECUTABLE_SUFFIX}"
|
||||
CACHE INTERNAL "size tool"
|
||||
)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH "${AVR_TOOLCHAIN_DIR}")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#
|
||||
# This file is responsible for setting the following variables:
|
||||
#
|
||||
# ~~~
|
||||
# BUILD_NUMBER (1035)
|
||||
# PROJECT_VERSION (4.0.3)
|
||||
# PROJECT_VERSION_FULL (4.0.3-BETA+1035.PR111.B4)
|
||||
# PROJECT_VERSION_SUFFIX (-BETA+1035.PR111.B4)
|
||||
# PROJECT_VERSION_SUFFIX_SHORT (+1035)
|
||||
#
|
||||
# The `PROJECT_VERSION` variable is set as soon as the file is included.
|
||||
# To set the rest, the function `resolve_version_variables` has to be called.
|
||||
#
|
||||
# ~~~
|
||||
|
||||
FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/Firmware/Configuration.h CFG_VER_DATA REGEX "#define FW_[A-Z]+ ([0-9]+)" )
|
||||
LIST(GET CFG_VER_DATA 0 PROJECT_VERSION_MAJOR)
|
||||
LIST(GET CFG_VER_DATA 1 PROJECT_VERSION_MINOR)
|
||||
LIST(GET CFG_VER_DATA 2 PROJECT_VERSION_REV)
|
||||
STRING(REGEX MATCH "FW_MAJOR ([0-9]+)" PROJECT_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||
SET(PROJECT_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
|
||||
STRING(REGEX MATCH "FW_MINOR ([0-9]+)" PROJECT_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
||||
SET(PROJECT_VERSION_MINOR ${CMAKE_MATCH_1})
|
||||
|
||||
STRING(REGEX MATCH "FW_REVISION +([0-9]+)" PROJECT_VERSION_REV "${PROJECT_VERSION_REV}")
|
||||
SET(PROJECT_VERSION_REV ${CMAKE_MATCH_1})
|
||||
|
||||
SET(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_REV}")
|
||||
SET(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_REV}" PARENT_SCOPE)
|
||||
|
||||
|
||||
function(resolve_version_variables)
|
||||
# BUILD_NUMBER
|
||||
if(NOT BUILD_NUMBER)
|
||||
git_count_parent_commits(BUILD_NUMBER)
|
||||
set(ERRORS "GIT-NOTFOUND" "HEAD-HASH-NOTFOUND")
|
||||
if(BUILD_NUMBER IN_LIST ERRORS)
|
||||
message(WARNING "Failed to resolve build number: ${BUILD_NUMBER}. Setting to zero.")
|
||||
set(BUILD_NUMBER "0")
|
||||
endif()
|
||||
set(BUILD_NUMBER
|
||||
${BUILD_NUMBER}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
|
||||
# PROJECT_VERSION_SUFFIX
|
||||
if(PROJECT_VERSION_SUFFIX STREQUAL "<auto>")
|
||||
# TODO: set to +<sha>.dirty?.debug?
|
||||
set(PROJECT_VERSION_SUFFIX "+${BUILD_NUMBER}.LOCAL")
|
||||
set(PROJECT_VERSION_SUFFIX
|
||||
"+${BUILD_NUMBER}.LOCAL"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
|
||||
# PROJECT_VERSION_SUFFIX_SHORT
|
||||
if(PROJECT_VERSION_SUFFIX_SHORT STREQUAL "<auto>")
|
||||
set(PROJECT_VERSION_SUFFIX_SHORT
|
||||
"+${BUILD_NUMBER}"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
|
||||
# PROJECT_VERSION_FULL
|
||||
set(PROJECT_VERSION_FULL
|
||||
"${PROJECT_VERSION}${PROJECT_VERSION_SUFFIX}"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
get_filename_component(PROJECT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||
get_filename_component(PROJECT_ROOT_DIR "${PROJECT_CMAKE_DIR}" DIRECTORY)
|
||||
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
if(NOT Python3_FOUND)
|
||||
message(FATAL_ERROR "Python3 not found.")
|
||||
endif()
|
||||
|
||||
function(get_recommended_gcc_version var)
|
||||
execute_process(
|
||||
COMMAND "${Python3_EXECUTABLE}" "${PROJECT_ROOT_DIR}/utils/bootstrap.py"
|
||||
"--print-dependency-version" "avr-gcc"
|
||||
OUTPUT_VARIABLE RECOMMENDED_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RETVAL
|
||||
)
|
||||
|
||||
if(NOT "${RETVAL}" STREQUAL "0")
|
||||
message(FATAL_ERROR "Failed to obtain recommended gcc version from utils/bootstrap.py")
|
||||
endif()
|
||||
|
||||
set(${var}
|
||||
${RECOMMENDED_VERSION}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(get_dependency_directory dependency var)
|
||||
execute_process(
|
||||
COMMAND "${Python3_EXECUTABLE}" "${PROJECT_ROOT_DIR}/utils/bootstrap.py"
|
||||
"--print-dependency-directory" "${dependency}"
|
||||
OUTPUT_VARIABLE DEPENDENCY_DIRECTORY
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RETVAL
|
||||
)
|
||||
|
||||
if(NOT "${RETVAL}" STREQUAL "0")
|
||||
message(FATAL_ERROR "Failed to find directory with ${dependency}")
|
||||
endif()
|
||||
|
||||
set(${var}
|
||||
${DEPENDENCY_DIRECTORY}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(objcopy target format suffix)
|
||||
add_custom_command(
|
||||
TARGET ${target} POST_BUILD
|
||||
COMMAND "${CMAKE_OBJCOPY}" -O ${format} -S "$<TARGET_FILE:${target}>"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${target}${suffix}"
|
||||
COMMENT "Generating ${format} from ${target}..."
|
||||
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/${target}${suffix}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(report_size target)
|
||||
add_custom_command(
|
||||
TARGET ${target} POST_BUILD
|
||||
COMMAND echo "" # visually separate the output
|
||||
COMMAND "${CMAKE_SIZE_UTIL}" -B "$<TARGET_FILE:${target}>"
|
||||
USES_TERMINAL
|
||||
)
|
||||
endfunction()
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Bootstrap Script
|
||||
#
|
||||
# This script
|
||||
# 1) records the recommended versions of dependencies, and
|
||||
# 2) when run, checks that all of them are present and downloads
|
||||
# them if they are not.
|
||||
#
|
||||
# pylint: disable=line-too-long
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import zipfile
|
||||
from argparse import ArgumentParser
|
||||
from pathlib import Path
|
||||
from urllib.request import urlretrieve
|
||||
|
||||
project_root_dir = Path(__file__).resolve().parent.parent
|
||||
dependencies_dir = project_root_dir / '.dependencies'
|
||||
|
||||
# All dependencies of this project.
|
||||
#
|
||||
# yapf: disable
|
||||
dependencies = {
|
||||
'ninja': {
|
||||
'version': '1.10.2',
|
||||
'url': {
|
||||
'Linux': 'https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-linux.zip',
|
||||
'Windows': 'https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-win.zip',
|
||||
'Darwin': 'https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip',
|
||||
},
|
||||
},
|
||||
'cmake': {
|
||||
'version': '3.22.5',
|
||||
'url': {
|
||||
'Linux': 'https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-linux-x86_64.tar.gz',
|
||||
'Windows': 'https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-windows-x86_64.zip',
|
||||
'Darwin': 'https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-macos-universal.tar.gz',
|
||||
},
|
||||
},
|
||||
'avr-gcc': {
|
||||
'version': '7.3.0',
|
||||
'url': {
|
||||
'Linux': 'http://downloads.arduino.cc/tools/avr-gcc-7.3.0-atmel3.6.1-arduino7-x86_64-pc-linux-gnu.tar.bz2',
|
||||
'Windows': 'http://downloads.arduino.cc/tools/avr-gcc-7.3.0-atmel3.6.1-arduino7-i686-w64-mingw32.zip',
|
||||
'Darwin': 'http://downloads.arduino.cc/tools/avr-gcc-7.3.0-atmel3.6.1-arduino7-x86_64-apple-darwin14.tar.bz2',
|
||||
},
|
||||
},
|
||||
'prusa3dboards': {
|
||||
'version': '1.0.5-2',
|
||||
'url': {
|
||||
'Linux': 'https://raw.githubusercontent.com/prusa3d/Arduino_Boards/devel/IDE_Board_Manager/prusa3dboards-1.0.5-2.tar.bz2',
|
||||
'Windows': 'https://raw.githubusercontent.com/prusa3d/Arduino_Boards/devel/IDE_Board_Manager/prusa3dboards-1.0.5-2.tar.bz2',
|
||||
'Darwin': 'https://raw.githubusercontent.com/prusa3d/Arduino_Boards/devel/IDE_Board_Manager/prusa3dboards-1.0.5-2.tar.bz2',
|
||||
}
|
||||
},
|
||||
}
|
||||
pip_dependencies = ["pyelftools","polib","regex"]
|
||||
# yapf: enable
|
||||
|
||||
|
||||
def directory_for_dependency(dependency, version):
|
||||
return dependencies_dir / (dependency + '-' + version)
|
||||
|
||||
|
||||
def find_single_subdir(path: Path):
|
||||
members = list(path.iterdir())
|
||||
if path.is_dir() and len(members) > 1:
|
||||
return path
|
||||
elif path.is_dir() and len(members) == 1:
|
||||
return find_single_subdir(members[0]) if members[0].is_dir() else path
|
||||
else:
|
||||
raise RuntimeError
|
||||
|
||||
|
||||
def download_and_unzip(url: str, directory: Path):
|
||||
"""Download a compressed file and extract it at `directory`."""
|
||||
extract_dir = directory.with_suffix('.temp')
|
||||
shutil.rmtree(directory, ignore_errors=True)
|
||||
shutil.rmtree(extract_dir, ignore_errors=True)
|
||||
|
||||
print('Downloading ' + directory.name)
|
||||
f, _ = urlretrieve(url, filename=None)
|
||||
print('Extracting ' + directory.name)
|
||||
if '.tar.bz2' in url or '.tar.gz' in url or '.tar.xz' in url:
|
||||
obj = tarfile.open(f)
|
||||
else:
|
||||
obj = zipfile.ZipFile(f, 'r')
|
||||
obj.extractall(path=str(extract_dir))
|
||||
|
||||
subdir = find_single_subdir(extract_dir)
|
||||
shutil.move(str(subdir), str(directory))
|
||||
shutil.rmtree(extract_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def run(*cmd):
|
||||
process = subprocess.run([str(a) for a in cmd],
|
||||
stdout=subprocess.PIPE,
|
||||
check=True,
|
||||
encoding='utf-8')
|
||||
return process.stdout.strip()
|
||||
|
||||
|
||||
def fix_executable_permissions(dependency, installation_directory):
|
||||
to_fix = ('ninja', 'clang-format')
|
||||
if dependency not in to_fix:
|
||||
return
|
||||
for fpath in installation_directory.iterdir():
|
||||
if fpath.is_file and fpath.with_suffix('').name in to_fix:
|
||||
st = os.stat(fpath)
|
||||
os.chmod(fpath, st.st_mode | stat.S_IEXEC)
|
||||
|
||||
|
||||
def recommended_version_is_available(dependency):
|
||||
version = dependencies[dependency]['version']
|
||||
directory = directory_for_dependency(dependency, version)
|
||||
return directory.exists() and directory.is_dir()
|
||||
|
||||
|
||||
def get_installed_pip_packages():
|
||||
result = run(sys.executable, '-m', 'pip', 'list',
|
||||
'--disable-pip-version-check', '--format', 'json')
|
||||
data = json.loads(result)
|
||||
return [(pkg['name'].lower(), pkg['version']) for pkg in data]
|
||||
|
||||
|
||||
def install_dependency(dependency):
|
||||
specs = dependencies[dependency]
|
||||
installation_directory = directory_for_dependency(dependency,
|
||||
specs['version'])
|
||||
url = specs['url']
|
||||
if isinstance(url, dict):
|
||||
url = url[platform.system()]
|
||||
download_and_unzip(url=url, directory=installation_directory)
|
||||
fix_executable_permissions(dependency, installation_directory)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = ArgumentParser()
|
||||
# yapf: disable
|
||||
parser.add_argument(
|
||||
'--print-dependency-version', type=str,
|
||||
help='Prints recommended version of given dependency and exits.')
|
||||
parser.add_argument(
|
||||
'--print-dependency-directory', type=str,
|
||||
help='Prints installation directory of given dependency and exits.')
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
# yapf: enable
|
||||
|
||||
if args.print_dependency_version:
|
||||
try:
|
||||
version = dependencies[args.print_dependency_version]['version']
|
||||
print(version)
|
||||
return 0
|
||||
except KeyError:
|
||||
print('Unknown dependency "%s"' % args.print_dependency_version)
|
||||
return 1
|
||||
|
||||
if args.print_dependency_directory:
|
||||
try:
|
||||
dependency = args.print_dependency_directory
|
||||
version = dependencies[dependency]['version']
|
||||
install_dir = directory_for_dependency(dependency, version)
|
||||
print(install_dir)
|
||||
return 0
|
||||
except KeyError:
|
||||
print('Unknown dependency "%s"' % args.print_dependency_directory)
|
||||
return 1
|
||||
|
||||
# if no argument present, check and install dependencies
|
||||
for dependency in dependencies:
|
||||
if recommended_version_is_available(dependency):
|
||||
continue
|
||||
install_dependency(dependency)
|
||||
|
||||
# also, install pip packages
|
||||
installed_pip_packages = get_installed_pip_packages()
|
||||
for package in pip_dependencies:
|
||||
is_installed = any(installed[0] == package
|
||||
for installed in installed_pip_packages)
|
||||
if is_installed:
|
||||
continue
|
||||
print('Installing Python package %s' % package)
|
||||
run(sys.executable, '-m', 'pip', 'install', package,
|
||||
'--disable-pip-version-check')
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Loading…
Reference in New Issue