CMakelist.txt优化

东拼西凑把功能都实现了,回头看看CMakelist乱七八糟。把自己作为小白,整理下CMakelist的知识点并且优化一下本身的代码做一个记录。

目录

一、子目录CMakelist.txt

1.原代码:

2.理解:

3.可优化项/问题:

1.  手动设置 CMAKE_C_FLAGS 是低级用法

2.  pkg-config 的 CFLAGS 写入 CMAKE_C_FLAGS 是冗余且错误的

3.删掉: ${GST_LIBRARIES} hv ${OpenCV_INCLUDE_DIRS}

1. ${GST_LIBRARIES} 没有被保留,是因为:

 2. hv 不写,是因为已经用了变量 ${HV_LIB}:

4.set(EXTRA_LIBS ...) 不用写

问题总结

4.优化后代码:

二、根目录CMakelist.txt

1.原代码:

2.理解:

3.可优化项:

1.重复 pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)。

2.strEqualIgnoreCase函数根本没必要,可以使用cmake的add_compile_definitions。

3.很多没有必要的,写死的自定义头文件路径

4.有链接cuda库的话,最好告诉cmake

4.优化后代码:

优点:

三、疑问点:

1.为什么项目中会有多个 CMakeLists.txt(“大 CMakeLists” 和“小 CMakeLists”)

1. "大" CMakeLists.txt:顶层构建文件

2. "小" CMakeLists.txt:子模块或子目录构建文件

2.为什么大小的 CMakeLists.txt 都用 pkg_check_modules?能不能写一起

能不能写在一起?


一、子目录CMakelist.txt

1.原代码:

# configure a header file to pass some of the CMake settings to the source code
# 配置一个头文件,将部分 CMake 设置传入源码中
configure_file (
  "${PROJECT_SOURCE_DIR}/src/versionConfig.h.in"
  "${PROJECT_BINARY_DIR}/versionConfig.h"  
  )
# 设置 C 编译选项:无优化(-O0)、调试信息(-ggdb)、开启所有警告(-Wall)、保留帧指针(方便调试)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb -Wall -fno-omit-frame-pointer")
# 添加各个库对应的编译宏(来自 pkg-config 的 CFLAGS),确保头文件能正确识别
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GLIB_CFLAGS} ${GSTREAMER_CFLAGS} ${GSTREAMER_SDP_CFLAGS} ${GSTREAMER_WEBRTC_CFLAGS} ${JSON_GLIB_CFLAGS} ${LIBSOUP_CFLAGS}")
# 源文件列表,后续将用于创建静态库(add_library)
set(SOURCES
  base/relay.cpp
  base/panTilt.cpp
  base/utils.cpp
  base/video.cpp
  base/sentinel.cpp
  base/websocketlog.cpp
  base/preset.cpp
  base/database.cpp
  base/preview.cpp
  base/httpApi.cpp
  base/ota.cpp
  base/deviceInit.cpp
  base/crashHandler.cpp
  base/bird_man.cpp
  router.cpp
)
# 编译可执行程序,主函数在 main.cpp,辅助源文件 handler.cpp
add_executable(${PROJECT_NAME} main.cpp handler.cpp)

# strip the excecutable file when CMAKE_BUILD_TYPE=release
# 当构建类型为 Release 时,strip 可执行文件(去除符号表以减小体积)
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE  "-s")

# target_link_libraries(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_lib ${CRYPTO_LIB})
# 将之前的源码编译为一个静态库,方便多个目标共享
add_library(${PROJECT_NAME}_lib ${SOURCES})

