Embedded Development Board Learning


Visual Studio Code for ARM with CMake #3 Toolchain CMake

Fecha: enero 24, 2023

Autor: Guillermo Garcia

Categorías: Visual Studio Code Etiquetas:

Visual Studio Code como entorno de desarrollo para proyecto Embedded Systems

We have defined a project structure and added the necessary source files in the previous article, Visual Studio Code for ARM with CMake #2 Project. In this article, we will configure the build environment with the CMake Toolchain.

Toolchain CMake File

To generate an executable file, we first need to invoke the GCC compiler, specifying which source files should be compiled to create the executable. Interacting with the compiler directly through commands is often impractical in software development, where the source files increase as the project grows.

How can we make the process of interacting with the compiler more efficient? Well, for that, we will use CMake.

CMake

CMake is used to control the software compilation process through a simple platform and configuration files that are independent of the compiler.

The GNU C/C++ GCC compiler is based on GNU Make, which makes it possible to manage the compilation process using the Make utility. The Make utility requires a makefile that defines a set of tasks to be executed.

Creating the makefile is not complicated, but it takes time to write the necessary routine and requires knowledge of the GNU environment. To simplify this, we use CMake.

CMake generates build pipelines, meaning it creates a file for a sub-compilation environment. In conclusion, during the compilation process, CMake will generate a makefile with the necessary instructions for the GNU Make environment to interact with the compiler and generate the executable file.

CMake build process

CMake Toolchain Files

Every CMake-based project contains a script called CMakeLists.txt, in this file the instructions for performing the compilation are described. We also need to tell CMake where our compilation tools are installed, so we add a file called Buildtools.cmake.

CMake files added

CMakeLists.txt File

We create the CMakeLists.txt file where we will mainly describe the source files that we want to be compiled, as well as specific parameters of our hardware.

cmake_minimum_required(VERSION 3.23.1)

# Optional: print out extra messages to see what is going on. Comment it to have less verbose messages
set(CMAKE_VERBOSE_MAKEFILE ON)

# Path to toolchain file. This one has to be before 'project()' below
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/Buildtools.cmake)

# Setup project, output and linker file
project(VSC_G071RB)
set(EXECUTABLE ${PROJECT_NAME}.elf)
set(LINKER_FILE ${CMAKE_SOURCE_DIR}/Device/STM32G071RBTX_FLASH.ld)

enable_language(C ASM)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

# Optional: issue a message to be sure it uses the correct toolchain file.
message(STATUS "CMAKE_TOOLCHAIN_FILE is: ${CMAKE_TOOLCHAIN_FILE}")

# List of source files
set(SRC_FILES
        main/main.c

        Device/stm32g0xx_it.c
        Device/system_stm32g0xx.c
        Device/startup_stm32g071xx.s
        Device/stm32g0xx_hal_msp.c
        
        Drivers/Src/stm32g0xx_hal.c 
        Drivers/Src/stm32g0xx_hal_rcc.c 
        Drivers/Src/stm32g0xx_hal_rcc_ex.c 
        Drivers/Src/stm32g0xx_hal_flash.c
        Drivers/Src/stm32g0xx_hal_flash_ex.c
        Drivers/Src/stm32g0xx_hal_dma.c
        Drivers/Src/stm32g0xx_hal_dma_ex.c
        Drivers/Src/stm32g0xx_hal_gpio.c 
        Drivers/Src/stm32g0xx_hal_cortex.c 
        Drivers/Src/stm32g0xx_hal_exti.c 
        Drivers/Src/stm32g0xx_hal_tim.c 
        Drivers/Src/stm32g0xx_hal_tim_ex.c 
        Drivers/Src/stm32g0xx_hal_pwr.c
        Drivers/Src/stm32g0xx_hal_pwr_ex.c
        )

# Build the executable based on the source files
add_executable(${EXECUTABLE} ${SRC_FILES})

# List of compiler defines, prefix with -D compiler option
target_compile_definitions(${EXECUTABLE} PRIVATE
        -DSTM32G071xx
        -DUSE_HAL_DRIVER
        )

# List of includ directories
target_include_directories(${EXECUTABLE} PRIVATE
        main
        CMSIS/Include
        CMSIS/Device/ST/STM32G0xx
        Device
        Drivers/Inc/
        Drivers/Inc/Legacy
        )

# Compiler options
target_compile_options(${EXECUTABLE} PRIVATE
        -mcpu=cortex-m0
        -mthumb
        -mfloat-abi=soft
        -fdata-sections
        -ffunction-sections
        
        -Wall
        -O0
        -Og
        -gdwarf-2
        )

