Overview
Concepts
SOC Project: Each SOC project root directory contains a
CMakeLists.txt
as the build entry point. All MCU projects under it are added here.MCU Project: Each MCU project uses unified toolchain and configuration parameters (some configurations may vary due to firmware or ROM). Different MCU projects may use different toolchains. An MCU project includes builds of one or more firmwares.
Firmware: Mainly includes
image1
,image2
,image3
, with differences as follows:image1
: Defines the common infrastructure for bootloader and system flash layout in MCU systems, providing a secure bootloader with convenient software upgrade support.image2
: The main application firmware of the SOC, typically containing a real-time OS (FreeRTOS) and application tasks.image3
: Highly configurable, allowing users to include only required security services. Protected by Read Protection (RDP), decrypted in the secure bootloader, and loaded into TrustZone-protected SRAM.
Component: Components are organized under the
component
directory at the same level as SOC projects. Each subdirectory represents a functional module with its ownCMakeLists.txt
defining compilation and linking configurations.Firmware Build: In each MCU project’s
[asdk|vsdk]/make/[image1|image2|image3]/CMakeLists.txt
, add required components and define generation rules.
SDK CMake Structure
The project’s CMakeLists.txt
directory structure and invocation relationships are shown below:
Attention
In the diagram above, the CMakeLists.txt
in image1
, image2
, and image3
directories can independently add components for their respective firmwares.
Directory structure of cmake
:
cmake
├── flags # Global compile and link options
│ ├── ca32
│ │ ├── compile_options.cmake
│ │ └── link_options.cmake
│ ├── common
│ │ ├── compile_options.cmake
│ │ └── link_options.cmake
│ ├── km0
│ │ ├── compile_options.cmake
│ │ └── link_options.cmake
│ ├── km4
│ │ ├── compile_options.cmake
│ │ └── link_options.cmake
│ └── kr4
│ ├── compile_options.cmake
│ └── link_options.cmake
├── CMakeLists-template.cmake # CMakeLists.txt template for component
├── common.cmake # Project related APIs
├── global_define.cmake # Global defined parameters
├── utility_base.cmake # Utility APIs (lower level)
├── utility.cmake # Utility APIs (upper level)
└── toolchain # Toolchain defines
├── ameba-toolchain-asdk-10.3.1.cmake
├── ameba-toolchain-asdk-12.3.1.cmake
├── ameba-toolchain-check.cmake
├── ameba-toolchain-common.cmake
└── ameba-toolchain-vsdk-10.3.1.cmake
Global Compilation Configuration
Refers to compilation settings that are **shared by all components** within a specified scope.
Compilation Configuration Contents
Sources
Include directories
Compile options
Definitions
Link options
Link libraries
Note
Sources, include directories, compile options, and definitions are used for component compilation.
Link options and link libraries are used for firmware linking.
Global Compilation Configuration Sources
Primarily consists of two sources:
Settings in
cmake/flags
, refer to SDK CMake StructureAdditional content appended by each component’s Component Public Part
Attention
The order of components’ appended configurations in the final global compilation settings (e.g., the order of header file paths) depends on the sequence in which components are added to the firmware
This ordering is unreliable. For order-sensitive configurations (like header file paths), it’s recommended to handle them through alternative approaches. For details see Component Private Part
Scope of Global Compilation Configuration
The global compilation configuration applies to each MCU project. For example, RTL8721Dx
has separate configurations for km0
and km4
, while RTL8730E
has configurations for km0
, km4
, and ca32
. These configurations are isolated. Components under the same MCU project use the same global compilation configuration. See the following diagram:
Key points:
Each MCU project contains an independent compilation scope.
Different firmwares (
image1
,image2
,image3
) under the same MCU project share the same compilation config.The same component is compiled with different global configurations across MCU projects (e.g.,
at_cmd
inproject_mcu1
vs.project_mcu2
).
Component Compilation CMakeLists.txt
Consists of Component Public Part and Component Private Part:
The former appends configurations to the Global Compilation Configuration.
The latter defines the component’s library build configuration.
Component Public Part
Appends the following to the Global Compilation Configuration:
Include directories: Added to global if other components need headers from this component.
Definitions: Global preprocessor macros added to global when this component is added (rarely used).
Link libraries: Required if the component is provided as a prebuilt library (not source). Use ameba_add_external_app_library to build the library.
Configuration variables: public_includes
, public_definitions
, public_libraries
. Update these in the highlighted section of code block below. See examples in cmake/CMakeLists-template.cmake
and APIs in List Operations.
1##########################################################################################
2## * This part defines public part of the component
3## * Public part will be used as global build configures for all component
4
5set(public_includes) #public include directories, NOTE: relative path is OK
6set(public_definitions) #public definitions
7set(public_libraries) #public libraries(files), NOTE: linked with whole-archive options
8
9#------------------------------------------------------------------#
10# Component public part, user config begin(DO NOT remove this line)
11
12# set public_includes, public_definitions, public_libraries in this section
13
14# Component public part, user config end(DO NOT remove this line)
15#------------------------------------------------------------------#
16
17#WARNING: Fixed section, DO NOT change!
18ameba_global_include(${public_includes})
19ameba_global_define(${public_defines})
20ameba_global_library(${public_libraries}) #default: whole-achived
Note
If there’s no need to update the three types of configurations mentioned above for the current component, the highlighted code section can be left blank.
Component Private Part
Defines the component library build:
Source files: Source files for current component
Private includes: Only for current component
Private definitions: Only for current component
Private compile options: Only for current component
Configuration variables: private_sources
, private_includes
, private_definitions
, private_compile_options
. Update these in the highlighted section of code block below. See examples in cmake/CMakeLists-template.cmake
and APIs in List Operations.
Attention
The final compilation configuration of a component (particularly include directories, definitions and compile options) is composed of both Component Private Part and Component Public Part, with the former taking higher priority for include directories and compile options . For example, the actual header search paths for a component include:
Private include directories added by the current component.
Global include directories from Global Compilation Configuration, which includes paths appended by both the current component and other components.
Therefore, configurations already added in Component Public Part should not be duplicated in Component Private Part.
General recommendations:
Prefer placing include directories in the Component Private Part to avoid header file pollution.
Exceptions: For generic or low-level components used by many others, placing includes in Component Public Part is preferred to improve reusability.
1##########################################################################################
2## * This part defines private part of the component
3## * Private part is used to build target of current component
4## * NOTE: The build API guarantees the global build configures(mentioned above)
5## * applied to the target automatically. So if any configure was already added
6## * to public above, it's unnecessary to add again below.
7
8#NOTE: User defined section, add your private build configures here
9# You may use if-else condition to set these predefined variable
10# They are only for ameba_add_internal_library/ameba_add_external_app_library/ameba_add_external_soc_library
11set(private_sources) #private source files, NOTE: relative path is OK
12set(private_includes) #private include directories, NOTE: relative path is OK
13set(private_definitions) #private definitions
14set(private_compile_options) #private compile_options
15
16#------------------------------#
17# Component private part, user config begin
18
19 # set private_sources, private_includes, private_definitions, private_compile_options in this section
20
21# Component private part, user config end
22#------------------------------#
23
24#WARNING: Select right API based on your component's release/not-release/standalone
25
26###NOTE: For open-source component, always build from source
27ameba_add_internal_library(foo
28 p_SOURCES
29 ${private_sources}
30 p_INCLUDES
31 ${private_includes}
32 p_DEFINITIONS
33 ${private_definitions}
34 p_COMPILE_OPTIONS
35 ${private_compile_options}
36)
Note
The code block above uses ameba_add_internal_library to generate library files. Other APIs can also be selected as needed. For details, see Add Library. For modifications to the highlighted code section, refer to Modifying Existing Component Build Config.
If the component already has a directory with standalone build scripts, see Integrating Code with Standalone Build System.
Best Practices
Modifying Existing Component Build Config
Refer to the instructions in Component Compilation CMakeLists.txt, utilize Useful Types for Complex Logic Processing, and note that APIs from List Operations can be called multiple times. Below are some examples:
Add public header file paths. It is recommended to use relative paths:
ameba_list_append(public_includes ${CMAKE_CURRENT_SOURCE_DIR} # Access current dir by CMAKE_CURRENT_SOURCE_DIR, same as . ${CMAKE_CURRENT_SOURCE_DIR}/foo # Access sub dir by CMAKE_CURRENT_SOURCE_DIR, same as ./foo foo # Access sub dir directly )
Add the link library paths. For the variables used here, you can refer to MCU Project-related Constants:
ameba_list_append(public_libraries ${c_SDK_LIB_APP_DIR}/lib_foo.a )
Add private sources. It is recommended to use relative paths:
ameba_list_append(private_sources foo/foo.c bar/bar.c )
Add private header file paths. It is recommended to use relative paths:
ameba_list_append(public_includes ../common # Access parent dir foo bar )
Add definitions:
ameba_list_append(private_definitions __RTOS__ MBEDTLS_CONFIG_FILE="mbedtls/config.h" )
Add compile options:
ameba_list_append(private_compile_options -Wno-unused-parameter )
Quickly Compile & Link Source Files for Testing
Steps:
Copy
cmake/CMakeLists-template.cmake
to your source directory asCMakeLists.txt
.Refer to Modifying Existing Component Build Config configure Component Public Part and Component Private Part.
Select ameba_add_internal_library in Component Private Part.
Refer to CMakeLists.txt invocation relationships add the component directory in the firmware’s
CMakeLists.txt
:ameba_add_subdirectory(path/to/your/cmakelists)
Compile and test
Integrating Code with Standalone Build System
For third-party code with independent build systems (e.g., CMake/Makefile-based components), non-intrusive integration solutions can be implemented to link them into the firmware. Specific adaptation strategies should be selected based on their build system types:
Create a wrapper
CMakeLists.txt
in some directory using the templatecmake/CMakeLists-template.cmake
.Refer to Modifying Existing Component Build Config to config Component Public Part
In Component Private Part, add the original CMake project via
ameba_add_subdirectory()
and use ameba_port_standalone_internal_library to link the target:ameba_add_subdirectory(path/to/your/cmakelists) # Add the real CMakeLists.txt dir of the wrapped component ameba_port_standalone_internal_library(foo) # Add the real target of the wrapped component to link
Refer to CMakeLists.txt invocation relationships add the component directory in the firmware’s
CMakeLists.txt
:ameba_add_subdirectory(path/to/your/wrap/cmakelists)
Compile and test
Create a wrapper
CMakeLists.txt
in some directory using the templatecmake/CMakeLists-template.cmake
.Refer to Modifying Existing Component Build Config to configure the Component Public Part, specifically setting the
public_libraries
variable to the path of the final library file.In Component Private Part, Use
add_custom_target
to invoke makefile as below:add_custom_target(foo ALL # Replace foo with new name as you wish COMMAND ${CMAKE_COMMAND} -E echo "Building foo project" # Some prompt message while building COMMAND make -j -C /path/to/your/makefile all # Set your makefile path COMMENT "Building foo project using make" ) ameba_target_depend(${c_CURRENT_IMAGE} foo) # Add dependency, foo MUST be same as in add_custom_target above
Refer to CMakeLists.txt invocation relationships add the component directory in the firmware’s
CMakeLists.txt
:ameba_add_subdirectory(path/to/your/wrap/cmakelists)
Compile and test
Adjusting Submodule Organization Relationships in Components
When a component is complex and contains multiple subcomponents, the CMakeLists.txt
in the component root directory should manage their organizational relationships. Pay attention to:
Configuration Checks: Since MCU projects generally don’t check switches and directly add components, configuration checks must be performed here. Example from
component/bluetooth/CMakeLists.txt
:if(NOT CONFIG_BT) ameba_info("CONFIG_BT is off, bluetooth will not be built") return() endif()
Subcomponent Addition Logic: When splitting subcomponents, handle the addition logic using Useful Types for Complex Logic Processing Example from
component/bluetooth/CMakeLists.txt
:ameba_add_subdirectory_ifnot(CONFIG_BT_INIC api) ameba_add_subdirectory_if(CONFIG_BT_AUDIO_CODEC_SUPPORT bt_audio) ameba_add_subdirectory(bt_mp) ameba_add_subdirectory(driver) ameba_add_subdirectory_ifnot(CONFIG_BT_INIC example) ameba_add_subdirectory(osif) ameba_add_subdirectory(rtk_coex) if(CONFIG_BT_ZEPHYR) ameba_add_subdirectory(zephyr) elseif(NOT CONFIG_BT_INIC) ameba_add_subdirectory(rtk_stack) # refer to ble_mesh_stack endif()
Adding New Components in Component Directory
To add a new independent component:
Add component path variables in
cmake/global_define.cmake
as below:ameba_set(c_CMPT_WIFI_DIR ${c_COMPONENT_DIR}/wifi) ameba_set(c_CMPT_WPAN_DIR ${c_COMPONENT_DIR}/wpan) ameba_set(c_CMPT_CRASHDUMP_DIR ${c_COMPONENT_DIR}/soc/common/crashdump) ameba_set(c_CMPT_LZMA_DIR ${c_COMPONENT_DIR}/soc/common/lzma) ameba_set(c_CMPT_FOO_DIR ${c_COMPONENT_DIR}/foo) # new component
Attention
For SOC/MCU-related components, add them in the
ameba_reset_global_define()
macro:macro(ameba_reset_global_define) ameba_set(c_CMPT_USRCFG_DIR ${c_COMPONENT_DIR}/soc/usrcfg/${c_SOC_TYPE}) ameba_set(c_CMPT_BOOTLOADER_DIR ${c_CMPT_SOC_DIR}/bootloader) ameba_set(c_CMPT_FOO_DIR ${c_CMPT_SOC_DIR}/foo) # new component endmacro()
Create component directory under
component
and addCMakeLists.txt
following Component Compilation CMakeLists.txt.Add in firmware’s
CMakeLists.txt
:ameba_add_subdirectory(${c_CMPT_FOO_DIR})
Commonly Used CMake Interfaces and Preset Constants
List Operations
ameba_list_append
ameba_list_append(<list_name> [<value> ...])
Appends elements to a list, supports appending multiple elements. Parameter description:
list_name
: List variable namevalue
: Value(s) to append
ameba_list_append_if
ameba_list_append_if(<condition> <list_name> [<value> ...] [p_ELSE <else value> ...])
Appends elements to a list conditionally, supports appending multiple elements. Parameter description:
condition
: Variable name representing the conditionlist_name
: List variable namevalue
: Value(s) to append whencondition
is truep_ELSE
: Optional keyword parameter, followed by value(s) to append whencondition
is falseelse value
: Value(s) to append whencondition
is false
Attention
If the variable represented by condition
is undefined or defined with a bool value of FALSE
, it will be considered as false.
ameba_list_append_ifnot
ameba_list_append_ifnot(<condition> <list_name> [<value> ...] [p_ELSE <else value> ...])
Appends elements to a list conditionally (opposite functionality to ameba_list_append_if()
). Parameter description:
condition
: Variable name representing the conditionlist_name
: List variable namevalue
: Value(s) to append whencondition
is falsep_ELSE
: Optional keyword parameter, followed by value(s) to append whencondition
is trueelse value
: Value(s) to append whencondition
is true
Attention
If the variable represented by condition
is undefined or defined with a bool value of FALSE
, it will be considered as false.
ameba_list_append_ifdef
ameba_list_append_ifdef(<condition> <list_name> [<value> ...] [p_ELSE <else value> ...])
Appends elements to a list based on variable definition status. Parameter description:
condition
: Variable name representing the conditionlist_name
: List variable namevalue
: Value(s) to append whencondition
is defined (Note:condition
can beFALSE
)p_ELSE
: Optional keyword parameter, followed by value(s) to append whencondition
is undefinedelse value
: Value(s) to append whencondition
is undefined
Add Library
The following APIs are used to compile code into static libraries or to perform further processing on existing targets.
Note
These APIs have the following characteristics:
The firmware that links the static library depends on which firmware’s
CMakeLists.txt
it is added in. For example, if added in image2/CMakeLists.txt, the static library will be linked to firmwareimage2
.The actual target name generated by the
name
parameter in these APIs is combined with other information such as c_MCU_PROJECT_NAME and c_CURRENT_IMAGE. Users can obtain the real target name using the variablec_CURRENT_TARGET_NAME
after API calls.These APIs internally apply Global Compilation Configuration to compile the current target.
ameba_add_internal_library
ameba_add_internal_library(<name>
[p_SOURCES <sources> ...]
[p_INCLUDES <include dirs> ...]
[p_COMPILE_OPTIONS <compile options> ...]
[p_DEFINITIONS <definitions> ...]
[p_DEPENDENCIES <dependencies> ...]
)
Adds a static library, compiles it, and automatically links the target to the current firmware. The library file is generated under the build
directory. Parameter descriptions:
name
: Target name. The actual library file islib_${name}.a
.p_SOURCES
: Source files for the target.p_INCLUDES
: Include directories for the target.p_COMPILE_OPTIONS
: Compile options for the target.p_DEFINITIONS
: Preprocessor definitions for the target.p_DEPENDENCIES
: Dependencies for the target.
Attention
The library file generated by this API resides in the build directory. It does not check CONFIG_AMEBA_RLS
internally and is always active.
ameba_port_standalone_internal_library
ameba_port_standalone_internal_library(<name>)
Links an existing static library target to the current firmware:
name
: Target name.
Tip
Particularly useful for non-intrusive adaptation of third-party library CMakeLists.txt
refer to Integrating Code with Standalone Build System.
Attention
This API does not check CONFIG_AMEBA_RLS
internally and is always active.
ameba_add_external_app_library
ameba_add_external_app_library(<name>
[p_SOURCES <sources> ...]
[p_INCLUDES <include dirs> ...]
[p_COMPILE_OPTIONS <compile options> ...]
[p_DEFINITIONS <definitions> ...]
[p_DEPENDENCIES <dependencies> ...]
)
Adds a static library, compiles it, but does not automatically link the target to the current firmware. It must be specified in Component Public Part. The library file is output to the ${c_SDK_LIB_APP_DIR}
directory (see MCU Project-related Constants) and undergoes objcopy -g -D
processing. Parameter descriptions:
name
: Target name. The actual library file islib_${name}.a
.p_SOURCES
: Source files for the target.p_INCLUDES
: Include directories for the target.p_COMPILE_OPTIONS
: Compile options for the target.p_DEFINITIONS
: Preprocessor definitions for the target.p_DEPENDENCIES
: Dependencies for the target.
Attention
This API does nothing and returns immediately if CONFIG_AMEBA_RLS
is TRUE
.
Add Subdirectory
ameba_add_subdirectory
ameba_add_subdirectory(<dir>)
Add a directory for compilation. Refer to add_subdirectory. When dir
is an external path, the last-level directory name will be used as binary_dir
. Parameter description:
dir
: Directory to be added for compilation
ameba_add_subdirectory_if
ameba_add_subdirectory_if(<condition> <dir>)
Add a directory for compilation based on specified condition. Other behaviors are same as ameba_add_subdirectory. Parameter description:
condition
: Variable name representing the conditiondir
: Directory to add for compilation when condition is met
ameba_add_subdirectory_ifnot
ameba_add_subdirectory_ifnot(<condition> <dir>)
Add a directory for compilation based on specified condition. Other behaviors are same as ameba_add_subdirectory. Parameter description:
condition
: Variable name representing the conditiondir
: Directory to add for compilation when condition is NOT met
Attention
Variables represented by condition
that are undefined or defined with a bool value of FALSE
will be considered unmet
ameba_add_subdirectory_if_exist
ameba_add_subdirectory_if_exist(<dir>)
When path doesn’t exist: silently return if CONFIG_AMEBA_RLS
is TRUE
, otherwise throw error. When path exists, behaves same as ameba_add_subdirectory. Parameter description:
dir
: Directory to add for compilation when path exists
Constants Definition
The CMake script cmake/global_define.cmake
defines several constants that can be directly used in script writing. Some examples are listed below:
General Constants
Variable Name |
Value |
---|---|
|
Root dir of the repo |
|
|
|
|
|
|
Frequently Asked Questions & Suggestions
View Detailed Compilation Parameters of a Source File
Add the following code at the beginning of the target source file or introduce syntax errors, then compile. The compiler will report errors at the corresponding source file location and print detailed compilation parameters.
#error debug
Undefined Reference Error
This error typically occurs during the linking stage when generating axf files. Common causes include:
Cause 1: The library containing the symbol is not linked
Cause 2: The source file containing the symbol is not compiled
Cause 3: The code block containing the symbol is not compiled
The following uses RTL8721Dx
as an example to demonstrate troubleshooting steps for the above causes. Below is a sample link error output (partial information retained for demonstration):
1[5/42] Linking C executable project_km4/asdk/make/image2/target_img2_km4.axf
2FAILED: project_km4/asdk/make/image2/target_img2_km4.axf
3ccache /opt/rtk-toolchain/asdk-10.3.1-4354/linux/newlib/bin/arm-none-eabi-gcc
4-O2
5-o project_km4/asdk/make/image2/target_img2_km4.axf
6
7-Wl,--whole-archive
8project_km4/asdk/make/image2/at_cmd/lib_at_cmd.a
9project_km4/asdk/make/image2/swlib/lib_swlib.a
10project_km4/asdk/make/image2/file_system/fatfs/lib_fatfs.a
11project_km4/asdk/make/image2/file_system/littlefs/lib_littlefs.a
12project_km4/asdk/make/image2/file_system/kv/lib_kv.a
13project_km4/asdk/make/image2/file_system/vfs/lib_vfs.a
14project_km4/asdk/make/image2/fwlib/lib_fwlib.a
15project_km4/asdk/make/image2/hal/lib_hal.a
16project_km4/asdk/make/image2/misc/lib_misc.a
17project_km4/asdk/make/image2/lwip/lib_lwip.a
18
19-Wl,--no-whole-archive
20
21-lm
22-O2
23-o project_km4/asdk/make/image2/target_img2_km4.axf
24
25-Wl,--whole-archive
26project_km4/asdk/make/image2/at_cmd/lib_at_cmd.a
27project_km4/asdk/make/image2/cmsis-dsp/lib_cmsis_dsp.a
28
29-Wl,--no-whole-archive
30
31-lm
32-lstdc++
33ld: amebadplus_gcc_project/project_km4/asdk/lib/soc/lib_chipinfo.a(ameba_rom_patch.o): in function `io_assert_failed':
34(.text.io_assert_failed+0x12): undefined reference to `rtk_log_write_nano'
Key information from highlighted lines 1, 2, 33, 34:
MCU Project:
km4
Firmware: image2, File:
target_img2_km4.axf
Undefined symbol:
rtk_log_write_nano
, called in functionio_assert_failed()
Source file:
log.c
Component:
swlib
Library:
lib_swlib.a
Troubleshooting steps:
The library containing the symbol is not linked
Verify if link parameters contain
lib_swlib.a
Line 9 shows
project_km4/asdk/make/image2/swlib/lib_swlib.a
is linked. If missing, check:Whether
swlib
component is added in image2’sCMakeLists.txt
Check the component’s
CMakeLists.txt
. If APIs such as ameba_add_external_app_library are used, ensure that thepublic_libraries
in their Component Public Part are correctly added.
The source file containing the symbol is not compiled
Search for
log.o
in CMake’sbuild
directory:
find build/project_km4 -name log.o
Sample output:
build/project_km4/asdk/make/image1/swlib/CMakeFiles/swlib_target_loader_km4.dir/log.o
build/project_km4/asdk/make/image2/swlib/CMakeFiles/swlib_target_img2_km4.dir/log.o
dir /s build\project_km4\log.o
Sample output:
C:\Users\sdk\amebadplus_gcc_project\build\project_km4\asdk\make\image1\swlib\CMakeFiles\swlib_target_loader_km4.dir
2025/03/12 14:56 21,096 log.o
C:\Users\sdk\amebadplus_gcc_project\build\project_km4\asdk\make\image2\swlib\CMakeFiles\swlib_image2_km4.dir
2025/03/12 14:56 21,096 log.o
If highlighted entries are missing, check
swlib
’sCMakeLists.txt
for source file omissions or logic errors
The code block containing the symbol is not compiled
Locate
log.o
using steps from Cause 2Check if
log.o
contains the symbol using toolchain commands(refer to Installing Toolchain get the directory of toolchain):/opt/rtk-toolchain/asdk-10.3.1/linux/newlib/bin/arm-none-eabi-nm build/project_km4/asdk/make/image2/swlib/CMakeFiles/swlib_target_img2_km4.dir/log.o | grep -w rtk_log_write_nano
C:\rtk-toolchain\asdk-10.3.1-4354\mingw32\newlib\bin\arm-none-eabi-nm.exe build\project_km4\asdk\make\image2\swlib\CMakeFiles\swlib_image2_km4.dir\log.o | findstr /R "\<rtk_log_write_nano\>"
Valid output should contain (note
T
type):00000000 T rtk_log_write_nano
If missing, check conditional compilation in
log.c
Useful Types for Complex Logic Processing
SOC Type
Identify SOC types (e.g., amebadplus
, amebalite
, amebasmart
) using variables: CONFIG_AMEBADPLUS
, CONFIG_AMEBALITE
, CONFIG_AMEBASMART
if(CONFIG_AMEBADPLUS)
# Add code for amebadplus here
elseif(CONFIG_AMEBALITE)
# Add code for amebalite here
elseif(CONFIG_AMEBASMART)
# Add code for amebasmart here
endif()
Attention
SOC type distinctions should be minimized. Prefer feature-based configuration switches instead.
If such usage is mandatory, adhere to the principle of upward compatibility to ensure future SOC type additions require no modification of this logic (e.g., avoid adding new
elseif
clauses). Example implementation incomponent/rtk_coex/CMakeLists.txt
:if(NOT CONFIG_AMEBAD) if (CONFIG_COEXIST_HOST) include(rtk_coex_api.cmake) endif() endif()
MCU Type
Identify MCU types (e.g., km0
, km4
, kr4
, ca32
) using string variable c_MCU_TYPE
:
if(${c_MCU_TYPE} STREQUAL "km0")
# Add code for km0 here
elseif(${c_MCU_TYPE} STREQUAL "km4")
# Add code for km4 here
elseif(${c_SOC_TYPE} STREUQAL "ca32")
# Add code for ca32 here
endif()
Common CMake Debugging Methods
Logging
Use CMake’s built-in message()
or more readable alternatives: ameba_debug()
, ameba_info()
, ameba_warning()
, ameba_fatal()
.
Example usage to halt execution for analysis:
message(FATAL_ERROR "stop here")
Troubleshooting Common CMake Errors
Tip
Always check the first error in terminal output when troubleshooting CMake issues
External Command Parameter Error
Typically caused by incorrect parameters in COMMAND
sections of add_custom_target()
or add_custom_command()
, often due to empty CMake variables. Sample error output showing CMake’s -E
usage:
1FAILED: build/lib_atcmd.a
2/usr/bin/cmake -E copy build/lib_atcmd.a
3CMake Error: cmake version 3.30.2
4Usage: /usr/bin/cmake -E <command> [arguments...]
5Available commands:
6capabilities - Report capabilities built into cmake in JSON format
7cat [--] <files>... - concat the files and print them to the standard output
8chdir dir cmd [args...] - run command in a given directory
9...
Corresponding CMake code example:
1add_custom_command(
2 OUTPUT lib/lib_atcmd.a
3 COMMAND ${CMAKE_COMMAND} -E copy build/lib_atcmd.a ${output_path}
4 DEPENDS build/lib_atcmd.a
5)
This error occurs when ${output_path}
is empty, resulting in incomplete copy command as shown in line 2.
Copied and replaced a source file but did not trigger recompilation
The CMake build system uses incremental compilation by default, meaning it only recompiles when source code or header files change. Its mechanism for detecting changes is **based on whether the file’s modification timestamp is newer than the previous build**.
When replacing a file with an older version (via copy-paste) while keeping its original modification timestamp (default behavior in Windows Explorer), the incremental compilation **will not be triggered** because the timestamp remains unchanged.
Recommended solutions for Windows environments:
1. **Create a new file** and copy the content into it (generates a new timestamp)
2. Use the build.py -c
command to clean the build directory
Advanced Learning Readings
Special Compilation Configurations
Set Compilation Configuration Per Source File
To set compilation configurations, such as predefined macros, for specific source files. For example, adding a predefined macro __FILE_Z_STR__
to each source file that expands to the filename string of the corresponding source file. Implementation is as follows:
ameba_list_append(private_sources
foo.c
bar.c
)
foreach(src ${private_sources})
cmake_path(GET src FILENAME filename)
set_source_files_properties(${src} PROPERTIES COMPILE_DEFINITIONS "__FILE_Z_STR__=\"${filename}\"")
endforeach()
Use the CMake built-in interface set_source_files_properties to precisely set compilation configurations for each source file.
Set Compile Options Per Source File Type
ameba_list_append(private_compile_options
-Wno-multichar # for both asm/c/cpp language
$<$<COMPILE_LANGUAGE:C>:-Wno-pointer-sign> # for c language only
$<$<COMPILE_LANGUAGE:CXX>:-Wno-narrowing> # for cpp language only
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17> # for cpp language only
)
Suppress Compilation Warnings as Errors
The global compilation configuration in cmake/flags/common/compile_options.cmake
enables -Werror
by default, which treats all compilation warnings as errors. To disable this behavior, use one of the following methods:
Method 1: Component-Specific Disable. Add compilation options in the target component’s
CMakeLists.txt
:ameba_list_append(private_compile_options -Wno-error # Disable warning-as-error for this component )
Method 2: Global Disable. Modify the global configuration file
cmake/flags/common/compile_options.cmake
and comment out the-Werror
line