【问题标题】:Optimize in CMake by default默认在 CMake 中优化
【发布时间】:2017-05-12 17:05:26
【问题描述】:

我有一个使用 CMake 作为其构建系统的 C++ 项目。我想要以下行为:

如果 cmake 以cmake .. 调用,则CMAKE_CXX_FLAGS-O3 -Wall -Wextra

如果 cmake 以cmake .. -DCMAKE_BUILD_TYPE=Debug 调用,则CMAKE_CXX_FLAGS-g -Wall -Wextra

我尝试了以下

message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")

set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra")

但这有一个大问题。首先,如果使用第二次调用,那么-O3-g 标志都会传递给编译器。此外,如果我使用第二次调用和之后的第一次调用,CMAKE_BUILD_TYPE 将保持 Debug 尽管没有明确订购 - 所以我得到了一个 Debug 版本,尽管我想要一个优化的版本。

为什么?我该怎么做才能获得所需的行为?

【问题讨论】:

    标签: c++ cmake compiler-optimization


    【解决方案1】:

    首先:CMake 的推荐用法是始终在命令行上明确指定CMAKE_BUILD_TYPE(当且仅当使用单一配置生成器时)。您的用例偏离了此最佳实践,因此请将此答案视为“您如何做”,而不一定是“您应该如何做”。

    要解决第一个问题,您应该能够在 CMakeList 的早期执行此操作:

    if(NOT CMAKE_BUILD_TYPE)
      set(CMAKE_BUILD_TYPE Release)
    endif()
    
    set(CMAKE_CXX_FLAGS "-Wall -Wextra")
    set(CMAKE_CXX_FLAGS_DEBUG "-g")
    set(CMAKE_CXX_FLAGS_RELEASE "-O3")
    

    这将确保如果您根本不指定构建类型,它将默认为“发布”,因此将使用CMAKE_CXX_FLAGS_RELEASE

    第二个更难解决。从命令行传递的变量(例如CMAKE_BUILD_TYPE=Debug)由 CMake 缓存,因此在后续调用中重新使用(这是必要的,因为如果您在构建)。

    唯一的解决方案是让用户再次显式切换构建类型,使用cmake .. -DCMAKE_BUILD_TYPE=Release

    考虑为什么这是必要的:正如我所说,如果自上次 CMake 运行以来 CMake 的输入(CMakeLists.txt 文件或其依赖项)发生了变化,CMake 可以重新触发自身作为构建的一部分。在这种情况下,它也将在没有命令行参数(如-DCMAKE_BUILD_TYPE=whatever)的情况下运行,并将依赖缓存提供与上次相同的值。这种情况与您手动运行cmake .. 没有额外的参数没有区别。

    如果没有在命令行上明确指定,我可以提供一个 hacky 解决方案来始终将 CMAKE_BUILD_TYPE 重置为 Release。但是,这也意味着生成为Debug 的构建系统将在发生自动重新生成时重新生成为Release。我很确定这不是你想要的。

    【讨论】:

    • 这在我进行调试构建之前有效。在一次调试构建之后,所有后续的都是调试构建,即使使用了cmake ..
    • 我不记得我在哪里读过它,但从 CMakeLists.txt 中设置 CMAKE_BUILD_TYPE 被认为是不好的做法。更喜欢从 CMake 命令行传递它。
    • @marmistrz 我添加了关于为什么会发生这种情况以及如何“重置”它的更新。我正在想办法实现隐式重置,但这并不容易。
    • @roalz OP 首先想要相当非标准的 CMake 使用。不过,我会添加一个合适的免责声明。
    • “CMake 的推荐用法是始终在命令行上明确指定 CMAKE_BUILD_TYPE ...” - 不是根据这个 Debian 错误报告:CMake sets the default optimization level to -O3
    【解决方案2】:

    对于特定于发布目标的 CXX 标志,您应该设置
    CMAKE_CXX_FLAGS_RELEASE
    而不是
    CMAKE_CXX_FLAGS

    在您的情况下,您可以使用:

    设置(CMAKE_CXX_FLAGS“-Wall -Wextra”)
    设置(CMAKE_CXX_FLAGS_DEBUG“-g”)
    设置(CMAKE_CXX_FLAGS_RELEASE "-O3")

    this StackOverflow answer 中很好地描述了一种更现代的 CMake 方法(我建议,如果您使用的是 2.8.12 或更高版本),并且涉及使用 target_compile_options

    【讨论】:

    • 我会说“-g -O0”。
    • 但是当cmake ..-O3 没有传递给编译器
    • @n.m. gcc 默认情况下根本不优化
    • @marmistrz 是的,但它仍然不会受到伤害。
    • @marmistrz:当没有指定 CMAKE_BUILD_TYPE 时,使用 CMAKE_CXX_FLAGS,如 CMake wiki 中所述:cmake.org/Wiki/CMake_Useful_Variables
    【解决方案3】:

    各种发布模式的默认优化级别为O3,即often isn't the best choice。在CMakeLists.txt文件中,这些可以修改为O2:

    # Modify compile flags to change optimization level from O3 to O2
    string(REGEX REPLACE "([\\/\\-]O)3" "\\12"
      CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    string(REGEX REPLACE "([\\/\\-]O)3" "\\12"
      CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
    string(REGEX REPLACE "([\\/\\-]O)3" "\\12"
      CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
    string(REGEX REPLACE "([\\/\\-]O)3" "\\12"
      CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
    

    这些正则表达式将被修改(例如):

    • -O3-O2 通常用于基于 Linux 的编译器
    • /O3/O2 通常用于基于 Windows 的编译器

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-28
      • 1970-01-01
      • 2022-09-06
      • 1970-01-01
      • 1970-01-01
      • 2018-07-04
      • 1970-01-01
      相关资源
      最近更新 更多