diff --git a/.cmake-format.py b/.cmake-format.py new file mode 100644 index 000000000..a9489146f --- /dev/null +++ b/.cmake-format.py @@ -0,0 +1,21 @@ +# If a statement is wrapped to more than one line, than dangle the closing +# parenthesis on it's own line. +dangle_parens = True +dangle_align = 'child' + +# If true, the parsers may infer whether or not an argument list is sortable +# (without annotation). +autosort = True + +# How wide to allow formatted cmake files +line_width = 100 + +additional_commands = { + "target_sources": { + "kwargs": { + "PUBLIC": "*", + "PRIVATE": "*", + "INTERFACE": "*", + } + }, +} diff --git a/CMakeLists.txt b/CMakeLists.txt index f49377df7..d526860d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,93 +1,115 @@ -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.19) include(cmake/Utilities.cmake) include(cmake/GetGitRevisionDescription.cmake) -SET(PROJECT_VERSION_SUFFIX +set(PROJECT_VERSION_SUFFIX "" 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 '+..' if set to ''." ) -SET(PROJECT_VERSION_SUFFIX_SHORT +set(PROJECT_VERSION_SUFFIX_SHORT "" CACHE STRING "Short version suffix to be shown on splash screen. Defaults to '+' if set to ''." ) -SET(BUILD_NUMBER +set(BUILD_NUMBER "" CACHE STRING "Build number of the firmware. Resolved automatically if not specified." ) - -INCLUDE(cmake/ProjectVersion.cmake) +include(cmake/ProjectVersion.cmake) resolve_version_variables() +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" + ) -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() +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( +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}") +set(FN_PREFIX "FW${PROJECT_VERSION}${PROJECT_VERSION_SUFFIX_SHORT}") -MESSAGE(WARNING " +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." -) + ) -OPTION(SECONDARY_LANGUAGES "Secondary language support in the firmware" ON) +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}) +# Language configuration +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) add_subdirectory(lib) -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}") +# Get LANG_MAX_SIZE from sources +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... :-/ +# Ditto, this in xflash_layout.h but needs invocation of the preprocessor... :-/ +set(LANG_BIN_MAX 249856) 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}" - ) + ${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}." - ) + 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}) + string(REPLACE " " ";" CUSTOM_COMPILE_OPTIONS "${CUSTOM_COMPILE_OPTIONS}") + add_compile_options(${CUSTOM_COMPILE_OPTIONS}) endif() # @@ -103,14 +125,13 @@ set(CMAKE_CXX_STANDARD 17) # support _DEBUG macro (some code uses to recognize debug builds) if(CMAKE_BUILD_TYPE STREQUAL "Debug") - add_compile_definitions(_DEBUG) + add_compile_definitions(_DEBUG) endif() - # # Firmware - get file lists. # -SET(FW_SOURCES +set(FW_SOURCES adc.cpp backlight.cpp BlinkM.cpp @@ -181,7 +202,7 @@ SET(FW_SOURCES xflash.c xflash_dump.cpp xyzcal.cpp -) + ) list(TRANSFORM FW_SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/Firmware/) set(AVR_SOURCES @@ -208,298 +229,313 @@ set(AVR_SOURCES 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/) - # # Target configuration # if(CMAKE_CROSSCOMPILING) - # Reproducible build support - function(set_reproducible_sources source_list prefix) - foreach(file IN LISTS ${source_list}) - get_filename_component(base ${file} NAME) - set(target "${prefix}${base}") - set_property(SOURCE ${file} APPEND PROPERTY COMPILE_OPTIONS "-frandom-seed=${target}.o") - endforeach() - endfunction() - - function(set_reproducible_target target) - set_target_properties(${target} PROPERTIES STATIC_LIBRARY_OPTIONS "-D") - endfunction() - - set_reproducible_sources(AVR_SOURCES "core/") - - add_link_options(-fdebug-prefix-map=${CMAKE_SOURCE_DIR}=) - add_link_options(-fdebug-prefix-map=${CMAKE_BINARY_DIR}=) - if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "8") - add_compile_options(-ffile-prefix-map=${CMAKE_SOURCE_DIR}=) - endif() - - # TODO: get date from the last git commit to set as epoch - set(ENV{SOURCE_DATE_EPOCH} 0) - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8") - string(TIMESTAMP SOURCE_DATE_EPOCH "%Y-%m-%d") - add_compile_definitions(SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH}") - string(TIMESTAMP SOURCE_TIME_EPOCH "%H:%M:%S") - add_compile_definitions(SOURCE_TIME_EPOCH="${SOURCE_TIME_EPOCH}") - endif() - - # default optimization flags - set(CMAKE_CXX_FLAGS_DEBUG "-Og -g") - set(CMAKE_CXX_FLAGS_RELEASE "-Os -g -DNDEBUG") - set(CMAKE_C_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) - set(CMAKE_C_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) - - # mcu and target-related settings - add_compile_options(-mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_PRUSA_EINSY_RAMBO -DARDUINO_ARCH_AVR) - add_link_options(-mmcu=atmega2560 -Wl,-u,vfprintf -lprintf_flt -lm) - - # disable some C++ language features - add_compile_options($<$:-fno-threadsafe-statics>) - add_compile_options($<$:-fno-rtti>) - - # disable exceptions - add_compile_options($<$:-fno-exceptions>) - add_compile_options($<$:-fno-unwind-tables>) - - # split and gc sections - add_compile_options(-ffunction-sections -fdata-sections) - add_link_options(-ffunction-sections -fdata-sections -Wl,--gc-sections) - - # LTO (with custom options) - add_compile_options(-flto -fno-fat-lto-objects) - add_link_options(-flto) - - # Create this target before we apply the GC options - add_library(avr_core STATIC ${AVR_SOURCES}) - set_reproducible_target(avr_core) - target_include_directories(avr_core PRIVATE - ${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/ - ${PRUSA_BOARDS_DIR}/variants/prusa_einsy_rambo/ + # Reproducible build support + function(set_reproducible_sources source_list prefix) + foreach(file IN LISTS ${source_list}) + get_filename_component(base ${file} NAME) + set(target "${prefix}${base}") + set_property( + SOURCE ${file} + APPEND + PROPERTY COMPILE_OPTIONS "-frandom-seed=${target}.o" ) + endforeach() + endfunction() + + function(set_reproducible_target target) + set_target_properties(${target} PROPERTIES STATIC_LIBRARY_OPTIONS "-D") + endfunction() + + set_reproducible_sources(AVR_SOURCES "core/") + + add_link_options(-fdebug-prefix-map=${CMAKE_SOURCE_DIR}=) + add_link_options(-fdebug-prefix-map=${CMAKE_BINARY_DIR}=) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "8") + add_compile_options(-ffile-prefix-map=${CMAKE_SOURCE_DIR}=) + endif() + + # TODO: get date from the last git commit to set as epoch + set(ENV{SOURCE_DATE_EPOCH} 0) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8") + string(TIMESTAMP SOURCE_DATE_EPOCH "%Y-%m-%d") + add_compile_definitions(SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH}") + string(TIMESTAMP SOURCE_TIME_EPOCH "%H:%M:%S") + add_compile_definitions(SOURCE_TIME_EPOCH="${SOURCE_TIME_EPOCH}") + endif() + + # default optimization flags + set(CMAKE_CXX_FLAGS_DEBUG "-Og -g") + set(CMAKE_CXX_FLAGS_RELEASE "-Os -g -DNDEBUG") + set(CMAKE_C_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + set(CMAKE_C_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) + + # mcu and target-related settings + add_compile_options( + -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_PRUSA_EINSY_RAMBO + -DARDUINO_ARCH_AVR + ) + add_link_options(-mmcu=atmega2560 -Wl,-u,vfprintf -lprintf_flt -lm) + + # disable some C++ language features + add_compile_options($<$:-fno-threadsafe-statics>) + add_compile_options($<$:-fno-rtti>) + + # disable exceptions + add_compile_options($<$:-fno-exceptions>) + add_compile_options($<$:-fno-unwind-tables>) + + # split and gc sections + add_compile_options(-ffunction-sections -fdata-sections) + add_link_options(-ffunction-sections -fdata-sections -Wl,--gc-sections) + + # LTO (with custom options) + add_compile_options(-flto -fno-fat-lto-objects) + add_link_options(-flto) + + # Create this target before we apply the GC options + add_library(avr_core STATIC ${AVR_SOURCES}) + set_reproducible_target(avr_core) + target_include_directories( + avr_core PRIVATE ${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/ + ${PRUSA_BOARDS_DIR}/variants/prusa_einsy_rambo/ + ) 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 +# Meta targets 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) +set_target_properties(ALL_MULTILANG PROPERTIES EXCLUDE_FROM_ALL FALSE) function(add_base_binary variant_name) - add_executable(${variant_name} ${FW_SOURCES} ${FW_HEADERS} ${VARIANT_CFG_FILE}) + add_executable(${variant_name} ${FW_SOURCES} ${FW_HEADERS} ${VARIANT_CFG_DST}) + set_target_properties(${variant_name} PROPERTIES EXCLUDE_FROM_ALL TRUE) - 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_include_directories( + ${variant_name} + PRIVATE ${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/ + ${PRUSA_BOARDS_DIR}/variants/prusa_einsy_rambo/ + ${CMAKE_SOURCE_DIR}/Firmware ) - target_link_libraries(${variant_name} avr_core) + 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}) + # 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) + # 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} --prefix ${CMAKE_SOURCE_DIR} -CSd ${variant_name} > ${variant_name}.asm - BYPRODUCTS ${variant_name}.asm ${variant_name}.map + # 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} --prefix ${CMAKE_SOURCE_DIR} -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} + # 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}) + 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 + # 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_CONTROL) endfunction() function(fw_add_variant variant_name) - # Set FW_SOURCES to be reproducible in this variant as it's set in a separate project - set_reproducible_sources(FW_SOURCES "Firmware/") + # Set FW_SOURCES to be reproducible in this variant as it's set in a separate project + set_reproducible_sources(FW_SOURCES "Firmware/") - # 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(variant_header "variants/${variant_name}.h") + 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") + # Single-language build + set(FW_EN "${variant_name}_EN-only") + set(FW_HEX ${CMAKE_BINARY_DIR}/${FN_PREFIX}-${FW_EN}.hex) - add_base_binary(${FW_EN}) - # target_compile_options(${variant_name} PRIVATE) # turn this on for lolz -Wdouble-promotion) + add_base_binary(${FW_EN}) + target_compile_definitions(${FW_EN} PUBLIC LANG_MODE=0 FW_VARIANT="${variant_header}") + add_custom_command( + TARGET ${FW_EN} + POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O ihex ${FW_EN} ${FW_EN}.hex + COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_EN}.hex ${FW_HEX} + BYPRODUCTS ${FW_EN}.hex ${FW_HEX} + COMMENT "Generating ${FW_EN}.hex" + ) + add_dependencies(ALL_ENGLISH ${FW_EN}) + + # Multi-language build/s + set(FW_LANG_BASE "${variant_name}_Multilang_base") + set(FW_LANG_PATCH "${variant_name}_Multilang_patch") + add_base_binary(${FW_LANG_BASE}) + target_compile_definitions(${FW_LANG_BASE} PUBLIC LANG_MODE=1 FW_VARIANT="${variant_header}") + + # Construct language map + set(LANG_TMP_DIR lang) + set(LANG_MAP ${LANG_TMP_DIR}/${variant_name}_lang.map) + + add_custom_command( + OUTPUT ${LANG_MAP} + COMMAND ${CMAKE_OBJCOPY} -O binary ${FW_LANG_BASE} ${FW_LANG_PATCH}.bin + COMMAND ${CMAKE_SOURCE_DIR}/lang/lang-map.py ${FW_LANG_BASE} ${FW_LANG_PATCH}.bin > ${LANG_MAP} + COMMAND ${CMAKE_OBJCOPY} -I binary -O ihex ${FW_LANG_PATCH}.bin ${FW_LANG_PATCH}.hex + DEPENDS ${FW_LANG_BASE} + BYPRODUCTS ${FW_LANG_PATCH}.bin ${FW_LANG_PATCH}.hex + COMMENT "Generating ${variant_name} language map" + ) + + # Build language catalogs + 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") - 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" + OUTPUT ${LANG_BIN} + #[[ + # Check po file: + #COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/lang/lang-check.py --no-warning --map ${LANG_MAP} ${PO_FILE} + #]] + 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} ${PO_FILE} + COMMENT "Generating ${variant_name}_${LANG}.bin" + ) + list(APPEND LANG_BINS ${LANG_BIN}) + endforeach() + + string(FIND ${variant_name} "MK3" HAS_XFLASH) + if(${HAS_XFLASH} GREATER_EQUAL 0) + # X-Flash based build (catalogs appended to patched binary) + set(FW_LANG_FINAL "${variant_name}_Multilang") + set(LANG_HEX ${CMAKE_BINARY_DIR}/${FN_PREFIX}-${FW_LANG_FINAL}.hex) + set(LANG_CATBIN ${LANG_TMP_DIR}/${variant_name}_cat.bin) + set(LANG_CATHEX ${LANG_TMP_DIR}/${variant_name}_cat.hex) + + add_custom_command( + OUTPUT ${LANG_CATBIN} + COMMAND ${CMAKE_COMMAND} -E cat ${LANG_BINS} > ${LANG_CATBIN} + DEPENDS ${LANG_BINS} + COMMENT "Merging language catalogs" + ) + #[[ + #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_CATHEX} + COMMAND ${CMAKE_OBJCOPY} -I binary -O ihex ${LANG_CATBIN} ${LANG_CATHEX} + DEPENDS ${LANG_CATBIN} + COMMENT "Generating Hex for language data" + ) + + add_custom_command( + OUTPUT ${FW_LANG_FINAL}.hex + COMMAND ${CMAKE_COMMAND} -E cat ${FW_LANG_PATCH}.hex ${LANG_CATHEX} > ${FW_LANG_FINAL}.hex + COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_LANG_FINAL}.hex ${LANG_HEX} + BYPRODUCTS ${LANG_HEX} + DEPENDS ${FW_LANG_PATCH}.hex ${LANG_CATHEX} + COMMENT "Generating final ${FW_LANG_FINAL}.hex" + ) + + add_custom_target(${FW_LANG_FINAL} DEPENDS ${FW_LANG_FINAL}.hex) + add_dependencies(ALL_MULTILANG ${FW_LANG_FINAL}) + else() + set(ALL_VARIANT_HEXES "") + # Non-xflash, e.g. MK2.5 + foreach(LANG IN LISTS SELECTED_LANGUAGES) + set(FW_LANG_FINAL ${variant_name}-en_${LANG}) + set(LANG_HEX ${CMAKE_BINARY_DIR}/${FN_PREFIX}-${FW_LANG_FINAL}.hex) + set(LANG_BIN ${LANG_TMP_DIR}/${variant_name}_${LANG}.bin) + + # Patched binary with pre-baked secondary language + add_custom_command( + OUTPUT ${FW_LANG_FINAL}.bin + COMMAND ${CMAKE_OBJCOPY} -O binary ${FW_LANG_BASE} ${FW_LANG_FINAL}.bin + COMMAND ${CMAKE_SOURCE_DIR}/lang/lang-patchsec.py ${FW_LANG_BASE} ${LANG_BIN} + ${FW_LANG_FINAL}.bin + DEPENDS ${FW_LANG_BASE} ${LANG_BIN} + COMMENT "Generating ${FW_LANG_FINAL}.bin" ) - 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" + # Final hex files + add_custom_command( + OUTPUT ${FW_LANG_FINAL}.hex + COMMAND ${CMAKE_OBJCOPY} -I binary -O ihex ${FW_LANG_FINAL}.bin ${FW_LANG_FINAL}.hex + COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_LANG_FINAL}.hex ${LANG_HEX} + BYPRODUCTS ${LANG_HEX} + DEPENDS ${FW_LANG_FINAL}.bin + COMMENT "Creating ${FW_LANG_FINAL}.hex" ) - 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() + add_custom_target(${FW_LANG_FINAL} DEPENDS ${FW_LANG_FINAL}.hex) + list(APPEND ALL_VARIANT_HEXES ${FW_LANG_FINAL}) + 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) - # build a list of all supported variants - file(GLOB ALL_VARIANTS RELATIVE ${PROJECT_SOURCE_DIR}/Firmware/variants ${PROJECT_SOURCE_DIR}/Firmware/variants/*.h) - list(TRANSFORM ALL_VARIANTS REPLACE "\.h$" "") - set(FW_VARIANTS ${ALL_VARIANTS} CACHE STRING "Firmware variants to be built") + # build a list of all supported variants + file( + GLOB ALL_VARIANTS + RELATIVE ${PROJECT_SOURCE_DIR}/Firmware/variants + ${PROJECT_SOURCE_DIR}/Firmware/variants/*.h + ) + list(TRANSFORM ALL_VARIANTS REPLACE "\.h$" "") + set(FW_VARIANTS + ${ALL_VARIANTS} + CACHE STRING "Firmware variants to be built" + ) - foreach(THIS_VAR IN LISTS FW_VARIANTS) - if(NOT ${THIS_VAR} IN_LIST ALL_VARIANTS) - message(FATAL_ERROR "Variant ${THIS_VAR} does not exist") - endif() + foreach(THIS_VAR IN LISTS FW_VARIANTS) + if(NOT ${THIS_VAR} IN_LIST ALL_VARIANTS) + message(FATAL_ERROR "Variant ${THIS_VAR} does not exist") + endif() - message("Variant added: ${THIS_VAR}") - string(REPLACE "-E3Dv6full" "" DIR_NAME "${THIS_VAR}") - 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(${THIS_VAR})") - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/build_gen/${DIR_NAME}) - #fw_add_variant(${TRIMMED_NAME}) - endforeach(THIS_VAR IN LISTS FW_VARIANTS) + message("Variant added: ${THIS_VAR}") + string(REPLACE "-E3Dv6full" "" DIR_NAME "${THIS_VAR}") + 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(${THIS_VAR})" + ) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/build_gen/${DIR_NAME}) + endforeach(THIS_VAR IN LISTS FW_VARIANTS) endif() +# +# Tests +# if(NOT CMAKE_CROSSCOMPILING) - enable_testing() - add_subdirectory(tests) + enable_testing() + add_subdirectory(tests) endif() diff --git a/Firmware/Configuration.cpp b/Firmware/Configuration.cpp index f87849285..082ac0706 100644 --- a/Firmware/Configuration.cpp +++ b/Firmware/Configuration.cpp @@ -1,5 +1,5 @@ #include "Configuration.h" -#include "Configuration_prusa.h" +#include "Configuration_var.h" const uint16_t _nPrinterType PROGMEM=PRINTER_TYPE; const char _sPrinterName[] PROGMEM=PRINTER_NAME; diff --git a/Firmware/Configuration.h b/Firmware/Configuration.h index 454ccbc10..0a5355592 100644 --- a/Firmware/Configuration.h +++ b/Firmware/Configuration.h @@ -70,7 +70,7 @@ extern PGM_P sPrinterName; #define SOURCE_TIME_EPOCH __TIME__ #endif -#include "Configuration_prusa.h" +#include "Configuration_var.h" #define FW_PRUSA3D_MAGIC "PRUSA3DFW" #define FW_PRUSA3D_MAGIC_LEN 10 diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index 0917ee181..8bc1cd5a1 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -5,7 +5,7 @@ #include "temperature.h" #include "ultralcd.h" #include "ConfigurationStore.h" -#include "Configuration_prusa.h" +#include "Configuration_var.h" #ifdef MESH_BED_LEVELING #include "mesh_bed_leveling.h" diff --git a/Firmware/Configuration_var.h b/Firmware/Configuration_var.h new file mode 100644 index 000000000..c7dab9d0a --- /dev/null +++ b/Firmware/Configuration_var.h @@ -0,0 +1,10 @@ +// Include the printer's variant configuration header +#pragma once + +// This is set by the cmake build to be able to take control of +// the variant header without breaking existing build mechanisms. +#ifndef CMAKE_CONTROL +#include "Configuration_prusa.h" +#else +#include FW_VARIANT +#endif diff --git a/Firmware/config.h b/Firmware/config.h index 358c8ab81..eb57b9b16 100644 --- a/Firmware/config.h +++ b/Firmware/config.h @@ -2,7 +2,7 @@ #define _CONFIG_H -#include "Configuration_prusa.h" +#include "Configuration_var.h" #include "pins.h" #if (defined(VOLT_IR_PIN) && defined(IR_SENSOR)) @@ -62,7 +62,7 @@ // 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 +#ifndef CMAKE_CONTROL //LANG - Multi-language support //#define LANG_MODE 0 // primary language only #define LANG_MODE 1 // sec. language support diff --git a/Firmware/first_lay_cal.cpp b/Firmware/first_lay_cal.cpp index 5d7f0aa9b..7a848e7df 100644 --- a/Firmware/first_lay_cal.cpp +++ b/Firmware/first_lay_cal.cpp @@ -4,7 +4,7 @@ //! @brief First layer (Z offset) calibration #include "first_lay_cal.h" -#include "Configuration_prusa.h" +#include "Configuration_var.h" #include "language.h" #include "Marlin.h" #include "cmdqueue.h" diff --git a/Firmware/messages.cpp b/Firmware/messages.cpp index 2ca690691..bb6157b55 100644 --- a/Firmware/messages.cpp +++ b/Firmware/messages.cpp @@ -1,8 +1,8 @@ //messages.c #include "language.h" -//this is because we need include Configuration_prusa.h (CUSTOM_MENDEL_NAME) -#include "Configuration_prusa.h" +//this is because we need CUSTOM_MENDEL_NAME +#include "Configuration_var.h" //internationalized messages const char MSG_ALWAYS[] PROGMEM_I1 = ISTR("Always"); ////MSG_ALWAYS c=6 diff --git a/Firmware/mmu2_power.cpp b/Firmware/mmu2_power.cpp index a0359f016..ed9f8adb7 100644 --- a/Firmware/mmu2_power.cpp +++ b/Firmware/mmu2_power.cpp @@ -1,5 +1,5 @@ #include "mmu2_power.h" -#include "Configuration_prusa.h" +#include "Configuration_var.h" #include "pins.h" #include "fastio.h" #include diff --git a/Firmware/pat9125.cpp b/Firmware/pat9125.cpp index 18cf7c1ae..7a1e191c9 100644 --- a/Firmware/pat9125.cpp +++ b/Firmware/pat9125.cpp @@ -4,7 +4,7 @@ #include #include "config.h" #include -#include "Configuration_prusa.h" +#include "Configuration_var.h" #if defined(FILAMENT_SENSOR) && (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125) diff --git a/Firmware/sm4.c b/Firmware/sm4.c index 0b6f2f50c..994e016aa 100644 --- a/Firmware/sm4.c +++ b/Firmware/sm4.c @@ -9,7 +9,7 @@ #include "boards.h" #define false 0 #define true 1 -#include "Configuration_prusa.h" +#include "Configuration_var.h" #ifdef NEW_XYZCAL diff --git a/Firmware/swi2c.c b/Firmware/swi2c.c index d143ec600..032b39a83 100644 --- a/Firmware/swi2c.c +++ b/Firmware/swi2c.c @@ -4,7 +4,7 @@ #include #include #include "stdbool.h" -#include "Configuration_prusa.h" +#include "Configuration_var.h" #include "pins.h" #include "fastio.h" diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index 53223d7f6..d3846db91 100755 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -44,7 +44,7 @@ #include "adc.h" #include "ConfigurationStore.h" #include "Timer.h" -#include "Configuration_prusa.h" +#include "Configuration_var.h" #include "Prusa_farm.h" #if (ADC_OVRSAMPL != OVERSAMPLENR) diff --git a/Firmware/tone04.c b/Firmware/tone04.c index 55a0a0e9c..f9a427c32 100644 --- a/Firmware/tone04.c +++ b/Firmware/tone04.c @@ -3,7 +3,7 @@ // timer2 is used for System timer. #include "system_timer.h" -#include "Configuration_prusa.h" +#include "Configuration_var.h" #ifdef SYSTEM_TIMER_2 diff --git a/Firmware/xyzcal.cpp b/Firmware/xyzcal.cpp index e8689d3b5..311371c98 100644 --- a/Firmware/xyzcal.cpp +++ b/Firmware/xyzcal.cpp @@ -1,6 +1,6 @@ //xyzcal.cpp - xyz calibration with image processing -#include "Configuration_prusa.h" +#include "Configuration_var.h" #ifdef NEW_XYZCAL #include "xyzcal.h" @@ -551,7 +551,7 @@ void go_manhattan(int16_t x, int16_t y, int16_t z, int16_t acc, uint16_t min_del // DBG(_n("\n")); } -void xyzcal_scan_pixels_32x32_Zhop(int16_t cx, int16_t cy, int16_t min_z, int16_t max_z, uint16_t delay_us, uint8_t *pixels){ +void __attribute__((noinline)) xyzcal_scan_pixels_32x32_Zhop(int16_t cx, int16_t cy, int16_t min_z, int16_t max_z, uint16_t delay_us, uint8_t *pixels){ if (!pixels) return; int16_t z_trig; diff --git a/cmake/Utilities.cmake b/cmake/Utilities.cmake index fc37f14cd..1ae37d25c 100644 --- a/cmake/Utilities.cmake +++ b/cmake/Utilities.cmake @@ -38,6 +38,7 @@ function(get_dependency_directory dependency var) message(FATAL_ERROR "Failed to find directory with ${dependency}") endif() + file(TO_CMAKE_PATH "${DEPENDENCY_DIRECTORY}" DEPENDENCY_DIRECTORY) set(${var} ${DEPENDENCY_DIRECTORY} PARENT_SCOPE