# Linker options
target_link_options(${EXECUTABLE} PRIVATE
        -T${LINKER_FILE}
        -mcpu=cortex-m0
        -mthumb
        -mfloat-abi=soft
        --specs=rdimon.specs
        --specs=nano.specs
        -lc
        -lm
        -lnosys
        -Wl,-Map=${PROJECT_NAME}.map,--cref
        -Wl,--gc-sections
        -Xlinker -print-memory-usage -Xlinker
        )

# Optional: Print executable size as part of the post build process
add_custom_command(TARGET ${EXECUTABLE}
        POST_BUILD
        COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE})

# Optional: Create hex, bin and S-Record files after the build
add_custom_command(TARGET ${EXECUTABLE}
        POST_BUILD
        COMMAND ${CMAKE_OBJCOPY} -O srec --srec-len=64 ${EXECUTABLE} ${PROJECT_NAME}.s19
        COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE} ${PROJECT_NAME}.hex
        COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE} ${PROJECT_NAME}.bin)

Buildtools.cmake File

We create the Buildtools.cmake file so that CMake knows where the compiler is installed.

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)

set(ARM_TOOLCHAIN_DIR "C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin")
set(BINUTILS_PATH ${ARM_TOOLCHAIN_DIR}) 

set(TOOLCHAIN_PREFIX ${ARM_TOOLCHAIN_DIR}/arm-none-eabi-)

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

set(CMAKE_C_COMPILER "${TOOLCHAIN_PREFIX}gcc.exe")
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PREFIX}g++.exe")

set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL "objcopy tool")
set(CMAKE_SIZE_UTIL ${TOOLCHAIN_PREFIX}size CACHE INTERNAL "size tool")

set(CMAKE_FIND_ROOT_PATH ${BINUTILS_PATH})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Configuration and Generation Steps

When we run CMake, two important steps take place. First, a configuration process (Configure step) is executed, where internal CMake files, such as the CMakeCache.txt file, are created. The second process is the generation step (Generate step), where an equivalent makefile for our project is generated.

CMake files added

The CMakeLists.txt script is executed during the configuration step. This script is responsible for defining the targets (source files). Each target represents an executable, a library, or some other result of the (build pipeline).

If the configuration step is successful, meaning CMakeLists.txt completes without errors, CMake will generate a (build pipeline) using the targets defined by the script.

The configuration process should only be done once unless a full cleanup of the build is desired. This is thanks to the cache stored in the CMakeCache.txt file.

Compiling

Now let’s run CMake and see the result of the compilation.

Configuration Process

To start CMake we will specify two important parameters, first CMAKE_MAKE_PROGRAM to indicate that we are using the makefile generator, and CMAKE_TOOLCHAIN_FILE indicating the file where the compilation tools are located.

We will go to the build folder in our project and execute the command:

C:/VSC_G071RB\build>cmake -DCMAKE_MAKE_PROGRAM=make.exe -DCMAKE_TOOLCHAIN_FILE="Buildtools.cmake" -G "Unix Makefiles" ..
" -G "Unix Makefiles" ..
-- The C compiler identification is GNU 10.3.1
-- The CXX compiler identification is GNU 10.3.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-gcc.exe - skipped
-- Detecting C compile features       
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-g++.exe - skipped
-- Detecting CXX compile features       
-- Detecting CXX compile features - done
-- The ASM compiler identification is GNU
-- Found assembler: C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-gcc.exe
-- CMAKE_TOOLCHAIN_FILE is: C:/VSC_G071RB/Buildtools.cmake
-- Configuring done
-- Generating done
-- Build files have been written to: C:/VSC_G071RB/build

We see how this generates files inside the build folder:

CMake Configuration Files

If we look at the contents of the build folder we still do not have an executable file, this is because the compiler has not yet been invoked.

Generation Process

It is time to compile the project here is where the makefiles generated by CMake are needed, we execute the command:

