From 475b785d2cf0d433c008f9ceadcaaf6c5d9e62b3 Mon Sep 17 00:00:00 2001 From: hdf89shfdfs <31327577+hdf89shfdfs@users.noreply.github.com> Date: Mon, 16 Nov 2020 17:05:33 -0500 Subject: [PATCH] Use CMAKE_CXX_STANDARD when available (#953) * Use CMAKE_CXX_STANDARD when available If the use has provided the variable CMAKE_CXX_STANDARD use that instead of providing a default cache variable. * Typo --- CMakeLists.txt | 48 +++++++++-------------- cmake/guidelineSupportLibrary.cmake | 61 +++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 cmake/guidelineSupportLibrary.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d84ef4f..86d09ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,8 @@ cmake_minimum_required(VERSION 3.1.3...3.16) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") +include(guidelineSupportLibrary) + project(GSL VERSION 3.1.0 LANGUAGES CXX) include(ExternalProject) @@ -8,39 +11,30 @@ find_package(Git) # Use GNUInstallDirs to provide the right locations on all platforms include(GNUInstallDirs) -# creates a library GSL which is an interface (header files only) +# Creates a library GSL which is an interface (header files only) add_library(GSL INTERFACE) -# determine whether this is a standalone project or included by other projects +# NOTE: If you want to use GSL prefer to link against GSL using this alias target +# EX: +# target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL) +# +# Add Microsoft.GSL::GSL alias for GSL so that dependents can be agnostic about +# whether GSL was added via `add_subdirectory` or `find_package` +add_library(Microsoft.GSL::GSL ALIAS GSL) + +# Determine whether this is a standalone project or included by other projects set(GSL_STANDALONE_PROJECT OFF) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(GSL_STANDALONE_PROJECT ON) -endif () - -set(GSL_CXX_STANDARD "14" CACHE STRING "Use c++ standard") -set(GSL_CXX_STD "cxx_std_${GSL_CXX_STANDARD}") - -if (MSVC) - set(GSL_CXX_STD_OPT "-std:c++${GSL_CXX_STANDARD}") -else() - set(GSL_CXX_STD_OPT "-std=c++${GSL_CXX_STANDARD}") endif() -# when minimum version required is 3.8.0 remove if below -# both branches do exactly the same thing -if (CMAKE_VERSION VERSION_LESS 3.7.9) - include(CheckCXXCompilerFlag) - CHECK_CXX_COMPILER_FLAG("${GSL_CXX_STD_OPT}" COMPILER_SUPPORTS_CXX_STANDARD) +# This GSL implementation generally assumes a platform that implements C++14 support. +set(gsl_min_cxx_standard "14") - if(COMPILER_SUPPORTS_CXX_STANDARD) - target_compile_options(GSL INTERFACE "${GSL_CXX_STD_OPT}") - else() - message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no c++${GSL_CXX_STANDARD} support. Please use a different C++ compiler.") - endif() -else () - target_compile_features(GSL INTERFACE "${GSL_CXX_STD}") - # on *nix systems force the use of -std=c++XX instead of -std=gnu++XX (default) - set(CMAKE_CXX_EXTENSIONS OFF) +if (GSL_STANDALONE_PROJECT) + gsl_set_default_cxx_standard(${gsl_min_cxx_standard}) +else() + gsl_client_set_cxx_standard(${gsl_min_cxx_standard}) endif() # add definitions to the library and targets that consume it @@ -111,10 +105,6 @@ else() endif() install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL) -# Add Microsoft.GSL::GSL alias for GSL so that dependents can be agnostic about -# whether GSL was added via `add_subdirectory` or `find_package` -add_library(Microsoft.GSL::GSL ALIAS GSL) - option(GSL_TEST "Generate tests." ${GSL_STANDALONE_PROJECT}) if (GSL_TEST) enable_testing() diff --git a/cmake/guidelineSupportLibrary.cmake b/cmake/guidelineSupportLibrary.cmake new file mode 100644 index 0000000..e29e80c --- /dev/null +++ b/cmake/guidelineSupportLibrary.cmake @@ -0,0 +1,61 @@ +# This cmake module is meant to hold helper functions/macros +# that make maintaining the cmake build system much easier. +# This is especially helpful since gsl needs to provide coverage +# for multiple versions of cmake. +# +# Any functions/macros should have a gsl_* prefix to avoid problems +if (DEFINED guideline_support_library_include_guard) + return() +endif() +set(guideline_support_library_include_guard ON) + +function(gsl_set_default_cxx_standard min_cxx_standard) + set(GSL_CXX_STANDARD "${min_cxx_standard}" CACHE STRING "Use c++ standard") + + set(GSL_CXX_STD "cxx_std_${GSL_CXX_STANDARD}") + + if (MSVC) + set(GSL_CXX_STD_OPT "-std:c++${GSL_CXX_STANDARD}") + else() + set(GSL_CXX_STD_OPT "-std=c++${GSL_CXX_STANDARD}") + endif() + + # when minimum version required is 3.8.0 remove if below + # both branches do exactly the same thing + if (CMAKE_VERSION VERSION_LESS 3.7.9) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("${GSL_CXX_STD_OPT}" COMPILER_SUPPORTS_CXX_STANDARD) + + if(COMPILER_SUPPORTS_CXX_STANDARD) + target_compile_options(GSL INTERFACE "${GSL_CXX_STD_OPT}") + else() + message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no c++${GSL_CXX_STANDARD} support. Please use a different C++ compiler.") + endif() + else() + target_compile_features(GSL INTERFACE "${GSL_CXX_STD}") + # on *nix systems force the use of -std=c++XX instead of -std=gnu++XX (default) + set(CMAKE_CXX_EXTENSIONS OFF) + endif() +endfunction() + +# The best way for a project to specify the GSL's C++ standard is by the client specifying +# the CMAKE_CXX_STANDARD. However, this isn't always ideal. Since the CMAKE_CXX_STANDARD is +# tied to the cmake version. And many projects have low cmake minimums. +# +# So provide an alternative approach in case that doesn't work. +function(gsl_client_set_cxx_standard min_cxx_standard) + if (DEFINED CMAKE_CXX_STANDARD) + if (${CMAKE_CXX_STANDARD} VERSION_LESS ${min_cxx_standard}) + message(FATAL_ERROR "GSL: Requires at least CXX standard ${min_cxx_standard}, user provided ${CMAKE_CXX_STANDARD}") + endif() + + # Set the GSL standard to what the client desires + set(GSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}" PARENT_SCOPE) + + # Exit out early to avoid extra unneccessary work + return() + endif() + + # Otherwise pick a reasonable default + gsl_set_default_cxx_standard(${min_cxx_standard}) +endfunction()