CMake

CMake is an open-source, cross-platform build system that uses CMakeLists.txt files to describe the build rules of a project. Its core function is to generate platform-specific build files (such as Makefile on Linux/Unix or Visual Studio projects on Windows) from a project description, enabling efficient, portable multi-platform compilation.

The diagram outlines a configuration and build process that involves Kconfig and several CMake scripts. Each element of the process plays a vital role in project configuration and build setup. Below are descriptions of each component along with its role:

../../../../_images/cmake_intro.png

CMake Introduction

The SDK project structure is meticulously designed to facilitate an organized setup for software development. At the root, the src\ directory houses C source files alongside a CMakeLists.txt, which outlines the dependencies and source file configuration for the compilation process. Its counterpart, the inc\ directory, contains header files essential for declaring interfaces, with its own CMakeLists.txt for managing dependencies.

Delving deeper, the config\cmake folder includes pivotal CMake scripts such as build.cmake for managing sub-library descriptions, compile.cmake for handling compilation parameters, and version_generate.cmake for version control automation. A top-level CMakeLists.txt serves as the primary entry point for configuring the build across the entire SDK. Additional configuration is supported by specific setup scripts located in board\evb\my_app\gcc and bin\ic_type\, where localized CMakeLists.txt files help in tailoring the build to specific platforms and output formats.

SDK\
├──── src\
│      ├── CMakeLists.txt         # Specifies source files and dependencies.
│      └── *.c
├──── inc\
│      ├── CMakeLists.txt         # Specifies header files and dependencies.
│      └── *.h
├──── config\cmake
│      ├── build.cmake
│      ├── compile.cmake
│      └── version_generate.cmake
├──── CMakeLists.txt              # Top-level entry.
├──── board\evb\
│      └──my_APP/gcc
│           └──CMakeLists.txt     # Before build/after build/linker setting
└──── bin\ic_type\
       └──CMakeLists.txt          # Specifies lib files and dependencies.

Structure of APP CMakeLists

A typical CMake project structure looks like this:

cmake_minimum_required(VERSION 3.16)
project(MyAPP VERSION 1.0 LANGUAGES C CXX)
add_executable(myAPP main.c foo.c)
target_include_directories(myAPP PRIVATE include/)
target_compile_definitions(myAPP PRIVATE USE_FOO=1)
target_link_libraries(myAPP m)
  1. Add target

    CMake manages project objects as targets. To add an APP target, use the add_executable command:

    Format:

    add_executable(<name> <options>... <sources>...)
    

    Example:

    add_executable(btAudioTrx " ")
    

    Where <name> is the name of the APP target. Options are usually left as default, and sources can be omitted here and added later. For example, in the btAudioTrx project, this is sufficient for initialization.

  2. Set APP target properties

    After adding the btAudioTrx target, you can set properties for this target with the set_target_properties command:

    Format:

    set_target_properties(<targets> ...
        PROPERTIES <prop1> <value1>
                   [<prop2> <value2>] ...)
    

    Example:

    set_target_properties(btAudioTrx PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY ${lib_output_path}
        LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
        RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}
        OUTPUT_NAME btAudioTrx${build_bank})
    
  3. Add required libraries for the APP

    To add libraries, use the target_link_libraries command:

    target_link_libraries(<target> ... <item>...)
    

    <target> is the APP target, <item> is the library being added. Use PUBLIC or PRIVATE as appropriate. For most single-project builds, either is acceptable.

    For released SDK, libraries are not compiled, So each library has two targets for compatibility, one for a collection of header files and another for the implementation. For example, add the math library like so:

    if(compile_lib)
        target_link_libraries(btAudioTrx
                    PUBLIC ${audioLib_link}
                    PUBLIC ${btmLib_link})
    endif()
    #remove to sdk/bin
        target_link_libraries(btAudioTrx
                    PUBLIC btmLib
                    PUBLIC audioLib
                    PUBLIC m)
    

    Both m and libm.a are the default math libraries and can be added together.

    Once a library is linked, its include paths are automatically added; there is no need to add them separately.

  4. Add Preinclude Header Files and Predefines

    To add default preinclude headers, use:

    target_precompile_headers(<target>
        <INTERFACE|PUBLIC|PRIVATE> [header1...]
        [<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
    
    target_compile_definitions(<target>
        <INTERFACE|PUBLIC|PRIVATE> [items1...]
        [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
    

    Example:

    #preinclude kconfig.h
    target_precompile_headers(btAudioTrx PRIVATE  ${kconfig_header_dir_path}/config.h)
    
    #preinclude RAM_TYPE_DATA_ON
    target_compile_definitions(btAudioTrx PUBLIC RAM_TYPE_DATA_ON=0)
    
  5. Add Boot Files

    The boot files, such as system_rtl87x3.c and startup.s, are responsible for hardware initialization and setting up the runtime environment. These files typically contain startup routines and low-level hardware configurations. Make sure to add them to your target sources using CMake as shown below. You can usually copy this section directly from the provided template or standard setup:

    target_sources(btAudioTrx
                PRIVATE ${realtek_start_up_boot_file}
                PRIVATE ${arm_start_up_boot_file})
    set_property(SOURCE ${arm_start_up_boot_file} PROPERTY LANGUAGE C)
    
  6. Add linker Script

    The linker script, such as APP.ld, tells the compiler how to organize different code and data sections in the final binary. This is essential to ensure the application is linked correctly according to the chip and memory layout. This step is generally included as is from your template.

    generate_ldscript("${CMAKE_CURRENT_SOURCE_DIR}/APP_rtl87x3e.ld" btAudioTrx)
    
  7. Add Post Build script

    Post-build scripts are used to automate a series of steps after compilation, such as converting the output file format (ELF to HEX), embedding encryption info, and generating the final deployable binary. Here's a sample post-build process:

    set(gcc_tool_path ${REALTEK_SDK_BASE_PATH}/tool/Gadgets/gcc_tool)
    set(debug_table_tool_path ${REALTEK_SDK_BASE_PATH}/tool/Gadgets/build_debug_table_tool)
    add_custom_command(TARGET  btAudioTrx POST_BUILD
            WORKING_DIRECTORY  ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}
            COMMAND ${CMAKE_OBJCOPY} -O ihex   ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}/btAudioTrx_${build_bank}.elf  ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}/btAudioTrx_${build_bank}.hex
            COMMAND ${gcc_tool_path}/Hex2Bin.exe  ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}/btAudioTrx_${build_bank}.hex ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}/btAudioTrx_${build_bank}.bin
            COMMAND ${gcc_tool_path}/prepend_header.exe /APP_code ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}/btAudioTrx_${build_bank}.bin   /${encryption_type} ${gcc_tool_path}/../${encryption_key}
            COMMAND ${gcc_tool_path}/prepend_header.exe /APP_code ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}/btAudioTrx_${build_bank}.bin   /mp_ini ${CMAKE_CURRENT_SOURCE_DIR}/../mdk/mp.ini
            COMMAND bash ${gcc_tool_path}/md5_generate.sh ${CMAKE_CURRENT_SOURCE_DIR}/bin/${bin_output_path}/btAudioTrx_${build_bank}_MP.bin ${version_path}
            )
    

Basic Workflow

  1. Write the CMake configuration Create a CMakeLists.txt file in the project's root directory to define the project name, source files, dependencies, etc.

  2. Use cmake to generate local build files Run cmake through the command line to convert the configuration into the local build system (e.g., Makefile or Visual Studio project).

  3. Build the project Run commands like make or compile within your IDE.

Basic command-line usage:

# Generate build files (example for Linux)
cmake -B build
# Build the project
cmake --build build

Quick Troubleshooting

  • Compiler cannot find header files: Check header paths and target_include_directories.

  • Missing third-party library linkage: Confirm target_link_libraries is correctly added.

  • Variable not effective: Verify the scope of CMake variables.