WM-IOS Building System Programming Manual
WM-IOS is a building system designed based on the concept of component , which facilitates the construction of project architectures with clear hierarchical structures.
Users do not need to have a lot of knowledge about cmake rules, they can easily create their own projects by modifying variable values based on templates.
When in use, the project directory and WM-IOS directory can be separated for flexible and convenient use, making it easier for open source code projects to spread.
Directory Structure:
Directory/File |
Function |
---|---|
components |
component directory |
docs |
documentation directory |
examples |
Project or directory |
tools |
tools directory |
Components
All libraries are organized as components in the component directory or within the project directory. Each component is placed in its own directory, and the name of this directory represents the component name.
All source files must be within a component. To keep the project structure cleaner, components are not nested; all components are at the same level.
Each project can include one or more components but must contain a component named main (i.e., the examples/project_template/main directory). Each component includes the following files:
CMakeLists.txt Required. Declares the component’s source files and calls the component registration function to register itself. For detailed examples, refer to the CMakeLists.txt in examples/project_template/main .
Kconfig : Optional. Contains configuration options for the component. In the component or other components that depend on it, these configuration options can be used with a CONFIG_ prefix. For example, in components/cli , the Kconfig file includes the option COMPONENT_CLI_ENABLED. In its CMakeLists.txt , the variable if(CONFIG_COMPONENT_CLI_ENABLED) is used to decide whether to register the component based on user configuration.
Hint
Most components are disabled by default. When a component is used in the project, the build system will automatically enable the corresponding component. This mechanism can effectively shorten compilation time but may not cover all scenarios. If there is a conflict between automatically enabled components and manually configured ones in menuconfig you can disable this mechanism during compilation using wm.py build –disable-autoconf.
Engineering Catalog
The project directories are under the examples directory. Of course, this directory name can be changed as needed. The directory can contain multiple project directories, and you can switch to the desired directory to compile the specific project. Each project directory must have a main component, and you can also include many custom components. You can refer to the examples/project_template directory.
Files in the project directory:
CMakeLists.txt: This is a mandatory project property file. It must include include(${SDK_PATH}/tools/cmake/project.cmake) first, and then use the project function to declare the project name, such as project(project_template) . You can also write other conditions or variables using CMake syntax. Refer to examples/project_template/CMakeLists.txt for an example.
prj.config : This is an optional default configuration file for the project. When executing cmake to build, it will load the default configuration from here.
Attention
You can execute wm.py saveconfig to save the current project configuration directly to the prj.config file. If necessary, you can manually add or remove configuration items in the prj.config file.
After modifying prj.config , you need to delete the build directory (or execute wm.py distclean)and recompile to apply the new configuration because the current build system prioritizes using the configuration file already present in the build directory.
Quickly Creating a Project
Typically, you just need to copy the contents from examples/project_template to create a new project. Then rename the project_template directory according to your needs, for example, to project. You can also copy other existing example projects, such as examples/hello_world.
In the main folder of the new project, there is a CMakeLists.txt file where you can modify the project’s source code settings.
The ADD_INCLUDE list variable defines the header file paths that need to be exposed so they can be referenced by other components. When setting this, you can write one path per line, like this:
list(APPEND ADD_INCLUDE "include"
)
The ADD_PRIVATE_INCLUDE list variable defines the header file paths that do not need to be exposed. They will only be referenced by the source code under main. When setting this, you can write one path per line, like this:
list(APPEND ADD_PRIVATE_INCLUDE "myinc"
)
The ADD_SRCS list variable defines the source code files that need to be compiled, like this:
list(APPEND ADD_SRCS "src/main.c"
"src/test.c"
)
When all the source code needs to be compiled and does not need to be written one by one, it can also be added in batches by directory, such as adding all the source code in the src folder:
append_srcs_dir(ADD_SRCS "src")
If you want to exclude certain files after including all files from the src directory, for example, excluding test2.c, you can do it like this:
list(REMOVE_ITEM ADD_SRCS "src/test2.c"
)
The ADD_DEFINITIONS list variable defines the options that need to be added during compilation, such as adding macro definitions AAABBB=1 and BBBBDDDD=2:
list(APPEND ADD_DEFINITIONS -DAAABBB=1
-DBBBBDDDD=2
)
The ADD_LINK_SEARCH_PATH list variable defines the paths to search for libraries during linking, such as:
list(APPEND ADD_LINK_SEARCH_PATH "${CONFIG_TOOLCHAIN_PATH}/lib"
)
The ADD_STATIC_LIB list variable defines the third-party library files (without source code) that will be used, for example, using libtest.a in the lib folder:
list(APPEND ADD_STATIC_LIB "lib/libtest.a"
)
The CMAKE_C_LINK_FLAGS list variable defines the linking parameters. For example, if you use the math library, you need to add`-lm`:
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -lm" PARENT_SCOPE)
You can also add third-party library files for linking here, such as test/libtest.a and libtest2:
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -Wl,--whole-archive test/libtest.a -ltest2 -Wl,--no-whole-archive -Wl,--end-group" PARENT_SCOPE)
Tip
Except for the ADD_SRCS variable for source code, other items can be left empty or deleted if not needed.
When adding new components, you can refer to the above description of the main component. Most of the time, you can directly refer to the components in the components folder or examples/project_template to create your own components.
If you need to add multiple linking parameters(CMAKE_C_LINK_FLAGS), you only need to keep PARENT_SCOPE in the last one, and remove it from the previous ones.
Engineering Code Entrance
As mentioned above, each project must include a main component , and the main component must contain a main function. When the system starts, it will automatically execute the main function .
Therefore, the entry point for the user’s code is the main function , where users can insert their own code:
int main(void)
{
/* do some things */
return 0;
}
Generally, it is recommended to only add initialization code (such as creating user tasks) in the main function . The specific business logic should be implemented in the user tasks.
Embedding Files into Code
Users do not need to manually convert files to C language arrays and insert them into code files. By using the file embedding functionality, you can directly access the file content in the code through a variable.
In the project folder or component folder, modify the CMakeLists.txt file to set the files to be embedded. Two different embedding methods are provided.
ADD_EMBEDDED_FILES:
The ADD_EMBEDDED_FILES list variable defines the paths and names of the files to be added. Each path should be written on a new line. This variable directly stores file references. For example, to add data.png from the src/png folder under the main component, you can write:
list(APPEND ADD_EMBEDDED_FILES "src/png/data.png"
)
To use the file in the code, you need to use a symbol name composed of __binary_
, the component name, and the expanded path of ADD_EMBEDDED_FILES
, with .
and \
replaced by _
. For example, to use data.png from the src/png folder under the main component, you can write:
extern const uint8_t png_demos[] asm("__binary_main_src_png_data_png");
Among them, __binary_main_src_png_data_png
is the symbol name, which is generated according to the rules in the example above and cannot be changed. png_demos
is the alias of the added file, which can be changed according to actual needs.
To get the length of the file, using the example above
extern const uint32_t png_demos_len asm("__binary_main_src_png_data_png_length");
Among them, __binary_main_src_png_data_png_length
is the generated symbol name according to the rule and cannot be changed. png_demos_len
is an alias for the embedded file, which can be renamed as needed.
ADD_EMBEDDED_TEXTFILES:
The ADD_EMBEDDED_TEXTFILES list variable defines the paths and names of the text files to be added. Each path should be written on a new line. The content of the files added here will be converted to strings (i.e., a \0
will be appended at the end). For example, to add data.txt from the src/txt folder under the main component, you can write:
list(APPEND ADD_EMBEDDED_FILES "src/txt/data.txt"
)
The method of using the files is the same as for ADD_EMBEDDED_FILES.
Adding Custom Files to Firmware
You can add custom files to the firmware to be included in the compiled and programmed image, and then programmed to a specified Flash location.
In the CMakeLists.txt file in the main folder of the project, set the custom files to be added, and then modify the partition table to specify the programming location.
1. Adding Custom Files to Firmware:
- The ADD_BINARY_FILES list variable defines the paths and names of the custom files to be added to the firmware. Each path should be written on a new line. This variable is used to add custom files to the firmware. For example, to add data1_demos.bin and data2_demos.bin from the src/bin folder under the component, you can write:
set(ADD_BINARY_FILES "src/bin/data1_demos" "src/bin/data2_demos.bin" )
2. Modifying the Partition Table:
After adding the files, you need to add entries in the partition table. The partition names should be the filenames of the custom files added above (without the path and file extension). For example, for the custom files added above, the partition table entries would be:
# name |
offset |
size |
flag |
data1_demos |
0xA0000 |
0x10000 |
0x0 |
data2_demos |
0xB0000 |
0x80000 |
0x0 |
For details on custom partition tables, please refer to partition_table mechanism