# 设置需要链接的库变量(方便统一管理)
set(EXTRA_LIBS
    ${GST_LIBRARIES}
    ${GST_RTSP_SERVER_LIBRARIES}
    ${GLIB_LIBRARIES}
    ${GSTREAMER_LIBRARIES}
    ${GSTREAMER_SDP_LIBRARIES}
    ${GSTREAMER_WEBRTC_LIBRARIES}
    ${JSON_GLIB_LIBRARIES}
    ${SOUP_LIBRARIES}
    ${OpenCV_LIBS}
    ${HV_LIB}
    ${HV_HCCORE}
    ${HV_HCNET}
)
# 将这些库链接到静态库中
target_link_libraries(${PROJECT_NAME}_lib
    PUBLIC
    sqlite3
    pthread
    curl
    dl
    crypto   # sha256
    ${EXTRA_LIBS}
    ${GLIB_LIBRARIES}
    ${GSTREAMER_LIBRARIES}
    ${GSTREAMER_SDP_LIBRARIES}
    ${GSTREAMER_WEBRTC_LIBRARIES}
    ${JSON_GLIB_LIBRARIES}
    ${SOUP_LIBRARIES}
    ${HV_LIB}
    ${HV_HCCORE}
    ${HV_HCNET}
    cudart nvdsgst_meta nvds_meta nvds_yml_parser  curl  hv ${OpenCV_INCLUDE_DIRS}  /usr/lib/aarch64-linux-gnu
)


# 最终将库链接到主可执行程序 Laserbird
target_link_libraries(Laserbird
 	   ${PROJECT_NAME}_lib
         ${GSTREAMER_LIBRARIES} cudart nvdsgst_meta nvds_meta nvds_yml_parser  curl  hv ${OpenCV_INCLUDE_DIRS}  /usr/lib/aarch64-linux-gnu
    ${GSTREAMER_LIBRARIES} ${GSTREAMER_APP_LIBRARIES}
)	

2.理解:

CMAKE_C_FLAGS :

CMAKE_C_FLAGS 是一个 CMake 内置变量,用于设置 C语言编译时的全局编译选项(flags)

当在 CMake 中编译 .c 文件(C语言源文件)时,CMake 会将 CMAKE_C_FLAGS 中的内容作为参数传递给编译器(如 gccclang),例如:

set(CMAKE_C_FLAGS "-O2 -Wall")

表示:所有用 C 编写的源文件在编译时都会加上 -O2 -Wall

3.可优化项/问题:

1.  手动设置 CMAKE_C_FLAGS 是低级用法

  • 容易引发覆盖默认配置的行为。

  • target_compile_options()target_compile_definitions() 冲突。

  • 会污染所有 target 的编译选项,难以维护。

推荐使用:

target_compile_options(${PROJECT_NAME} PRIVATE -O0 -ggdb -Wall -fno-omit-frame-pointer)

2.  pkg-configCFLAGS 写入 CMAKE_C_FLAGS 是冗余且错误的

CMake 本来就已经通过 pkg_check_modules() 得到了包含路径变量:

  • GLIB_INCLUDE_DIRS

  • GLIB_LIBRARY_DIRS

直接通过 include_directories()link_directories() 来处理就够了。
不需要手动拼 -I/pathCMAKE_C_FLAGS

3.删掉: ${GST_LIBRARIES} hv ${OpenCV_INCLUDE_DIRS}

1. ${GST_LIBRARIES} 没有被保留,是因为:

在CMake 中,使用了:

pkg_check_modules(GST REQUIRED gstreamer-1.0)

这个会生成以下变量:

  • GST_LIBRARIES

  • GST_INCLUDE_DIRS

  • GST_CFLAGS

但在 EXTRA_LIBS 中,已经有了:

set(EXTRA_LIBS ${GST_LIBRARIES} ... )

并且最终 target_link_libraries(Laserbird) 已经包含了:

target_link_libraries(Laserbird Laserbird_lib ${EXTRA_LIBS} ... )

所以 GST_LIBRARIES 实际上是已经被链接进来了,就不需要单独再写一次(否则会重复)。


 2. hv 不写,是因为已经用了变量 ${HV_LIB}

之前有写:

find_library(HV_LIB hv)

