This repository contains the implementation for using the SEGGER Toolchain with CMake.
The CMake project has integrated support for multiple compilers as GCC and Clang. Such compilers that are "known" by CMake are identified as those and CMake configures itself to fit to their interface and behavior. As of writing, the SEGGER toolchain/compiler is not natively "known" by CMake, though SEGGER may possibly contribute native suuport to future CMake upstream versions.
While the SEGGER Compiler is based on Clang, it has different CLI options etc..
CMake provides the possibility to specify a so-called toolchain file with all related settings in order to make CMake utilize other compilers/toolchains with their specific settings. Such a file needs to be passed to the CMake configure call (see https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html for details).
The toolchain file provided by this repository allows the usage of cmake executable with and without built-in SEGGER ID detection.
If a cmake executable without built-in SEGGER compiler identification is used, then the provided segger-toolchain.cmake shall detect that situation and activate some workaround methods (provided as part of the segger-toolchain-cmake package in the "segger_cmake_modules" subfolder) in order to enforce compiler/assembler ID for SEGGER and correct binutils configuration.
The core component of this package is the segger-toolchain.cmake CMake Toolchain file,
which enables easy use of the SEGGER Toolchain with CMake projects and Ninja or make build systems.
This guide provides a quick start based on a sample project and further information for existing and new projects.
- SEGGER Toolchain with CMake Integration (this package)
- SEGGER Embedded Studio, version
8.24or later - Ninja, added to the
PATHenvironment variable - CMake, version
3.22.0or later added to thePATHenvironment variable - Visual Studio Code
- CMake Tools VS Code Extension (https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools)
- (optional, for debugging) VS Code extension "cortex-debug" by Marus25 (https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug)
- (optional, for debugging) J-Link Software and Documentation Pack
- (optional, for debugging) Arm GNU Toolchain (https://developer.arm.com/downloads/-/gnu-rm)
- NOTE: Newer versions can be found here, but are currently NOT recommended due to various issues encountered with them: https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
The segger-toolchain-cmake package includes a simple ready-to-run sample project,
which demonstrates the integration of the SEGGER Toolchain into a CMake project.
Download the segger-toolchain-cmake package and place it at a convenient location (we'll call that folder SGR_CM_TC in this description):
- For Windows:
%HOMEPATH%\SGR_CM_TC - For posix systems (Linux etc.):
$HOME/SGR_CM_TC - The resulting folder structure/content should look like this (only displaying relevant components here):
tree.com %HOMEPATH%\SGR_CM_TC Folder PATH listing C:\...\SGR_CM_TC | Readme.md | segger-toolchain.cmake +---Samples | \---MltCfgApp | | CMakeLists.txt | | CMakePresets.json | +---.vscode | +---bsp | +---cmake_modules | \---source \---segger_cmake_modules \---Compiler SEGGERClang-ASM.cmake SEGGERClang-C.cmake SEGGERClang-CXX.cmake SEGGERClang-FindBinUtils.cmake SEGGERClang.cmake
- Open
SGR_CM_TC/Samples/MltCfgAppin VS Code - Select the CMake Extension sidebar
- In Project Status -> Configure select the configuration to use (segger_arm_cortex_m4)
- Click on the Configure icon (or hit Ctrl-Shift-P and enter CMake: Configure)
- In Project Status -> Build select the build configuration to use (debug_build_segger_arm_cortex_m4)
- Click on the Build icon (or hit F7 or hit Ctrl-Shift-P and enter CMake: Build)
The test application has now been built. It can now run through some tests using CTest or be loaded onto a suitable target hardware (we will use the SEGGER emPower Board) for debugging.
- Select the CTest Extension sidebar
- Click on Run Tests icon (or hit Ctrl-Shift-P and enter CMake: Run Tests)
- Open
.vscode/launch.jsonin the editor - Set the "serverpath" to the J-Link GDB Server CL of your J-Link installation (
C:/Program Files/SEGGER/JLink/JLinkGDBServerCL.exe) - Set the "gdbPath" to the GDB Server from your Arm GNU Toolchain installation (
C:/tools/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb.exe) - Select the Run and Debug sidebar
- Select Debug with J-Link as Debug Configuration
- Connect J-Link and target hardware
- Click Start Debugging icon (or hit F5 or hit Ctrl-Shift-P and enter Debug: Start Debugging)
The test application gets loaded via J-Link to the target hardware and can now be debugged.
NOTE: Refer also to the section Details on using CMake in VSCode for more information
-
In a command-line shell, change directory to the
SGR_CM_TC/Samples/MltCfgAppfolder:- For Windows:
cd %HOMEPATH%\SGR_CM_TC\Samples\MltCfgApp
- For posix systems:
cd $HOME/SGR_CM_TC/Samples/MltCfgApp
- For Windows:
-
Let CMake configure the project for the build-folder named
"cbuild":
(This will create multiple build configurations e.g. "Debug", "Release" etc. as subfolders of the"cbuild"-folder).-
For Windows:
cmake -S . -B cbuild -G"Ninja Multi-Config" --toolchain %HOMEPATH%\SGR_CM_TC\segger-toolchain.cmake -DCMAKE_SYSTEM_PROCESSOR=arm-cortex-m4
-
For posix systems:
cmake -S . -B cbuild -G"Ninja Multi-Config" --toolchain $HOME/SGR_CM_TC/segger-toolchain.cmake -DCMAKE_SYSTEM_PROCESSOR=arm-cortex-m4
-
Example output:
C:\Users\mighty-mouse\SGR_CM_TC\Samples\MltCfgApp>cmake -S . -B cbuild -G"Ninja Multi-Config" --toolchain %HOMEPATH%\SGR_CM_TC\segger-toolchain.cmake -DCMAKE_SYSTEM_PROCESSOR=arm-cortex-m4 -- The C compiler identification is SEGGERClang -- Found binutils: arm-none-eabi -- The CXX compiler identification is SEGGERClang -- Found binutils: arm-none-eabi -- The ASM compiler identification is SEGGERClang -- Found binutils: arm-none-eabi -- Found assembler: C:/Program Files/SEGGER/SEGGER Embedded Studio 8.24/bin/cc-segger.exe -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: C:/Program Files/SEGGER/SEGGER Embedded Studio 8.24/bin/cc-segger.exe - skipped -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: C:/Program Files/SEGGER/SEGGER Embedded Studio 8.24/bin/cc++-segger.exe - skipped -- ================================================================================================================ SEGGER_CMAKE_TOOLCHAIN_VERSION = 1.0.3 SEGGER_TOOLCHAIN_PKG_ROOT = C:/Program Files/SEGGER/SEGGER Embedded Studio 8.24 Available build configuration types = Debug, Release, RelWithDebInfo ================================================================================================================ -- Configuring done -- Generating done -- Build files have been written to: C:/Users/mighty-mouse/SGR_CM_TC/Samples/MltCfgApp/cbuild
-
-
Let CMake build the project for the desired build-configuration ("Debug"):
cmake --build cbuild --config Debug # The output file will be written to the "cbuild/Debug" directory.Example output:
C:\Users\mighty-mouse\SGR_CM_TC\Samples\MltCfgApp>cmake --build cbuild --config Debug [7/7] Linking CXX executable Debug\SimpleApp.elf C:\Users\mighty-mouse\SGR_CM_TC\Samples\MltCfgApp>dir cbuild\Debug Volume in drive C has no label. Directory of C:\Users\mighty-mouse\SGR_CM_TC\Samples\MltCfgApp\cbuild\Debug 23/06/2025 15:46 <DIR> . 23/06/2025 15:46 <DIR> .. 23/06/2025 15:46 377.341 SimpleApp.elf 23/06/2025 15:46 1.090.080 SimpleApp.map 2 File(s) 1.467.421 bytes 2 Dir(s) 862.768.513.024 bytes free
The SEGGER Toolchain can easily be added to existing projects, which already use CMake, Ninja or make, and a different Toolchain such as gcc.
The basic steps are:
- Add the segger-toolchain-cmake package to the project.
- Add SEGGER Toolchain-specific files to the project.
- Adapt the project CMakeLists.txt file.
- Configure the build.
- Build the project.
- Open the existing project directory (we'll call it
$ProjectDir). - Download and extract the segger-toolchain-cmake package into
$ProjectDir/segger-toolchain-cmake(or add it as a git submodule).
The target startup code, runtime initialization, and linker script are specific to the compiler and linker.
To switch from gcc (or another toolchain) to the SEGGER Toolchain, they need to be updated.
Generic files to start with are available in the Embedded Studio installation directory (we'll call it $StudioDir).
Pre-configured, target-specific files are available in Embedded Studio's CPU Support Packages.
- Create a new folder
$ProjectDir/segger - Copy
$StudioDir/samples/Cortex_M_Startup.sto$ProjectDir/segger/Cortex_M_Startup.s - Copy
$StudioDir/samples/SEGGER_THUMB_Startup.sto$ProjectDir/segger/SEGGER_THUMB_Startup.s - Copy
$StudioDir/samples/SEGGER_Flash.icfto$ProjectDir/segger/SEGGER_Flash.icf - Copy the folder
$ProjectDir/segger-toolchain-cmake/Samples/cmake_modulesto$ProjectDir/cmake_modules - Copy/edit files under
$ProjectDir/cmake_modules/Platform/and adapt to project needs.
- Set CMAKE_SYSTEM_PROCESSOR at the start of CMakeLists.txt (before
project())set(CMAKE_SYSTEM_PROCESSOR arm-cortex-m4)
- Add the copied
cmake_modulesfolder to CMAKE_MODULE_PATH so that CMake can find thePlatformfolder in it.if(NOT "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" IN_LIST CMAKE_MODULE_PATH) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules") endif()
- Add the startup code to the project sources and remove existing ones
# Add the additional device-specific files to the source-list for the application. target_sources(${PROJECTNAME} PRIVATE segger/Cortex_M_Startup.s segger/SEGGER_THUMB_Startup.s )
- Set the appropriate compiler and assembler flags. For a switch from gcc to the SEGGER Toolchain no change might be necessary. Otherwise, use the provided Platform files (described below) as reference.
- Add the linker script as a dependency to re-link the project on changes
set_target_properties(${PROJECTNAME} PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/segger/SEGGER_Flash.icf )
- Set the linker options for the SEGGER Linker
target_link_options(${PROJECTNAME} PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/segger/SEGGER_Flash.icf # Set memory regions of device -Wl,--add-region:FLASH1=0x00100000@0x00000000 -Wl,--add-region:RAM1=0x00010000@0x20000000 # Application-specific configuration -Wl,--defsym=__STACKSIZE__=2048 -Wl,--defsym=__HEAPSIZE__=2048 # I/O Configuration -Wl,--defsym=__SEGGER_RTL_vfprintf=__SEGGER_RTL_vfprintf_int_nwp -Wl,--defsym=__SEGGER_RTL_vfscanf=__SEGGER_RTL_vfscanf_int -io=rtt # Entry Point -e_start # Optional settings --full-section-headers --merge-sections --merge-strings --map-text --map-standard --no-outline --relax --no-springboard --no-tail-merge --tp-model=auto --list-all-undefineds )
- Create a build directory (we'll use
$ProjectDir/build-segger) and cd into it:mkdir build-segger && cd build-segger
- Call cmake with the "Ninja Multi-Config" generator and the segger-toolchain file:
cmake -G "Ninja Multi-Config" --toolchain ../segger-toolchain-cmake/segger-toolchain.cmake -S ..
- Call cmake with the configuration to build.
cmake --build . --config Debug
- Mandatory variables for SEGGER toolchain:
CMAKE_TOOLCHAIN_FILE: path to segger-toolchain.cmakeCMAKE_SYSTEM_PROCESSOR: name of the target System-Processor. See below for important rules.
- Optional variables for SEGGER toolchain:
SEGGER_TOOLCHAIN_PKG_ROOT=%DIRPATH%: Path to the root of the SEGGER Embedded Studio installation directory. If this is not specified, segger-toolchain.cmake shall attempt to detect it automatically.SEGGER_USE_GCC=1: Use the SEGGER compiler in GNU/gcc mode.SEGGER_USE_GNU_LINKER=1: (Only in combination with SEGGER_USE_GCC=1) For GNU/gcc mode, use the GNU linker instead of the SEGGER linker. If SEGGER_USE_GNU_LINKER is not set, the SEGGER linker will be used (even if using the SEGGER toolchain in GNU/gcc mode).
The CMake documentation states that the value of CMAKE_SYSTEM_PROCESSOR "can be chosen freely". However for SEGGER toolchain support to work properly, CMAKE_SYSTEM_PROCESSOR must be of the form:
<supported_cpu_family>-<free_string>
where:
<supported_cpu_family>= any of the cpu family names as found under the gcc folder of SEGGER Embedded Studio installation location.
At the time of writing, the following cpu family names are valid:aarch64, andes, arm, corev, riscv32<free_string>= an arbitrary string without whitespace.
- The SEGGER CMake integration uses the
<supported_cpu_family>part ofCMAKE_SYSTEM_PROCESSORto find the correct binutils that correspond to the CPU family in use. - CMake uses
<supported_cpu_family>-<free_string>to find the so-called "Platform" files which can be located at a project-defined location.
arm-any_nice_stringriscv32-another_nice_stringarm-cortex-m4: (assuming <project_folder>/cmake_modules has been added toCMAKE_MODULE_PATH) this will cause Cmake to process the files:<project_folder>/cmake_modules/Platform/Generic-SEGGERClang-C-arm-cortex-m4.cmakefor details for compiling C language files<project_folder>/cmake_modules/Platform/Generic-SEGGERClang-CXX-arm-cortex-m4.cmakefor details for compiling C++ language files<project_folder>/cmake_modules/Platform/Generic-SEGGERClang-ASM-arm-cortex-m4.cmakefor details for compiling assembler language files
Background and implementation:
From the CMake Documentation we read this:
CMAKE_SYSTEM_PROCESSOR
This variable is optional; it sets the processor or hardware name of the target system. It is used in CMake for one purpose, to load the${CMAKE_SYSTEM_NAME}-COMPILER_ID-${CMAKE_SYSTEM_PROCESSOR}.cmakefile. This file can be used to modify settings such as compiler flags for the target. You should only have to set this variable if you are using a cross-compiler where each target needs special build settings. The value can be chosen freely, so it could be, for example, i386 IntelPXA255, or MyControlBoardRev42.
NOTE: the COMPILER_ID as mentioned in the documentation is actually a combination of the compiler ID + compiler language. Therefore for GNU/gcc COMPILER_ID may be GNU-C and for SEGGER COMPILER_ID may be SEGGERClang-C or SEGGERClang-CXX etc.
We can use the behaviour of CMake as documented above to move cpu/architecture specific toolchain settings into the files within this folder.
By appending this folder to CMAKE_MODULE_PATH in the project CMakeLists.txt, we make sure that
these files get processed accordingly during cmakes compiler detection phase.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")CMake and the SEGGER toolchain can be used with VS Code and its CMake Tools extension.
This example shows how to build the MltCfgApp sample project with the SEGGER toolchain in VSCode.
The description is based on the steps described in the previous chapter.
There are various ways through which the CMake Tools VSCode Extension can be made aware of the SEGGER toolchain:
- Using
cmake-kits.json - Using
CMakePresets.json
Of these two methods, using CMakePresets.json is recommended and shall be described here, since it is the most versatile approach and is also used by Cmake natively. For details on this approach, please refer to https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html.
The MltCfgApp sample project comes with a preconfigured CMakePresets.json file CMakePresets.json, that demonstrates the ability to build the project for 3 different embedded targets (ARM based and RISCV based) as well as for building the same application to run natively on the Windows host (using MSVC).
The most important aspects for enabling the SEGGER toolchain using presets is to define 2 variables using the cacheVariables fields:
CMAKE_TOOLCHAIN_FILECMAKE_SYSTEM_PROCESSOR
These 2 variables must be defined according to the description provided in the above sections. One may make use of the macro-expansions provided by Cmake (see https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html#macro-expansion).
{
"hidden": true,
"name": "segger_base",
"description": "Base config-preset for SEGGER toolchain",
"generator": "Ninja Multi-Config",
"binaryDir": "${sourceDir}/preset_output/build/${presetName}",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/../../segger-toolchain.cmake"
},
"environment": {
"PATH": "$penv{PATH};C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\Common7\\IDE\\CommonExtensions\\Microsoft\\CMake\\Ninja"
}
},
{
"inherits": "segger_base",
"name": "segger_arm_cortex_m4",
"displayName": "segger_arm_cortex_m4",
"description": "Build for cortex M4 with SEGGER compiler.",
"cacheVariables": {
"CMAKE_SYSTEM_PROCESSOR": "arm-cortex-m4"
}
}Debugging using SEGGER J-Link or SEGGER J-Trace:
Debugging with a debugger probe is supported by using the VS-Code extension "cortex-debug" by Marus25 (see Prerequisites for VS-Code).
For debugging with VSCode, a corresponding launch/debug configuration is required (in the launch.json file).
A detailed description of using cortex-debug and J-Link can be found at these locations:
- https://github.com/Marus/cortex-debug/wiki
- https://github.com/Marus/cortex-debug/wiki/J-Link-Specific-Configuration
- https://github.com/Marus/cortex-debug/wiki/SEGGER-RTT-support
Example excerpt from the launch.json file, showing how to start a debug session with J-Link connected to the SEGGER emPower eval board:
{
"name": "Debug with JLink",
"cwd": "${workspaceFolder}",
"executable": "${command:cmake.launchTargetPath}",
"request": "launch",
"type": "cortex-debug",
"servertype": "jlink",
"serverpath": "C:/Program Files/SEGGER/JLink/JLinkGDBServerCL.exe",
"device": "MK66FX1M0xxx18",
"interface": "jtag",
"showDevDebugOutput": "none",
"gdbPath": "C:/tools/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb.exe",
"liveWatch": {
"enabled": true,
"samplesPerSecond": 4
},
"breakAfterReset": false,
"runToEntryPoint": "main",
"rttConfig": {
"enabled": true,
"address": "auto",
"decoders": [
{
"label": "jlink_rtt_console",
"port": 0,
"type": "console",
"inputmode": "disabled",
"prompt": "jlink_rtt:0> ",
"noclear": false
}
]
}
}