I wrote an CMakeLists.txt
to build a project with either g++
or clang++
.
To catch as many as possible bugs I use both libc++
with -D_LIBCPP_DEBUG2=2
(for clang++
) and libstdc++
with -D_GLIBCXX_DEBUG
(for both g++
and clang++
).
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -fno-inline -DDEBUG=1 -march=x86-64 -mtune=generic")
#[[
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_LIBCPP_DEBUG2=2")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG")
endif()
]]
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG=1 -march=native")
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-fno-omit-frame-pointer -DNDEBUG=1 -march=native")
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -gline-tables-only")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -Og -ggdb")
endif()
elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG=1 -march=native")
else()
message(STATUS "Wrong build type selected, defaulted to Debug.")
set(CMAKE_BUILD_TYPE "Debug")
endif()
Commented out code is the point where I should to know which library currently will be used with current compiler.
How to achieve this? I know, that libstdc++
defines __GLIBCXX__
and libc++
defines _LIBCPP_VERSION
, but how to detect them?
With the assistance of CMake's CheckCXXSymbolExists module, you can determine whether libc++ or libstdc++ is configured to be used in your project. Here's how you can do it:
include(CheckCXXSymbolExists)
if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
set(header version)
else()
set(header ciso646)
endif()
check_cxx_symbol_exists(_LIBCPP_VERSION ${header} LIBCPP)
if(LIBCPP)
# Logic for libc++
endif()
check_cxx_symbol_exists(__GLIBCXX__ ${header} GLIBCXX)
if(GLIBCXX)
# Logic for libstdc++
endif()
In this implementation, we use the <version> header if the compiler supports C++20. Otherwise, we resort to the <ciso646> header. Note that while <ciso646>
is removed in C++20, it may still exist in implementations for backward compatibility purposes.