然后在 EXTRA_LIBStarget_link_libraries 里面都已经写了:

${HV_LIB}

所以再写一次 hv 是重复的,甚至可能引发链接冲突。

统一用变量 ${HV_LIB} 更清晰、可控,万一未来换路径也方便。


target_link_libraries(Laserbird ... ${OpenCV_INCLUDE_DIRS} )

应该是:

target_link_libraries(Laserbird ... ${OpenCV_LIBS} )

因为:

  • OpenCV_INCLUDE_DIRS 是用于 include_directories() 加头文件路径的;

  • OpenCV_LIBS 才是链接 OpenCV 所需的库文件路径。

4.set(EXTRA_LIBS ...) 不用写

set(EXTRA_LIBS ...) 是为了方便统一管理多个库路径和名称,但不是必须的。可以不写 set(EXTRA_LIBS ...),直接把这些库展开写进 target_link_libraries(...),功能上没有区别。

set(EXTRA_LIBS a b c)等价于之后在 target_link_libraries() 中写:

target_link_libraries(my_target
  a b c
)
#写set这样
set(EXTRA_LIBS
    pthread
    curl
    dl
    crypto
    ${OpenCV_LIBS}
)

target_link_libraries(${PROJECT_NAME}_lib
    ${EXTRA_LIBS}
)
# 不写就这样
target_link_libraries(${PROJECT_NAME}_lib
    pthread
    curl
    dl
    crypto
    ${OpenCV_LIBS}
)

问题总结

问题描述优化建议
重复链接库多次链接同一个库,比如 curl, hv, OpenCV_INCLUDE_DIRS(误用)只链接一次,整理到一个 target_link_libraries()
变量误用OpenCV_INCLUDE_DIRS 用于头文件,但把它当库用了应使用 OpenCV_LIBS
直接使用路径作为库/usr/lib/aarch64-linux-gnu 被直接放入 link 中应通过 link_directories() 管理路径,或更好的是用 find_library()
CMake 风格不统一有些地方使用旧语法(比如 add_definitions),不推荐使用 target_compile_definitions 替代
CMake 可维护性差所有逻辑都堆在一起拆分成主 CMakeLists.txt 和子模块 src/CMakeLists.txt
宏设置堆叠复杂比如 CMAKE_C_FLAGS 多次 set合并设置逻辑,保持整洁

4.优化后代码:

# configure a header file to pass some of the CMake settings to the source code
# 配置一个头文件,将部分 CMake 设置传入源码中
configure_file (
  "${PROJECT_SOURCE_DIR}/src/versionConfig.h.in"
  "${PROJECT_BINARY_DIR}/versionConfig.h"  
  )
# # 设置 C 编译选项:无优化(-O0)、调试信息(-ggdb)、开启所有警告(-Wall)、保留帧指针(方便调试)
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb -Wall -fno-omit-frame-pointer")
# # 添加各个库对应的编译宏(来自 pkg-config 的 CFLAGS),确保头文件能正确识别
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GLIB_CFLAGS} ${GSTREAMER_CFLAGS} ${GSTREAMER_SDP_CFLAGS} ${GSTREAMER_WEBRTC_CFLAGS} ${JSON_GLIB_CFLAGS} ${LIBSOUP_CFLAGS}")

# # 给目标添加调试相关编译选项(只影响这个 target)
# target_compile_options(${PROJECT_NAME}_lib PRIVATE -O0 -ggdb -Wall -fno-omit-frame-pointer)
# target_compile_options(${PROJECT_NAME} PRIVATE -O0 -ggdb -Wall -fno-omit-frame-pointer)


# 源文件列表,后续将用于创建静态库(add_library)
set(SOURCES
  base/relay.cpp
  base/panTilt.cpp
  base/utils.cpp
  base/video.cpp
  base/sentinel.cpp
  base/websocketlog.cpp
  base/preset.cpp
  base/database.cpp
  base/preview.cpp
  base/httpApi.cpp
  base/ota.cpp
  base/deviceInit.cpp
  base/crashHandler.cpp
  base/bird_man.cpp
  router.cpp
)

