cmake多exe生成设计

本文详细描述了一个使用CMake构建的项目结构,涉及环境设置、输出目录、库目录配置、Qt5组件查找、依赖项链接以及动态链接库的复制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目结构

在这里插入图片描述

项目Cmake

project(DemoApp)
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11)

message(STATUS "CMAKE_BUILD_TYPE is ${CMAKE_BUILD_TYPE}")

#设置环境相关
message(STATUS "====================set env===================")
set(PROJECT_OUTPUT_DIR ${PROJECT_SOURCE_DIR}/bin)
message(STATUS "PROJECT_OUTPUT_DIR is ${PROJECT_OUTPUT_DIR}")

set(PROJECT_LIBRARY_DIR ${PROJECT_SOURCE_DIR}/Library)
set(PROJECT_LIBRARY_INCLUDE_DIR ${PROJECT_LIBRARY_DIR}/${CMAKE_BUILD_TYPE}/include)
set(PROJECT_LIBRARY_LIB_DIR ${PROJECT_LIBRARY_DIR}/${CMAKE_BUILD_TYPE}/lib)
set(PROJECT_LIBRARY_DLL_DIR ${PROJECT_LIBRARY_DIR}/${CMAKE_BUILD_TYPE}/dll)
message(STATUS "PROJECT_LIBRARY_DIR is ${PROJECT_LIBRARY_DIR}")
message(STATUS "PROJECT_LIBRARY_INCLUDE_DIR is ${PROJECT_LIBRARY_INCLUDE_DIR}")
message(STATUS "PROJECT_LIBRARY_LIB_DIR is ${PROJECT_LIBRARY_LIB_DIR}")
message(STATUS "PROJECT_LIBRARY_DLL_DIR is ${PROJECT_LIBRARY_DLL_DIR}")

#同时生成lib与DLL
message(STATUS "PROJECT_BINARY_DIR is ${PROJECT_BINARY_DIR}")
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIR}) #DLL生成路径
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) #lib生成路径
set(CMAKE_PDB_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) #pdb生成路径

# 处理编译字符集问题
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")

#设置QT相关配置
message(STATUS "====================set QT===================")
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

#定义QT路径,如果环境变量QT_PATH存在,则使用环境变量,否则使用默认路径
if (DEFINED ENV{QTDIR})
    set(CMAKE_PREFIX_PATH $ENV{QTDIR}/msvc2017_64/lib/cmake)
else ()
    set(CMAKE_PREFIX_PATH D:/Library/Qt5.14.2/5.14.2/msvc2017_64/lib/cmake) # 配置QT路径
endif ()
message(STATUS "CMAKE_PREFIX_PATH is ${CMAKE_PREFIX_PATH}")

find_package(Qt5 COMPONENTS # 查找QT的模块
        Core
        Gui
        Widgets
        SerialPort
        WebSockets
        Network
        REQUIRED)
set(PROJECT_REQUIRED_QT5_DLL Core Gui Widgets SerialPort WebSockets Network)
message(STATUS "Qt5Gui_PRIVATE_INCLUDE_DIRS is ${Qt5Gui_PRIVATE_INCLUDE_DIRS}")

#设置项目依赖相关配置
message(STATUS "====================set project depedency===================")
#定义头文件需要寻址的路径
include_directories(
        ${PROJECT_LIBRARY_INCLUDE_DIR} #头文件
        ${Qt5Gui_PRIVATE_INCLUDE_DIRS} #QTGUI库默认头文件路径
        DemoApp/include #模块头文件
        DemoApp1/include #模块头文件
)
#定义库文件需要寻址的路径
link_directories(
        ${PROJECT_LIBRARY_LIB_DIR}
)

#设置子目录相关配置
message(STATUS "====================set subdirectory===================")
add_subdirectory(DemoApp)
add_subdirectory(DemoApp1)


DemoApp

#定义头文件路径
include_directories(./include)

