CMake is an open-source, cross-platform tool that generates native build tool files unique to your compiler and platform using compiler and platform agnostic configuration files.

Visual Studio Code and CMake are combined in the CMake Tools extension to make it simple to configure, build, and debug your C++ project.

To create the project, we’ll use CMake in conjunction with Make. CMake needs to know where to look for the tools. The CC and CXX environment variables are checked. They specify which compiler is the system’s default. CMake will utilize these new settings as default compilers if we manually adjust CC or CXX to other values. CMake keeps information about the current toolchain in the following variables after successful detection:

CMAKE_C_COMPILER,

CMAKE_CXX_COMPILER

They both contain paths to the C and C++ compilers.

When we cross-compile to another platform, we must use a whole different toolchain in terms of the binaries’ names and locations. This can be accomplished in one of two ways:

  1. pass values for the toolchain variables from the command line,
  2. specify toolchain file.

First option is very explicit thus easy to understand, but big number of arguments makes it harder to use CMake in terminal:

cmake .. -DCMAKE_C_COMPILER=<path_to_c_compiler> -DCMAKE_CXX_COMPILER=<path_to_cxx_compiler> -DCMAKE_AR=<path_to_ar> -DCMAKE_LINKER=<path_to_linker> etc…

Second option is more elegant and is the preferred way of choosing the toolchain. All we need to do is to put toolchain variables into a separate file (e.g. <toolchain_name>.cmake) and set CMAKE_TOOLCHAIN_FILE variable to the path of that file. This can be done both in the command line or in CMakeLists.txt before project() command:

cmake .. -DCMAKE_TOOLCHAIN_FILE=<path_to_toolchain_file>

CMake: Toolchain File

  1. # File: arm-toolchain.cmake
  2. # Toolchain file for arm-none-eabi-gcc
  3.  
  4. set(CMAKE_SYSTEM_NAME Generic)
  5. set(CMAKE_SYSTEM_PROCESSOR ARM)
  6. set(CMAKE_CROSSCOMPILING “TRUE”)
  7.  
  8. # Set system depended extensions
  9. if(WIN32)
  10.  set(ARM_TOOLCHAIN_EXT “.exe” )
  11. else()
  12.  set(ARM_TOOLCHAIN_EXT “” )
  13. endif()
  14.  
  15. if(WIN32)
  16.    set(ARM_TOOLCHAIN_DIR “C:/ProgramData/chocolatey/bin”)
  17. else()
  18.    set(ARM_TOOLCHAIN_DIR “/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin”)
  19. endif()
  20.  
  21. set(BINUTILS_PATH ${ARM_TOOLCHAIN_DIR})
  22.  
  23. set(TOOLCHAIN_PREFIX ${ARM_TOOLCHAIN_DIR}/arm-none-eabi-)
  24.  
  25. set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
  26.  
  27. set(CMAKE_C_COMPILER “${TOOLCHAIN_PREFIX}gcc${ARM_TOOLCHAIN_EXT}”)
  28. set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
  29. set(CMAKE_CXX_COMPILER “${TOOLCHAIN_PREFIX}g++${ARM_TOOLCHAIN_EXT}”)
  30.  
  31. set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL “objcopy tool”)
  32. set(CMAKE_SIZE_UTIL ${TOOLCHAIN_PREFIX}size CACHE INTERNAL “size tool”)
  33.  
  34. set(CMAKE_FIND_ROOT_PATH ${BINUTILS_PATH})
  35. set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
  36. set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
  37. set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

ARM_TOOLCHAIN_DIR specifies the compiler to be used. Additionally it defines extra tools as size and objcopy.

CMake: CMakeLists.txt

To tell CMake what to do, create a file named CMakeList.txt in the project root.

File: CMakeList.txt

CMake file for tm4c123gxl

cmake_minimum_required(VERSION 3.15.3)

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()’

set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/arm-toolchain.cmake)

Setup project, output and linker file

project(blinky VERSION 0.1)
set(EXECUTABLE ${PROJECT_NAME}.elf)
set(LINKER_FILE ${CMAKE_SOURCE_DIR}/ld/tm4c123gh6pm.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
src/main.c
src/tm4c_startup.c
inc/tm4c_startup.h
)

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 -DPART_TM4C123GH6PM)

List of include directories

target_include_directories(${EXECUTABLE} PRIVATE
src
inc
if(WIN32)
“E:/ti/TivaWare_C_Series-2.2.0.295”
else()
“/home/jshankar/ti/TivaWare_C_Series-2.2.0.295”
endif()
)

Compiler options