C:\VSC_G071RB\build>cmake --build .
"C:/Program Files/CMake/bin/cmake.exe" -SC:/VSC_G071RB -BC:/VSC_G071RB/build --check-build-system CMakeFiles/Makefile.cmake 0
"C:/Program Files/CMake/bin/cmake.exe" -E cmake_progress_start C:/VSC_G071RB/build/CMakeFiles C:/VSC_G071RB/build//CMakeFiles/progress.marks
make.exe  -f CMakeFiles/Makefile2 all
make.exe[1]: Entering directory `/c/VSC_G071RB/build'
make.exe  -f CMakeFiles/VSC_G071RB.elf.dir/build.make CMakeFiles/VSC_G071RB.elf.dir/depend
make.exe[2]: Entering directory `/c/VSC_G071RB/build'
"C:/Program Files/CMake/bin/cmake.exe" -E cmake_depends "Unix Makefiles" C:/VSC_G071RB C:/VSC_G071RB C:/VSC_G071RB/build C:/VSC_G071RB/build C:/VSC_G071RB/build/CMakeFiles/VSC_G071RB.elf.dir/DependInfo.cmake --color=
Scanning dependencies of target VSC_G071RB.elf
make.exe[2]: Leaving directory `/c/VSC_G071RB/build'
make.exe  -f CMakeFiles/VSC_G071RB.elf.dir/build.make CMakeFiles/VSC_G071RB.elf.dir/build
make.exe[2]: Entering directory `/c/VSC_G071RB/build'
[  5%] Building C object CMakeFiles/VSC_G071RB.elf.dir/main/main.c.obj
[ 95%] Building C object CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_pwr_ex.c.obj
"C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-gcc.exe" -DSTM32G071xx -DUSE_HAL_DRIVER -IC:/Users/urie_/Documents/FreeRTOS/VSC_G071RB/main -IC:/CMSIS/Include -IC:/Users/urie_/Documents/FreeRTOS/VSC_G071RB/CMSIS/Device/ST/STM32G0xx -IC:/VSC_G071RB/Device -IC:/VSC_G071RB/Drivers/Inc -IC:/VSC_G071RB/Drivers/Inc/Legacy -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -fdata-sections -ffunction-sections -Wall -O0 -Og -gdwarf-2 -std=c99 -MD -MT CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_pwr_ex.c.obj -MF CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_pwr_ex.c.obj.d -o CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_pwr_ex.c.obj -c C:/Users/urie_/Documents/FreeRTOS/VSC_G071RB/Drivers/Src/stm32g0xx_hal_pwr_ex.c
[100%] Linking C executable VSC_G071RB.elf
"C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-gcc.exe" -TC:/Users/urie_/Documents/FreeRTOS/VSC_G071RB/Device/STM32G071RBTX_FLASH.ld -mcpu=cortex-m0 -mthumb -mfloat-abi=soft --specs=rdimon.specs --specs=nano.specs -lc -lm -lnosys -Wl,-Map=VSC_G071RB.map,--cref -Wl,--gc-sections -Xlinker -print-memory-usage "CMakeFiles/VSC_G071RB.elf.dir/main/main.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Device/stm32g0xx_it.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Device/system_stm32g0xx.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Device/startup_stm32g071xx.s.obj" "CMakeFiles/VSC_G071RB.elf.dir/Device/stm32g0xx_hal_msp.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_rcc.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_rcc_ex.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_flash.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_flash_ex.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_dma.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_dma_ex.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_gpio.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_cortex.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_exti.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_tim.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_tim_ex.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_pwr.c.obj" "CMakeFiles/VSC_G071RB.elf.dir/Drivers/Src/stm32g0xx_hal_pwr_ex.c.obj"  -o VSC_G071RB.elf
Memory region         Used Size  Region Size  %age Used
             RAM:        1600 B        36 KB      4.34%
           FLASH:        3740 B       128 KB      2.85%
"C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-size" VSC_G071RB.elf
   text    data     bss     dec     hex filename
   3720      20    1588    5328    14d0 VSC_G071RB.elf
"C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-objcopy" -O srec --srec-len=64 VSC_G071RB.elf VSC_G071RB.s19
"C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-objcopy" -O ihex VSC_G071RB.elf VSC_G071RB.hex
"C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin/arm-none-eabi-objcopy" -O binary VSC_G071RB.elf VSC_G071RB.bin
make.exe[2]: Leaving directory `/c/Users/urie_/Documents/FreeRTOS/VSC_G071RB/build'
[100%] Built target VSC_G071RB.elf
make.exe[1]: Leaving directory `/c/Users/urie_/Documents/FreeRTOS/VSC_G071RB/build'
"C:/Program Files/CMake/bin/cmake.exe" -E cmake_progress_start
 C:/VSC_G071RB/build/CMakeFiles 0 

If there are no errors in the compilation we observe our executable file inside the build directory.

Generated executable files


Card image cap
Guillermo Garcia I am an embedded systems software engineer. I like constant learning, IoT systems and sharing knowledge


Comentarios... no existen comentarios.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subscribe


Subscribe to receive the latest content.
Loading