#把目录src和inc下面的所有文件作为变量存储
file(GLOB_RECURSE SRC_FILES "src/*")
file(GLOB_RECURSE INC_FILES "include/*")

#静态资源设置文件
set(QRC_FILES ./assets.qrc)

add_executable(DemoApp ${SRC_FILES} ${INC_FILES} ${QRC_FILES})
target_link_libraries(DemoApp
        Qt5::Core
        Qt5::Gui
        Qt5::Widgets
        Qt5::WebSockets
        Qt5::Network
)


#设置依赖的QT DLL及外部DLL拷贝名、配置文件
file(GLOB_RECURSE MY_COMPONENTS "${PROJECT_LIBRARY_DLL_DIR}/*")
file(GLOB_RECURSE MY_CONFIGS "${PROJECT_SOURCE_DIR}/config/*")

if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
    set(DEBUG_SUFFIX)
    if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
        set(DEBUG_SUFFIX "d")
    endif ()

    #往上跳2级找到bin目录
    set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")
    if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
        set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
        if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
            set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
        endif ()
    endif ()

    if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll" "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
    endif ()

    #拷贝QT的DLL
    foreach (QT_LIB ${PROJECT_REQUIRED_QT5_DLL})
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll" "${PROJECT_OUTPUT_DIR}")
        message(STATUS "COPY QT_LIB ${QT_LIB}")
    endforeach (QT_LIB)
    
    #拷贝依赖的DLL和exe
    foreach (MY_COMPONENT ${MY_COMPONENTS})
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${MY_COMPONENT}" "${PROJECT_OUTPUT_DIR}")
        message(STATUS "COPY MY_COMPONENT ${MY_COMPONENT}")
    endforeach (MY_COMPONENT)

    #如果本地存在配置文件夹,则在输出目录先建目录,再拷贝config文件
    if (EXISTS "${PROJECT_SOURCE_DIR}/config/")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_OUTPUT_DIR}/config/")
        message(STATUS "CREATE config path is ${PROJECT_SOURCE_DIR}/config/")

        #拷贝依赖的xml文件
        foreach (MY_CONFIG ${MY_CONFIGS})
            add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${MY_CONFIG}" "${PROJECT_OUTPUT_DIR}/config/")
            message(STATUS "COPY MY_CONFIG ${MY_CONFIG}")
        endforeach (MY_CONFIG)
    endif ()
endif ()

DemoApp1

#定义头文件路径
include_directories(./include)

#把目录src和inc下面的所有文件作为变量存储
file(GLOB_RECURSE SRC_FILES "src/*")
file(GLOB_RECURSE INC_FILES "include/*")

add_executable(DemoApp1 ${SRC_FILES} ${INC_FILES})
target_link_libraries(DemoApp1
        Qt5::Core
        Qt5::Gui
        Qt5::Widgets
        Qt5::WebSockets
        Qt5::Network
)