target_compile_options(${EXECUTABLE} PRIVATE
-mcpu=cortex-m4
-mthumb
-mfpu=fpv4-sp-d16
-mfloat-abi=hard
-fdata-sections
-ffunction-sections
-Wall
-O0
-g3
)

Linker options

target_link_options(${EXECUTABLE} PRIVATE
-T${LINKER_FILE}
-mcpu=cortex-m4
-mthumb
-mfpu=fpv4-sp-d16
-mfloat-abi=hard
-specs=nano.specs
-specs=nosys.specs
-lc
-lm
-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)

The most important sections/entries are:

  • project(<your project name here>): Give your project a name
  • set(LINKER_FILE <your linker file here>): specify the linker file name
  • set(SRC_FILES <your source files here>): list of source files to compile
  • target_compile_definitions(${EXECUTABLE} PRIVATE <compiler defines here>): list of compiler #defines
  • target_include_directories(${EXECUTABLE} PRIVATE <list of include dir>): list of include directories
  • target_compile_options(${EXECUTABLE} PRIVATE <compiler options>): list of compiler options
  • target_link_options(${EXECUTABLE} PRIVATE <linker options>): list of linker options

Configure

Next we are going to build it. Actually we need to ‘configure’ it first. With CMake it is a two stage process: running CMake to create (or configure) the make files and then we use ‘make’ to build it.

  • Close VSCode and Restart again
  • Open Command Palette … (CTRL+SHIFT+P)
  • Select CMake:Delete cache and Reconfigure

CMake: Config Output

[variant] Loaded new set of variants

[kit] Successfully loaded 3 kits from /home/jshankar/.local/share/CMakeTools/cmake-tools-kits.json

[proc] Executing command: /opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc -v

[cmakefileapi-driver] This version of CMake does not support the “toolchains” object kind. Compiler paths will be determined by reading CMakeCache.txt.

[main] Configuring folder: blinky 

[proc] Executing command: /usr/bin/cmake –no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_C_COMPILER:FILEPATH=/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc -DCMAKE_CXX_COMPILER:FILEPATH=/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-g++ -S/home/jshankar/codeprojects/tm4c123gxl/blinky -B/home/jshankar/codeprojects/tm4c123gxl/blinky/build -G “Unix Makefiles”

[cmake] Not searching for unused variables given on the command line.

[cmake] — CMAKE_TOOLCHAIN_FILE is: /home/jshankar/codeprojects/tm4c123gxl/blinky/arm-toolchain.cmake

[cmake] — Configuring done

[cmake] — Generating done

[cmake] — Build files have been written to: /home/jshankar/codeprojects/tm4c123gxl/blinky/build

Build it with make

Open a terminal in the build output folder:

View–>Terminal

cd build 

make

Instead of calling ‘make’ inside the build folder, following can be used which does the one or the other:

cmake –build .

  • The benefit of doing it this way is that if the CMakeList.txt has changed, it will also perform a configuration step first.
  • If you’re making changes to the structure, make sure you do a configure to ensure everything is working properly.

Cleaning

A ‘clean’ is to delete all the files inside the build folder. But CMake has a ‘clean’ command too:

cd build

cmake –build . –target clean

make

To do a ‘clean followed by a build’ use the following:

cd build

cmake –build . –clean-first

Make: Build Output

/usr/bin/cmake -S/home/jshankar/codeprojects/tm4c123gxl/blinky -B/home/jshankar/codeprojects/tm4c123gxl/blinky/build –check-build-system CMakeFiles/Makefile.cmake 0

/usr/bin/cmake -E cmake_progress_start /home/jshankar/codeprojects/tm4c123gxl/blinky/build/CMakeFiles /home/jshankar/codeprojects/tm4c123gxl/blinky/build/CMakeFiles/progress.marks

make -f CMakeFiles/Makefile2 all

make[1]: Entering directory ‘/home/jshankar/codeprojects/tm4c123gxl/blinky/build’

make -f CMakeFiles/blinky.elf.dir/build.make CMakeFiles/blinky.elf.dir/depend

make[2]: Entering directory ‘/home/jshankar/codeprojects/tm4c123gxl/blinky/build’

cd /home/jshankar/codeprojects/tm4c123gxl/blinky/build && /usr/bin/cmake -E cmake_depends “Unix Makefiles” /home/jshankar/codeprojects/tm4c123gxl/blinky /home/jshankar/codeprojects/tm4c123gxl/blinky /home/jshankar/codeprojects/tm4c123gxl/blinky/build /home/jshankar/codeprojects/tm4c123gxl/blinky/build /home/jshankar/codeprojects/tm4c123gxl/blinky/build/CMakeFiles/blinky.elf.dir/DependInfo.cmake –color=

