diff options
author | Brad King <brad.king@kitware.com> | 2019-04-10 17:38:41 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2019-04-17 15:00:44 (GMT) |
commit | fb3370b6a1681190ffd8daf63975c44ce8fc1c49 (patch) | |
tree | 1e837d6bb039320c6f38c60b69c9439abc720e5f /Tests | |
parent | f621e7fa5df8d35cc379f9f7825f3d75b8489876 (diff) | |
download | CMake-fb3370b6a1681190ffd8daf63975c44ce8fc1c49.zip CMake-fb3370b6a1681190ffd8daf63975c44ce8fc1c49.tar.gz CMake-fb3370b6a1681190ffd8daf63975c44ce8fc1c49.tar.bz2 |
MSVC: Add abstraction for runtime library selection
Replace our hard-coded defaults for `/MD` and `/MDd` with a first-class
abstraction to select the runtime library from an enumeration of logical
names. We've long hesitated to do this because the idea of "runtime
library selection" touches on related concepts on several platforms.
Avoid that scope creep by simply defining an abstraction that applies
only when targeting the MSVC ABI on Windows.
Removing the old default flags requires a policy because existing
projects may rely on string processing to edit them and choose a runtime
library under the old behavior. Add policy CMP0091 to provide
compatibility.
Fixes: #19108
Diffstat (limited to 'Tests')
22 files changed, 243 insertions, 0 deletions
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 3746965..4114a67 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1995,6 +1995,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang") ADD_TEST_MACRO(PrecompiledHeader foo) endif() + ADD_TEST_MACRO(MSVCRuntimeLibrary) + if(CMAKE_Fortran_COMPILER) + ADD_TEST_MACRO(MSVCRuntimeLibrary.Fortran) + endif() endif() if(MSVC OR "${CMAKE_GENERATOR}" MATCHES "(MSYS|MinGW) Makefiles") diff --git a/Tests/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/CMakeLists.txt new file mode 100644 index 0000000..b7a6e86 --- /dev/null +++ b/Tests/MSVCRuntimeLibrary/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.14) +cmake_policy(SET CMP0091 NEW) +project(MSVCRuntimeLibrary) + +function(verify_combinations threads lang src) + set(verify_tc_config_ Release) + set(verify_tc_config_Debug Debug) + set(verify_def_MultiThreaded -DVERIFY_MT) + set(verify_def_Debug -DVERIFY_DEBUG) + set(verify_def_DLL -DVERIFY_DLL) + foreach(dbg "" Debug) + foreach(dll "" DLL) + # Construct the name of this runtime library combination. + set(rtl "${threads}${dbg}${dll}") + + # Test that try_compile builds with this RTL. + set(CMAKE_MSVC_RUNTIME_LIBRARY "${rtl}") + set(CMAKE_TRY_COMPILE_CONFIGURATION "${verify_tc_config_${dbg}}") + set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + try_compile(${rtl}_COMPILES + ${CMAKE_CURRENT_BINARY_DIR}/try_compile/${rtl} + ${CMAKE_CURRENT_SOURCE_DIR}/${src} + COMPILE_DEFINITIONS ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}} + OUTPUT_VARIABLE ${rtl}_OUTPUT + ) + if(${rtl}_COMPILES) + message(STATUS "try_compile with ${rtl} worked") + else() + string(REPLACE "\n" "\n " ${rtl}_OUTPUT " ${${rtl}_OUTPUT}") + message(SEND_ERROR "try_compile with ${rtl} failed:\n${${rtl}_OUTPUT}") + endif() + + # Test that targets build with this RTL. + set(CMAKE_MSVC_RUNTIME_LIBRARY "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${rtl}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>") + add_library(${rtl}-${lang} ${src}) + set_property(TARGET ${rtl}-${lang} PROPERTY BOOL_TRUE TRUE) + target_compile_definitions(${rtl}-${lang} PRIVATE ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}}) + endforeach() + endforeach() +endfunction() + +function(verify lang src) + add_library(default-${lang} ${src}) + target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>") + verify_combinations(MultiThreaded ${lang} ${src}) +endfunction() + +verify(C verify.c) +verify(CXX verify.cxx) diff --git a/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt new file mode 100644 index 0000000..169ba07 --- /dev/null +++ b/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.14) +cmake_policy(SET CMP0091 NEW) +project(MSVCRuntimeLibraryFortran Fortran) + +foreach(t MultiThreaded SingleThreaded) + foreach(dbg "" Debug) + foreach(dll "" DLL) + set(var "CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_${t}${dbg}${dll}") + # ifort does not actually define these, so inject them + string(REPLACE "-threads" "-threads;-D_MT" "${var}" "${${var}}") + string(REPLACE "-dbglibs" "-dbglibs;-D_DEBUG" "${var}" "${${var}}") + endforeach() + endforeach() +endforeach() +string(APPEND CMAKE_Fortran_FLAGS " -w") + +function(verify_combinations threads lang src) + set(verify_tc_config_ Release) + set(verify_tc_config_Debug Debug) + set(verify_def_MultiThreaded -DVERIFY_MT) + set(verify_def_Debug -DVERIFY_DEBUG) + set(verify_def_DLL -DVERIFY_DLL) + foreach(dbg "" Debug) + foreach(dll "" DLL) + # Construct the name of this runtime library combination. + set(rtl "${threads}${dbg}${dll}") + + # Test that targets build with this RTL. + set(CMAKE_MSVC_RUNTIME_LIBRARY "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${rtl}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>") + add_library(${rtl}-${lang} ${src}) + set_property(TARGET ${rtl}-${lang} PROPERTY BOOL_TRUE TRUE) + target_compile_definitions(${rtl}-${lang} PRIVATE ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}}) + endforeach() + endforeach() +endfunction() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +function(verify lang src) + add_library(default-${lang} ${src}) + target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>") + verify_combinations(MultiThreaded ${lang} ${src}) +endfunction() + +verify(Fortran verify.F90) +# Intel Fortran for Windows supports single-threaded RTL but it is +# not implemented by the Visual Studio integration. +if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") + verify_combinations(SingleThreaded Fortran verify.F90) +endif() diff --git a/Tests/MSVCRuntimeLibrary/Fortran/verify.F90 b/Tests/MSVCRuntimeLibrary/Fortran/verify.F90 new file mode 100644 index 0000000..6fe5e05 --- /dev/null +++ b/Tests/MSVCRuntimeLibrary/Fortran/verify.F90 @@ -0,0 +1 @@ +#include "../verify.h" diff --git a/Tests/MSVCRuntimeLibrary/verify.c b/Tests/MSVCRuntimeLibrary/verify.c new file mode 100644 index 0000000..741bca6 --- /dev/null +++ b/Tests/MSVCRuntimeLibrary/verify.c @@ -0,0 +1 @@ +#include "verify.h" diff --git a/Tests/MSVCRuntimeLibrary/verify.cxx b/Tests/MSVCRuntimeLibrary/verify.cxx new file mode 100644 index 0000000..741bca6 --- /dev/null +++ b/Tests/MSVCRuntimeLibrary/verify.cxx @@ -0,0 +1 @@ +#include "verify.h" diff --git a/Tests/MSVCRuntimeLibrary/verify.h b/Tests/MSVCRuntimeLibrary/verify.h new file mode 100644 index 0000000..58d65fe --- /dev/null +++ b/Tests/MSVCRuntimeLibrary/verify.h @@ -0,0 +1,29 @@ +#ifdef VERIFY_DEBUG +# ifndef _DEBUG +# error "_DEBUG not defined by debug runtime library selection" +# endif +#else +# ifdef _DEBUG +# error "_DEBUG defined by non-debug runtime library selection" +# endif +#endif + +#ifdef VERIFY_DLL +# ifndef _DLL +# error "_DLL not defined by DLL runtime library selection" +# endif +#else +# ifdef _DLL +# error "_DLL defined by non-DLL runtime library selection" +# endif +#endif + +#ifdef VERIFY_MT +# ifndef _MT +# error "_MT not defined by multi-threaded runtime library selection" +# endif +#else +# ifdef _MT +# error "_MT defined by single-threaded runtime library selection" +# endif +#endif diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 68411d6..a8dcb4b 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -195,6 +195,9 @@ add_RunCMake_test(LinkStatic) if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$") add_RunCMake_test(MetaCompileFeatures) endif() +if(MSVC) + add_RunCMake_test(MSVCRuntimeLibrary) +endif() add_RunCMake_test(ObjectLibrary) add_RunCMake_test(ParseImplicitIncludeInfo) if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF") diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt new file mode 100644 index 0000000..803058d --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error in CMakeLists.txt: + MSVC_RUNTIME_LIBRARY value 'BogusValue' not known for this C compiler.$ diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake new file mode 100644 index 0000000..c3ea2fd --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0091 NEW) +include(CMP0091-common.cmake) diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake new file mode 100644 index 0000000..734cc9f --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0091 OLD) +include(CMP0091-common.cmake) diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake new file mode 100644 index 0000000..26f86a0 --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake @@ -0,0 +1,2 @@ + +include(CMP0091-common.cmake) diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake new file mode 100644 index 0000000..7827d2a --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake @@ -0,0 +1,37 @@ +enable_language(C) + +cmake_policy(GET CMP0091 cmp0091) +if(cmp0091 STREQUAL "NEW") + if(NOT CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT) + message(SEND_ERROR "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT not set under NEW behavior") + endif() +else() + if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT) + message(SEND_ERROR "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT is set under OLD behavior") + endif() +endif() + +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + if(CMAKE_C_FLAGS_DEBUG MATCHES "[/-]MDd( |$)") + set(have_MDd 1) + else() + set(have_MDd 0) + endif() + if(CMAKE_C_FLAGS_RELEASE MATCHES "[/-]MD( |$)") + set(have_MD 1) + else() + set(have_MD 0) + endif() + if(cmp0091 STREQUAL "NEW") + if(have_MDd OR have_MD) + message(SEND_ERROR "Have a -MD* flag under NEW behavior.") + endif() + else() + if(NOT (have_MDd AND have_MD)) + message(SEND_ERROR "Do not have -MD* flags under OLD behavior.") + endif() + endif() +endif() + +set(CMAKE_MSVC_RUNTIME_LIBRARY BogusValue) +add_library(foo empty.c) diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt new file mode 100644 index 0000000..3e470a2 --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.14) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake new file mode 100644 index 0000000..fad18da --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +run_cmake(CMP0091-WARN) +run_cmake(CMP0091-OLD) +run_cmake(CMP0091-NEW) diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/empty.c b/Tests/RunCMake/MSVCRuntimeLibrary/empty.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/MSVCRuntimeLibrary/empty.c diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index df253a9..988312b 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -2,6 +2,7 @@ include(RunCMake) run_cmake(VsCSharpCompilerOpts) run_cmake(ExplicitCMakeLists) +run_cmake(RuntimeLibrary) run_cmake(SourceGroupCMakeLists) run_cmake(VsConfigurationType) diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake new file mode 100644 index 0000000..6b43d47 --- /dev/null +++ b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake @@ -0,0 +1,34 @@ +macro(RuntimeLibrary_check tgt rtl_expect) + set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/${tgt}.vcxproj") + if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not exist.") + return() + endif() + + set(HAVE_Runtimelibrary 0) + + file(STRINGS "${vcProjectFile}" lines) + foreach(line IN LISTS lines) + if(line MATCHES "^ *<RuntimeLibrary>([^<>]+)</RuntimeLibrary>") + set(rtl_actual "${CMAKE_MATCH_1}") + if(NOT "${rtl_actual}" STREQUAL "${rtl_expect}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has RuntimeLibrary '${rtl_actual}', not '${rtl_expect}'.") + return() + endif() + set(HAVE_Runtimelibrary 1) + break() + endif() + endforeach() + + if(NOT HAVE_Runtimelibrary) + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a RuntimeLibrary field.") + return() + endif() +endmacro() + +RuntimeLibrary_check(default-C MultiThreadedDebugDLL) +RuntimeLibrary_check(default-CXX MultiThreadedDebugDLL) +RuntimeLibrary_check(MTd-C MultiThreadedDebug) +RuntimeLibrary_check(MTd-CXX MultiThreadedDebug) +RuntimeLibrary_check(MT-C MultiThreaded) +RuntimeLibrary_check(MT-CXX MultiThreaded) diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake new file mode 100644 index 0000000..6c77a25 --- /dev/null +++ b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake @@ -0,0 +1,16 @@ +set(CMAKE_CONFIGURATION_TYPES Debug) +cmake_policy(SET CMP0091 NEW) +enable_language(C) +enable_language(CXX) + +add_library(default-C empty.c) +add_library(default-CXX empty.cxx) + +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebug") +add_library(MTd-C empty.c) +add_library(MTd-CXX empty.cxx) + +add_library(MT-C empty.c) +set_property(TARGET MT-C PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded") +add_library(MT-CXX empty.cxx) +set_property(TARGET MT-CXX PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded") diff --git a/Tests/RunCMake/VS10Project/empty.c b/Tests/RunCMake/VS10Project/empty.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/VS10Project/empty.c diff --git a/Tests/RunCMake/VS10Project/empty.cxx b/Tests/RunCMake/VS10Project/empty.cxx new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/VS10Project/empty.cxx |