在项目中更改CMAKE_CXX_FLAGS

53

我在我的CMakeLists.txt中有以下内容:

project( Matfile )

SET ( CMAKE_CXX_FLAGS "-std=c++0x" )

set ( SOURCES
      "foo.cpp"
      "bar.cpp"
    )

add_library(
        Matfile
        ${SOURCES}
)

作为你的助手,我将翻译以下内容。这是关于编程的问题。
正如你所想象的那样,我想做的是使用标志-std=c++0x编译我的C++源代码(我正在使用gcc,需要C++11功能)。不幸的是,这并不起作用,因为当我使用cmake生成makefile时,变量CMAKE_CXX_FLAGS完全无效。
如何在项目文件中设置此变量?
这似乎是一个非常愚蠢的问题,但我花了不少于两个小时来弄清楚这个问题。

set 命令对于标志看起来格式良好(尽管对于 gcc v4.7 及以后版本,标志应该是 -std=c++11)。你所说的“完全无效”是什么意思?如果运行 make VERBOSE=1,输出是什么? - Fraser
2
可能在Makefile中正确设置了CMAKE_CXX_FLAGS,但在CMakeCache.txt文件中显示为空。因此,在CMakeCache中检查是不够的,除非您强制将其写回缓存(使用set(var value CACHE STRING "" FORCE))。 - Alexander Oh
11个回答

65

如果您使用的是2.8.12或更新版本,则最直接的解决方案应该是使用add_compile_options()。 对于旧版本,您可以“滥用”add_definitions()。 尽管它仅用于添加-D标志,但它也适用于任何其他编译器标志。 但是,我认为它不应该被这样使用,并且在将来的版本中可能会出现问题。

add_compile_options(-std=c++0x) # CMake 2.8.12 or newer
或者
add_definitions(-std=c++0x) # CMake 2.8.11 or older

从CMake 3.3开始,您还可以使用奇怪的生成器表达式语法将此标志仅应用于特定语言(例如只有C或C ++):

 add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-std=c++14> $<$<COMPILE_LANGUAGE:C>:-std=c99>)

然而,这将无法与Visual Studio生成器一起使用,因此请确保仅在Make/Ninja生成器中使用它,或使用target_compile_options()在每个目标范围内设置它。


4
好的,但是在这种情况下存在一个问题,这些参数不仅被添加到 CXX 而且也被添加到 C_COMPILER 中,而 C 不支持一些专门用于 CXX 的参数,尤其是 -std=c++0x。在这种情况下更好的解决方案是使用 set(CMAKE_CXX_FLAGS ...) - vlk
1
CMake 3.3及更高版本现在使用生成器表达式来解决这个问题。 - ar31

30

在 CMake 3.1 及以上版本中设置 C++ 标准的正确方法是:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED on)

可以单独为一个目标指定标准
set_property(TARGET mylib PROPERTY CXX_STANDARD 11)

自CMake 3.8以来,target_compile_features命令有一个新选项,允许设置目标所需的标准:
target_compile_features(mylib PUBLIC cxx_std_11)

优点在于它将需求传递给了依赖目标。如果您使用所需功能编译了一个库,任何链接到它的二进制文件都将自动设置此要求。

14

使用 FORCE 标志有帮助吗?

SET ( CMAKE_CXX_FLAGS "-std=c++0x" CACHE STRING "compile flags" FORCE)

2
这是唯一一个让标志在ccmake curses GUI中显示的答案,这正是我想要的。谢谢! - sudo make install
1
@Christopher Bruns 有没有什么方法可以做到这一点并保留文档字符串(即不指定“编译标志”)? - David Doria
@DavidDoria 是的,你可以重用之前的文档字符串,但这不太美观。https://cmake.org/Wiki/CMake/Tutorials/SettingVariableGroups - Christopher Bruns
这个 SET 是指在其他文件中添加或替换配置集吗? - S.R

5
也许这样会更好:
set_source_files_properties(${SOURCES}
       PROPERTIES
       COMPILE_FLAGS  "-std=c++0x")

3
谢谢,这个可以用。但如果是一个更大的项目,有更多的输出文件,比如几个库文件和几个可执行文件,假设它们都需要使用相同的编译标志,那我需要重复这些语句很多次吗?有没有一条命令可以为所有源文件设置编译标志? - Spiros

3

关于ar31提供的使用生成器表达式来扩展ADD_COMPILE_OPTIONS()的回答,我想再多说一点。如果你想添加多个用空格分隔的标志,可能会遇到问题,因为cmake存在一个生成器表达式中的恶意bug

我使用的解决方案是FOREACH循环,以下是我正在开发的项目的示例:

IF(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    # common flags
    SET(MY_C_AND_CXX_FLAGS -mtune=generic -pipe -fPIC -Wformat -Wformat-security -fomit-frame-pointer -fstack-protector-strong --param ssp-buffer-size=4 -fexceptions -D_FORTIFY_SOURCE=2 -feliminate-unused-debug-types)

    SET(MY_C_FLAGS   ${MY_C_FLAGS}   ${MY_C_AND_CXX_FLAGS})
    SET(MY_CXX_FLAGS ${MY_CXX_FLAGS} ${MY_C_AND_CXX_FLAGS})

    IF(MINGW)
        SET(MY_C_FLAGS   ${MY_C_FLAGS}   -static-libgcc)
        SET(MY_CXX_FLAGS ${MY_CXX_FLAGS} -static-libgcc -static-libstdc++)
    ENDIF(MINGW)

    IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
        SET(MY_C_FLAGS   ${MY_C_FLAGS}   -g2 -Wall)
        SET(MY_CXX_FLAGS ${MY_CXX_FLAGS} -g2 -Wall)
    ELSE()
        SET(MY_C_FLAGS   ${MY_C_FLAGS}   -O2 -Wno-error)
        SET(MY_CXX_FLAGS ${MY_CXX_FLAGS} -O2 -Wno-error)
    ENDIF()

    FOREACH(C_COMPILE_FLAG ${MY_C_FLAGS})
        ADD_COMPILE_OPTIONS($<$<COMPILE_LANGUAGE:C>:${C_COMPILE_FLAG}>)
    ENDFOREACH()

    FOREACH(CXX_COMPILE_FLAG ${MY_CXX_FLAGS})
        ADD_COMPILE_OPTIONS($<$<COMPILE_LANGUAGE:CXX>:${CXX_COMPILE_FLAG}>)
    ENDFOREACH()

    # for the gcc -fstack-protector* flags we need libssp
    # clang does not have this
    IF(CMAKE_COMPILER_IS_GNUCXX)
        SET(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -lssp")
        SET(CMAKE_C_LINK_EXECUTABLE   "${CMAKE_C_LINK_EXECUTABLE}   -lssp")
    ENDIF()
ENDIF()

# Assembler flags

IF(ASM_ENABLED)
    FOREACH(ASM_FLAG -I${CMAKE_SOURCE_DIR}/src/filters/hq/asm/ -O1 -w-orphan-labels)
        ADD_COMPILE_OPTIONS($<$<COMPILE_LANGUAGE:ASM_NASM>:${ASM_FLAG}>)
    ENDFOREACH()
ENDIF(ASM_ENABLED)

2

在需要向编译器请求特定标准的特定情况下,cmake 3.1通过提供请求标准版本或一组编译器功能的方法来解决问题。

请参考此答案官方文档


1

我曾经遇到和-lstdc++fs相关的问题。

最终解决方法是使用target_link_libraries

set(CMAKE_CXX_STANDARD 17)

add_executable(main main.cpp)

target_link_libraries(main -lstdc++fs)

1

0

这是我目前使用的解决方案:

if(CMAKE_COMPILER_IS_GNUCXX)
    add_definitions(-std=c++0x)
    add_definitions(-std=gnu++11)
endif()

或者,如果您有较旧版本的cmake,并且希望在cmake-gui中看到它:

set_property(CACHE CMAKE_CXX_FLAGS PROPERTY VALUE "-std=c++0x")

0
我曾遇到一个有关 C++ / clr 项目的情况,在其中需要修改两个变量 - CMAKE_CXX_FLAGSCMAKE_CXX_FLAGS_DEBUGCMAKE_CXX_FLAGS 可以使用 set_source_files_properties / COMPILE_FLAGS 修改,但是不能修改 CMAKE_CXX_FLAGS_DEBUG
我得出结论,创建单独的、针对特定项目的 cmake 文件,在单独的文件夹中进行。如果项目是隔离的,则变量修改仅在当前的 C++/clr 项目内工作。
我想如果您想要多个C++项目和多个C++/clr项目,将它们至少分别放在两个不同的文件夹中(如果不是更多)是有意义的——本地C++专用和托管C++专用。
类似的方法也可以在cmake测试应用程序中找到: https://github.com/Kitware/CMake/blob/master/Tests/CSharpLinkToCxx/CMakeLists.txt 这里是相同的事情,只是解释更详细:
# These variables affects also other C++ projects, that's why separate cmake for this c++ dll

# Clr compiling requires these:

# "Enable C++ Exceptions" - "Yes (/EHsc)" => "Yes with SEH Exceptions (/EHa)"
string(REPLACE "/EHsc" "/EHa" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")

# "Basic Run-time checks" - "Both (/RTC1, equiv. to /RTCsu) (/RTC1)" => "Default"
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")

这是一种方法。但是,如果您想在循环中生成本地c++和托管c++项目,则一种方法是禁用全局标志:

# Disable global flag, configure on per project basis, using target_compile_options, target_link_options
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/INCREMENTAL" "" CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
#string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")

然后为每个项目单独配置每个项目的设置,例如像这样:

if(${is_managed})
    # Managed C++ code
    set_target_properties(${project} PROPERTIES VS_GLOBAL_CLRSupport "true")
    set_property(TARGET ${project} PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.7.2")

    # Being able to debug dll
    target_link_options(${project} PRIVATE "$<$<CONFIG:Debug>:/ASSEMBLYDEBUG>")

    # Disable incremental linking
    target_link_options(${project} PRIVATE "$<$<CONFIG:Debug>:/INCREMENTAL:NO>")

    # "Enable C++ Exceptions" - "Yes with SEH Exceptions (/EHa)"
    set(compile_flags /EHa)
else()
    # Native C++ code
    # "Basic Run-time checks" - "Both (/RTC1, equiv. to /RTCsu) (/RTC1)" => "Default"
    target_compile_options(${project} PRIVATE "$<$<CONFIG:Debug>:/RTC1>")

    # Enable incremental linking
    target_link_options(${project} PRIVATE "$<$<CONFIG:Debug>:/INCREMENTAL>")

    # "Enable C++ Exceptions" - "Yes (/EHsc)"
    set(compile_flags /EHsc)
endif()
set_target_properties(${project} PROPERTIES COMPILE_FLAGS ${compile_flags})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接