make[2]: Leaving directory ‘/home/jshankar/codeprojects/tm4c123gxl/blinky/build’

make -f CMakeFiles/blinky.elf.dir/build.make CMakeFiles/blinky.elf.dir/build

make[2]: Entering directory ‘/home/jshankar/codeprojects/tm4c123gxl/blinky/build’

[ 33%] Building C object CMakeFiles/blinky.elf.dir/src/main.c.obj

/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc -DPART_TM4C123GH6PM -I/home/jshankar/codeprojects/tm4c123gxl/blinky/src -I/home/jshankar/codeprojects/tm4c123gxl/blinky/inc -I/home/jshankar/codeprojects/tm4c123gxl/blinky/if -I”/home/jshankar/codeprojects/tm4c123gxl/blinky/(” -I/home/jshankar/codeprojects/tm4c123gxl/blinky/WIN32 -I”/home/jshankar/codeprojects/tm4c123gxl/blinky/)” -I/home/jshankar/codeprojects/tm4c123gxl/blinky/E:/ti/TivaWare_C_Series-2.2.0.295 -I/home/jshankar/codeprojects/tm4c123gxl/blinky/else -I/home/jshankar/ti/TivaWare_C_Series-2.1.4.178 -I/home/jshankar/codeprojects/tm4c123gxl/blinky/endif  -g   -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fdata-sections -ffunction-sections -Wall -O0 -g3 -std=c99 -o CMakeFiles/blinky.elf.dir/src/main.c.obj   -c /home/jshankar/codeprojects/tm4c123gxl/blinky/src/main.c

[ 66%] Building C object CMakeFiles/blinky.elf.dir/src/tm4c_startup.c.obj

/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc -DPART_TM4C123GH6PM -I/home/jshankar/codeprojects/tm4c123gxl/blinky/src -I/home/jshankar/codeprojects/tm4c123gxl/blinky/inc -I/home/jshankar/codeprojects/tm4c123gxl/blinky/if -I”/home/jshankar/codeprojects/tm4c123gxl/blinky/(” -I/home/jshankar/codeprojects/tm4c123gxl/blinky/WIN32 -I”/home/jshankar/codeprojects/tm4c123gxl/blinky/)” -I/home/jshankar/codeprojects/tm4c123gxl/blinky/E:/ti/TivaWare_C_Series-2.2.0.295 -I/home/jshankar/codeprojects/tm4c123gxl/blinky/else -I/home/jshankar/ti/TivaWare_C_Series-2.1.4.178 -I/home/jshankar/codeprojects/tm4c123gxl/blinky/endif  -g   -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fdata-sections -ffunction-sections -Wall -O0 -g3 -std=c99 -o CMakeFiles/blinky.elf.dir/src/tm4c_startup.c.obj   -c /home/jshankar/codeprojects/tm4c123gxl/blinky/src/tm4c_startup.c

[100%] Linking C executable blinky.elf

/usr/bin/cmake -E cmake_link_script CMakeFiles/blinky.elf.dir/link.txt –verbose=1

/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc -g  -T/home/jshankar/codeprojects/tm4c123gxl/blinky/ld/tm4c123gh6pm.ld -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -specs=nano.specs -specs=nosys.specs -lc -lm -Wl,-Map=blinky.map,–cref -Wl,–gc-sections -Xlinker -print-memory-usage CMakeFiles/blinky.elf.dir/src/main.c.obj CMakeFiles/blinky.elf.dir/src/tm4c_startup.c.obj  -o blinky.elf 

Memory region         Used Size  Region Size  %age Used

           FLASH:         980 B       256 KB      0.37%

            SRAM:         540 B        32 KB      1.65%

/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-size blinky.elf

   text    data     bss     dec     hex filename

    980       0     540    1520     5f0 blinky.elf

/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-objcopy -O srec –srec-len=64 blinky.elf blinky.s19

/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-objcopy -O ihex blinky.elf blinky.hex

/opt/toolchains/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-objcopy -O binary blinky.elf blinky.bin

make[2]: Leaving directory ‘/home/jshankar/codeprojects/tm4c123gxl/blinky/build’

[100%] Built target blinky.elf

make[1]: Leaving directory ‘/home/jshankar/codeprojects/tm4c123gxl/blinky/build’

/usr/bin/cmake -E cmake_progress_start /home/jshankar/codeprojects/tm4c123gxl/blinky/build/CMakeFiles 0

author avatar
Aravind S S