From 1b3d654c764b25cdd979acca0c956564cfe8358d Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Tue, 25 Feb 2025 23:37:17 +0100 Subject: Initial --- cmake/arm-gcc-toolchain.cmake | 35 ++++++++++ cmake/clang-arm-gcc-toolchain.cmake | 91 ++++++++++++++++++++++++++ cmake/device.cmake | 2 + cmake/device_utils.cmake | 15 +++++ cmake/utils.cmake | 123 ++++++++++++++++++++++++++++++++++++ 5 files changed, 266 insertions(+) create mode 100644 cmake/arm-gcc-toolchain.cmake create mode 100644 cmake/clang-arm-gcc-toolchain.cmake create mode 100644 cmake/device.cmake create mode 100644 cmake/device_utils.cmake create mode 100644 cmake/utils.cmake (limited to 'cmake') diff --git a/cmake/arm-gcc-toolchain.cmake b/cmake/arm-gcc-toolchain.cmake new file mode 100644 index 0000000..d7dc340 --- /dev/null +++ b/cmake/arm-gcc-toolchain.cmake @@ -0,0 +1,35 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ARM) + +set(TOOLCHAIN_PREFIX "arm-none-eabi-") + +set(SPECS "-specs=nosys.specs -specs=nano.specs") + +# Without that flag CMake is not able to pass test compilation check +if (${CMAKE_VERSION} VERSION_EQUAL "3.6.0" OR ${CMAKE_VERSION} VERSION_GREATER "3.6") + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endif () + +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc CACHE STRING "") +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER} CACHE STRING "") +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++ CACHE STRING "") + +# Default C compiler flags +set(CMAKE_C_FLAGS_DEBUG_INIT "-g3 -Og -Wall -DDEBUG ${SPECS}") +set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -Wall ${SPECS}") +set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -Wall ${SPECS}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -Wall ${SPECS}") +# Default C++ compiler flags +set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g3 -Og -Wall -DDEBUG ${SPECS}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -Wall ${SPECS}") +set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -Wall ${SPECS}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -Wall ${SPECS}") + +find_program(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy DOC "objcopy tool") +find_program(CMAKE_SIZE_UTIL ${TOOLCHAIN_PREFIX}size DOC "size tool") + +if (NOT TARGET toolchain) + add_library(toolchain INTERFACE) + target_compile_options(toolchain INTERFACE "-fno-exceptions") + target_link_options(toolchain INTERFACE "-Wl,--gc-sections" "-Wl,--print-memory-usage") +endif () diff --git a/cmake/clang-arm-gcc-toolchain.cmake b/cmake/clang-arm-gcc-toolchain.cmake new file mode 100644 index 0000000..091dad3 --- /dev/null +++ b/cmake/clang-arm-gcc-toolchain.cmake @@ -0,0 +1,91 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ARM) + +set(TOOLCHAIN_PREFIX arm-none-eabi-) +set(TOOLCHAIN_TRIPLE arm-none-eabi) +find_program(BINUTILS_PATH ${TOOLCHAIN_PREFIX}gcc NO_CACHE) + +if (NOT BINUTILS_PATH) + message(FATAL_ERROR "ARM GCC toolchain not found") +endif () + +cmake_path(GET BINUTILS_PATH PARENT_PATH ARM_TOOLCHAIN_DIR) +set(ARM_GCC_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) +execute_process(COMMAND ${ARM_GCC_C_COMPILER} -print-sysroot + OUTPUT_VARIABLE ARM_GCC_SYSROOT OUTPUT_STRIP_TRAILING_WHITESPACE) +# get GNU ARM GCC version +execute_process(COMMAND ${ARM_GCC_C_COMPILER} --version + OUTPUT_VARIABLE ARM_GCC_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) +string(REGEX MATCH " [0-9]+\.[0-9]+\.[0-9]+" ARM_GCC_VERSION ${ARM_GCC_VERSION}) +string(STRIP ${ARM_GCC_VERSION} ARM_GCC_VERSION) + +# set compiler triple +set(triple ${TOOLCHAIN_TRIPLE}) +set(CMAKE_ASM_COMPILER clang) +set(CMAKE_ASM_COMPILER_TARGET ${triple}) +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET ${triple}) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_CXX_COMPILER_TARGET ${triple}) + +set(CMAKE_C_FLAGS_INIT " -B${ARM_TOOLCHAIN_DIR}") +set(CMAKE_CXX_FLAGS_INIT " -B${ARM_TOOLCHAIN_DIR} ") +# Without that flag CMake is not able to pass test compilation check +if (${CMAKE_VERSION} VERSION_EQUAL "3.6.0" OR ${CMAKE_VERSION} VERSION_GREATER "3.6") + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +else () + set(CMAKE_EXE_LINKER_FLAGS_INIT "-nostdlib") +endif () + +set(CMAKE_OBJCOPY llvm-objcopy CACHE INTERNAL "objcopy tool") +set(CMAKE_SIZE_UTIL llvm-size CACHE INTERNAL "size tool") +# Default C compiler flags +set(CMAKE_C_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -Wall") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE_INIT}" CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Oz -Wall") +set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL_INIT}" CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -Wall") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING "" FORCE) +# Default C++ compiler flags +set(TOOLCHAIN_CXX_INCLUDE_DIRS_FLAG "") +string(APPEND TOOLCHAIN_CXX_INCLUDE_DIRS_FLAG " -cxx-isystem ${ARM_GCC_SYSROOT}/include/c++/${ARM_GCC_VERSION}") +string(APPEND TOOLCHAIN_CXX_INCLUDE_DIRS_FLAG " -cxx-isystem ${ARM_GCC_SYSROOT}/include/c++/${ARM_GCC_VERSION}/arm-none-eabi") +string(APPEND TOOLCHAIN_CXX_INCLUDE_DIRS_FLAG " -cxx-isystem ${ARM_GCC_SYSROOT}/include/c++/${ARM_GCC_VERSION}/backward") +set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g3 -Og -Wall -pedantic -DDEBUG ${TOOLCHAIN_CXX_INCLUDE_DIRS_FLAG}") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -Wall ${TOOLCHAIN_CXX_INCLUDE_DIRS_FLAG}") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE_INIT}" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Oz -Wall ${TOOLCHAIN_CXX_INCLUDE_DIRS_FLAG}") +set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL_INIT}" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -Wall ${TOOLCHAIN_CXX_INCLUDE_DIRS_FLAG}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING "" FORCE) + +set(CMAKE_SYSROOT ${ARM_GCC_SYSROOT}) +set(CMAKE_FIND_ROOT_PATH ${ARM_GCC_SYSROOT}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) + + +if (ARCH_FLAGS) + execute_process(COMMAND ${ARM_GCC_C_COMPILER} ${ARCH_FLAGS} -print-libgcc-file-name + OUTPUT_VARIABLE __ARM_GCC_LIBGCC + OUTPUT_STRIP_TRAILING_WHITESPACE) + cmake_path(GET __ARM_GCC_LIBGCC PARENT_PATH LIBGCC_DIR) + + execute_process(COMMAND ${ARM_GCC_C_COMPILER} ${ARCH_FLAGS} -print-multi-directory + OUTPUT_VARIABLE ARM_GCC_MULTIDIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if (NOT TARGET toolchain) + add_library(toolchain INTERFACE) + target_compile_options(toolchain INTERFACE "-fno-exceptions") + target_link_directories(toolchain INTERFACE "${LIBGCC_DIR}") + target_link_libraries(toolchain INTERFACE -nostdlib -lc_nano -lnosys -lgcc -lstdc++_nano -lm) + target_link_options(toolchain INTERFACE "-Wl,--gc-sections" "-Wl,--print-memory-usage") + + target_sources(toolchain INTERFACE "${LIBGCC_DIR}/crti.o" "${ARM_GCC_SYSROOT}/lib/${ARM_GCC_MULTIDIR}/crt0.o" "${LIBGCC_DIR}/crtbegin.o" "${LIBGCC_DIR}/crtend.o" "${LIBGCC_DIR}/crtn.o") + endif () +endif () diff --git a/cmake/device.cmake b/cmake/device.cmake new file mode 100644 index 0000000..d5b28da --- /dev/null +++ b/cmake/device.cmake @@ -0,0 +1,2 @@ +include("${CMAKE_CURRENT_SOURCE_DIR}/device/${DEVICE}/${DEVICE}.cmake") +message(STATUS "Device: ${DEVICE}") diff --git a/cmake/device_utils.cmake b/cmake/device_utils.cmake new file mode 100644 index 0000000..5309f5c --- /dev/null +++ b/cmake/device_utils.cmake @@ -0,0 +1,15 @@ +include(utils) + +function (create_device_target arch_flags device_defines include_dirs linker_script system_code) + add_library(device OBJECT) + + target_sources(device PRIVATE "${system_code}") + + target_compile_options(device PUBLIC "${arch_flags}") + target_compile_definitions(device PUBLIC "${device_defines}") + target_include_directories(device PRIVATE "${include_dirs}") + target_include_directories(device PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/device") + + target_link_options(device INTERFACE "${arch_flags}") + target_linker_script(device INTERFACE "${linker_script}") +endfunction () diff --git a/cmake/utils.cmake b/cmake/utils.cmake new file mode 100644 index 0000000..17fb235 --- /dev/null +++ b/cmake/utils.cmake @@ -0,0 +1,123 @@ +# Get all subdirectories under ${current_dir} and store them in ${result} variable +macro(subdirlist result current_dir) + file(GLOB children "${current_dir}/*") + set(dirlist "") + + foreach(child ${children}) + if (IS_DIRECTORY "${child}") + list(APPEND dirlist "${child}") + endif() + endforeach() + + set(${result} ${dirlist}) +endmacro() + +# Prepend ${CMAKE_CURRENT_SOURCE_DIR} to a ${directory} name and save it in PARENT_SCOPE ${variable} +macro(prepend_cur_dir variable directory) + set(${variable} "${CMAKE_CURRENT_SOURCE_DIR}/${directory}") +endmacro() + +# Add custom command to print firmware size in Berkeley format +function(firmware_size target) + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_SIZE_UTIL} -B "$" + ) +endfunction() + +# Add a command to generate firmware in a provided format +function(generate_object target suffix type) + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O ${type} "$" "${CMAKE_CURRENT_BINARY_DIR}/${target}${suffix}" + ) +endfunction() + +# Set linker script for a target +function(target_linker_script target scope script) + target_link_options(${target} "${scope}" "-T${script}") + + get_target_property(_cur_link_deps ${target} LINK_DEPENDS) + if (_cur_link_deps STREQUAL "_cur_link_deps-NOTFOUND") + set(_cur_link_deps "") + endif() + + string(APPEND _cur_link_deps "${script}") + set_target_properties(${target} PROPERTIES LINK_DEPENDS ${_cur_link_deps}) +endfunction() + +# Write file only if content has changed +function(write_file_if_changed file content) + if (EXISTS "${file}") + file(READ "${file}" existing_content) + else() + set(existing_content "") + endif() + + if (NOT "${existing_content}" STREQUAL "${content}") + file(WRITE "${file}" "${content}") + endif() +endfunction() + +# Embed a file into a target +function(embed_file target file symbol) + cmake_path(IS_ABSOLUTE file is_absolute) + if (NOT is_absolute) + set(file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + endif() + + cmake_path(GET file FILENAME filename) + + set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") + if (NOT EXISTS "${generated_dir}") + file(MAKE_DIRECTORY "${generated_dir}") + endif() + + set(generated_objects "${generated_dir}_objects") + if (NOT EXISTS "${generated_objects}") + file(MAKE_DIRECTORY "${generated_objects}") + endif() + + set(asm_path "${generated_objects}/${filename}.S") + write_file_if_changed("${asm_path}" +".global ${symbol}_data +.global ${symbol}_size +.section .rodata +.align 4 +${symbol}_data: + .incbin \"${file}\" +1: +${symbol}_size: + .int 1b - ${symbol}_data +") + + add_custom_command(OUTPUT "${asm_path}" + COMMAND ${CMAKE_COMMAND} -E touch "${asm_path}" + DEPENDS "${file}") + + target_sources("${target}" PRIVATE "${asm_path}") + + set(header_path "${generated_dir}/${filename}") + + write_file_if_changed("${header_path}.h" +"#pragma once + +#ifdef __cplusplus +extern \"C\" { +#endif + +extern const char ${symbol}_data[]; +extern const unsigned int ${symbol}_size; + +#ifdef __cplusplus +} +#endif +") + + write_file_if_changed("${header_path}.hpp" +"#pragma once + +#include \"${header_path}.h\" +#include + +inline const std::span ${symbol}{${symbol}_data, ${symbol}_size}; +") +endfunction() -- cgit v1.2.3-54-g00ecf