# target_link_libraries(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_lib ${CRYPTO_LIB})
# 将之前的源码编译为一个静态库,方便多个目标共享
add_library(${PROJECT_NAME}_lib ${SOURCES})

# 目标库链接
target_link_libraries(${PROJECT_NAME}_lib
  PUBLIC
    sqlite3 pthread curl dl 
    crypto # sha256
    ${OpenCV_LIBS}
    ${GLIB_LIBRARIES}
    ${GSTREAMER_LIBRARIES}
    ${GSTREAMER_APP_LIBRARIES}
    ${GSTREAMER_SDP_LIBRARIES}
    ${GSTREAMER_WEBRTC_LIBRARIES}
    ${GST_RTSP_SERVER_LIBRARIES}
    ${JSON_GLIB_LIBRARIES}
    ${SOUP_LIBRARIES}
    ${HV_LIB}
    ${HV_HCCORE}
    ${HV_HCNET}
    cudart
    nvdsgst_meta
    nvds_meta
    nvds_yml_parser 
)

# 编译可执行程序,主函数在 main.cpp,辅助源文件 handler.cpp
add_executable(${PROJECT_NAME} main.cpp handler.cpp)
#把名为 ${PROJECT_NAME}_lib 的库 链接到目标 ${PROJECT_NAME} 上,并且使用的是 PRIVATE 可见性。
target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_lib)

# strip the excecutable file when CMAKE_BUILD_TYPE=release
# 当构建类型为 Release 时,strip 可执行文件(去除符号表以减小体积)
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE  "-s")

二、根目录CMakelist.txt


1.原代码:

# 禁止 in-source 构建,防止源码目录被污染(必须单独创建 build 目录)
if(" ${CMAKE_SOURCE_DIR}" STREQUAL " ${CMAKE_BINARY_DIR}")
  message(FATAL_ERROR "
FATAL: In-source builds are not allowed.
       You should create a separate directory for build files.
")
endif()
# 设定 CMake 最低版本为 3.10.0。
cmake_minimum_required(VERSION 3.10.0)
# 定义项目名 Laserbird,版本为 2.2.9。
project(Laserbird VERSION 2.2.9)

# 自定义函数 strEqualIgnoreCase,用于大小写无关字符串比较。
Function(strEqualIgnoreCase isEqual str1 str2)
  string(TOLOWER ${str1} first)
  string(TOLOWER ${str2} second)
  string(COMPARE EQUAL "${first}" "${second}" equal)
  set(${isEqual} ${equal} PARENT_SCOPE)
endfunction(strEqualIgnoreCase)

# Debug by default, strip the excecutable file when release
# 若未设置构建类型,则默认启用 Debug 模式并添加宏 DEBUG。
# 若设置了构建类型但是 Debug(不区分大小写),也添加宏 DEBUG。
# 最后打印当前的构建类型。
if (NOT CMAKE_BUILD_TYPE)
  add_definitions(-DDEBUG)
  # set(CMAKE_BUILD_TYPE Debug)
  set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type" FORCE)
else()
  strEqualIgnoreCase(isDebug ${CMAKE_BUILD_TYPE} "debug")
  if (isDebug)
    add_definitions(-DDEBUG)
  endif()
endif()
message("buildtype: " ${CMAKE_BUILD_TYPE})

# 添加 JWT 开关,默认开启crypto。
# 如果开启了,就定义宏 JWT,并寻找 libcrypto。
# 若找不到则提醒。
option(JWT "Whether to enable JWT" ON)
if (${JWT})
  add_definitions(-DJWT)
  find_library(CRYPTO_LIB crypto REQUIRED)
  if(NOT CRYPTO_LIB)
    message("crypto not found")
  endif()
endif()
# 设置最终可执行文件输出路径为 build/bin。
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

# 设置 CUDA 架构为 7.5(即支持 Turing 架构,如 RTX 20 系列)。
# 设置 CUDA 和 C++ 的标准为 C++14。
set(CMAKE_CUDA_ARCHITECTURES 75)
set(CMAKE_CUDA_STANDARD 14)
set(CMAKE_CXX_STANDARD 14)

# 加头文件搜索路径,例如 include 文件夹、${PROJECT_BINARY_DIR} 生成的 versionConfig.h 文件等。
include_directories(include  "${PROJECT_BINARY_DIR}")
include_directories(/home/comnova)
# preview include
include_directories(/usr/include/glib-2.0)
include_directories(/usr/lib/aarch64-linux-gnu/glib-2.0/include)
include_directories(/usr/include/gstreamer-1.0)
include_directories(/usr/include/libsoup-2.4)
include_directories(/usr/include/json-glib-1.0)
# include_directories(/usr/lib/aarch64-linux-gnu/pkgconfig)

# 查找 libhv;
# 若找不到就假设使用源码方式编译 libhv,并添加其子目录。
find_library(HV_LIB hv)
if(NOT HV_LIB)
  set(HV_LIB hv)
  message("hv not found: compile with source code")
  add_subdirectory(third_party/libhv)
endif()
# 查找 SDK 所需的 HCCore 和 HCNet 库。
find_library(HV_HCCORE HCCore REQUIRED)
if(NOT HV_HCCORE)
   message("HCCORE not found")
endif()

find_library(HV_HCNET hcnetsdk REQUIRED)
if(NOT HV_HCNET)
   message("HCNET not found")
endif()

# 添加额外的 CMake 模块查找路径(通常用于自定义 .cmake 文件)。
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")


# 查找所需的包
# 使用 pkg-config 工具查找并配置 GStreamer、RTSP、WebRTC、OpenCV、GLib 等依赖库。
find_package(PkgConfig REQUIRED)
pkg_check_modules(GST REQUIRED gstreamer-1.0)
pkg_check_modules(GST_RTSP_SERVER REQUIRED gstreamer-rtsp-server-1.0)

find_package(TensorRT REQUIRED)
find_package(OpenCV REQUIRED)
pkg_check_modules(GLIB REQUIRED glib-2.0)
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
pkg_check_modules(GSTREAMER_SDP REQUIRED gstreamer-sdp-1.0)
pkg_check_modules(GSTREAMER_WEBRTC REQUIRED gstreamer-webrtc-1.0)
pkg_check_modules(JSON_GLIB REQUIRED json-glib-1.0)
pkg_check_modules(SOUP REQUIRED libsoup-2.4)

set(LIB_INSTALL_DIR /opt/nvidia/deepstream/deepstream/lib/)
set(APP_INSTALL_DIR /opt/nvidia/deepstream/deepstream/bin/)
set(APP_INSTALL_ROOT /opt/nvidia/deepstream/deepstream)

# appsink appsrc
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
pkg_check_modules(GSTREAMER_APP REQUIRED gstreamer-app-1.0)
# 添加 appsrc/appsink 的头文件路径;
# 添加链接库路径。
include_directories(${GSTREAMER_APP_INCLUDE_DIRS})
link_directories(${GSTREAMER_LIBRARY_DIRS} ${GSTREAMER_APP_LIBRARY_DIRS})


# 包含头文件路径
include_directories(
    ${GLIB_INCLUDE_DIRS}
    ${GSTREAMER_SDP_INCLUDE_DIRS}
    ${GSTREAMER_WEBRTC_INCLUDE_DIRS}
    ${JSON_GLIB_INCLUDE_DIRS}
    ${SOUP_INCLUDE_DIRS}
    ${OpenCV_INCLUDE_DIRS}
    /usr/local/cuda/include
    ${GSTREAMER_INCLUDE_DIRS}
    ${GST_RTSP_SERVER_INCLUDE_DIRS}
    ${APP_INSTALL_ROOT}/sources/includes
    /usr/lib/aarch64-linux-gnu/
    /home/comnova/Downloads/LFL/bird_man/includes
    /home/comnova/Downloads/LFL/bird_man/includes/libhv/include
    /home/comnova/bird_man/includes/libhv/include/hv
)

# 链接库路径
# 合并了各个依赖库和项目内部路径,供头文件查找使用。
link_directories(
    ${GLIB_LIBRARY_DIRS}
    ${GSTREAMER_LIBRARY_DIRS}
    ${GSTREAMER_SDP_LIBRARY_DIRS}
    ${GSTREAMER_WEBRTC_LIBRARY_DIRS}
    ${JSON_GLIB_LIBRARY_DIRS}
    ${SOUP_LIBRARY_DIRS}
    ${LIB_INSTALL_DIR}
    ${GST_RTSP_SERVER_LIBRARY_DIRS}
    /usr/local/cuda/lib64
)
# 进入 src 子目录编译代码,src/CMakeLists.txt 必须存在。
add_subdirectory(src)
# 设置编译器选项
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GLIB_CFLAGS_OTHER} ${GSTREAMER_CFLAGS_OTHER} ${GSTREAMER_SDP_CFLAGS_OTHER} ${GSTREAMER_WEBRTC_CFLAGS_OTHER} ${JSON_GLIB_CFLAGS_OTHER} ${SOUP_CFLAGS_OTHER}")

