I've a CMake project that's opened with Visual Studio 2019. I need c++17 features for my code, so I've set the corresponding flag in the CMakeLists.txt
cmake_minimum_required (VERSION 3.10.0)
project (datalog)
message (STATUS "Building project ${PROJECT_NAME}")
find_package(stxxl CONFIG REQUIRED)
include_directories (${CMAKE_SOURCE_DIR}/src)
set (PROJECT_SRC
main.cpp
)
add_executable (${PROJECT_NAME} ${PROJECT_SRC})
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)
target_link_libraries(${PROJECT_NAME} stxxl)
When I build I obtain a lot of errors, because the library that I'm linking, stxxl
, installed with vcpkg
, has the following piece of code:
STXXL_BEGIN_NAMESPACE
template <class Type>
struct compat_unique_ptr {
#if __cplusplus >= 201103L && ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40400)
typedef std::unique_ptr<Type> result;
#else
// auto_ptr is inherently broken and is deprecated by unique_ptr in c++0x
typedef std::auto_ptr<Type> result;
#endif
};
STXXL_END_NAMESPACE
The problem is that __cplusplus
has value 199711L
instead of the correct value 201703L
, so code tries to use auto_ptr
that's removed in C++17 standard.
I've also tried to set the flag manually in Visual Studio, adding this section in the CmakeLists.txt
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17 /Zc:__cplusplus")
endif()
But nothing changes. I'm also using some C++17 features, so going back at the moment is not an option.
I can manually update the stxxl
header file to get rid of the macro, but it's a workaround, and every developer should create the same fix. Instead, I'd like to know why I'm getting the error and how to set the macro to the correct value with Visual Studio and CMake. Do you have any suggestion?
Select the Configuration Properties > C/C++ > Language property page. In C++ Language Standard (or for C, C Language Standard), choose the language standard to support from the dropdown control, then choose OK or Apply to save your changes.
Search for cppstandard in your vs code extension settings and choose the version of C++ you want the extension to use from the drop down. In order to make sure your debugger is using the same version, make sure you have something like this for your tasks.
Support for C11 and C17 standards is available in Visual Studio 2019 version 16.8 and later. Support requires an updated Universal C Runtime (UCRT) and Windows SDK version to work properly with the conforming preprocessor ( /Zc:preprocessor ).
C++17 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++17 replaced the prior version of the C++ standard, called C++14, and was later replaced by C++20.
As far as i can tell from this, you need to add /Zc:__cplusplus
manually (at least for now).
Your CMakeList snippet worked for me, are you sure, that __cplusplus
is actually set incorrectly and it's not just the __GNUC__
Macro, that's missing?
That said, I'd recommend to test if the version of VisualStudio is actually new enough:
# /Zc:__cplusplus is required to make __cplusplus accurate
# /Zc:__cplusplus is available starting with Visual Studio 2017 version 15.7
# (according to https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus)
# That version is equivalent to _MSC_VER==1914
# (according to https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019)
# CMake's ${MSVC_VERSION} is equivalent to _MSC_VER
# (according to https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html#variable:MSVC_VERSION)
if ((MSVC) AND (MSVC_VERSION GREATER_EQUAL 1914))
target_compile_options(stxxl INTERFACE "/Zc:__cplusplus")
endif()
Note: I used target_compile_options to add the necessary option to the interface of your library target. This way all targets, that depend on that library (via target_link_libraries) will be compiled with that flag, but targets, that don't need it (and might be incompatible with it) won't get it.
If you want to add the flag to one of your own targets, you can use target_compile_options(stxxl PUBLIC "/Zc:__cplusplus")
(PUBLIC
instead of INTERFACE
). INTERFACE
means the option is used when other targets depend on that target, PRIVATE
means the option is used for the target itself and PUBLIC
means both. (IMHO this artical explains it well.)
Apart from that, you shouldn't set the c++ standard version via compile flags, but instead using target_compile_features if the newer version is required and usingset_target_properties(your_target_name PROPERTIES CXX_STANDARD 17)
if you just wish to use the newer version if it is available.
In your case the latter is probably sufficient as your codesnippet has a fallback if the c++ version is older.
If changing the code of stxxl (via pull request, etc.) is an option, the code could test _MSVC_LANG
and _MSC_VER
. This way it would work without requiring /Zc:__cplusplus
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With