Question

I have the following content in my CMakeLists.txt:

project( Matfile )

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

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

add_library(
        Matfile
        ${SOURCES}
)

As you may imagine, what I want to do is to compile my C++ sources using the flag -std=c++0x (I'm using gcc and I need the C++11 features). Unfortunately, this does not work, in the sense that, when I use cmake to generate the makefiles, the variable CMAKE_CXX_FLAGS is completely void.

How can I set this variable in the project file?

It seems to be a very stupid question, but I just spent not less than two houres trying to figure this out.

Était-ce utile?

La solution

The most straightforward solution should be using add_compile_options() if you are using version 2.8.12 or newer. For older versions you can "abuse" add_definitions(). While it is only meant for add -D flags, it also works with any other compiler flag. However, I think it is not meant to be used that way and could break in a future version.

add_compile_options(-std=c++0x) # CMake 2.8.12 or newer

or

add_definitions(-std=c++0x) # CMake 2.8.11 or older

Starting with CMake 3.3 you can also make this flag only apply to a specific language (e.g. only C or C++) using the strange generator expressions syntax:

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

However this will not work with the Visual studio generator, so make sure to only use this for Make/Ninja generators or use target_compile_options() to set it on a per-target scope.

Autres conseils

The correct way to set the C++ standard in CMake 3.1 and later is:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED on)

It is possible to specify the standard for one individual target also:

set_property(TARGET mylib PROPERTY CXX_STANDARD 11)

Since CMake 3.8 there is a new option to the target_compile_features command that allows to set the required standard for a target:

target_compile_features(mylib PUBLIC cxx_std_11)

The advantage would be that it propagates the requirement to dependent targets. If you compile a library with the cxx_std_11 required feature, any binary that links to it will automatically have this requirement set.

Does it help to use the FORCE flag?

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

Perhaps this would work better:

set_source_files_properties(${SOURCES}
       PROPERTIES
       COMPILE_FLAGS  "-std=c++0x")

To expand a bit on the ADD_COMPILE_OPTIONS() with generator expression answer by ar31, you may run into a problem when you want to add multiple flags separated by spaces, as cmake has a nasty bug in generator expressions.

The solution I used was a FOREACH loop, here is an example from the project I'm working on:

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)

In the specific case of requiring a particular standard to the compiler, cmake 3.1 solves the issue by providing a way to request a standard version or a set of compiler features. Refer to this answer and to the official documentation.

checkout the ucm_add_flags and ucm_print_flags macros of ucm - to add compiler flags to the appropriate cmake variables and to inspect the results

I've come up with a better method that works on older versions of cmake, e.g. Ubuntu 14 has 2.8.12, and target expressions are 3.3 feature.

Here is how you would set some C++ specific flags:

STRING(REGEX REPLACE "<FLAGS>" "<FLAGS> -std=gnu++11 -fpermissive -fexceptions " CMAKE_CXX_COMPILE_OBJECT ${CMAKE_CXX_COMPILE_OBJECT})

This is the solution I currently use:

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

Or, if you have an older version of cmake and you want to see it show up in cmake-gui:

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

I had this situation with C++ / clr project, where I needed to modify two variables - CMAKE_CXX_FLAGS and CMAKE_CXX_FLAGS_DEBUG. CMAKE_CXX_FLAGS can be modified using set_source_files_properties / COMPILE_FLAGS, but not CMAKE_CXX_FLAGS_DEBUG. I've concluded to create separate, project specific cmake file, in separate folder. If project is isolated - then variable modifying will work only within current C++/clr project.

I guess if you want to have multiple C++ projects and multiple C++/clr projects, makes sense to separate them at least in two different folder (if not more) - native C++ specific, and managed C++ specific.

In similar manner you can find out on cmake test application: https://github.com/Kitware/CMake/blob/master/Tests/CSharpLinkToCxx/CMakeLists.txt

Here is the same thing, only with more explanation:

# 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}")

This is one approach. If you however want to generate native c++ and managed c++ projects in a loop - one approach is to disable global flags:

# 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}")

and then configure each project setting individually for each project, for example like this:

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})

I had similar problem with -lstdc++fs.

In the end, the thing that solve it to me was target_link_libraries:

set(CMAKE_CXX_STANDARD 17)

add_executable(main main.cpp)

target_link_libraries(main -lstdc++fs)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top