【问题标题】:How can I set specific compiler flags for a specific target in a specific build configuration using CMake?如何使用 CMake 在特定构建配置中为特定目标设置特定编译器标志?
【发布时间】:2012-04-29 07:18:38
【问题描述】:

我有一个 CMakeLists,我想在其中使用 C 运行时的动态版本构建一些目标,并使用静态版本构建一些其他目标。

因为这需要针对每个目标进行设置,所以默认设置CMAKE_CXX_FLAGS_<Config>的方法不起作用;这会覆盖所有目标。

为此,我尝试了以下方法:

# @fn       set_target_dynamic_crt
# @brief    Sets the given target to use the dynamic version of the CRT (/MD or
#           /MDd)
# @param    ...  A list of targets to which this setting should be applied.
function( set_target_dynamic_crt )
    if ( MSVC )
        message (WARNING ${CMAKE_BUILD_TYPE})
        if (CMAKE_BUILD_TYPE STREQUAL "Debug")
            set_target_properties ( ${ARGN} PROPERTIES COMPILE_FLAGS "/MDd" )
        else()
            set_target_properties ( ${ARGN} PROPERTIES COMPILE_FLAGS "/MD" )
        endif()
    endif()
endfunction()

但是,这总是选择发布版本(/MD),当我查询构建类型(上面的message 调用)时,我得到空字符串。 (我怀疑这是因为我使用的是 Visual Studio 生成器;我已经看到不止一个引用说 CMAKE_BUILD_TYPE 仅适用于 makefile...)

如何为每个目标设置这样的编译选项?

【问题讨论】:

  • 现在有一个比下面显示的更好的解决方案来解决这个问题。我也发布了它,因为我遇到了同样的问题并且没有先找到您的问题,请参见此处:stackoverflow.com/questions/18065299/…

标签: c++ visual-c++ cmake


【解决方案1】:

在 CMake 2.8.12 中,我添加了一个 target_compile_options 命令来解决这个需求:

http://public.kitware.com/Bug/view.php?id=6493

http://www.cmake.org/cmake/help/git-master/manual/cmake-generator-expressions.7.html

target_compile_options(tgt PRIVATE "/MD$<$<CONFIG:Debug>:d>")

http://www.cmake.org/cmake/help/git-next/manual/cmake-buildsystem.7.html#build-specification-with-generator-expressions

有关 CMAKE_BUILD_TYPE 的更多信息以及生成器表达式更好的几个原因(例如 IMPORTED 目标配置映射)。

【讨论】:

  • 直到 2.8.12 才实现此功能的事实是我至今仍未使用 CMake 的原因之一。除此之外,直到版本 3.13 才引入了针对特定 linker 选项!在此之前,您必须使用 target_link_libraries 随意添加选项,而这并不是有意的。
【解决方案2】:

对于这种情况,我知道的唯一选择是将您的项目按目标拆分为子目录并使用add_subdirectory

根据您的项目当前的设置方式,我猜这可能是一个痛苦的过程。

结果将是一个顶级 CMakeLists.txt,看起来像例如

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Test)
add_subdirectory(libB)
add_subdirectory(libA)
add_executable(main_exe "main.cpp")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
target_link_libraries(main_exe lib_a lib_b)

那么libA/CMakeLists.txt 可以指定MDMDd 标志:

project(LibA)
add_library(lib_a a.cpp a.hpp)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")

libB/CMakeLists.txt 用于MTMTd 标志:

project(LibB)
add_library(lib_b b.cpp b.hpp)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")

如果您有很多目标,您当然可以将所有需要链接到静态 CRT 的目标添加到一个子目录中,并将 CMakeLists.txt 和所有动态 CRT 目标添加到另一个子目录中。

【讨论】:

  • 请注意,现在使用 target_compile_options() cmake 函数有更好的解决方案。它是全新的(2013 年 6 月),仅在每日编译中可用,但这很整洁!见这里:stackoverflow.com/questions/18065299/…
【解决方案3】:

CMAKE_BUILD_TYPE 仅对单配置生成器有效。多配置生成器(MSVC 和 Xcode)可以在一个构建目录中构建多个配置,因此 CMAKE_BUILD_TYPE 标志没有意义。

COMPILE_FLAGS 目标属性不区分不同的配置(有关详细信息,请参阅kitware bugtracker)。

一种解决方法是有两个构建目录,类似于人们使用 Makefile 生成器的方式,并在构建二进制文件以进行分发时定义一个附加标志。 (即 Release 配置)

【讨论】:

  • 这个变通方法不起作用——你最终不得不在无数不同的地方设置它。 (具体来说,要更改配置,你必须把所有一百多个项目都翻一遍,然后在构建时在VS IDE中进行更改等)
  • 不,我的意思是您应该使用您在问题中发布的确切代码,但不要使用 CMAKE_BUILD_TYPE,而是使用 MY_RELEASEBUILD,并且仅在您要创建用于分发的构建时才定义它。 (假设在本地运行时使用 /MDd 是可以的)
  • 但是你必须在VS里面选择正确的东西来匹配,并且不能为每个目标设置它。这样做的重点是能够使用 CMAke 的构建配置支持。
  • 不可能。不过,我认为我的理解并不正确。我提出了类似 mkdir build 的建议;光盘构建; cmake ../ ;光盘 .. ; mkdir 构建发布; cd 构建发布; cmake -DRELEASE_BUILD=1。是的,这很糟糕,但至少它可以让你在本地测试标志(它也适用于你的构建服务器等)
  • 它会导致比维护单独的特定于平台的 make 文件更难维护。是的,它在“工作”的反常意义上“工作”——但不是以证明成本合理的方式。
【解决方案4】:

假设我想将-On 选项添加到 vmovq_n_u8.c 并生成 vmovq_O3.out 和 vmovq_O0.out。我通过target_compile_options 完成了以下操作:

add_executable(vmovq_O3.out vmovq_n_u8.c)
add_executable(vmovq_O0.out vmovq_n_u8.c)

target_compile_options(vmovq_O3.out PRIVATE -O3)
target_compile_options(vmovq_O0.out PRIVATE -O0)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多