2.理解:

  • 防止 in-source 构建,保护源码。

  • 明确设置最低 CMake 版本和项目版本。

  • 使用自定义函数做大小写无关比较,逻辑清晰。

  • 设置 Debug 默认选项,且根据不同构建类型设置宏。

  • 使用 option 控制 JWT 功能,灵活配置。

  • 利用 pkg_check_modules 查找依赖包,系统化管理依赖。

  • 明确设置 CUDA 架构和语言标准。

  • 清晰的 include_directorieslink_directories

  • 处理第三方库 hv 的查找和源码编译。

  • 组织结构清晰,利用子目录组织源代码。

3.可优化项:

1.重复 pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)

2.strEqualIgnoreCase函数根本没必要,可以使用cmake的add_compile_definitions。

3.很多没有必要的,写死的自定义头文件路径

其他网关里面没有,会导致编译报错

    /home/comnova/Downloads/LFL/bird_man/includes

    /home/comnova/Downloads/LFL/bird_man/includes/libhv/include

    /home/comnova/bird_man/includes/libhv/include/hv

4.有链接cuda库的话,最好告诉cmake

project(Laserbird VERSION 2.2.9 LANGUAGES C CXX CUDA)

4.优化后代码:

# 禁止 in-source 构建,防止源码目录被污染(必须单独创建 build 目录)
if(" ${CMAKE_SOURCE_DIR}" STREQUAL " ${CMAKE_BINARY_DIR}")
  message(FATAL_ERROR "
FATAL: In-source builds are not allowed.
       You should create a separate directory for build files.
")
endif()
# 设定 CMake 最低版本为 3.10.0。
cmake_minimum_required(VERSION 3.10.0)
# 定义项目名 Laserbird,版本为 2.2.9。有链接cuda库最好加上
project(Laserbird VERSION 2.2.9 LANGUAGES C CXX CUDA) 

# 若未设置构建类型,则默认启用 Debug 模式并添加宏 DEBUG。
#  使用add_compile_definitions
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type" FORCE)
endif()

string(TOLOWER "${CMAKE_BUILD_TYPE}" build_type_lower)
if(build_type_lower STREQUAL "debug")
  add_compile_definitions(DEBUG)
endif()

# 添加 JWT 开关,默认开启。如果开启了,就定义宏 JWT,并寻找 libcrypto。
option(JWT "Enable JWT support" ON)
if(JWT)
  add_compile_definitions(JWT)
endif()

# 查找 libcrypto(JWT需要)
if(JWT)
  find_library(CRYPTO_LIB crypto REQUIRED)
  if(NOT CRYPTO_LIB)
    message(WARNING "libcrypto not found, JWT might not work properly")
  endif()
endif()

# 添加额外的 CMake 模块查找路径(通常用于自定义 .cmake 文件)。
# 用于查找TensorRT
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

# 使用 pkg-config 工具查找并配置 GStreamer、RTSP、WebRTC、OpenCV、GLib 等依赖库。
find_package(PkgConfig REQUIRED)

pkg_check_modules(GST REQUIRED gstreamer-1.0)
pkg_check_modules(GST_RTSP_SERVER REQUIRED gstreamer-rtsp-server-1.0)
pkg_check_modules(GLIB REQUIRED glib-2.0)
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
pkg_check_modules(GSTREAMER_SDP REQUIRED gstreamer-sdp-1.0)
pkg_check_modules(GSTREAMER_WEBRTC REQUIRED gstreamer-webrtc-1.0)
pkg_check_modules(JSON_GLIB REQUIRED json-glib-1.0)
pkg_check_modules(SOUP REQUIRED libsoup-2.4)
# appsink appsrc
pkg_check_modules(GSTREAMER_APP REQUIRED gstreamer-app-1.0)

find_package(TensorRT REQUIRED)
find_package(OpenCV REQUIRED)

# 查找 libhv;若找不到就假设使用源码方式编译 libhv,并添加其子目录。
find_library(HV_LIB hv)
if(NOT HV_LIB)
  set(HV_LIB hv)
  message("hv not found: compile with source code")
  add_subdirectory(third_party/libhv)
endif()

# 查找 SDK 所需的 HCCore 和 HCNet 库。
find_library(HV_HCCORE HCCore REQUIRED)
if(NOT HV_HCCORE)
   message("HCCORE not found")
endif()

find_library(HV_HCNET hcnetsdk REQUIRED)
if(NOT HV_HCNET)
   message("HCNET not found")
endif()

# 设置 CUDA 架构为 7.5(即支持 Turing 架构,如 RTX 20 系列),CUDA 和 C++ 的标准为 C++14。
set(CMAKE_CUDA_ARCHITECTURES 75)
set(CMAKE_CUDA_STANDARD 14)
set(CMAKE_CXX_STANDARD 14)

# 设置最终可执行文件输出路径为 build/bin。
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

# -------------------------------
# 没有使用这些变量的地方,cmake不会自动使用它们,除非显式调用
set(LIB_INSTALL_DIR /opt/nvidia/deepstream/deepstream/lib/)
set(APP_INSTALL_ROOT /opt/nvidia/deepstream/deepstream/sources/includes)

# 包含头文件路径
include_directories(
    ${GLIB_INCLUDE_DIRS}
    ${GSTREAMER_SDP_INCLUDE_DIRS}
    ${GSTREAMER_WEBRTC_INCLUDE_DIRS}
    ${JSON_GLIB_INCLUDE_DIRS}
    ${SOUP_INCLUDE_DIRS}
    ${OpenCV_INCLUDE_DIRS}
    /usr/local/cuda/include
    ${GSTREAMER_INCLUDE_DIRS}
    ${GST_RTSP_SERVER_INCLUDE_DIRS}
    ${GSTREAMER_APP_INCLUDE_DIRS} 
    include  "${PROJECT_BINARY_DIR}"
    /home/comnova
    # preview include
    /usr/include/glib-2.0
    /usr/lib/aarch64-linux-gnu/glib-2.0/include
    /usr/include/gstreamer-1.0
    /usr/include/libsoup-2.4
    /usr/include/json-glib-1.0
    ${APP_INSTALL_ROOT}
)

# 统一链接库目录
set(COMMON_LINK_DIRS
  ${GLIB_LIBRARY_DIRS}
  ${GSTREAMER_LIBRARY_DIRS}
  ${GSTREAMER_SDP_LIBRARY_DIRS}
  ${GSTREAMER_WEBRTC_LIBRARY_DIRS}
  ${JSON_GLIB_LIBRARY_DIRS}
  ${SOUP_LIBRARY_DIRS}
  ${LIB_INSTALL_DIR}
  ${GST_RTSP_SERVER_LIBRARY_DIRS}
  ${GSTREAMER_APP_LIBRARY_DIRS}
  /usr/local/cuda/lib64
)

# 将链接库路径加入全局(也可改为target_link_directories绑定具体目标)
link_directories(${COMMON_LINK_DIRS})
# 进入 src 子目录编译代码,src/CMakeLists.txt 必须存在。
add_subdirectory(src)
优点:
  • 禁止 in-source 构建:防止污染源码。

  • 编译类型控制:自动设置为 Debug 并定义宏,调试友好。

  • 选项配置(如 JWT):支持可选组件,方便扩展。

  • 依赖项查找清晰:利用 pkg_check_modules 管理依赖,清楚易改。

  • 头文件和库路径配置全面:考虑到 DeepStream、GLib、GStreamer 等,覆盖全面。

  • src 子目录管理:模块化项目结构,推荐实践。

  • 兼顾 CUDA 支持:未来如需集成加速,非常方便。

三、疑问点:

1.为什么项目中会有多个 CMakeLists.txt(“大 CMakeLists” 和“小 CMakeLists”)

1. "大" CMakeLists.txt:顶层构建文件

  • 位于项目根目录(通常是项目的 Laserbird/ 根目录)。

  • 作用是整体配置整个工程(项目名、构建类型、全局依赖库、头文件目录等)。

  • 它负责调用子目录构建,例如:

add_subdirectory(src)

2. "小" CMakeLists.txt:子模块或子目录构建文件

  • 位于 src/src/base/ 等子目录中。

  • 专注于构建该子模块的目标,例如编译 .cpp 源文件、设置自己的依赖。

  • 由“大的”CMakeLists 用 add_subdirectory() 加入。

    示例:src/CMakeLists.txt 里可能会写:

add_library(${PROJECT_NAME}_lib
    base/relay.cpp
    base/utils.cpp
    ...
)
原因说明
模块化管理每个模块(如 src/base)负责自己的构建逻辑,避免顶层文件过于臃肿。
可维护性强项目增大后,逻辑拆分清晰,团队协作更容易。
可重用性子模块可以单独构建/调试,甚至复用到别的项目。
递归构建CMake 会递归读取并构建每个 add_subdirectory() 加入的模块。
类型路径作用
大 CMakeLists项目根目录设置全局变量、项目名称、依赖、入口点等
小 CMakeLists子模块目录(如 src/设置子模块源文件、编译规则、依赖、输出等

2.为什么大小的 CMakeLists.txt 都用 pkg_check_modules?能不能写一起

  • 顶层 CMakeLists.txt:用于总体管理项目(设置版本、子模块、全局变量等);

  • 子模块 CMakeLists.txt(例如在 src/third_party/ 中):每个模块需要自己依赖某些库,所以也用 pkg_check_modules

能不能写在一起?

  • 能,但不推荐所有都写在顶层。因为有些模块可能不需要全部依赖库,把所有 pkg_check_modules 写到顶层会导致不必要的依赖增加。

  • 模块化设计推荐:

    • 顶层只查找全局共享的库(如 glib);

    • 每个子模块根据需要调用 pkg_check_modules 处理自身依赖(如 json-glib、opencv、gstreamer);

    • 再通过 target_include_directories()target_link_libraries() 精确添加依赖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值