Using CMake with TI Clang Compilers and SysConfig#
This article describes how to use CMake to build projects with TI Clang compilers and SysConfig. Examples of TI Clang compilers include tiarmclang and c29clang.
Presumptions#
You are already familiar with CMake
You have never used CMake with a TI Clang compiler or SysConfig
You use CMake version 3.29 or later
Article Overview#
The article is centered on two examples. The first is very simple. The second is more complex. For each example, the full CMakeLists.txt file is shown. Then it is described a piece at a time.
Tool Versions#
In the examples, the host system is Windows 11. The versions of the tools are as follows:
C:\examples>tiarmclang --version
TI Arm Clang Compiler 4.0.2.LTS
Target: arm-ti-none-eabi
Thread model: posix
InstalledDir: C:\ti\compilers\ti-cgt-armllvm_4.0.2.LTS\bin
C:\examples>cmake --version
cmake version 4.0.0
CMake suite maintained and supported by Kitware (kitware.com/cmake).
C:\examples>gmake --version
GNU Make 4.1
Built for Windows32
Copyright (C) 1988-2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
C:\examples>sysconfig_cli.bat --version
1.21.1+3772
The gmake used is supplied with Code Composer Studio, or CCS for short. A typical directory location is:
C:\ti\ccs2000\ccs\utils\bin
As your system configuration varies from this one, expect to see differences when you build the examples.
Both examples use the tiarmclang compiler. Changing to another TI Clang compiler, such as c29clang, is straightforward.
CMake Usage in this Article#
There are several different ways of using CMake. The purpose of these examples is to show one way CMake can be used with TI Clang compilers and SysConfig. There are many other ways to do it, and one of those ways is likely to be better for your use case.
Example One#
Introduction#
This example is a build only demonstration. The resulting executable does not run. The purpose is to highlight the details of CMake configuration that are specific to TI Clang compilers.
At the start, the example directory ex1 has two files:
CMakeLists.txt
stub.c
CMakeLists.txt#
# The first version of CMake to support TI Clang compilers is 3.29
cmake_minimum_required(VERSION 3.29)
# Cross compiling for a target system that is an embedded device
set(CMAKE_SYSTEM_NAME Generic)
# Find the compiler in the system path
find_program(CMAKE_C_COMPILER tiarmclang)
# Create the project
project(
stub # Project is named stub
LANGUAGES C # Uses the programming language C
)
# Build the executable from source files in the project
add_executable(
stub # Executable is named stub
stub.c # Has one source file
)
stub.c#
int main()
{
return 0;
}
Typical Build Commands#
C:\examples\ex1>cmake -B build . -DCMAKE_MAKE_PROGRAM=gmake -G"Unix Makefiles"
-- The C compiler identification is TIClang 4.0.2
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/ti/compilers/ti-cgt-armllvm_4.0.2.LTS/bin/tiarmclang.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (18.8s)
-- Generating done (0.1s)
-- Build files have been written to: C:/examples/ex1/build
C:\examples\ex1>cmake --build build
[ 50%] Building C object CMakeFiles/stub.dir/stub.c.obj
[100%] Linking C executable stub.out
[100%] Built target stub
C:\examples\ex1>dir/b build
CMakeCache.txt
CMakeFiles
cmake_install.cmake
Makefile
stub.map
stub.out
Description of the Build Commands#
The first command creates a directory named build, then it configures the project and generates a gmake build system. Several files and directories are automatically generated into the directory build. It is very likely this command looks different on your system.
The second command calls the build system, gmake in this case, to compile and link the project.
The third command shows the contents of the directory build. The file stub.out is the final executable.
Description of CMakeLists.txt#
The comments are mostly clear. The command find_program needs more explanation. If you do not want to rely on automatically finding the compiler program on the system path, then consider specifying the full path with a command similar to:
set(CMAKE_C_COMPILER /ti/compilers/ti-cgt-armllvm_4.0.2.LTS/bin/tiarmclang)
Example Two#
Introduction#
This example is simple in some ways, and complicated in others. It uses both tiarmclang and SysConfig. It is based on an example project from the SIMPLELINK-LOWPOWER-SDK. SDK stands for software development kit. A typical location for this SDK example project is:
C:\ti\simplelink_cc13xx_cc26xx_sdk_8_30_01_01\examples\nortos\CC1352R1_LAUNCHXL\drivers\empty
At the start, the example directory ex2 contains these files:
Name |
Contents |
Copied from SDK example? |
|---|---|---|
CMakeLists.txt |
CMake configuration |
no |
empty.c |
C source |
yes |
main_nortos.c |
C source |
yes |
empty.syscfg |
SysConfig script |
yes |
cc13x2_cc26x2_nortos.cmd |
Linker command file |
yes |
Details such as compiler options, SysConfig options, etc. are all copied, in a conceptual sense, from the SDK example project. The example project was built in CCS. Then a build log was saved from the Output View. Compiler options, and similar details, come from that build log.
CMakeLists.txt#
#---------------------------------------------------------------------
# General configuration
#---------------------------------------------------------------------
# The first version of CMake to support tiarmclang is 3.29
cmake_minimum_required(VERSION 3.29)
# Cross compiling for target system that is an embedded device
set(CMAKE_SYSTEM_NAME Generic)
# Find the compiler in the system path
find_program(CMAKE_C_COMPILER tiarmclang)
# Create the project
project(
empty_CC1352R1_LAUNCHXL_nortos_ticlang
LANGUAGES C
)
# Directory to the SDK used
set(SDK_ROOT /ti/simplelink_cc13xx_cc26xx_sdk_8_30_01_01)
#---------------------------------------------------------------------
# Configuration related to SysConfig
#---------------------------------------------------------------------
# Find the SysConfig command line interface (CLI) command in the system path
find_program(SYSCONFIG_CLI sysconfig_cli.bat)
# Directory to the generated SysConfig files
set(SYSCONFIG_GENDIR ${CMAKE_BINARY_DIR}/sysconfig_generated)
# SysConfig Input Script
set(SYSCONFIG_INPUT_FILE_NAME empty.syscfg)
set(SYSCONFIG_INPUT ${CMAKE_SOURCE_DIR}/${SYSCONFIG_INPUT_FILE_NAME})
# SysConfig stamp file. Described in the block comment at the end.
set(SYSCONFIG_STAMP_FILE ${SYSCONFIG_GENDIR}/${SYSCONFIG_INPUT_FILE_NAME}.stamp)
# SysConfig invocation command line
set(SYSCONFIG_CLI_CMD
${SYSCONFIG_CLI}
--script ${SYSCONFIG_INPUT}
-o ${SYSCONFIG_GENDIR}
--compiler ticlang
-s ${SDK_ROOT}/.metadata/product.json
)
# Ask SysConfig what files it generates. Then categorize them. This occurs
# when CMake configures the project.
execute_process(
COMMAND ${SYSCONFIG_CLI_CMD} --listGeneratedFiles
OUTPUT_VARIABLE SYSCONFIG_GEN_FILES_STR
)
string(REPLACE "\n" ";" SYSCONFIG_GEN_FILES ${SYSCONFIG_GEN_FILES_STR})
set(SYSCONFIG_GEN_CFILES ${SYSCONFIG_GEN_FILES})
set(SYSCONFIG_GEN_HFILES ${SYSCONFIG_GEN_FILES})
set(SYSCONFIG_GEN_LNKCMD ${SYSCONFIG_GEN_FILES})
set(SYSCONFIG_GEN_COMPILER_OPTS ${SYSCONFIG_GEN_FILES})
list(FILTER SYSCONFIG_GEN_CFILES INCLUDE REGEX ".*\\.c$")
list(FILTER SYSCONFIG_GEN_HFILES INCLUDE REGEX ".*\\.h$")
list(FILTER SYSCONFIG_GEN_LNKCMD INCLUDE REGEX ".*\\.cmd\\.")
list(FILTER SYSCONFIG_GEN_COMPILER_OPTS INCLUDE REGEX ".*\\.opt$")
# Cause CMake to run when the SysConfig input is modified, because that may
# change the list of generated files
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SYSCONFIG_INPUT}
)
# Run SysConfig over the input script. Described further in a block comment
# at the end.
add_custom_command(
DEPENDS ${SYSCONFIG_INPUT}
OUTPUT ${SYSCONFIG_STAMP_FILE}
BYPRODUCTS ${SYSCONFIG_GEN_FILES}
COMMAND ${SYSCONFIG_CLI_CMD}
COMMAND ${CMAKE_COMMAND} -E touch ${SYSCONFIG_STAMP_FILE}
COMMENT "Running SysConfig on ${SYSCONFIG_INPUT}"
VERBATIM
)
add_custom_target(SysConfig_build ALL DEPENDS ${SYSCONFIG_STAMP_FILE})
#---------------------------------------------------------------------
# Configuration related to compiling
#---------------------------------------------------------------------
# Compiler options which specify the variant of the Arm processor in the
# system. These are often copied from an SDK example for that system. They
# rarely change.
set(PROCESSOR_OPTIONS
-march=armv7e-m
-mcpu=cortex-m4
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-mlittle-endian
-mthumb
)
# These compiler options typically change as the project evolves. Because
# CMake replaces an undefined variable with an empty string, one way to
# disable an option is to comment out that line.
set(OPTIMIZATION_OPTION -Oz)
set(LTO_OPTION -flto)
set(DEBUG_OPTION -gdwarf-3)
# Compiler options
add_compile_options(
${PROCESSOR_OPTIONS}
${OPTIMIZATION_OPTION}
${LTO_OPTION}
${DEBUG_OPTION}
@${SYSCONFIG_GEN_COMPILER_OPTS}
)
# C files
set(SOURCES
${CMAKE_SOURCE_DIR}/empty.c
${CMAKE_SOURCE_DIR}/main_nortos.c
${SYSCONFIG_GEN_CFILES}
)
# Cause C files to depend on the SysConfig generated compiler options file
set_source_files_properties(
${SOURCES}
PROPERTIES OBJECT_DEPENDS
${SYSCONFIG_GEN_COMPILER_OPTS}
)
# Directories searched for header files
include_directories(
${SDK_ROOT}/source
${SDK_ROOT}/kernel/nortos
${SDK_ROOT}/kernel/nortos/posix
${SYSCONFIG_GENDIR}
)
#---------------------------------------------------------------------
# Configuration related to linking
#---------------------------------------------------------------------
# Linker Options
add_link_options(
${LTO_OPTION} # Required when compiling AND linking
LINKER:--reread_libs
LINKER:--warn_sections
LINKER:--rom_model
)
# Directories searched for libraries
link_directories(
${SDK_ROOT}/source
${SDK_ROOT}/kernel/nortos
${SDK_ROOT}/kernel/nortos/posix
)
# Libraries and linker command files
link_libraries(
${CMAKE_SOURCE_DIR}/cc13x2_cc26x2_nortos.cmd
${SYSCONFIG_GEN_LNKCMD}
)
#---------------------------------------------------------------------
# Final configuration that pulls everything together
#---------------------------------------------------------------------
add_executable(
empty_CC1352R1_LAUNCHXL_nortos_ticlang
${SOURCES}
)
#[[
This is the block comment about running SysConfig mentioned earlier.
These abbreviations apply only within this comment:
- SI: Input script. Same as ${SYSCONFIG_INPUT}.
- SO: All the generated files. Same as ${SYSCONFIG_GEN_FILES}.
- STAMP: The stamp file. Same as ${SYSCONFIG_STAMP_FILE}.
- mt(): Modification Time. The last time the given file or files was modified.
For a typical C file, when CMake sees that
mt(C-file) > mt(object-file)
it causes that C file to be compiled. SysConfig is different. It generates
multiple files. When those files already exist, SysConfig only changes those
it must. This means, after SysConfig runs, it may be the case that for some
of the generated files
mt(SI) > mt(SO)
To make this work, the STAMP file is introduced. The important property of
STAMP is that, after SysConfig runs
mt(STAMP) > mt(SI)
The add_custom_command command invokes SysConfig and updates mt(STAMP). The
add_custom_target command causes the built-in CMake target ALL to depend
on STAMP, which means the entire build depends on running SysConfig.
]]
Typical Build Commands#
C:\examples\ex2>cmake -B build . -DCMAKE_MAKE_PROGRAM=gmake -G"Unix Makefiles"
-- The C compiler identification is TIClang 4.0.2
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/ti/compilers/ti-cgt-armllvm_4.0.2.LTS/bin/tiarmclang.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (22.2s)
-- Generating done (0.1s)
-- Build files have been written to: C:/examples/ex2/build
C:\examples\ex2>cmake --build build
[ 16%] Running SysConfig on C:/examples/ex2/empty.syscfg
Running script...
Validating...
Generating Code (empty.syscfg)...
Writing C:\examples\ex2\build\sysconfig_generated\ti_devices_config.c...
Writing C:\examples\ex2\build\sysconfig_generated\ti_drivers_config.c...
Writing C:\examples\ex2\build\sysconfig_generated\ti_drivers_config.h...
Writing C:\examples\ex2\build\sysconfig_generated\ti_utils_build_linker.cmd.genlibs...
Writing C:\examples\ex2\build\sysconfig_generated\ti_utils_build_linker.cmd.genmap...
Writing C:\examples\ex2\build\sysconfig_generated\ti_utils_build_compiler.opt...
Writing C:\examples\ex2\build\sysconfig_generated\syscfg_c.rov.xs...
[ 16%] Built target SysConfig_build
[ 33%] Building C object CMakeFiles/empty_CC1352R1_LAUNCHXL_nortos_ticlang.dir/empty.c.obj
[ 50%] Building C object CMakeFiles/empty_CC1352R1_LAUNCHXL_nortos_ticlang.dir/main_nortos.c.obj
[ 66%] Building C object CMakeFiles/empty_CC1352R1_LAUNCHXL_nortos_ticlang.dir/sysconfig_generated/ti_devices_config.c.obj
[ 83%] Building C object CMakeFiles/empty_CC1352R1_LAUNCHXL_nortos_ticlang.dir/sysconfig_generated/ti_drivers_config.c.obj
[100%] Linking C executable empty_CC1352R1_LAUNCHXL_nortos_ticlang.out
[100%] Built target empty_CC1352R1_LAUNCHXL_nortos_ticlang
C:\examples\ex2>dir/b build
CMakeCache.txt
CMakeFiles
cmake_install.cmake
empty_CC1352R1_LAUNCHXL_nortos_ticlang.map
empty_CC1352R1_LAUNCHXL_nortos_ticlang.out
Makefile
sysconfig_generated
Description of the Build Commands#
The build commands are the same ones from example 1. But the results are different. SysConfig is run. More files are compiled. The file empty_CC1352R1_LAUNCHXL_nortos_ticlang.out is the final executable.
Description of CMakeLists.txt#
Overview#
The file is divided into 5 parts. Each part starts with a:
#---------------------------------------------------------------------
# Comment like this
#---------------------------------------------------------------------
These parts are:
General configuration
Configuration related to SysConfig
Configuration related to compiling
Configuration related to linking
Final configuration that pulls everything together
The rest of the article echoes a few lines from CMakeLists.txt, then describes them.
General Configuration#
Source#
# The first version of CMake to support tiarmclang is 3.29
cmake_minimum_required(VERSION 3.29)
# Cross compiling for target system that is an embedded device
set(CMAKE_SYSTEM_NAME Generic)
# Find the compiler in the system path
find_program(CMAKE_C_COMPILER tiarmclang)
# Create the project
project(
empty_CC1352R1_LAUNCHXL_nortos_ticlang
LANGUAGES C
)
# Directory to the SDK used
set(SDK_ROOT /ti/simplelink_cc13xx_cc26xx_sdk_8_30_01_01)
Description#
These lines are very similar to the first several lines from example 1. One additional variable, SDK_ROOT, is used for the base directory location of the SDK.
Final configuration that pulls everything together#
Source#
add_executable(
empty_CC1352R1_LAUNCHXL_nortos_ticlang
${SOURCES}
)
Description#
This is similar to the add_executable command at the end of example 1. It specifies more C source files, and by means of the variable SOURCES.