Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot set __cplusplus to C++17 standard with Visual Studio and CMake

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?

like image 299
Jepessen Avatar asked Jul 18 '19 20:07

Jepessen


People also ask

How do I change to C 17 in Visual Studio?

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.

How set C++ standard code in Visual Studio?

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.

Does Visual Studio support C17?

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

What is STD C ++ 17?

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.


1 Answers

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 using
set_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.

like image 141
T S Avatar answered Sep 30 '22 08:09

T S