c++项目结构与CMakeLists.txt

  • 写c++项目有一段时间了,以前对于项目中代码、编译文件、可执行文件以及项目中其他文件的组织不够有秩序,存放的路径位置有些松散。
  • 后来调整了下各种文件的文件夹归属,以及对应的如何在CMakeList.txt设置可执行文件输出目录,设置库文件的路径和源码的路径。
  • 以上仅仅是个人的使用习惯,如果可改善的地方,还望指出,谢谢!!

c++项目结构

文件树状图

├─.git
├─bin
│  ├─config
│  ├─Log
│  └─models
│      └─onnx
├─build
│  ├─.cmake
│  ├─CMakeFiles
│  ├─Release
│  └─x64
├─data
├─doc
├─lib
│  ├─camera
│  │  ├─include
│  │  └─lib
│  ├─cuda118
│  │  ├─include
│  │  └─lib
│  ├─curl
│  │  ├─bin
│  │  ├─include
│  │  └─lib
│  ├─freetype
│  │  ├─include
│  │  └─lib
│  │      ├─Debug
│  │      └─Release
│  ├─httplib
│  ├─libhv
│  │  ├─include
│  │  └─lib
│  ├─log4cpp
│  │  ├─include
│  │  └─lib
│  ├─nlohmann
│  │  └─include
│  ├─opencv411
│  │  ├─include
│  │  └─lib
│  ├─openssl
│  │  ├─bin
│  │  ├─include
│  │  └─lib
│  └─TensorRT-8.6.1.6
├─src
│  ├─algorithm
│  │ ├─InferWorker.cpp
│  │ ├─InferWorker.h
│  │ └─下同,省略
│  ├─application
│  ├─camera
│  ├─communication
│  ├─config
│  ├─logtool
│  ├─threadtool
│  ├─tool
│  ├─trtbase
│  └─main.cpp
├─.gitignore
├─CMakeLists.txt
├─README.md

文件层级说明

  • bin 项目生成的可执行程序等
    • config 项目的配置文件
    • Log 项目运行过程中产生的日志
    • models 项目运行时用到的模型
  • build 项目编译生成的文件
  • data 项目相关数据
  • doc 项目相关文档
  • lib 项目使用到的第三方库
    • 一般我会将库的头文件和库文件都一起放在这个目录里
  • src 项目源码
    • 每个模块的代码以文件夹区分
  • .gitignore git忽略配置文件
  • CMakeLists.txt
  • README.md 项目说明文档

CMakeLists.txt

设置项目的可执行文件生成路径

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE})

使用APPEND来添加头文件目录和库文件目录

list(APPEND Ex_INC_DIR "lib/camera/include")
list(APPEND Ex_Lib_DIR "lib/camera/lib")

list(APPEND Ex_INC_DIR "lib/freetype/include")
list(APPEND Ex_Lib_DIR "lib/freetype/lib")
# 下同省略

include_directories(${Ex_INC_DIR})
link_directories(${Ex_Lib_DIR})

使用函数收集文件夹下的源码

function(collect_files DIR VARIABLE_PREFIX)
    file(GLOB_RECURSE ${VARIABLE_PREFIX}_SRCS 
        "${DIR}/*.cpp"
        "${DIR}/*.c"
        "${DIR}/*.cxx"
    )
    file(GLOB_RECURSE ${VARIABLE_PREFIX}_HEADERSS 
        "${DIR}/*.h"
        "${DIR}/*.hpp"
        "${DIR}/*.hxx"
    )
    set(${VARIABLE_PREFIX}_HEADERS 
        ${${VARIABLE_PREFIX}_HEADERSS}
        # PARENT_SCOPE修改的是上一级作用域变量的值
        PARENT_SCOPE
    )
    set(${VARIABLE_PREFIX}_ALL_FILES 
        ${${VARIABLE_PREFIX}_SRCS}
        ${${VARIABLE_PREFIX}_HEADERSS}
        # PARENT_SCOPE修改的是上一级作用域变量的值
        PARENT_SCOPE
    )
endfunction()

collect_files(${CMAKE_SOURCE_DIR}/src DIR_src)
collect_files(${CMAKE_SOURCE_DIR}/src/algorithm DIR_algorithm)

set(ALL_FILES
    ${DIR_src_ALL_FILES}
    ${DIR_algorithm_ALL_FILES})

source_group(TREE ${CMAKE_SOURCE_DIR} FILES ${ALL_FILES})

add_executable(${PROJECT_NAME} ${ALL_FILES})

设置vs启动项

set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})

完整示例
  • 相似的操作省略掉了一些
cmake_minimum_required(VERSION 3.16)
project(ProjestName LANGUAGES CXX CUDA)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 设置输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE})