<think>嗯,用户这次想了解CMake生成器表达式的返回值和用途,而且特别提到要参考之前的回答和引用材料。看来用户是在深入学习CMake的高级特性,可能正在处理实际的跨平台构建问题。翻看对话历史,我之前已经详细解释过生成器表达式的作用原理和典型场景,包括条件化配置、避免属性外溢等核心功能。用户现在聚焦在“返回值”这个具体层面,说明ta需要更精确的技术细节。注意到系统指令要求严格的数学公式格式(虽然CMake内容基本用不到LaTeX数学公式),但需要在示例代码中谨慎处理符号转义。用户提供的四个引用材料里,[1][2][3]是CMake官方资源,[4]虽然关于LLVM但展示了AST处理思路,可以类比生成器表达式的解析过程。用户可能遇到的实际问题是:为什么表达式在某些条件下返回空值?或者如何组合个表达式返回值?尤其需要强调两类返回类型:1)布尔表达式在条件不满足时实际上返回空字符串(相当于false),例如$<CONFIG:Debug>在Release模式下会展开为空2)路径表达式在不同生成器下返回值差异,比如$<TARGET_FILE>在Windows返回.exe,而Linux无扩展名特别要解释清楚“返回值的延迟性”——所有生成器表达式在configure阶段都是未展开的字符串,直到generate阶段才变成具体值。这正好对应引用[2]提到的cmake命令工作流程。在回答结构上,应该先分类返回值类型(布尔/字符串/调试),再分别说明各类的转换规则和典型用途。对于用户可能困惑的点,比如为何布尔表达式不直接返回true/false,而用1/空值,要结合CMake设计哲学解释(兼容各构建系统语法)。最后生成的相关问题要引导用户走向更深入的应用场景,比如返回值在install规则中的特殊处理(引用[1]的OpenCV项目就大量使用这类技巧)。</think> CMake生成器表达式(Generator Expressions)在生成构建系统时**动态计算并返回字符串或布尔值**,其返回值类型和用途如下: --- ### 一、返回值的两种类型 1. **字符串类型** ```cmake $<TARGET_FILE_BASE_NAME:myapp> # 返回"myapp"(不含扩展名)[^1] $<PLATFORM_ID> # 返回当前平台ID,如"Linux"、"Windows" ``` **用途**:动态生成路径、编译器选项、文件名等,例如: ```cmake set(output_name "$<TARGET_FILE_NAME:app>$<CONFIG:DEBUG>:_debug>") # Release模式返回"app", Debug模式返回"app_debug" ``` 2. **布尔类型(0/1)** ```cmake $<CONFIG:Debug> # Debug模式下返回1,否则0 $<CXX_COMPILER_ID:GNU> # GCC编译器返回1,否则0 ``` **用途**:条件化控制编译逻辑,例如: ```cmake target_compile_options(app PRIVATE "$<$<CONFIG:DEBUG>:-O0;-g>" # 仅Debug模式添加调试选项 ) ``` --- ### 二、核心应用场景 #### 1. 跨平台路径处理 ```cmake install(TARGETS app DESTINATION bin/$<PLATFORM_ID>) # 安装到bin/Linux或bin/Win64[^2] ``` #### 2. 编译器差异化配置 ```cmake target_compile_definitions(app PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>" "$<$<CXX_COMPILER_ID:GNU>:USE_GNU_EXTENSIONS>" ) ``` #### 3. 构建/安装路径隔离 ```cmake target_include_directories(app PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>" # 构建时使用源码目录 "$<INSTALL_INTERFACE:include>" # 安装后使用系统目录[^1] ) ``` #### 4. 目标间依赖传递 ```cmake add_custom_command(TARGET app POST_BUILD COMMAND $<TARGET_FILE:test_runner> verify_app # 动态获取test_runner路径[^3] ) ``` --- ### 三、特殊返回规则 1. **嵌套表达式** ```cmake "$<$<AND:$<CONFIG:DEBUG>,$<PLATFORM_ID:Linux>>:-fsanitize=address>" # 仅在Linux+Debug时返回-fsanitize=address ``` 2. **空值处理** 条件不满足时返回空字符串,避免语法错误: ```cmake "$<$<PLATFORM_ID:Darwin>:-framework CoreFoundation>" # 非macOS返回空 ``` > 表达式在`cmake --build`阶段展开(非configure阶段),可通过`cmake -E echo "表达式"`验证返回值[^2]。 --- ### 四、典型示例分析 ```cmake set(EXTENSION "$<$<PLATFORM_ID:Windows>:.exe>") add_executable(app main.cpp) set_target_properties(app PROPERTIES SUFFIX $<CONFIG>_${EXTENSION} # Release模式返回".exe",Debug返回"_DEBUG.exe" ) ``` - **Windows+Release** → `.exe` - **Windows+Debug** → `_DEBUG.exe` - **Linux+Release** → 空后缀 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值