• 使用CMakeLists.txt简化项目构建过程


    在软件开发过程中,项目的构建是一个不可避免的环节。而随着项目规模的增大,手动管理编译过程变得越来越繁琐。为了简化构建流程并实现跨平台支持,CMake作为一种流行的构建系统被广泛采用。本文将介绍CMakeLists.txt文件的结构,以及如何使用CMake管理项目的编译过程。

    一、CMakeLists.txt 文件结构

    CMakeLists.txt 文件结构是指 CMakeLists.txt 文件中的基本部分和语法规则。CMakeLists.txt 文件是 CMake 的配置文件,用于描述整个项目的组成和构建规则。每个项目通常包含一个或多个 CMakeLists.txt 文件,位于项目的根目录或子目录中。CMake 通过递归地处理这些文件,构建项目的目标文件、库文件和可执行文件。

    下面是 CMakeLists.txt 文件的基本结构和语法:

    # 根据需要设置 CMake 最低版本号
    cmake_minimum_required(VERSION 3.10)
    
    # 设置项目名称和支持的语言
    project(MyProject LANGUAGES CXX)
    
    # 添加源文件和库文件
    add_library(MyLibrary SHARED my_library.cpp)
    
    # 指定头文件目录和库文件目录
    target_include_directories(MyLibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
    target_link_directories(MyLibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/lib)
    
    # 添加依赖项
    target_link_libraries(MyLibrary PRIVATE some_library)
    
    # 设置编译选项
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
    
    # 定义安装规则
    install(TARGETS MyLibrary DESTINATION /usr/lib)
    install(DIRECTORY include/ DESTINATION /usr/include)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    上述代码展示了 CMakeLists.txt 文件的基本结构和语法。它由多个命令和参数组成,下面对每个部分的作用进行解释:

    • cmake_minimum_required: 该命令用于指定 CMake 的最低版本号要求,即项目所需的 CMake 版本号。在 CMakeLists.txt 文件的开头位置,需要使用该命令设置 CMake 的最低版本号。

    • project: 该命令用于设置项目名称和支持的编程语言。支持的语言可以是 C、C++、Java 等,也可以是多种编程语言的组合。

    • add_library: 该命令用于添加源文件和库文件。源文件可以是 .cpp 文件,库文件可以是动态库或静态库。

    • target_include_directoriestarget_link_directories: 这两个命令分别用于指定头文件目录和库文件目录的位置。target_include_directories 命令用于设置头文件目录的位置,target_link_directories命令用于设置库文件目录的位置。

    • target_link_libraries: 该命令用于添加依赖项,即项目所依赖的外部库文件。这些库文件可以是系统自带的标准库,也可以是第三方库。

    • set: 该命令用于设置编译选项,如编译器的标准版本、编译器警告选项等。

    • install: 该命令用于定义项目的安装规则,指定哪些文件需要被安装到特定的位置。通常情况下,可执行文件被安装到 /usr/bin 目录,库文件被安装到 /usr/lib 目录,头文件被安装到 /usr/include 目录。

    二、示例项目介绍

    以一个UVC项目为例:

    
    list(APPEND CMAKE_MODULE_PATH "/home/lizh/workspaces/rv1126_facial_gate_release/external/rkmedia/cmake")
    
    cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
    set(CMAKE_CXX_STANDARD 11)
    add_definitions(-DDBUG)
    add_definitions(-g)
    PROJECT(uvc_app)
    include(FindPkgConfig)
    pkg_check_modules (JSON-C REQUIRED IMPORTED_TARGET json-c)
    
    include_directories(uvc)
    
    
    set(USE_RKAIQ ON)
    
    if(USE_RKAIQ)
        find_package(RkAiq REQUIRED)
        include_directories(${RKAIQ_INCLUDE_DIRS})
        add_definitions(-DRKAIQ)
    endif()
    
    #head file path
    set(BASE_PATH /home/lizh/workspaces/rv1126_facial_gate_release/external/camera_engine_rkaiq)
    include_directories(
    ${BASE_PATH}/xcore
    ${BASE_PATH}/xcore/base
    ${BASE_PATH}/aiq_core
    ${BASE_PATH}/algos
    ${BASE_PATH}/common
    ${BASE_PATH}/common/linux
    ${BASE_PATH}/hwi
    ${BASE_PATH}/hwi/isp20
    ${BASE_PATH}/ipc
    ${BASE_PATH}/iq_parser
    ${BASE_PATH}/uAPI
    ${BASE_PATH}/ipc_server
    #algos/awb
    #../core/inc/luma
    #../core/inc/stat_3a_ae
    #../core/inc/stat_3a_af
    #../core/inc/orb
    #../core/inc/common
    ${BASE_PATH}/
    ${BASE_PATH}/include
    ${BASE_PATH}/include/common
    ${BASE_PATH}/include/common/mediactl
    ${BASE_PATH}/include/iq_parser
    ${BASE_PATH}/include/uAPI
    ${BASE_PATH}/include/xcore
    ${BASE_PATH}/include/xcore/base
    ${BASE_PATH}/include/algos
    ${BASE_PATH}/include/algos/a3dlut
    ${BASE_PATH}/include/algos/ablc
    ${BASE_PATH}/include/algos/accm
    ${BASE_PATH}/include/algos/acgc
    ${BASE_PATH}/include/algos/acp
    ${BASE_PATH}/include/algos/adebayer
    ${BASE_PATH}/include/algos/adehaze
    ${BASE_PATH}/include/algos/adpcc
    ${BASE_PATH}/include/algos/ae
    ${BASE_PATH}/include/algos/af
    ${BASE_PATH}/include/algos/afd
    ${BASE_PATH}/include/algos/afec
    ${BASE_PATH}/include/algos/agamma
    ${BASE_PATH}/include/algos/adegamma
    ${BASE_PATH}/include/algos/agic
    ${BASE_PATH}/include/algos/ahdr
    ${BASE_PATH}/include/algos/aie
    ${BASE_PATH}/include/algos/aldch
    ${BASE_PATH}/include/algos/alsc
    ${BASE_PATH}/include/algos/anr
    ${BASE_PATH}/include/algos/anr/tnr_md
    ${BASE_PATH}/include/algos/aorb
    ${BASE_PATH}/include/algos/ar2y
    ${BASE_PATH}/include/algos/asd
    ${BASE_PATH}/include/algos/asharp
    ${BASE_PATH}/include/algos/awb
    ${BASE_PATH}/include/algos/awdr
    ${BASE_PATH}/include/common/gen_mesh
    ${BASE_PATH}/include/ipc_server
    )
    
    include_directories(/home/lizh/workspaces/rv1126_facial_gate_release/external/rkmedia/include/easymedia)
    include_directories(/home/lizh/workspaces/rv1126_facial_gate_release/external/rkmedia/include/rkmedia)
    
    include_directories(/home/lizh/workspaces/rv1126_facial_gate_release/external/rkmedia)
    include_directories(/home/lizh/workspaces/rv1126_facial_gate_release/external/camera_engine_rkaiq)
    
    set(LIB_SOURCE
        uvc/uvc-gadget.c
        uvc/uvc_video.cpp
        uvc/yuv.c
        uvc/uvc_control.c
        uvc/uvc_encode.cpp
        uvc/mpi_enc.c
        uvc/uevent.c
        uvc/drm.c
        cJSON/cJSON.c
        uvc/mpp_osd.c
    )
    
    add_library(rkuvc SHARED ${LIB_SOURCE})
    target_link_libraries(rkuvc pthread drm rockchip_mpp easymedia)
    
    set(SOURCE
        main.c
        ${LIB_SOURCE}
    )
    
    set(UVC_APP_DEPENDENT_LIBS
        pthread
        drm
        rockchip_mpp
        rt
        rga
        easymedia
    )
    
    set(UVC_APP_INC
        ${CMAKE_CURRENT_SOURCE_DIR}/uvc/
    )
    
    option(ENABLE_USB3  "support usb3.0 config" OFF)
    if (${ENABLE_USB3})
        add_definitions(-DUSE_USB3)
    endif()
    
    option(ENABLE_AISERVER  "rockchip aiserver" OFF)
    if (${ENABLE_AISERVER})
        add_definitions(-DUSE_RK_AISERVER)
        set(SOURCE
            ${SOURCE}
            uvc/uvc_ipc.cpp
           )
        find_package(Protobuf REQUIRED)
        if(PROTOBUF_FOUND)
            message(STATUS "protobuf library found")
            set(UVC_APP_DEPENDENT_LIBS ${UVC_APP_DEPENDENT_LIBS} protobuf-lite)
            include_directories(${PROTOBUF_INCLUDE_DIRS})
            include_directories(${CMAKE_CURRENT_BINARY_DIR})
            protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS
                                  ${CMAKE_CURRENT_SOURCE_DIR}/uvc/uvc_data.proto)
            set(UVC_APP_INC ${UVC_APP_INC} ${PROTO_HDRS})
            set(SOURCE ${SOURCE} ${PROTO_SRCS} ${PROTO_HDRS})
        endif()
    else()
        add_definitions(-fno-rtti)
    	option(USE_ROCKIT "uvc camera use rockit" OFF)
    	if(USE_ROCKIT)
    		add_definitions(-DUSE_ROCKIT=1)
    		SET(UVC_APP_DEPENDENT_LIBS
    		   ${UVC_APP_DEPENDENT_LIBS}
    		   rockit
    		   )
    		install(FILES conf/uvc.json DESTINATION ../etc/uvc_app/)
    	else()
    #		add_definitions(-DUSE_RKMEDIA=1)
    #		add_definitions(-DEPTZ_ENABLE=1)
    #		include_directories(${ROCKX_HEADER_DIR})
    #		set(UVC_APP_DEPENDENT_LIBS
    #		    ${UVC_APP_DEPENDENT_LIBS}
    #		    easymedia
    #		    rockx
    #		    rga
    #		    ${CMAKE_CURRENT_LIST_DIR}/libs/libuvcAlgorithm.so)
    #		set(SOURCE
    #		   ${SOURCE}
    #		   process/eptz_control.cpp
    #		   process/zoom_control.cpp
    #		   )
    #		set(Algorithm_LIBS ${CMAKE_CURRENT_LIST_DIR}/libs/libuvcAlgorithm.so)
    #		install(FILES ${Algorithm_LIBS} DESTINATION lib)
    	endif()
    endif()
    
    option(DBSERVER_SUPPORT  "enbale dbserver" OFF)
    if (${DBSERVER_SUPPORT})
        add_definitions(-DDBSERVER_SUPPORT)
        set(UVC_APP_DEPENDENT_LIBS ${UVC_APP_DEPENDENT_LIBS} IPCProtocol)
    endif()
    
    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
        add_definitions(-DUSE_ARM64)
    else()
        target_link_libraries(rkuvc ${CMAKE_SOURCE_DIR}/libs/libmjpeg_fps_ctr.a)
        SET(UVC_APP_DEPENDENT_LIBS
                       ${UVC_APP_DEPENDENT_LIBS}
                       ${CMAKE_SOURCE_DIR}/libs/libmjpeg_fps_ctr.a
                       )
    
        option(ENABLE_MINILOGGER  "enbale minilogger" ON)
        if (${ENABLE_MINILOGGER})
            find_package(MiniLogger REQUIRED)
            add_definitions(-DENABLE_MINILOGGER)
            set(UVC_APP_DEPENDENT_LIBS ${UVC_APP_DEPENDENT_LIBS} MiniLogger::MiniLogger)
            target_link_libraries(rkuvc MiniLogger::MiniLogger)
        endif()
    endif()
    
    option(COMPILES_CAMERA "compile:with rkmedia v4l2 flow " OFF)
    option(EPTZ_SUPPORT "uvc support eptz" OFF)
    if(COMPILES_CAMERA)
    	include_directories(process)
    	add_definitions(-DCAMERA_CONTROL)
    	set(SOURCE
    	   ${SOURCE}
    	   process/camera_control.cpp
    	   process/camera_pu_control.cpp
    	   )
    endif()
    
    ADD_EXECUTABLE(uvc_app ${SOURCE})
    #target_link_libraries(uvc_app ${UVC_APP_DEPENDENT_LIBS} PkgConfig::JSON-C)
    target_link_libraries(uvc_app ${UVC_APP_DEPENDENT_LIBS} PkgConfig::JSON-C rkuvc -lrkaiq)
    
    
    install(DIRECTORY ./uvc DESTINATION include
            FILES_MATCHING PATTERN "*.h")
    
    install(TARGETS uvc_app DESTINATION bin)
    install(DIRECTORY . DESTINATION bin
            FILES_MATCHING PATTERN "*.sh"
            PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
            GROUP_READ GROUP_WRITE GROUP_EXECUTE
            WORLD_READ WORLD_WRITE WORLD_EXECUTE)
    
    if(EXISTS "mpp_enc_cfg.conf")
    	set(ETC_DST "${PROJECT_SOURCE_DIR}/../../target/etc/")
    	file(COPY mpp_enc_cfg.conf DESTINATION ${ETC_DST})
    endif(EXISTS "mpp_enc_cfg.conf")
    
    if(DEFINED INSTALL_LIBRKUVC)
    install(TARGETS rkuvc DESTINATION lib)
    endif()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236

    这是一个CMakeLists.txt文件,用于构建名为uvc_app的项目。以下是对该文件的解析:

    首先,使用cmake_minimum_required指定需要的最低CMake版本,并设置C++标准为11。

    然后,通过PROJECT命令设置项目名称为uvc_app。

    接着,使用include命令包含FindPkgConfig模块,并通过pkg_check_modules命令查找名为JSON-C的依赖库。这里使用了IMPORTED_TARGET参数来导入json-c库。

    然后,使用include_directories命令添加一系列头文件路径。

    继续,使用add_library命令将LIB_SOURCE中的源文件编译为名为rkuvc的共享库,并链接pthread、drm、rockchip_mpp和easymedia等库。

    然后,通过设置变量SOURCE指定项目的源文件。

    紧接着,设置UVC_APP_DEPENDENT_LIBS变量,包含项目所依赖的库。

    接下来,根据ENABLE_USB3和ENABLE_AISERVER选项的设置,进行相关的定义和处理。

    然后,根据DBSERVER_SUPPORT选项的设置,进行相关定义和库的链接。

    根据CMAKE_SIZEOF_VOID_P的大小来选择性地进行处理。

    最后,使用ADD_EXECUTABLE命令将源文件编译为可执行文件uvc_app,并链接依赖的库。

    最后,使用INSTALL命令将相关文件安装到指定目录。

    三、CMakeLists.txt详解

    CMakeLists.txt 是 CMake 构建系统使用的脚本文件,通过这个文件,CMake 能够为各种环境生成标准的构建文件。

    CMakeLists.txt 配置文件的编写主要包含以下几个部分:

    1. cmake_minimum_required: 这个命令是用来设定运行这个 cmake 的最低版本要求的,对于不同版本的 cmake,其支持的命令、变量、属性等有所区别。
    cmake_minimum_required(VERSION 3.5)
    
    • 1
    1. project: 这个命令表明产生的工作空间的名称,一般与你的项目名称相同。
    project(MyProject)
    
    • 1
    1. set: 主要用来显式的定义变量。
    set(SRC_LIST main.c)
    
    • 1
    1. add_executableadd_library: 这两个命令分别是用来添加需要编译的可执行文件和库。如:
    add_executable(main ${SRC_LIST})
    
    • 1

    这个命令会生成一个可执行文件 main,源文件是通过前面 set 命令定义的 SRC_LIST 变量。

    add_library(my_lib STATIC ${SRC_LIST})
    
    • 1

    这个命令会生成一个静态库 my_lib,源文件是通过前面 set 命令定义的 SRC_LIST 变量。

    1. target_link_libraries: 这个命令用来为 target 添加需要链接的共享库。
    target_link_libraries(main my_lib)
    
    • 1
    1. include_directorieslink_directories: 这两个命令分别用于指定头文件的搜索路径和库文件的搜索路径。
    include_directories(${PROJECT_SOURCE_DIR}/include)
    link_directories(${PROJECT_SOURCE_DIR}/lib)
    
    • 1
    • 2
    1. find_package: 这个命令用来找系统中已存在的库。比如你的程序需要用到 Boost 库,你就需要使用此命令来找 Boost。
    find_package(Boost REQUIRED)
    if(Boost_FOUND)
        include_directories(${Boost_INCLUDE_DIRS})
        target_link_libraries(main ${Boost_LIBRARIES})
    endif()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这些是 CMakeLists.txt 中常用的一些命令,实际上 CMake 还支持更加复杂的语法,能够适应不同的编译需求。你可以在官方的文档中找到更详细的信息。

    四、配置和构建示例项目

    1. 创建一个名为"build"的目录,并进入该目录:
    mkdir build
    cd build
    
    • 1
    • 2
    1. 执行CMake命令生成构建文件:
    cmake ..
    
    • 1
    1. 使用生成的构建工具编译项目:
    make
    
    • 1
    1. 安装项目:
    make install
    
    • 1

    五、常见问题和使用技巧

    常见问题:

    1. CMake如何使用?

    CMake是一个跨平台的自动化构建工具,常用于C++项目。可以通过编写CMakeLists.txt文件来描述项目和配置构建过程。在控制台进入目标文件夹,然后运行cmake .即可开始构建。详细使用方法可以参考官方文档。

    1. 如何添加一个依赖库?

    可以通过find_package命令查找已安装的库,或者在CMakeLists.txt中添加依赖库的路径和链接方式。

    1. 如何设置编译选项?

    可以使用add_definitions命令添加编译器选项。例如,add_definitions(-DDEBUG)可以定义一个DEBUG宏。

    1. 如何设置输出路径?

    可以使用set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)命令指定可执行文件的输出路径。

    1. 如何使用外部头文件或源文件?

    可以使用include_directories命令添加头文件路径,或者通过add_library将外部源文件编译为库再进行链接。

    使用技巧:

    1. 使用target_link_libraries命令来链接库,这样可以避免手动设置链接路径和依赖关系。

    2. 在编写CMakeLists.txt文件时,应该将尽可能多的信息保存为变量,方便后续修改和维护。

    3. 可以使用file(GLOB sources "*.cpp")命令来自动搜索所有符合要求的源文件,方便管理。

    4. 如果需要编译多个可执行文件,可以使用add_executable()命令多次定义。同时,需要注意使用不同的变量名来保存源文件列表,避免相互覆盖。

    5. 在构建前应该清理CMake缓存。通常可以在构建目录中运行rm CMakeCache.txt命令来删除已有的缓存文件。

    佳实践:

    1. 建议将CMakeLists.txt文件拆分为多个小文件,并使用include命令进行引用。这样可以使文件结构更加清晰,方便维护。

    2. 建议使用CMake版本控制工具(如cmake-format)格式化代码和自动补全缺失的标准选项,以保证更好的代码风格和可读性。

    3. 建议使用CTest进行测试管理,该工具可以方便地为项目添加单元测试和集成测试。

    4. 建议在CMakeLists.txt中使用if语句来控制编译选项,例如根据平台或库是否安装来切换编译选项。

    5. 建议使用CMake的交叉编译功能,以支持在其他平台上构建项目。可以通过设置CMAKE_TOOLCHAIN_FILE路径来使用交叉编译。

    结论:
    CMakeLists.txt作为CMake构建系统的核心文件,为我们提供了一种简化项目构建过程的方式。通过了解CMakeLists.txt文件的结构和使用方法,我们可以更高效地管理项目的编译过程,提高开发效率。希望本文能够帮助读者更好地理解和使用CMake。

  • 相关阅读:
    python基于协同过滤推荐算法的电影观后感推荐管理系统的设计
    RGMII 与 GMII 转换电路设计
    前端面试题(三)
    【前端小程序】关于小程序中.env 文件夹
    Godot UI线程,Task异步和消息弹窗通知
    git patch 合入patch
    【sqlite3 如何避免插入重复数据】
    ElementUI入门及nodejs环境的搭建
    数据管理能力成熟度评估模型_DCMM解读
    Python基于Excel生成矢量图层及属性表信息:ArcPy
  • 原文地址:https://blog.csdn.net/weixin_37787043/article/details/134000097