# 根据构建类型设置输出目录变量
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(OUTPUT_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG})
    set(LIB_SUFFIX "d")
else()
    set(OUTPUT_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE})
    set(LIB_SUFFIX "")
endif()

if(WIN32)
    add_definitions(-DNOMINMAX)  # 禁用min/max宏
    add_definitions(-DWIN32_LEAN_AND_MEAN)  # 减少Windows头文件
    add_definitions(-D_CRT_SECURE_NO_WARNINGS)  # 禁用安全警告
    
    # 如果是Visual Studio
    if(MSVC)
        # 设置字符集为UTF-8
        add_definitions(/utf-8)
        # 禁用特定警告
        add_compile_options(/wd4251)  # DLL接口警告
        add_compile_options(/wd4819)  # 代码页警告
        # 通用编译选项
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
        # Debug模式编译选项
        set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd /Zi /Od /RTC1")
        # Release模式编译选项
        set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD /O2 /DNDEBUG")
    endif()
endif()

list(APPEND Ex_INC_DIR "lib/camera/include")
list(APPEND Ex_Lib_DIR "lib/camera/lib")

list(APPEND Ex_INC_DIR "lib/freetype/include")
list(APPEND Ex_Lib_DIR "lib/freetype/lib")

if(WIN32)
    file(GLOB cam_Lib "lib/camera/lib/*64.lib")
    file(GLOB free_Lib "lib/freetype/lib/Release/*.lib")
else()
    file(GLOB cam_Lib "lib/camera/lib/x64/*.so")
    file(GLOB free_Lib "lib/freetype/lib/Release/*.so")
endif()

function(collect_files DIR VARIABLE_PREFIX)
    file(GLOB_RECURSE ${VARIABLE_PREFIX}_SRCS 
        "${DIR}/*.cpp"
        "${DIR}/*.c"
        "${DIR}/*.cxx"
    )
    file(GLOB_RECURSE ${VARIABLE_PREFIX}_HEADERSS 
        "${DIR}/*.h"
        "${DIR}/*.hpp"
        "${DIR}/*.hxx"
    )
    set(${VARIABLE_PREFIX}_HEADERS 
        ${${VARIABLE_PREFIX}_HEADERSS}
        # PARENT_SCOPE修改的是上一级作用域变量的值
        PARENT_SCOPE
    )
    set(${VARIABLE_PREFIX}_ALL_FILES 
        ${${VARIABLE_PREFIX}_SRCS}
        # 可选:添加头文件以便 IDE 显示
        ${${VARIABLE_PREFIX}_HEADERSS}
        # PARENT_SCOPE修改的是上一级作用域变量的值
        PARENT_SCOPE
    )
endfunction()

collect_files(${CMAKE_SOURCE_DIR}/src DIR_src)
collect_files(${CMAKE_SOURCE_DIR}/src/algorithm DIR_algorithm)

list(APPEND Ex_INC_DIR "src")
list(APPEND Ex_INC_DIR "src/algorithm")

set(ALL_FILES
    ${DIR_src_ALL_FILES}
    ${DIR_algorithm_ALL_FILES})

# 在 Visual Studio 中能保持文件夹结构,便于开发
source_group(TREE ${CMAKE_SOURCE_DIR} FILES ${ALL_FILES})

include_directories(${PROJECT_NAME} PRIVATE ${Ex_INC_DIR})
link_directories(${PROJECT_NAME} PRIVATE ${Ex_Lib_DIR})

add_executable(${PROJECT_NAME} ${ALL_FILES})

target_link_libraries(${PROJECT_NAME} ${cam_Lib})

# 设置启动项目
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})

if(MSVC) 
    # 方法1:直接全局设置(所有构建类型均生效)
    # add_compile_options(/Zi)      # 编译器选项:生成调试信息
    # add_link_options(/DEBUG)      # 链接器选项:生成调试符号

    # 方法2:针对 Release 模式单独设置(推荐)
    # 设置编译器选项(/Zi)
    target_compile_options(${PROJECT_NAME} PRIVATE
        "$<$<CONFIG:Release>:/Zi>"
    )
    # 设置链接器选项(/DEBUG)
    target_link_options(${PROJECT_NAME} PRIVATE
        "$<$<CONFIG:Release>:/DEBUG>"
    )
    target_compile_options(${PROJECT_NAME} PRIVATE "/wd4005")  # 忽略宏重定义警告

    set_target_properties(${PROJECT_NAME} PROPERTIES
    # 设置所有配置的默认调试工作目录为输出目录
    VS_DEBUGGER_WORKING_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
    )
else()
    target_compile_options(${PROJECT_NAME} PRIVATE "-Wno-macro-redefined")
endif()

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