diff options
58 files changed, 854 insertions, 258 deletions
diff --git a/.clang-tidy b/.clang-tidy index 9ce5f42..c790467 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -44,6 +44,7 @@ readability-*,\ -readability-uppercase-literal-suffix,\ cmake-*,\ -cmake-ostringstream-use-cmstrcat,\ +-cmake-string-concatenation-use-cmstrcat,\ -cmake-use-bespoke-enum-class,\ " HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$' diff --git a/.gitlab/ci/cxx_modules_rules_msvc.cmake b/.gitlab/ci/cxx_modules_rules_msvc.cmake index 2b09b0e..cb327fd 100644 --- a/.gitlab/ci/cxx_modules_rules_msvc.cmake +++ b/.gitlab/ci/cxx_modules_rules_msvc.cmake @@ -1 +1,3 @@ set(CMake_TEST_CXXModules_UUID "a246741c-d067-4019-a8fb-3d16b0c9d1d3") + +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) diff --git a/Help/command/add_compile_options.rst b/Help/command/add_compile_options.rst index ad65357..0ccebc6 100644 --- a/Help/command/add_compile_options.rst +++ b/Help/command/add_compile_options.rst @@ -28,13 +28,16 @@ this command is in a compiler-specific conditional clause: .. code-block:: cmake if (MSVC) - # warning level 4 and all warnings as errors - add_compile_options(/W4 /WX) + # warning level 4 + add_compile_options(/W4) else() - # lots of warnings and all warnings as errors - add_compile_options(-Wall -Wextra -pedantic -Werror) + # additional warnings + add_compile_options(-Wall -Wextra -Wpedantic) endif() +To set per-language options, use the :genex:`$<COMPILE_LANGUAGE>` +or :genex:`$<COMPILE_LANGUAGE:languages>` generator expressions. + See Also ^^^^^^^^ diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst index 8f13f45..698f62d 100644 --- a/Help/command/target_compile_options.rst +++ b/Help/command/target_compile_options.rst @@ -19,7 +19,8 @@ Arguments ^^^^^^^^^ If ``BEFORE`` is specified, the content will be prepended to the property -instead of being appended. +instead of being appended. See policy :policy:`CMP0101` which affects +whether ``BEFORE`` will be ignored in certain cases. The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to specify the :ref:`scope <Target Usage Requirements>` of the following arguments. diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst index 78770f7..03eb076 100644 --- a/Help/dev/experimental.rst +++ b/Help/dev/experimental.rst @@ -41,7 +41,8 @@ to tell CMake how to invoke the C++20 module dependency scanning tool. MSVC 19.34 (provided with Visual Studio 17.4) and above contains the support that CMake needs and has these variables already set up as required and only -the UUID variable needs to be set. +the UUID and the ``CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP`` variables need to be +set. For example, add code like the following to a test project: diff --git a/Help/policy/CMP0101.rst b/Help/policy/CMP0101.rst index f02bccc..6781079 100644 --- a/Help/policy/CMP0101.rst +++ b/Help/policy/CMP0101.rst @@ -3,16 +3,24 @@ CMP0101 .. versionadded:: 3.17 -:command:`target_compile_options` now honors ``BEFORE`` keyword in all scopes. +:command:`target_compile_options` now always honors the ``BEFORE`` keyword. -In CMake 3.16 and below the :command:`target_compile_options` ignores the -``BEFORE`` keyword in private scope. CMake 3.17 and later honors -``BEFORE`` keyword in all scopes. This policy provides compatibility for -projects that have not been updated to expect the new behavior. +In CMake 3.16 and below, the :command:`target_compile_options` command +ignores the ``BEFORE`` keyword when inserting items into the +:prop_tgt:`COMPILE_OPTIONS` target property (``PRIVATE`` and ``PUBLIC`` +items). CMake 3.17 and later honors the ``BEFORE`` keyword in all cases. +This policy provides compatibility for projects that have not been updated +to expect the new behavior. -The ``OLD`` behavior for this policy is to not honor ``BEFORE`` keyword in -private scope. The ``NEW`` behavior of this policy is to honor -``BEFORE`` keyword in all scopes. +The behavior of inserting items into the :prop_tgt:`INTERFACE_COMPILE_OPTIONS` +target property (``PUBLIC`` and ``INTERFACE`` items) is not affected by this +policy. The ``BEFORE`` keyword has always been honored when adding items to +:prop_tgt:`INTERFACE_COMPILE_OPTIONS`. + +The ``OLD`` behavior for this policy is to not honor the ``BEFORE`` keyword +when inserting into the :prop_tgt:`COMPILE_OPTIONS` property. +The ``NEW`` behavior for this policy is to honor the ``BEFORE`` keyword in +all cases. This policy was introduced in CMake version 3.17. Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly. diff --git a/Help/release/3.25.rst b/Help/release/3.25.rst index 7d0cf0a..fdf8a94 100644 --- a/Help/release/3.25.rst +++ b/Help/release/3.25.rst @@ -223,11 +223,6 @@ Deprecated and Removed Features Other Changes ============= -* On Windows, when targeting the MSVC ABI, the :command:`find_library` command - now accepts ``.a`` file names after first considering ``.lib``. This is - symmetric with existing behavior when targeting the GNU ABI, in which the - command accepts ``.lib`` file names after first considering ``.a``. - * The :envvar:`SSL_CERT_FILE` and :envvar:`SSL_CERT_DIR` environment variables can now be used to override where to find certificate authorities for TLS/SSL operations. @@ -238,3 +233,16 @@ Other Changes * The :generator:`Xcode` generator no longer adds the per-config suffix ``$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)`` to library search paths. See policy :policy:`CMP0142`. + +Updates +======= + +Changes made since CMake 3.25.0 include the following. + +3.25.1 +------ + +* On Windows, when targeting the MSVC ABI, the :command:`find_library` + command no longer accepts ``.a`` file names. This behavior was added + in CMake 3.25.0, but has been reverted due finding GNU-ABI libraries + in cases we did not previously. diff --git a/Modules/CMakeDetermineRCCompiler.cmake b/Modules/CMakeDetermineRCCompiler.cmake index f8d55a5..d22741b 100644 --- a/Modules/CMakeDetermineRCCompiler.cmake +++ b/Modules/CMakeDetermineRCCompiler.cmake @@ -30,16 +30,19 @@ if(NOT CMAKE_RC_COMPILER) # finally list compilers to try if(CMAKE_RC_COMPILER_INIT) - set(CMAKE_RC_COMPILER_LIST ${CMAKE_RC_COMPILER_INIT}) - else() - set(CMAKE_RC_COMPILER_LIST rc) + set(_CMAKE_RC_COMPILER_LIST ${CMAKE_RC_COMPILER_INIT}) + set(_CMAKE_RC_COMPILER_FALLBACK ${CMAKE_RC_COMPILER_INIT}) + elseif(NOT _CMAKE_RC_COMPILER_LIST) + set(_CMAKE_RC_COMPILER_LIST rc) endif() # Find the compiler. - find_program(CMAKE_RC_COMPILER NAMES ${CMAKE_RC_COMPILER_LIST} DOC "RC compiler") - if(CMAKE_RC_COMPILER_INIT AND NOT CMAKE_RC_COMPILER) - set(CMAKE_RC_COMPILER "${CMAKE_RC_COMPILER_INIT}" CACHE FILEPATH "RC compiler" FORCE) + find_program(CMAKE_RC_COMPILER NAMES ${_CMAKE_RC_COMPILER_LIST} DOC "RC compiler") + if(_CMAKE_RC_COMPILER_FALLBACK AND NOT CMAKE_RC_COMPILER) + set(CMAKE_RC_COMPILER "${_CMAKE_RC_COMPILER_FALLBACK}" CACHE FILEPATH "RC compiler" FORCE) endif() + unset(_CMAKE_RC_COMPILER_FALLBACK) + unset(_CMAKE_RC_COMPILER_LIST) endif() mark_as_advanced(CMAKE_RC_COMPILER) diff --git a/Modules/CheckIncludeFiles.cmake b/Modules/CheckIncludeFiles.cmake index 8e82859..8fc6921 100644 --- a/Modules/CheckIncludeFiles.cmake +++ b/Modules/CheckIncludeFiles.cmake @@ -70,10 +70,11 @@ macro(CHECK_INCLUDE_FILES INCLUDE VARIABLE) message(FATAL_ERROR "Unknown arguments:\n ${ARGN}\n") endif() + string(MAKE_C_IDENTIFIER ${VARIABLE} _variable_escaped) if(_lang STREQUAL "C") - set(src ${VARIABLE}.c) + set(src ${_variable_escaped}.c) elseif(_lang STREQUAL "CXX") - set(src ${VARIABLE}.cpp) + set(src ${_variable_escaped}.cpp) else() message(FATAL_ERROR "Unknown language:\n ${_lang}\nSupported languages: C, CXX.\n") endif() diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake index b14ab06..e09b7c8 100644 --- a/Modules/CheckTypeSize.cmake +++ b/Modules/CheckTypeSize.cmake @@ -103,10 +103,11 @@ function(__check_type_size_impl type var map builtin language) endif() # Perform language check + string(MAKE_C_IDENTIFIER ${var} _var_escaped) if(language STREQUAL "C") - set(src ${var}.c) + set(src ${_var_escaped}.c) elseif(language STREQUAL "CXX") - set(src ${var}.cpp) + set(src ${_var_escaped}.cpp) else() message(FATAL_ERROR "Unknown language:\n ${language}\nSupported languages: C, CXX.\n") endif() diff --git a/Modules/Compiler/IAR.cmake b/Modules/Compiler/IAR.cmake index 53456f5..7908f96 100644 --- a/Modules/Compiler/IAR.cmake +++ b/Modules/Compiler/IAR.cmake @@ -8,54 +8,48 @@ # include_guard() -macro(__compiler_iar_ilink lang) - set(CMAKE_EXECUTABLE_SUFFIX ".elf") - set(CMAKE_${lang}_OUTPUT_EXTENSION ".o") - if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX") +macro(__compiler_iar_common lang) + if (${lang} MATCHES "^(C|CXX)$") set(CMAKE_${lang}_COMPILE_OBJECT "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>") set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> --preprocess=cnl <PREPROCESSED_SOURCE>") set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy") - set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ") set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEP_FILE>") string(APPEND CMAKE_${lang}_FLAGS_INIT " ") string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r") - string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Ohz -DNDEBUG") string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -Oh -DNDEBUG") + string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Ohz -DNDEBUG") string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG") endif() + set(CMAKE_${lang}_RESPONSE_FILE_FLAG "-f ") + set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ") + + set(CMAKE_${lang}_ARCHIVE_FINISH "") +endmacro() + +macro(__compiler_iar_ilink lang) + set(CMAKE_EXECUTABLE_SUFFIX ".elf") + set(CMAKE_${lang}_OUTPUT_EXTENSION ".o") + + __compiler_iar_common(${lang}) + set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> --silent <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>") set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <TARGET> --create <LINK_FLAGS> <OBJECTS>") set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> <TARGET> --create <LINK_FLAGS> <OBJECTS>") set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> <TARGET> --replace <LINK_FLAGS> <OBJECTS>") - set(CMAKE_${lang}_ARCHIVE_FINISH "") endmacro() macro(__compiler_iar_xlink lang) set(CMAKE_EXECUTABLE_SUFFIX ".bin") - if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX") - - set(CMAKE_${lang}_COMPILE_OBJECT "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>") - set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> --preprocess=cnl <PREPROCESSED_SOURCE>") - set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy") - - set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ") - set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEP_FILE>") - string(APPEND CMAKE_${lang}_FLAGS_INIT " ") - string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r") - string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Ohz -DNDEBUG") - string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -Oh -DNDEBUG") - string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG") - endif() + __compiler_iar_common(${lang}) set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> -S <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>") set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <TARGET> <LINK_FLAGS> <OBJECTS>") set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> <TARGET> <LINK_FLAGS> <OBJECTS>") set(CMAKE_${lang}_ARCHIVE_APPEND "") - set(CMAKE_${lang}_ARCHIVE_FINISH "") set(CMAKE_LIBRARY_PATH_FLAG "-I") endmacro() diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake index 212f6d1..10a9073 100644 --- a/Modules/Compiler/MSVC-CXX.cmake +++ b/Modules/Compiler/MSVC-CXX.cmake @@ -79,7 +79,6 @@ elseif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "19.34") - set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> <SOURCE> -nologo -TP" " -showIncludes" diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake index b14349f..d82f41d 100644 --- a/Modules/FindRuby.cmake +++ b/Modules/FindRuby.cmake @@ -71,9 +71,6 @@ Hints .. versionadded:: 3.18 -``Ruby_ROOT_DIR`` - Define the root directory of a Ruby installation. - ``Ruby_FIND_VIRTUALENV`` This variable defines the handling of virtual environments managed by ``rvm``. It is meaningful only when a virtual environment diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake index 09a12cc..d0f686c 100644 --- a/Modules/Platform/Android.cmake +++ b/Modules/Platform/Android.cmake @@ -5,6 +5,7 @@ if(CMAKE_ANDROID_NDK) endif() include(Platform/Linux) +unset(LINUX) set(ANDROID 1) diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake index bf96e63..088b238 100644 --- a/Modules/Platform/Windows-GNU.cmake +++ b/Modules/Platform/Windows-GNU.cmake @@ -157,7 +157,8 @@ macro(__windows_compiler_gnu lang) endif() if(NOT CMAKE_RC_COMPILER_INIT AND NOT CMAKE_GENERATOR_RC) - set(CMAKE_RC_COMPILER_INIT ${_CMAKE_TOOLCHAIN_PREFIX}windres windres) + set(_CMAKE_RC_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}windres windres) + set(_CMAKE_RC_COMPILER_FALLBACK windres) endif() enable_language(RC) diff --git a/Modules/Platform/Windows.cmake b/Modules/Platform/Windows.cmake index 5263161..d8b3957 100644 --- a/Modules/Platform/Windows.cmake +++ b/Modules/Platform/Windows.cmake @@ -19,8 +19,8 @@ set(CMAKE_LINK_LIBRARY_SUFFIX ".lib") set(CMAKE_DL_LIBS "") set(CMAKE_EXTRA_LINK_EXTENSIONS ".targets") -set(CMAKE_FIND_LIBRARY_PREFIXES "" "lib") -set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".a") +set(CMAKE_FIND_LIBRARY_PREFIXES "") +set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") # for borland make long command lines are redirected to a file # with the following syntax, see Windows-bcc32.cmake for use diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index bbf6e6e..c889e1e 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 25) -set(CMake_VERSION_PATCH 20221123) +set(CMake_VERSION_PATCH 20221129) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index fae6d54..27e31d4 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -8869,3 +8869,101 @@ void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const } } } + +bool cmGeneratorTarget::NeedCxxModuleSupport(std::string const& lang, + std::string const& config) const +{ + if (lang != "CXX"_s) { + return false; + } + return this->HaveCxxModuleSupport(config) == Cxx20SupportLevel::Supported && + this->GetGlobalGenerator()->CheckCxxModuleSupport(); +} + +bool cmGeneratorTarget::NeedDyndep(std::string const& lang, + std::string const& config) const +{ + return lang == "Fortran"_s || this->NeedCxxModuleSupport(lang, config); +} + +cmFileSet const* cmGeneratorTarget::GetFileSetForSource( + std::string const& config, cmSourceFile const* sf) const +{ + this->BuildFileSetInfoCache(config); + + auto const& path = sf->GetFullPath(); + auto const& per_config = this->Configs[config]; + + auto const fsit = per_config.FileSetCache.find(path); + if (fsit == per_config.FileSetCache.end()) { + return nullptr; + } + return fsit->second; +} + +bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang, + std::string const& config, + cmSourceFile const* sf) const +{ + bool const needDyndep = this->NeedDyndep(lang, config); + if (!needDyndep) { + return false; + } + auto const* fs = this->GetFileSetForSource(config, sf); + if (fs && + (fs->GetType() == "CXX_MODULES"_s || + fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) { + return true; + } + auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES"); + if (sfProp.IsSet()) { + return sfProp.IsOn(); + } + auto const tgtProp = this->GetProperty("CXX_SCAN_FOR_MODULES"); + if (tgtProp.IsSet()) { + return tgtProp.IsOn(); + } + return true; +} + +void cmGeneratorTarget::BuildFileSetInfoCache(std::string const& config) const +{ + auto& per_config = this->Configs[config]; + + if (per_config.BuiltFileSetCache) { + return; + } + + auto const* tgt = this->Target; + + for (auto const& name : tgt->GetAllFileSetNames()) { + auto const* file_set = tgt->GetFileSet(name); + if (!file_set) { + tgt->GetMakefile()->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" is tracked to have file set \"", name, + "\", but it was not found.")); + continue; + } + + auto fileEntries = file_set->CompileFileEntries(); + auto directoryEntries = file_set->CompileDirectoryEntries(); + auto directories = file_set->EvaluateDirectoryEntries( + directoryEntries, this->LocalGenerator, config, this); + + std::map<std::string, std::vector<std::string>> files; + for (auto const& entry : fileEntries) { + file_set->EvaluateFileEntry(directories, files, entry, + this->LocalGenerator, config, this); + } + + for (auto const& it : files) { + for (auto const& filename : it.second) { + per_config.FileSetCache[filename] = file_set; + } + } + } + + per_config.BuiltFileSetCache = true; +} diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 25e6a81..96eda2c 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -26,6 +26,7 @@ enum class cmBuildStep; class cmComputeLinkInformation; class cmCustomCommand; +class cmFileSet; class cmGlobalGenerator; class cmLocalGenerator; class cmMakefile; @@ -1229,4 +1230,21 @@ public: // Check C++ module status for the target. void CheckCxxModuleStatus(std::string const& config) const; + + bool NeedCxxModuleSupport(std::string const& lang, + std::string const& config) const; + bool NeedDyndep(std::string const& lang, std::string const& config) const; + cmFileSet const* GetFileSetForSource(std::string const& config, + cmSourceFile const* sf) const; + bool NeedDyndepForSource(std::string const& lang, std::string const& config, + cmSourceFile const* sf) const; + +private: + void BuildFileSetInfoCache(std::string const& config) const; + struct InfoByConfig + { + bool BuiltFileSetCache = false; + std::map<std::string, cmFileSet const*> FileSetCache; + }; + mutable std::map<std::string, InfoByConfig> Configs; }; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index a9485b5..8ca6ee6 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1439,6 +1439,19 @@ bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const return false; } +void cmGlobalGenerator::CxxModuleSupportCheck() const +{ + bool const diagnose = !this->DiagnosedCxxModuleSupport && + !this->CMakeInstance->GetIsInTryCompile(); + if (diagnose) { + this->DiagnosedCxxModuleSupport = true; + this->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, + "C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP " + "is experimental. It is meant only for compiler developers to try."); + } +} + void cmGlobalGenerator::ComputeBuildFileGenerators() { for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { @@ -1597,6 +1610,8 @@ void cmGlobalGenerator::Generate() // it builds by default. this->InitializeProgressMarks(); + this->DiagnosedCxxModuleSupport = false; + this->ProcessEvaluationFiles(); this->CMakeInstance->UpdateProgress("Generating", 0.1f); diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 89b2ea8..4ebf9f6 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -157,6 +157,8 @@ public: virtual bool InspectConfigTypeVariables() { return true; } + virtual bool CheckCxxModuleSupport() { return false; } + bool Compute(); virtual void AddExtraIDETargets() {} @@ -621,6 +623,8 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; + void CxxModuleSupportCheck() const; + /// @brief Qt AUTOMOC/UIC/RCC target generation /// @return true on success bool QtAutoGen(); @@ -728,6 +732,8 @@ private: std::map<std::string, int> LanguageToLinkerPreference; std::map<std::string, std::string> LanguageToOriginalSharedLibFlags; + mutable bool DiagnosedCxxModuleSupport = false; + // Deferral id generation. size_t NextDeferId = 0; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index e334666..618dfb7 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -591,7 +591,7 @@ void cmGlobalNinjaGenerator::Generate() this->TargetAll = this->NinjaOutputPath("all"); this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt"); this->DisableCleandead = false; - this->DiagnosedCxxModuleSupport = false; + this->DiagnosedCxxModuleNinjaSupport = false; this->PolicyCMP0058 = this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus( @@ -850,18 +850,12 @@ bool cmGlobalNinjaGenerator::CheckLanguages( bool cmGlobalNinjaGenerator::CheckCxxModuleSupport() { - bool const diagnose = !this->DiagnosedCxxModuleSupport && - !this->CMakeInstance->GetIsInTryCompile(); - if (diagnose) { - this->DiagnosedCxxModuleSupport = true; - this->GetCMakeInstance()->IssueMessage( - MessageType::AUTHOR_WARNING, - "C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP " - "is experimental. It is meant only for compiler developers to try."); - } + this->CxxModuleSupportCheck(); if (this->NinjaSupportsDyndeps) { return true; } + bool const diagnose = !this->DiagnosedCxxModuleNinjaSupport && + !this->CMakeInstance->GetIsInTryCompile(); if (diagnose) { std::ostringstream e; /* clang-format off */ diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 1628349..6f654f6 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -469,7 +469,7 @@ public: bool IsSingleConfigUtility(cmGeneratorTarget const* target) const; - bool CheckCxxModuleSupport(); + bool CheckCxxModuleSupport() override; protected: void Generate() override; @@ -592,7 +592,7 @@ private: codecvt::Encoding NinjaExpectedEncoding = codecvt::None; - bool DiagnosedCxxModuleSupport = false; + bool DiagnosedCxxModuleNinjaSupport = false; void InitOutputPathPrefix(); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index d39e155..095bf40 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -157,107 +157,6 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule( '_', config); } -bool cmNinjaTargetGenerator::NeedCxxModuleSupport( - std::string const& lang, std::string const& config) const -{ - if (lang != "CXX"_s) { - return false; - } - return this->GetGeneratorTarget()->HaveCxxModuleSupport(config) == - cmGeneratorTarget::Cxx20SupportLevel::Supported && - this->GetGlobalGenerator()->CheckCxxModuleSupport(); -} - -bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang, - std::string const& config) const -{ - return lang == "Fortran" || this->NeedCxxModuleSupport(lang, config); -} - -void cmNinjaTargetGenerator::BuildFileSetInfoCache(std::string const& config) -{ - auto& per_config = this->Configs[config]; - - if (per_config.BuiltFileSetCache) { - return; - } - - auto const* tgt = this->GeneratorTarget->Target; - - for (auto const& name : tgt->GetAllFileSetNames()) { - auto const* file_set = tgt->GetFileSet(name); - if (!file_set) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), - "\" is tracked to have file set \"", name, - "\", but it was not found.")); - continue; - } - - auto fileEntries = file_set->CompileFileEntries(); - auto directoryEntries = file_set->CompileDirectoryEntries(); - auto directories = file_set->EvaluateDirectoryEntries( - directoryEntries, this->LocalGenerator, config, this->GeneratorTarget); - - std::map<std::string, std::vector<std::string>> files; - for (auto const& entry : fileEntries) { - file_set->EvaluateFileEntry(directories, files, entry, - this->LocalGenerator, config, - this->GeneratorTarget); - } - - for (auto const& it : files) { - for (auto const& filename : it.second) { - per_config.FileSetCache[filename] = file_set; - } - } - } - - per_config.BuiltFileSetCache = true; -} - -cmFileSet const* cmNinjaTargetGenerator::GetFileSetForSource( - std::string const& config, cmSourceFile const* sf) -{ - this->BuildFileSetInfoCache(config); - - auto const& path = sf->GetFullPath(); - auto const& per_config = this->Configs[config]; - - auto const fsit = per_config.FileSetCache.find(path); - if (fsit == per_config.FileSetCache.end()) { - return nullptr; - } - return fsit->second; -} - -bool cmNinjaTargetGenerator::NeedDyndepForSource(std::string const& lang, - std::string const& config, - cmSourceFile const* sf) -{ - bool const needDyndep = this->NeedDyndep(lang, config); - if (!needDyndep) { - return false; - } - auto const* fs = this->GetFileSetForSource(config, sf); - if (fs && - (fs->GetType() == "CXX_MODULES"_s || - fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) { - return true; - } - auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES"); - if (sfProp.IsSet()) { - return sfProp.IsOn(); - } - auto const tgtProp = - this->GeneratorTarget->GetProperty("CXX_SCAN_FOR_MODULES"); - if (tgtProp.IsSet()) { - return tgtProp.IsOn(); - } - return true; -} - std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget( const std::string& config) { @@ -341,7 +240,7 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS)); } - auto const* fs = this->GetFileSetForSource(config, source); + auto const* fs = this->GeneratorTarget->GetFileSetForSource(config, source); if (fs && (fs->GetType() == "CXX_MODULES"_s || fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) { @@ -699,7 +598,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, const std::string& config) { // For some cases we scan to dynamically discover dependencies. - bool const needDyndep = this->NeedDyndep(lang, config); + bool const needDyndep = this->GetGeneratorTarget()->NeedDyndep(lang, config); if (needDyndep) { this->WriteCompileRule(lang, config, WithScanning::Yes); @@ -1387,7 +1286,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( !(language == "RC" || (language == "CUDA" && !flag)); int const commandLineLengthLimit = ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0; - bool const needDyndep = this->NeedDyndepForSource(language, config, source); + bool const needDyndep = + this->GeneratorTarget->NeedDyndepForSource(language, config, source); cmNinjaBuild objBuild(this->LanguageCompilerRule( language, config, needDyndep ? WithScanning::Yes : WithScanning::No)); diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index d09f04b..b5abb36 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -19,7 +19,6 @@ #include "cmOSXBundleGenerator.h" class cmCustomCommand; -class cmFileSet; class cmGeneratedFileStream; class cmGeneratorTarget; class cmLocalNinjaGenerator; @@ -64,10 +63,6 @@ protected: cmMakefile* GetMakefile() const { return this->Makefile; } - void BuildFileSetInfoCache(std::string const& config); - cmFileSet const* GetFileSetForSource(std::string const& config, - cmSourceFile const* sf); - enum class WithScanning { No, @@ -82,13 +77,8 @@ protected: const std::string& config) const; std::string LanguageDyndepRule(std::string const& lang, const std::string& config) const; - bool NeedDyndep(std::string const& lang, std::string const& config) const; - bool NeedDyndepForSource(std::string const& lang, std::string const& config, - cmSourceFile const* sf); bool NeedExplicitPreprocessing(std::string const& lang) const; bool CompileWithDefines(std::string const& lang) const; - bool NeedCxxModuleSupport(std::string const& lang, - std::string const& config) const; std::string OrderDependsTargetForTarget(const std::string& config); @@ -238,8 +228,6 @@ private: std::vector<cmCustomCommand const*> CustomCommands; cmNinjaDeps ExtraFiles; std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator; - bool BuiltFileSetCache = false; - std::map<std::string, cmFileSet const*> FileSetCache; }; std::map<std::string, ByConfig> Configs; diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h index 6bf7c3c..487beb4 100644 --- a/Source/cmTargetPropCommandBase.h +++ b/Source/cmTargetPropCommandBase.h @@ -24,8 +24,8 @@ public: NO_FLAGS = 0x0, PROCESS_BEFORE = 0x1, PROCESS_AFTER = 0x2, - PROCESS_SYSTEM = 0x3, - PROCESS_REUSE_FROM = 0x4 + PROCESS_SYSTEM = 0x4, + PROCESS_REUSE_FROM = 0x8 }; bool HandleArguments(std::vector<std::string> const& args, diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt index 669c412..0041b07 100644 --- a/Tests/Cuda/CMakeLists.txt +++ b/Tests/Cuda/CMakeLists.txt @@ -16,6 +16,7 @@ add_cuda_test_macro(Cuda.SeparableCompCXXOnly SeparableCompCXXOnly) add_cuda_test_macro(Cuda.Toolkit Toolkit) add_cuda_test_macro(Cuda.IncludePathNoToolkit IncludePathNoToolkit) add_cuda_test_macro(Cuda.SharedRuntimePlusToolkit SharedRuntimePlusToolkit) +add_cuda_test_macro(Cuda.StaticRuntimePlusToolkit StaticRuntimePlusToolkit) add_cuda_test_macro(Cuda.Complex CudaComplex) add_cuda_test_macro(Cuda.ProperLinkFlags ProperLinkFlags) @@ -24,10 +25,4 @@ if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang") add_cuda_test_macro(Cuda.ProperDeviceLibraries ProperDeviceLibraries) endif() -# The CUDA only ships the shared version of the toolkit libraries -# on windows -if(NOT WIN32) - add_cuda_test_macro(Cuda.StaticRuntimePlusToolkit StaticRuntimePlusToolkit) -endif() - add_cuda_test_macro(Cuda.WithC CudaWithC) diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt b/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt index 61a3190..088be3b 100644 --- a/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt +++ b/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt @@ -15,16 +15,19 @@ add_library(SharedToolkit SHARED shared.cpp) target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::nppif) target_link_libraries(SharedToolkit PUBLIC CUDA::cudart) -# The CUDA only ships the shared version of the toolkit libraries -# on windows -if(NOT WIN32) +# Verify the CUDA Toolkit has static libraries +if(TARGET CUDA::curand_static AND + TARGET CUDA::nppif_static) #shared runtime with static toolkit libraries add_library(StaticToolkit SHARED static.cpp) + target_compile_definitions(StaticToolkit INTERFACE "HAS_STATIC_VERSION") target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static) target_link_libraries(StaticToolkit PUBLIC CUDA::cudart) - #static runtime with mixed toolkit libraries + + #shared runtime with mixed toolkit libraries add_library(MixedToolkit SHARED mixed.cpp) + target_compile_definitions(MixedToolkit INTERFACE "HAS_MIXED_VERSION") target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand_static CUDA::nppif) target_link_libraries(MixedToolkit PUBLIC CUDA::cudart) endif() diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp index 2a4da22..d958c3a 100644 --- a/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp +++ b/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp @@ -1,19 +1,28 @@ #ifdef _WIN32 # define IMPORT __declspec(dllimport) +#else +# define IMPORT +#endif + IMPORT int shared_version(); + +#ifdef HAS_STATIC_VERSION +IMPORT int static_version(); +#else int static_version() { return 0; } +#endif + +#ifdef HAS_MIXED_VERSION +IMPORT int mixed_version(); +#else int mixed_version() { return 0; } -#else -int shared_version(); -int static_version(); -int mixed_version(); #endif int main() diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt b/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt index df6c392..bb3dadf 100644 --- a/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt +++ b/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt @@ -15,15 +15,23 @@ add_library(SharedToolkit SHARED shared.cpp) target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::nppif) target_link_libraries(SharedToolkit PUBLIC CUDA::cudart_static) -#static runtime with static toolkit libraries -add_library(StaticToolkit SHARED static.cpp) -target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static) -target_link_libraries(StaticToolkit PUBLIC CUDA::cudart_static) +# Verify the CUDA Toolkit has static libraries +if(TARGET CUDA::curand_static AND + TARGET CUDA::nppif_static) + #static runtime with static toolkit libraries + add_library(StaticToolkit SHARED static.cpp) + target_compile_definitions(StaticToolkit INTERFACE "HAS_STATIC_VERSION") + target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static) + target_link_libraries(StaticToolkit PUBLIC CUDA::cudart_static) -#static runtime with mixed toolkit libraries -add_library(MixedToolkit SHARED mixed.cpp) -target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static) -target_link_libraries(MixedToolkit PUBLIC CUDA::cudart_static) + #static runtime with mixed toolkit libraries + add_library(MixedToolkit SHARED mixed.cpp) + target_compile_definitions(MixedToolkit INTERFACE "HAS_MIXED_VERSION") + target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static) + target_link_libraries(MixedToolkit PUBLIC CUDA::cudart_static) +endif() add_executable(StaticRuntimePlusToolkit main.cpp) -target_link_libraries(StaticRuntimePlusToolkit PRIVATE SharedToolkit StaticToolkit MixedToolkit) +target_link_libraries(StaticRuntimePlusToolkit PRIVATE SharedToolkit + $<TARGET_NAME_IF_EXISTS:StaticToolkit> + $<TARGET_NAME_IF_EXISTS:MixedToolkit>) diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp index 95872f0..fdd7b53 100644 --- a/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp +++ b/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp @@ -1,6 +1,12 @@ // Comes from: // https://docs.nvidia.com/cuda/curand/host-api-overview.html#host-api-example +#ifdef _WIN32 +# define EXPORT __declspec(dllexport) +#else +# define EXPORT +#endif + /* * This program uses the host CURAND API to generate 100 * pseudorandom floats. @@ -25,7 +31,7 @@ } \ } while (0) -int curand_main() +EXPORT int curand_main() { size_t n = 100; size_t i; diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp index 5a09f8e..d958c3a 100644 --- a/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp +++ b/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp @@ -1,8 +1,29 @@ +#ifdef _WIN32 +# define IMPORT __declspec(dllimport) +#else +# define IMPORT +#endif -int shared_version(); -int static_version(); -int mixed_version(); +IMPORT int shared_version(); + +#ifdef HAS_STATIC_VERSION +IMPORT int static_version(); +#else +int static_version() +{ + return 0; +} +#endif + +#ifdef HAS_MIXED_VERSION +IMPORT int mixed_version(); +#else +int mixed_version() +{ + return 0; +} +#endif int main() { diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp index a05140d..6de6886 100644 --- a/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp +++ b/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp @@ -1,8 +1,16 @@ -int curand_main(); -int nppif_main(); +#ifdef _WIN32 +# define IMPORT __declspec(dllimport) +# define EXPORT __declspec(dllexport) +#else +# define IMPORT +# define EXPORT +#endif -int mixed_version() +IMPORT int curand_main(); +IMPORT int nppif_main(); + +EXPORT int mixed_version() { return curand_main() == 0 && nppif_main() == 0; } diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp index 2871090..ac5341c 100644 --- a/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp +++ b/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp @@ -1,6 +1,12 @@ // Comes from // https://devtalk.nvidia.com/default/topic/1037482/gpu-accelerated-libraries/help-me-help-you-with-modern-cmake-and-cuda-mwe-for-npp/post/5271066/#5271066 +#ifdef _WIN32 +# define EXPORT __declspec(dllexport) +#else +# define EXPORT +#endif + #include <cstdio> #include <iostream> @@ -8,7 +14,7 @@ #include <cuda_runtime_api.h> #include <nppi_filtering_functions.h> -int nppif_main() +EXPORT int nppif_main() { /** * 8-bit unsigned single-channel 1D row convolution. diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp index 9967b66..f3c3dbc 100644 --- a/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp +++ b/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp @@ -1,8 +1,16 @@ +#ifdef _WIN32 +# define IMPORT __declspec(dllimport) +# define EXPORT __declspec(dllexport) +#else +# define IMPORT +# define EXPORT +#endif + int curand_main(); int nppif_main(); -int shared_version() +EXPORT int shared_version() { return curand_main() == 0 && nppif_main() == 0; } diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp index ca7eb4c..6932fa3 100644 --- a/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp +++ b/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp @@ -1,8 +1,16 @@ -int curand_main(); -int nppif_main(); +#ifdef _WIN32 +# define IMPORT __declspec(dllimport) +# define EXPORT __declspec(dllexport) +#else +# define IMPORT +# define EXPORT +#endif -int static_version() +IMPORT int curand_main(); +IMPORT int nppif_main(); + +EXPORT int static_version() { return curand_main() == 0 && nppif_main() == 0; } diff --git a/Tests/CudaOnly/CMakeLists.txt b/Tests/CudaOnly/CMakeLists.txt index 39634ac..db08076 100644 --- a/Tests/CudaOnly/CMakeLists.txt +++ b/Tests/CudaOnly/CMakeLists.txt @@ -10,6 +10,7 @@ add_cuda_test_macro(CudaOnly.CompileFlags CudaOnlyCompileFlags) add_cuda_test_macro(CudaOnly.EnableStandard CudaOnlyEnableStandard) add_cuda_test_macro(CudaOnly.ExportPTX CudaOnlyExportPTX) add_cuda_test_macro(CudaOnly.SharedRuntimePlusToolkit CudaOnlySharedRuntimePlusToolkit) +add_cuda_test_macro(CudaOnly.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit) add_cuda_test_macro(CudaOnly.Standard98 CudaOnlyStandard98) add_cuda_test_macro(CudaOnly.Toolkit CudaOnlyToolkit) add_cuda_test_macro(CudaOnly.ToolkitBeforeLang CudaOnlyToolkitBeforeLang) @@ -28,12 +29,6 @@ if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang") add_cuda_test_macro(CudaOnly.GPUDebugFlag CudaOnlyGPUDebugFlag) endif() -# The CUDA only ships the shared version of the toolkit libraries -# on windows -if(NOT WIN32) - add_cuda_test_macro(CudaOnly.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit) -endif() - add_cuda_test_macro(CudaOnly.DeviceLTO CudaOnlyDeviceLTO) if(MSVC) diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt b/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt index 03fba22..0b01085 100644 --- a/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt +++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt @@ -16,16 +16,18 @@ target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::npp set_target_properties(SharedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY none) target_link_libraries(SharedToolkit PUBLIC CUDA::cudart) -# The CUDA only ships the shared version of the toolkit libraries -# on windows -if(NOT WIN32) +# Verify the CUDA Toolkit has static libraries +if(TARGET CUDA::curand_static AND + TARGET CUDA::nppif_static) #shared runtime with static toolkit libraries add_library(StaticToolkit SHARED static.cu) + target_compile_definitions(StaticToolkit INTERFACE "HAS_STATIC_VERSION") target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static) set_target_properties(StaticToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Shared) - #static runtime with mixed toolkit libraries + #shared runtime with mixed toolkit libraries add_library(MixedToolkit SHARED mixed.cu) + target_compile_definitions(MixedToolkit INTERFACE "HAS_MIXED_VERSION") target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand_static CUDA::nppif) set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Shared) endif() diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu index 2a4da22..d958c3a 100644 --- a/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu +++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu @@ -1,19 +1,28 @@ #ifdef _WIN32 # define IMPORT __declspec(dllimport) +#else +# define IMPORT +#endif + IMPORT int shared_version(); + +#ifdef HAS_STATIC_VERSION +IMPORT int static_version(); +#else int static_version() { return 0; } +#endif + +#ifdef HAS_MIXED_VERSION +IMPORT int mixed_version(); +#else int mixed_version() { return 0; } -#else -int shared_version(); -int static_version(); -int mixed_version(); #endif int main() diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt b/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt index 534bab2..ae03b66 100644 --- a/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt +++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt @@ -16,17 +16,25 @@ target_link_libraries(SharedToolkit PRIVATE Common CUDA::curand CUDA::nppif ) set_target_properties(SharedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY none) target_link_libraries(SharedToolkit PUBLIC CUDA::cudart_static) -#static runtime with static toolkit libraries -add_library(StaticToolkit SHARED static.cu) -target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static) +# Verify the CUDA Toolkit has static libraries +if(TARGET CUDA::curand_static AND + TARGET CUDA::nppif_static) + #static runtime with static toolkit libraries + add_library(StaticToolkit SHARED static.cu) + target_compile_definitions(StaticToolkit INTERFACE "HAS_STATIC_VERSION") + target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static) -#static runtime with mixed toolkit libraries -add_library(MixedToolkit SHARED mixed.cu) -target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static) -set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Static) + #static runtime with mixed toolkit libraries + add_library(MixedToolkit SHARED mixed.cu) + target_compile_definitions(MixedToolkit INTERFACE "HAS_MIXED_VERSION") + target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static) + set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Static) +endif() add_executable(CudaOnlyStaticRuntimePlusToolkit main.cu) -target_link_libraries(CudaOnlyStaticRuntimePlusToolkit PRIVATE SharedToolkit StaticToolkit MixedToolkit) +target_link_libraries(CudaOnlyStaticRuntimePlusToolkit PRIVATE SharedToolkit + $<TARGET_NAME_IF_EXISTS:StaticToolkit> + $<TARGET_NAME_IF_EXISTS:MixedToolkit>) if(UNIX) # Help the shared cuda runtime find libcurand and libnppif when they are not located diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu index 95872f0..fdd7b53 100644 --- a/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu +++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu @@ -1,6 +1,12 @@ // Comes from: // https://docs.nvidia.com/cuda/curand/host-api-overview.html#host-api-example +#ifdef _WIN32 +# define EXPORT __declspec(dllexport) +#else +# define EXPORT +#endif + /* * This program uses the host CURAND API to generate 100 * pseudorandom floats. @@ -25,7 +31,7 @@ } \ } while (0) -int curand_main() +EXPORT int curand_main() { size_t n = 100; size_t i; diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu index 5a09f8e..d958c3a 100644 --- a/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu +++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu @@ -1,8 +1,29 @@ +#ifdef _WIN32 +# define IMPORT __declspec(dllimport) +#else +# define IMPORT +#endif -int shared_version(); -int static_version(); -int mixed_version(); +IMPORT int shared_version(); + +#ifdef HAS_STATIC_VERSION +IMPORT int static_version(); +#else +int static_version() +{ + return 0; +} +#endif + +#ifdef HAS_MIXED_VERSION +IMPORT int mixed_version(); +#else +int mixed_version() +{ + return 0; +} +#endif int main() { diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu index a05140d..6de6886 100644 --- a/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu +++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu @@ -1,8 +1,16 @@ -int curand_main(); -int nppif_main(); +#ifdef _WIN32 +# define IMPORT __declspec(dllimport) +# define EXPORT __declspec(dllexport) +#else +# define IMPORT +# define EXPORT +#endif -int mixed_version() +IMPORT int curand_main(); +IMPORT int nppif_main(); + +EXPORT int mixed_version() { return curand_main() == 0 && nppif_main() == 0; } diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu index 2871090..ac5341c 100644 --- a/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu +++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu @@ -1,6 +1,12 @@ // Comes from // https://devtalk.nvidia.com/default/topic/1037482/gpu-accelerated-libraries/help-me-help-you-with-modern-cmake-and-cuda-mwe-for-npp/post/5271066/#5271066 +#ifdef _WIN32 +# define EXPORT __declspec(dllexport) +#else +# define EXPORT +#endif + #include <cstdio> #include <iostream> @@ -8,7 +14,7 @@ #include <cuda_runtime_api.h> #include <nppi_filtering_functions.h> -int nppif_main() +EXPORT int nppif_main() { /** * 8-bit unsigned single-channel 1D row convolution. diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu index 9967b66..f3c3dbc 100644 --- a/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu +++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu @@ -1,8 +1,16 @@ +#ifdef _WIN32 +# define IMPORT __declspec(dllimport) +# define EXPORT __declspec(dllexport) +#else +# define IMPORT +# define EXPORT +#endif + int curand_main(); int nppif_main(); -int shared_version() +EXPORT int shared_version() { return curand_main() == 0 && nppif_main() == 0; } diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu index ca7eb4c..6932fa3 100644 --- a/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu +++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu @@ -1,8 +1,16 @@ -int curand_main(); -int nppif_main(); +#ifdef _WIN32 +# define IMPORT __declspec(dllimport) +# define EXPORT __declspec(dllexport) +#else +# define IMPORT +# define EXPORT +#endif -int static_version() +IMPORT int curand_main(); +IMPORT int nppif_main(); + +EXPORT int static_version() { return curand_main() == 0 && nppif_main() == 0; } diff --git a/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake b/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake index f726759..d703839 100644 --- a/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake @@ -1,6 +1,7 @@ include(RunCMake) run_cmake(empty_keyword_args) +run_cmake(bad_keyword) if (CMAKE_C_COMPILER_ID MATCHES "GNU|LCC|Clang") macro(run_cmake_target test subtest target) diff --git a/Tests/RunCMake/target_compile_options/bad_keyword-result.txt b/Tests/RunCMake/target_compile_options/bad_keyword-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/target_compile_options/bad_keyword-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_compile_options/bad_keyword-stderr.txt b/Tests/RunCMake/target_compile_options/bad_keyword-stderr.txt new file mode 100644 index 0000000..e22013e --- /dev/null +++ b/Tests/RunCMake/target_compile_options/bad_keyword-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at bad_keyword\.cmake:[0-9]+ \(target_compile_options\): + target_compile_options called with invalid arguments diff --git a/Tests/RunCMake/target_compile_options/bad_keyword.cmake b/Tests/RunCMake/target_compile_options/bad_keyword.cmake new file mode 100644 index 0000000..b7e6fca --- /dev/null +++ b/Tests/RunCMake/target_compile_options/bad_keyword.cmake @@ -0,0 +1,5 @@ +add_library(iface INTERFACE) + +# SYSTEM is a recognized keyword for the base class used to implement the +# command. Verify that we don't allow it. +target_compile_options(iface SYSTEM PRIVATE) diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt index 6fc54b1..97c176f 100644 --- a/Utilities/ClangTidyModule/CMakeLists.txt +++ b/Utilities/ClangTidyModule/CMakeLists.txt @@ -16,6 +16,8 @@ add_library(cmake-clang-tidy-module MODULE OstringstreamUseCmstrcatCheck.cxx OstringstreamUseCmstrcatCheck.h + StringConcatenationUseCmstrcatCheck.cxx + StringConcatenationUseCmstrcatCheck.h UseBespokeEnumClassCheck.cxx UseBespokeEnumClassCheck.h UseCmstrlenCheck.cxx diff --git a/Utilities/ClangTidyModule/Module.cxx b/Utilities/ClangTidyModule/Module.cxx index c747cee..4dd7dcd 100644 --- a/Utilities/ClangTidyModule/Module.cxx +++ b/Utilities/ClangTidyModule/Module.cxx @@ -4,6 +4,7 @@ #include <clang-tidy/ClangTidyModuleRegistry.h> #include "OstringstreamUseCmstrcatCheck.h" +#include "StringConcatenationUseCmstrcatCheck.h" #include "UseBespokeEnumClassCheck.h" #include "UseCmstrlenCheck.h" #include "UseCmsysFstreamCheck.h" @@ -25,6 +26,8 @@ public: CheckFactories.registerCheck<OstringstreamUseCmstrcatCheck>( "cmake-ostringstream-use-cmstrcat"); CheckFactories.registerCheck<UsePragmaOnceCheck>("cmake-use-pragma-once"); + CheckFactories.registerCheck<StringConcatenationUseCmstrcatCheck>( + "cmake-string-concatenation-use-cmstrcat"); } }; diff --git a/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.cxx b/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.cxx new file mode 100644 index 0000000..df14c83 --- /dev/null +++ b/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.cxx @@ -0,0 +1,179 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "StringConcatenationUseCmstrcatCheck.h" + +#include <cassert> + +#include <clang/ASTMatchers/ASTMatchFinder.h> +#include <clang/Lex/Lexer.h> + +namespace clang { +namespace tidy { +namespace cmake { +using namespace ast_matchers; + +StringConcatenationUseCmstrcatCheck::StringConcatenationUseCmstrcatCheck( + StringRef Name, ClangTidyContext* Context) + : ClangTidyCheck(Name, Context) +{ +} + +void StringConcatenationUseCmstrcatCheck::registerMatchers(MatchFinder* Finder) +{ + auto IsString = expr(hasType(qualType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(classTemplateSpecializationDecl( + hasName("::std::basic_string"), + hasTemplateArgument( + 0, templateArgument(refersToType(asString("char"))))))))))); + + auto IsChar = expr(hasType(asString("char"))); + + auto IsCharPtr = expr(hasType(pointerType(pointee(asString("const char"))))); + + auto IsStringConcat = + cxxOperatorCallExpr(hasOperatorName("+"), + anyOf(allOf(hasLHS(IsString), hasRHS(IsString)), + allOf(hasLHS(IsString), hasRHS(IsChar)), + allOf(hasLHS(IsString), hasRHS(IsCharPtr)), + allOf(hasLHS(IsChar), hasRHS(IsString)), + allOf(hasLHS(IsCharPtr), hasRHS(IsString)))); + + auto IsStringAppend = cxxOperatorCallExpr( + hasOperatorName("+="), hasLHS(IsString), + anyOf(hasRHS(IsString), hasRHS(IsChar), hasRHS(IsCharPtr))); + + auto IsStringConcatWithLHS = + cxxOperatorCallExpr( + IsStringConcat, + optionally(hasLHS(materializeTemporaryExpr( + has(cxxBindTemporaryExpr(has(IsStringConcat.bind("lhs")))))))) + .bind("concat"); + + auto IsStringAppendWithRHS = + cxxOperatorCallExpr( + IsStringAppend, + optionally(hasRHS(materializeTemporaryExpr(has(implicitCastExpr( + has(cxxBindTemporaryExpr(has(IsStringConcat.bind("rhs")))))))))) + .bind("append"); + + Finder->addMatcher(IsStringConcatWithLHS, this); + Finder->addMatcher(IsStringAppendWithRHS, this); +} + +void StringConcatenationUseCmstrcatCheck::check( + const MatchFinder::MatchResult& Result) +{ + const CXXOperatorCallExpr* AppendNode = + Result.Nodes.getNodeAs<CXXOperatorCallExpr>("append"); + const CXXOperatorCallExpr* ConcatNode = + Result.Nodes.getNodeAs<CXXOperatorCallExpr>("concat"); + + if (AppendNode != nullptr) { + if (AppendNode->getBeginLoc().isValid()) { + assert(InProgressExprChains.find(AppendNode) == + InProgressExprChains.end()); + + ExprChain TmpExprChain = + std::make_pair(OperatorType::PlusEquals, + std::vector<const CXXOperatorCallExpr*>{ AppendNode }); + const CXXOperatorCallExpr* RHSNode = + Result.Nodes.getNodeAs<CXXOperatorCallExpr>("rhs"); + + if (RHSNode != nullptr) { + if (RHSNode->getBeginLoc().isValid()) { + InProgressExprChains[RHSNode] = std::move(TmpExprChain); + } + } else { + issueCorrection(TmpExprChain, Result); + } + } + } + + if (ConcatNode != nullptr) { + if (ConcatNode->getBeginLoc().isValid()) { + ExprChain TmpExprChain; + + if (!(InProgressExprChains.find(ConcatNode) == + InProgressExprChains.end())) { + TmpExprChain = std::move(InProgressExprChains[ConcatNode]); + InProgressExprChains.erase(ConcatNode); + if (TmpExprChain.first == OperatorType::PlusEquals) { + TmpExprChain.second.insert(TmpExprChain.second.begin() + 1, + ConcatNode); + } else { + TmpExprChain.second.insert(TmpExprChain.second.begin(), ConcatNode); + } + } else { + TmpExprChain = std::make_pair( + OperatorType::Plus, + std::vector<const CXXOperatorCallExpr*>{ ConcatNode }); + } + + const CXXOperatorCallExpr* LHSNode = + Result.Nodes.getNodeAs<CXXOperatorCallExpr>("lhs"); + + if (LHSNode != nullptr) { + if (LHSNode->getBeginLoc().isValid()) { + InProgressExprChains[LHSNode] = std::move(TmpExprChain); + } + } else { + issueCorrection(TmpExprChain, Result); + } + } + } +} + +void StringConcatenationUseCmstrcatCheck::issueCorrection( + const ExprChain& Chain, const MatchFinder::MatchResult& Result) +{ + std::vector<FixItHint> FixIts; + const CXXOperatorCallExpr* ExprNode; + std::vector<const clang::CXXOperatorCallExpr*>::const_iterator It = + Chain.second.begin(); + + if (Chain.first == OperatorType::PlusEquals) { + ExprNode = *It; + StringRef LHS = Lexer::getSourceText( + CharSourceRange::getTokenRange(ExprNode->getArg(0)->getSourceRange()), + Result.Context->getSourceManager(), Result.Context->getLangOpts()); + + FixIts.push_back(FixItHint::CreateReplacement( + ExprNode->getExprLoc(), "= cmStrCat(" + LHS.str() + ",")); + It++; + } else { + ExprNode = *It; + FixIts.push_back( + FixItHint::CreateInsertion(ExprNode->getBeginLoc(), "cmStrCat(")); + } + + while (It != std::end(Chain.second)) { + ExprNode = *It; + FixIts.push_back( + FixItHint::CreateReplacement(ExprNode->getOperatorLoc(), ",")); + It++; + } + It--; + ExprNode = *It; + + StringRef LastToken = Lexer::getSourceText( + CharSourceRange::getTokenRange(ExprNode->getArg(1)->getSourceRange()), + Result.Context->getSourceManager(), Result.Context->getLangOpts()); + FixIts.push_back(FixItHint::CreateInsertion( + ExprNode->getEndLoc().getLocWithOffset(LastToken.str().size()), ")")); + + It = Chain.second.begin(); + ExprNode = *It; + + if (Chain.first == OperatorType::PlusEquals) { + this->diag(ExprNode->getOperatorLoc(), + "use cmStrCat() instead of string append") + << FixIts; + } else { + this->diag(ExprNode->getBeginLoc(), + "use cmStrCat() instead of string concatenation") + << FixIts; + } +} +} +} +} diff --git a/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.h b/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.h new file mode 100644 index 0000000..43ff539 --- /dev/null +++ b/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.h @@ -0,0 +1,34 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <clang-tidy/ClangTidyCheck.h> +#include <clang/ASTMatchers/ASTMatchFinder.h> + +namespace clang { +namespace tidy { +namespace cmake { +class StringConcatenationUseCmstrcatCheck : public ClangTidyCheck +{ +public: + StringConcatenationUseCmstrcatCheck(StringRef Name, + ClangTidyContext* Context); + void registerMatchers(ast_matchers::MatchFinder* Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult& Result) override; + +private: + enum class OperatorType + { + Plus, + PlusEquals + }; + typedef std::pair<OperatorType, std::vector<const CXXOperatorCallExpr*>> + ExprChain; + std::map<const CXXOperatorCallExpr*, ExprChain> InProgressExprChains; + + void issueCorrection(const ExprChain& ExprChain, + const ast_matchers::MatchFinder::MatchResult& Result); +}; +} +} +} diff --git a/Utilities/ClangTidyModule/Tests/CMakeLists.txt b/Utilities/ClangTidyModule/Tests/CMakeLists.txt index b53d5d2..8220f39 100644 --- a/Utilities/ClangTidyModule/Tests/CMakeLists.txt +++ b/Utilities/ClangTidyModule/Tests/CMakeLists.txt @@ -15,3 +15,4 @@ add_run_clang_tidy_test(cmake-use-cmsys-fstream) add_run_clang_tidy_test(cmake-use-bespoke-enum-class) add_run_clang_tidy_test(cmake-ostringstream-use-cmstrcat) add_run_clang_tidy_test(cmake-use-pragma-once) +add_run_clang_tidy_test(cmake-string-concatenation-use-cmstrcat) diff --git a/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-fixit.cxx b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-fixit.cxx new file mode 100644 index 0000000..79aecd4 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-fixit.cxx @@ -0,0 +1,36 @@ +#include <string> + +template <typename... Args> +std::string cmStrCat(Args&&... args) +{ + return ""; +} + +std::string a = "This is a string variable"; +std::string b = " and this is a string variable"; +std::string concat; + +// Correction needed +void test1() +{ + concat = cmStrCat(a, b); + concat = cmStrCat(a, " and this is a string literal"); + concat = cmStrCat(a, 'O'); + concat = cmStrCat("This is a string literal", b); + concat = cmStrCat('O', a); + concat = cmStrCat(a, " and this is a string literal", 'O', b); + + concat = cmStrCat(concat, b); + concat = cmStrCat(concat, " and this is a string literal"); + concat = cmStrCat(concat, 'o'); + concat = cmStrCat(concat, b, " and this is a string literal ", 'o', b); +} + +// No correction needed +void test2() +{ + a = b; + a = "This is a string literal"; + a = 'X'; + cmStrCat(a, b); +} diff --git a/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-stdout.txt new file mode 100644 index 0000000..3cfdef8 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-stdout.txt @@ -0,0 +1,113 @@ +cmake-string-concatenation-use-cmstrcat.cxx:16:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat] + concat = a + b; + ^ ~ + cmStrCat( , ) +cmake-string-concatenation-use-cmstrcat.cxx:16:12: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:16:14: note: FIX-IT applied suggested code changes + concat = a + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:16:17: note: FIX-IT applied suggested code changes + concat = a + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:17:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat] + concat = a + " and this is a string literal"; + ^ ~ + cmStrCat( , ) +cmake-string-concatenation-use-cmstrcat.cxx:17:12: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:17:14: note: FIX-IT applied suggested code changes + concat = a + " and this is a string literal"; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:17:47: note: FIX-IT applied suggested code changes + concat = a + " and this is a string literal"; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:18:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat] + concat = a + 'O'; + ^ ~ + cmStrCat( , ) +cmake-string-concatenation-use-cmstrcat.cxx:18:12: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:18:14: note: FIX-IT applied suggested code changes + concat = a + 'O'; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:18:19: note: FIX-IT applied suggested code changes + concat = a + 'O'; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:19:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat] + concat = "This is a string literal" + b; + ^ ~ + cmStrCat( , ) +cmake-string-concatenation-use-cmstrcat.cxx:19:12: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:19:39: note: FIX-IT applied suggested code changes + concat = "This is a string literal" + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:19:42: note: FIX-IT applied suggested code changes + concat = "This is a string literal" + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:20:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat] + concat = 'O' + a; + ^ ~ + cmStrCat( , ) +cmake-string-concatenation-use-cmstrcat.cxx:20:12: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:20:16: note: FIX-IT applied suggested code changes + concat = 'O' + a; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:20:19: note: FIX-IT applied suggested code changes + concat = 'O' + a; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:21:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat] + concat = a + " and this is a string literal" + 'O' + b; + ^ ~ ~ ~ + cmStrCat( , , , ) +cmake-string-concatenation-use-cmstrcat.cxx:21:12: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:21:14: note: FIX-IT applied suggested code changes + concat = a + " and this is a string literal" + 'O' + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:21:48: note: FIX-IT applied suggested code changes + concat = a + " and this is a string literal" + 'O' + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:21:54: note: FIX-IT applied suggested code changes + concat = a + " and this is a string literal" + 'O' + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:21:57: note: FIX-IT applied suggested code changes + concat = a + " and this is a string literal" + 'O' + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:23:10: warning: use cmStrCat() instead of string append [cmake-string-concatenation-use-cmstrcat] + concat += b; + ^~ + = cmStrCat(concat, ) +cmake-string-concatenation-use-cmstrcat.cxx:23:10: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:23:14: note: FIX-IT applied suggested code changes + concat += b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:24:10: warning: use cmStrCat() instead of string append [cmake-string-concatenation-use-cmstrcat] + concat += " and this is a string literal"; + ^~ + = cmStrCat(concat, ) +cmake-string-concatenation-use-cmstrcat.cxx:24:10: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:24:44: note: FIX-IT applied suggested code changes + concat += " and this is a string literal"; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:25:10: warning: use cmStrCat() instead of string append [cmake-string-concatenation-use-cmstrcat] + concat += 'o'; + ^~ + = cmStrCat(concat, ) +cmake-string-concatenation-use-cmstrcat.cxx:25:10: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:25:16: note: FIX-IT applied suggested code changes + concat += 'o'; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:26:10: warning: use cmStrCat() instead of string append [cmake-string-concatenation-use-cmstrcat] + concat += b + " and this is a string literal " + 'o' + b; + ^~ ~ ~ ~ + = cmStrCat(concat, , , , ) +cmake-string-concatenation-use-cmstrcat.cxx:26:10: note: FIX-IT applied suggested code changes +cmake-string-concatenation-use-cmstrcat.cxx:26:15: note: FIX-IT applied suggested code changes + concat += b + " and this is a string literal " + 'o' + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:26:50: note: FIX-IT applied suggested code changes + concat += b + " and this is a string literal " + 'o' + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:26:56: note: FIX-IT applied suggested code changes + concat += b + " and this is a string literal " + 'o' + b; + ^ +cmake-string-concatenation-use-cmstrcat.cxx:26:59: note: FIX-IT applied suggested code changes + concat += b + " and this is a string literal " + 'o' + b; + ^ diff --git a/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat.cxx b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat.cxx new file mode 100644 index 0000000..13a20ac --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat.cxx @@ -0,0 +1,36 @@ +#include <string> + +template <typename... Args> +std::string cmStrCat(Args&&... args) +{ + return ""; +} + +std::string a = "This is a string variable"; +std::string b = " and this is a string variable"; +std::string concat; + +// Correction needed +void test1() +{ + concat = a + b; + concat = a + " and this is a string literal"; + concat = a + 'O'; + concat = "This is a string literal" + b; + concat = 'O' + a; + concat = a + " and this is a string literal" + 'O' + b; + + concat += b; + concat += " and this is a string literal"; + concat += 'o'; + concat += b + " and this is a string literal " + 'o' + b; +} + +// No correction needed +void test2() +{ + a = b; + a = "This is a string literal"; + a = 'X'; + cmStrCat(a, b); +} |