目录
1 CMake简介
CMake是一种跨平台编译工具,比Make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists文件,然后用CMake命令将CMakeLists文件转化为Make所需要的Makefile文件,其可以跨平台生成对应能用的Makefile,最后用make命令编译源码生成可执行程序或共享库,它的作用和qt的qmake是相似的。
2 单个源文件编译
2.1 目录结构
. ├── CMakeLists.txt └── main.c 0 directories, 2 files
2.2 编写 CMakeLists.txt
# CMake 最低版本号要求 cmake_minimum_required (VERSION 3.1) # 项目名称 project (Demo) # 指定生成目标 add_executable(BGM main.c)
2.3 执行编译
在当前目录执行cmake . -G "MSYS Makefiles"
,得到Makefile后再使用make命令编译得到BGM可执行文件。指令执行完毕后的目录结构:
. ├── BGM.exe ├── cmake_install.cmake ├── CMakeCache.txt ├── CMakeFiles ├── CMakeLists.txt ├── main.c └── Makefile
3 多个源文件编译
3.1 同一目录
3.1.1 目录结构
. ├── CMakeLists.txt ├── main.c ├── MathFunctions.c └── MathFunctions.h 0 directories, 4 files
3.1.2 编写 CMakeLists.txt
# CMake 最低版本号要求 cmake_minimum_required (VERSION 3.1) # 项目名称 project (Demo) # 查找当前目录下的所有源文件, 并将名称保存到 SRCS 变量 aux_source_directory(./ SRCS) # 指定生成目标 add_executable(BGM ${SRCS})
3.1.3 执行编译
在当前目录执行cmake . -G "MSYS Makefiles"
,得到Makefile后再使用make命令编译得到BGM可执行文件。指令执行完毕后的目录结构:
. ├── BGM.exe ├── cmake_install.cmake ├── CMakeCache.txt ├── CMakeFiles ├── CMakeLists.txt ├── main.c ├── Makefile ├── MathFunctions.c └── MathFunctions.h
3.2 多个目录
3.2.1 目录结构
现在进一步将MathFunctions.h
和MathFunctions.c
文件移动到math目录下:
. ├── CMakeLists.txt ├── main.c └── math ├── CMakeLists.txt ├── MathFunctions.c └── MathFunctions.h
对于多目录结构,需要分别在根目录和子目录里各编写一个CMakeLists.txt。本次编译采用方法为先将math目录里的文件编译成静态库,再由main函数调用。
3.2.2 编写 CMakeLists.txt
编写math子目录下的CMakeLists.txt:
# 查找当前目录下的所有源文件, 并将名称保存到 LIB_MathFunctions_SRCS 变量 aux_source_directory(./ LIB_MathFunctions_SRCS) # 生成链接库, 将当前目录中的源文件编译为静态链接库 add_library(MathFunctions STATIC ${LIB_MathFunctions_SRCS})
编写根目录下的CMakeLists.txt:
# CMake 最低版本号要求 cmake_minimum_required(VERSION 2.8) # 项目信息 project(BGM) # 查找当前目录下的所有源文件, 并将名称保存到 DIR_ROOT_SRCS 变量 aux_source_directory(./ DIR_ROOT_SRCS) # 添加 math 子目录, 这样 math 目录下的 CMakeLists.txt 文件和源代码也会被处理 add_subdirectory(./math) # 指定生成目标 add_executable(Demo ${DIR_ROOT_SRCS}) # 添加链接库, 指明可执行文件 Demo 需要连接一个名为 MathFunctions 的链接库 target_link_libraries(Demo MathFunctions)
3.2.3 执行编译
在build子目录下执行cmake .. -G "MSYS Makefiles"
,得到Makefile后再使用make命令编译得到Demo可执行文件。指令执行完毕后的目录结构:
. ├── build │ ├── cmake_install.cmake │ ├── CMakeCache.txt │ ├── CMakeFiles │ ├── Demo.exe │ ├── Makefile │ └── math ├── CMakeLists.txt ├── math │ ├── CMakeLists.txt │ ├── MathFunctions.c │ └── MathFunctions.h └── TestMain.c 4 directories, 9 files
附录
一个成熟项目的单元测试CMakeLists.txt参考:
# @file CMakeLists.txt # @author Nixon (Xinglong.Ni@geely.com) # @version 0.2 # @data 2023.09.12 # @brief build ota_utest in ubuntu env # @note [change history] # # @copyright GEELY AUTOMOBILE RESEARCH INSTITUTE CO.,LTD Copyright (c) 2023 # ------------------------------------------------------------------------- # [change history] # v0.1 2023.08.10 Nixon 1.初版 # v0.2 2023.09.12 Nixon 1.添加一些学习内容 # v0.3 2024.03.14 Nixon 1.优化 otamaster someip 模块路径 # ------------------------------------------------------------------------- # Makefile:在build子目录下执行 cmake .. -G "Unix Makefiles" # Ninja :在built子目录下执行 cmake .. -G "Ninja" # CMake 最低版本号要求 cmake_minimum_required(VERSION 3.14) # 项目信息 project(ota_utest) # 编译选项配置 set(CMAKE_CXX_STANDARD 14) # GoogleTest requires at least C++14 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 编译器选项 add_compile_options(-g) # add_compile_options(-g -ftest-coverage -fprofile-arcs) # -Wall -Wextra -g # -ftest-coverage: 用于在编译后生成 .gcno 记录文件, 包含用于重建基本块图和为块分配源行号的信息 # -fprofile-arcs: 用于在执行后生成 .gcda 记录数据文件, 包含弧过渡计数、值分布计数和一些摘要信息 # 添加 otamaster 模块 set(OTAMASTER_DIR "${CMAKE_SOURCE_DIR}/src/otamaster_0321_23R4_stest_fix_temp") file(GLOB OTA_MODULE_DIRS DIRECTORY "${OTAMASTER_DIR}/*") foreach(module_dir ${OTA_MODULE_DIRS}) aux_source_directory("${module_dir}/src" CFILES) # otamaster 各模块源文件 list(APPEND INC_DIRS "${module_dir}/inc") # otamaster 各模块头文件路径 endforeach() # 添加 otamaster someip IF 模块 set(OTAMASTER_SOMEIPIF_DIR "${OTAMASTER_DIR}/ota_someip_port") set(OTATCAMSrv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTATCAMSrv") list(APPEND INC_DIRS "${OTATCAMSrv_DIR}/client/impl/include") set(InstallationConsentSrv_DIR "${OTAMASTER_SOMEIPIF_DIR}/InstallationConsentSrv") list(APPEND INC_DIRS "${InstallationConsentSrv_DIR}/server/impl/include") set(OTAInstallInfoSrv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTAInstallInfoSrv") list(APPEND INC_DIRS "${OTAInstallInfoSrv_DIR}/client/impl/include") set(OTAInstallInfo1Srv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTAInstallInfo1Srv") list(APPEND INC_DIRS "${OTAInstallInfo1Srv_DIR}/client/impl/include") set(OTAInstallInfo2Srv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTAInstallInfo2Srv") list(APPEND INC_DIRS "${OTAInstallInfo2Srv_DIR}/client/impl/include") set(TCAMNADSrv_DIR "${OTAMASTER_SOMEIPIF_DIR}/TCAMNADSrv") list(APPEND INC_DIRS "${TCAMNADSrv_DIR}/client/impl/include") set(OTADownloadInfoSrv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTADownloadInfoSrv") list(APPEND INC_DIRS "${OTADownloadInfoSrv_DIR}/client/impl/include") set(OTADownloadInfo1Srv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTADownloadInfo1Srv") list(APPEND INC_DIRS "${OTADownloadInfo1Srv_DIR}/client/impl/include") set(OTADownloadInfo2Srv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTADownloadInfo2Srv") list(APPEND INC_DIRS "${OTADownloadInfo2Srv_DIR}/client/impl/include") set(OTADHUSrv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTADHUSrv") list(APPEND INC_DIRS "${OTADHUSrv_DIR}/client/impl/include") list(APPEND INC_DIRS "${OTADHUSrv_DIR}/server/impl/include") set(OTASilentInstallStsSrv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTASilentInstallStsSrv") list(APPEND INC_DIRS "${OTASilentInstallStsSrv_DIR}/client/impl/include") set(OTASilentInstallControlSrv_DIR "${OTAMASTER_SOMEIPIF_DIR}/OTASilentInstallControlSrv") list(APPEND INC_DIRS "${OTASilentInstallControlSrv_DIR}/client/impl/include") # 添加 utest 模块 set(UTEST_DIR "${CMAKE_SOURCE_DIR}/utest") file(GLOB UTEST_MODULE_DIRS DIRECTORY "${UTEST_DIR}/*") foreach(module_dir ${UTEST_MODULE_DIRS}) aux_source_directory("${module_dir}" CXXFILES) # UTEST 各模块源文件 list(APPEND INC_DIRS "${module_dir}") # UTEST 各模块头文件路径 endforeach() # 添加 gtest 模块 list(APPEND INC_DIRS "/usr/local/include/gtest") list(APPEND INC_DIRS "/usr/include/gtest") # 添加 gmock 模块 list(APPEND INC_DIRS "/usr/local/include/gmock") list(APPEND INC_DIRS "/usr/include/gmock") # 添加 mockcpp 模块 list(APPEND INC_DIRS "/usr/local/include/mockcpp") list(APPEND INC_DIRS "/usr/mockcpp/mockcpp/3rdparty") # 添加 zlib 模块 set(ZLIB_DIR "${CMAKE_SOURCE_DIR}/../6third_party/zlib") list(APPEND INC_DIRS "${ZLIB_DIR}") list(APPEND INC_DIRS "${ZLIB_DIR}/include") list(APPEND INC_DIRS "${ZLIB_DIR}/src") aux_source_directory("${ZLIB_DIR}/src" CFILES) aux_source_directory("${ZLIB_DIR}/microtar/src" CFILES) # 添加 3external_interface 模块 aux_source_directory("${CMAKE_SOURCE_DIR}/../3external_interface/src" CXXFILES) # 添加 uds_middleware 模块 set(UDS_MIDDLEWARE_DIR "${CMAKE_SOURCE_DIR}/../3external_interface/inc/uds_middleware") list(APPEND INC_DIRS "${UDS_MIDDLEWARE_DIR}/client/include") list(APPEND INC_DIRS "${UDS_MIDDLEWARE_DIR}/server/include") # 添加 csmw 模块 set(CSMW_DIR "${CMAKE_SOURCE_DIR}/../3external_interface/inc/csmw") list(APPEND INC_DIRS "${CSMW_DIR}/inc") # aux_source_directory("${CSMW_DIR}/src" CXXFILES) # 添加 apvp 模块 set(APVP_DIR "${CMAKE_SOURCE_DIR}/../3external_interface/inc") list(APPEND INC_DIRS "${APVP_DIR}") # aux_source_directory("${APVP_DIR}" CXXFILES) # 添加 frameworks/native/ota 模块 set(FRAMEWORKS_NATIVE_OTA_DIR "${CMAKE_SOURCE_DIR}/../3external_interface/inc/frameworks/native/ota") list(APPEND INC_DIRS "${FRAMEWORKS_NATIVE_OTA_DIR}/server/include") # aux_source_directory("${APVP_DIR}" CXXFILES) # 添加构建目标需要的自定义头文件路径 include_directories(${INC_DIRS}) # # 需要排除的UTEST文件夹 # set(EXCLUDED_UTEST_FOLDERS # ${UTEST_DIR}/inventoryclient # ${UTEST_DIR}/updateengine) # # 从源文件列表中移除需要排除的UTEST文件 # foreach(EXCLUDED_UTEST_FOLDER ${EXCLUDED_UTEST_FOLDERS}) # file(GLOB_RECURSE EXCLUDE_UTEST_FILES ${EXCLUDED_UTEST_FOLDER}/*.cpp) # list(REMOVE_ITEM CXXFILES ${EXCLUDE_UTEST_FILES}) # endforeach() # lib库路径 link_directories("/usr/local/lib") # 指定生成目标 add_executable(utest ${CFILES} ${CXXFILES}) # 连接目标库 target_link_libraries(utest curl gtest gmock mockcpp gcov pthread) # 定义UTEST宏 add_definitions(-DUTEST)