embedded-framework/doc/cmake_guide.md
2024-06-05 22:43:47 +08:00

300 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 1. CMake构建工具使用
  SDK使用CMake工具构建。
## 1.1. 安装
```code
详见://tools/cmake/Makefile
$ cd tools/cmake
$ make
$ cmake --version
cmake version 3.27.4
```
## 1.2. SDK构建配置脚本
* build目录下是基本的配置脚本。
```code
build/
├── cmake
│   ├── Makefile // 调用cmake命令生成Makefile文件
│   └── toolchain
│   └── linux.toolchain.cmake // 工具链配置文件已经一些全局变量;
├── global_config.cmake // 配置文件
└── sdk_config.cmake // 配置文件
```
### 1.2.1. //build/cmake/Makefile
  调用cmake命令生成Makefile文件。
```code
all:
@mkdir -p ../../cmake-shell;\ // 创建cmake输出目录这一步很关键所有cmake的中间文件都将会存放在此目录。
cd ../../cmake-shell;\
pwd;\
# 调用cmake命令并指定工具链配置文件生成Makefile文件。
cmake -DCMAKE_TOOLCHAIN_FILE="./build/cmake/toolchain/linux.toolchain.cmake" ..;\
cd ..
clean:
rm -rf ../../cmake-shell
```
在根目录执行make cmake 的时候即是调用上述Makefile生成Makefile文件。
### 1.2.2. //build/cmake/toolchain/linux.toolchain.cmake
  工具链配置文件或者一些跨平台差异化的配置文件。该文件在//build/cmake/Makefile中被指定当需要交叉编译时此文件的变量需要被重新配置。
```code
INCLUDE(CMakeForceCompiler)
set(LINUX_TEST "true")
set(CROSS_COMPILE_PREFIX "") // 工具链前缀
set(CMAKE_C_COMPILER "${CROSS_COMPILE_PREFIX}gcc") // 配置工具链
set(CMAKE_CXX_COMPILER "${CROSS_COMPILE_PREFIX}g++") // 配置工具链
# path to compiler and utilities
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# Name of the target platform
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# Version of the system
set(CMAKE_SYSTEM_VERSION 1)
cmake_policy(SET CMP0011 NEW)
cmake_policy(SET CMP0005 NEW)
add_definitions(-Wall -O2 -Os)
add_definitions(-Wno-unused-local-typedefs)
add_definitions(-Wstrict-aliasing -Wwrite-strings)
set(TOOLCHAIN_NAME arm-linux-gnueabihf)
set(TARGET_PLATFORM "linux") // 编译系统平台Linux表示在PC的ubuntu系统上编译
set(SUBMODULE_PATH_OF_IPC_SDK "") // 子仓库路面,此处为空,交叉编译时设置
set(PLATFORM_PATH "${CMAKE_CURRENT_SOURCE_DIR}") // 平台路径
set(TEST_COVERAGE "true") // 覆盖率报告开关
add_definitions(-DPLATFORM_PATH=\"${PLATFORM_PATH}\") // 定义一个宏
set(PROJECT_OUTPUT_FOLDER "output_files") // 编译的目标文件输出目录
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_OUTPUT_FOLDER}")
... // 此处省略不同模块的配置参数,一般是一些宏定义;
```
### 1.2.3. //CMakeLists.txt
  SDK跟目录下的第一个CMakeLists.txt文件cmake命令执行的时候会指定根目录到此目录下寻找CMakeLists.txt文件作为整个项目的构建起点。
## 1.3. 重要的配置
### 1.3.1. 目录设置
  目录结构都是通过.cmake脚本来配置的。
