可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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.
回答2:
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.
回答3:
Does it help to use the FORCE
flag?
SET ( CMAKE_CXX_FLAGS "-std=c++0x" CACHE STRING "compile flags" FORCE)
回答4:
Perhaps this would work better:
set_source_files_properties(${SOURCES}
PROPERTIES
COMPILE_FLAGS "-std=c++0x")
回答5:
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)
回答6:
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.
回答7:
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
回答8:
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})
回答9:
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")