Let's take a look at our CMake Project Structure:
cortex-m-cmake-demo/
library/
bsp/
CMakeLists.txt
source/
main.c
armclang.cmake
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
It decides the features that can be used.
It dictates the policies, which introduce behavior changes while preserving backward compatibility.
project(demo
VERSION 1.0.0
DESCRIPTION "This is a demo project"
)
The project() call sets up the project name.
The project name is stored in PROJECT_NAME.
enable_language(C ASM)
We are going to use C and Assembly for this project.
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
It specifies the language standard to compile for
i.e. -std=c11
The default is gnu11, which may cause different behavior in ARMClang.
set(CMAKE_SYSTEM_NAME Generic)
It indicates we are cross-compiling for bare metal embedded devices.
set(CMAKE_ASM_COMPILER "armclang")
set(CMAKE_CXX_COMPILER "armclang")
set(CMAKE_C_COMPILER "armclang")
set(CMAKE_AR "armar")
set(ARM_ELF2BIN "fromelf")
The compilers to use for ASM and C
set(CMAKE_C_COMPILER_TARGET arm-arm-none-eabi)
This will cause CMake to add the --target flag.
set(CMAKE_C_FLAGS_INIT "-mthumb -fdata-sections -fno-exceptions -g ")
set(CMAKE_ASM_FLAGS_INIT "-mthumb -masm=auto --target=arm-arm-none-eabi -g")
CMake offer a variable cache. The official manual describes how CMake searches for variables.
CMAKE_<LANG>_FLAGS_INIT initialize the CMAKE_<LANG>_FLAGS cache entry.
It is meant to be set by a toolchain file.
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
Whenever CMake starts it tries to compile a sample program.
Using STATIC_LIBRARY avoids running the linker.
add_subdirectory(library)
The CMakeLists file contained in that subdirectory is evaluated.
The CMakeLists in the subdirectory create a static library called bsp. We will discuss how to add a static library in the future.
set(EXECUTABLE ${PROJECT_NAME})
This creates a variable containing the executable name.
add_executable(${EXECUTABLE}
source/main.c
)
The executable target is added here.
target_link_libraries(${EXECUTABLE}
PRIVATE
bsp
)
We link the bsp libraries to the executable.
PRIVATE is used since the executable is the topmost product.
# Focus on CortexM23Lib here
target_link_libraries(CortexM23Lib
PUBLIC
CortexMLib
)
# Focus on CortexM23Lib here
target_link_libraries(CortexM23Lib
PUBLIC
CortexMLib
)
target_link_libraries(M2354Lib
PUBLIC
CortexM23Lib
)
target_link_libraries(M2351Lib
PUBLIC
CortexM23Lib
)
| Scope | Applies to Current Target | Applies to Dependent Target |
|---|---|---|
| PUBLIC | ✅ Used by current target | ✅ Propagate up to dependent targets |
| PRIVATE | ✅ Used by current target | ❌ Not propagated |
| INTERFACE | ❌ Not used by current target | ✅ Propagate up to dependent targets |
target_link_options(${EXECUTABLE}
PRIVATE
--library_type=microlib
--scatter=${CMAKE_CURRENT_SOURCE_DIR}/scatter/m2354.sct
--map
)
Put link flags for our executable
We need to provide scatter file (linker script). It tells the linker where to store the objects in memory.
add_custom_command(TARGET ${EXECUTABLE}
POST_BUILD
COMMAND ${ARM_ELF2BIN} --bin ${EXECUTABLE}.elf --output ${EXECUTABLE}.bin
)
This creates a custom command to generate binary file.