#### 1.3.1.1. 源码目录结构配置
详见://build/global_config.cmake
```code
set(EXEC_OUTPUT_PATH "${PLATFORM_PATH}/${PROJECT_OUTPUT_FOLDER}/bin")
set(LIBS_OUTPUT_PATH "${PLATFORM_PATH}/${PROJECT_OUTPUT_FOLDER}/libs")
set(TEST_TOOLS_OUTPUT_PATH "${PLATFORM_PATH}/${PROJECT_OUTPUT_FOLDER}/libs/test_tools")
set(EXTERNAL_LIBS_OUTPUT_PATH "${PLATFORM_PATH}/${PROJECT_OUTPUT_FOLDER}/libs/external")
set(TEST_OUTPUT_PATH "${PLATFORM_PATH}/${PROJECT_OUTPUT_FOLDER}/test")
set(PROJECT_ROOT_PATH "${PLATFORM_PATH}")
set(APPLICATION_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/application") # 应用层目录
set(MIDDLEWARE_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/middleware") # 中间件层目录
set(UTILS_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/utils") # 工具层目录
set(HAL_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/hal") # 硬件抽象层目录
set(TEST_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/test") # 自动化测试代码/example目录
set(EXTERNAL_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/external") # 外部依赖库目录
```
## 1.4. CMakeLists.txt基本语法
### 1.4.1. 概述
  概括性描述就是只需要告诉CMakeLists.txt文件构建时包含哪些配置文件依赖的头文件目录需要编译的源码文件依赖的目标目录如有输出的目标依赖的目标一般是库CMakeLists.txt即可生成一个Makefile代码来构建这个目标。
  整个SDK由很多的CMakeLists.txt文件组成绝大多数的CMakeLists.txt文件负责把该目录的源码编译成一个库SDK通过链接不同功能的库来构建不同的应用程序。
```code
./application/CMakeLists.txt
./application/HuntingCamera/CMakeLists.txt
./CMakeLists.txt
./hal/CMakeLists.txt
./middleware/AppManager/CMakeLists.txt
./middleware/CMakeLists.txt
./test/all/CMakeLists.txt
./test/application/CMakeLists.txt
./test/application/HuntingCamera/CMakeLists.txt
./test/application/MissionManager/CMakeLists.txt
./test/application/MissionManager/tool/CMakeLists.txt
./test/application/VersionReleaseTool/CMakeLists.txt
./test/CMakeLists.txt
./test/hal/CMakeLists.txt
./test/hal/tool/CMakeLists.txt
./test/middleware/AppManager/CMakeLists.txt
./tools/clang-tidy/CMakeLists.txt
./utils/CMakeLists.txt
./utils/Config/CMakeLists.txt
./utils/ConfigBase/CMakeLists.txt
```
### 1.4.2. 一个CMakeLists.txt示例
  CMakeLists.txt可以通过调用一些shell脚本来完成除编译之外的其它工具例如格式化代码。
```code
include(${CMAKE_SOURCE_DIR_IPCSDK}/build/global_config.cmake)
set(EXECUTABLE_OUTPUT_PATH ${EXEC_OUTPUT_PATH}) // 设置可执行文件的输出目录
set(LIBRARY_OUTPUT_PATH ${LIBS_OUTPUT_PATH}) // 设置库文件的输出目录
include_directories( // 该目标需要依赖的头文件的目录
./src
./include
${UTILS_SOURCE_PATH}/StatusCode/include
${UTILS_SOURCE_PATH}/Log/include
)
#do not rely on any other library
#link_directories( // 该目标需要链接依赖的库的目录,因为是目标是库,无需链接,此设置无
#)
aux_source_directory(./src SRC_FILES) // 需要编译的源码文件此处是src目录下的所有文件
set(TARGET_NAME StatusCode) // 设置输出目标名称
add_library(${TARGET_NAME} STATIC ${SRC_FILES})
target_link_libraries(${TARGET_NAME} Log) // 该目标需要依赖的库这一步很关键cmake将会根据依赖关系自动去编译需要的依赖库
if ("${COMPILE_IMPROVE_SUPPORT}" MATCHES "true")
add_custom_target( // 静态检测代码
StatusCode_code_check
COMMAND ${CLANG_TIDY_EXE}
-checks='${CLANG_TIDY_CHECKS}'
--header-filter=.*
--system-headers=false
${SRC_FILES}
${CLANG_TIDY_CONFIG}
-p ${PLATFORM_PATH}/cmake-shell
WORKING_DIRECTORY ${UTILS_SOURCE_PATH}/StatusCode
)
file(GLOB_RECURSE HEADER_FILES *.h)
add_custom_target( // 格式化代码
StatusCode_code_format
COMMAND ${CLANG_FORMAT_EXE}
-style=file
-i ${SRC_FILES} ${HEADER_FILES}
WORKING_DIRECTORY ${UTILS_SOURCE_PATH}/StatusCode
)
add_custom_command(
TARGET ${TARGET_NAME}
PRE_BUILD
COMMAND make StatusCode_code_check
COMMAND make StatusCode_code_format
WORKING_DIRECTORY ${PLATFORM_PATH}/cmake-shell/
)
endif()
define_file_name(${TARGET_NAME}) // 该函数实现log库打印时可打印文件名
file(GLOB_RECURSE INSTALL_HEADER_FILES include/*.h)
install(FILES ${INSTALL_HEADER_FILES} DESTINATION include) // 拷贝头文件到安装目录
```
### 1.4.3. 通过CMakeLists.txt构建开源库
  通过CMakeLists.txt构建开源库可以自动关联第三方的依赖库编译的时候自动按需编译对应的开源库。
```code
include(${CMAKE_SOURCE_DIR_IPCSDK}/build/global_config.cmake)
include(build/config_base.cmake)
set(EXECUTABLE_OUTPUT_PATH ${EXEC_OUTPUT_PATH})
set(LIBRARY_OUTPUT_PATH ${LIBS_OUTPUT_PATH})
include_directories(
./src
./include
${UTILS_SOURCE_PATH}/StatusCode/include
${UTILS_SOURCE_PATH}/Log/include
${EXTERNAL_SOURCE_PATH}/libconfig/libconfig-1.7.3/lib
)
# link_directories(
# ${EXTERNAL_SOURCE_PATH}/libconfig/libconfig-1.7.3/lib/.libs
# )
aux_source_directory(./src SRC_FILES)
set(TARGET_NAME ConfigBase)
add_library(${TARGET_NAME} STATIC ${SRC_FILES})
target_link_libraries(${TARGET_NAME} StatusCode Log libconfig.a)
if ("${COMPILE_IMPROVE_SUPPORT}" MATCHES "true")
add_custom_target(
ConfigBase_code_check
COMMAND ${CLANG_TIDY_EXE}
-checks='${CLANG_TIDY_CHECKS}'
--header-filter=.*
--system-headers=false
${SRC_FILES}
${CLANG_TIDY_CONFIG}
-p ${PLATFORM_PATH}/cmake-shell
WORKING_DIRECTORY ${UTILS_SOURCE_PATH}/ConfigBase
)
add_custom_command(
TARGET ${TARGET_NAME}
PRE_BUILD
COMMAND make ConfigBase_code_check
WORKING_DIRECTORY ${PLATFORM_PATH}/cmake-shell/
)
file(GLOB_RECURSE HEADER_FILES *.h)
add_custom_target(
ConfigBase_code_format
COMMAND ${CLANG_FORMAT_EXE}
-style=file
-i ${SRC_FILES} ${HEADER_FILES}
WORKING_DIRECTORY ${UTILS_SOURCE_PATH}/ConfigBase
)
add_custom_command(
TARGET ${TARGET_NAME}
PRE_BUILD
COMMAND make ConfigBase_code_check
COMMAND make ConfigBase_code_format
WORKING_DIRECTORY ${PLATFORM_PATH}/cmake-shell/
)
endif()
# build libconfig before make libConfigBase.a
add_custom_command(
# OUTPUT ${EXTERNAL_SOURCE_PATH}/libconfig/libconfig-1.7.3/lib/.libs/libconfig.a
OUTPUT ${EXTERNAL_LIBS_OUTPUT_PATH}/libconfig.a // 创建这个开源库输出文件的生成方法
COMMAND echo "Build libconfig-1.7.3. COMPILE_HOST = ${COMPILE_HOST}"
# COMMAND tar zxvf libconfig-1.7.3.tar.gz
COMMAND sh build_libconfig.sh ${TARGET_PLATFORM} ${COMPILE_HOST}
# 把生成的开源库拷贝到输出目录
COMMAND mv ${EXTERNAL_SOURCE_PATH}/libconfig/libconfig-1.7.3/lib/.libs/libconfig.a ${EXTERNAL_LIBS_OUTPUT_PATH}/libconfig.a
WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/libconfig/
)
add_custom_target(
libconfig.a // 创建一个库目标
# DEPENDS ${EXTERNAL_SOURCE_PATH}/libconfig/libconfig-1.7.3/lib/.libs/libconfig.a
DEPENDS ${EXTERNAL_LIBS_OUTPUT_PATH}/libconfig.a // 这个目标依赖开源库的编译输出文件
)
define_file_name(${TARGET_NAME})
config_owner(${TARGET_NAME})
file(GLOB_RECURSE INSTALL_HEADER_FILES include/*.h)
install(FILES ${INSTALL_HEADER_FILES} DESTINATION include)
```