diff options
83 files changed, 914 insertions, 52 deletions
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim index 5d412c2..f9efd9e 100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim @@ -416,6 +416,7 @@ syn keyword cmakeProperty contained \ VS_DOTNET_STARTUP_OBJECT \ VS_DOTNET_TARGET_FRAMEWORK_VERSION \ VS_DPI_AWARE + \ VS_FRAMEWORK_REFERENCES \ VS_GLOBAL_KEYWORD \ VS_GLOBAL_PROJECT_TYPES \ VS_GLOBAL_ROOTNAMESPACE diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index 77357c0..6169038 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -26,6 +26,7 @@ The first signature is for adding a custom command to produce an output: [JOB_POOL job_pool] [JOB_SERVER_AWARE <bool>] [VERBATIM] [APPEND] [USES_TERMINAL] + [CODEGEN] [COMMAND_EXPAND_LISTS] [DEPENDS_EXPLICIT_ONLY]) @@ -203,6 +204,18 @@ The options are: ``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc`` to be properly expanded. +``CODEGEN`` + .. versionadded:: 3.31 + + Adds the custom command to a global ``codegen`` target that can be + used to execute the custom command while avoiding the majority of the + build graph. + + This option is supported only by :ref:`Ninja Generators` and + :ref:`Makefile Generators`, and is ignored by other generators. + Furthermore, this option is allowed only if policy :policy:`CMP0171` + is set to ``NEW``. + ``IMPLICIT_DEPENDS`` Request scanning of implicit dependencies of an input file. The language given specifies the programming language whose @@ -454,6 +467,25 @@ will re-run whenever ``in.txt`` changes. where ``<config>`` is the build configuration, and then compile the generated source as part of a library. +.. versionadded:: 3.31 + Use the ``CODEGEN`` option to add a custom command's outputs to the builtin + ``codegen`` target. This is useful to make generated code available for + static analysis without building the entire project. For example: + + .. code-block:: cmake + + add_executable(someTool someTool.c) + + add_custom_command( + OUTPUT out.c + COMMAND someTool -o out.c + CODEGEN) + + add_library(myLib out.c) + + A user may build the ``codegen`` target to generate ``out.c``. + ``someTool`` is built as dependency, but ``myLib`` is not built at all. + Example: Generating Files for Multiple Targets """""""""""""""""""""""""""""""""""""""""""""" diff --git a/Help/cpack_gen/archive.rst b/Help/cpack_gen/archive.rst index 7f7921d..5836f91 100644 --- a/Help/cpack_gen/archive.rst +++ b/Help/cpack_gen/archive.rst @@ -91,14 +91,10 @@ CPack generators which are essentially archives at their core. These include: .. versionadded:: 3.18 - :Default: ``1`` + :Default: value of :variable:`CPACK_THREADS` If set to ``0``, the number of available cores on the machine will be used instead. - The default is ``1`` which limits compression to a single thread. Note that - not all compression modes support threading in all environments. Currently, - only the XZ compression may support it. - - See also the :variable:`CPACK_THREADS` variable. + Note that not all compression modes support threading in all environments. .. versionadded:: 3.21 diff --git a/Help/cpack_gen/rpm.rst b/Help/cpack_gen/rpm.rst index 4a2ce5f..ebd3766 100644 --- a/Help/cpack_gen/rpm.rst +++ b/Help/cpack_gen/rpm.rst @@ -246,9 +246,8 @@ List of CPack RPM generator specific variables: :Default: (system default) May be used to override RPM compression type to be used to build the - RPM. For example some Linux distribution now default to ``lzma`` or ``xz`` - compression whereas older cannot use such RPM. Using this one can enforce - compression type to be used. + RPM. For example some Linux distributions default to ``xz`` or ``zstd``. + Using this, one can specify a specific compression type to be used. Possible values are: @@ -264,6 +263,11 @@ List of CPack RPM generator specific variables: ``gzip`` GNU Gzip compression + ``zstd`` + .. versionadded:: 3.31 + + Zstandard compression + .. variable:: CPACK_RPM_PACKAGE_AUTOREQ CPACK_RPM_<component>_PACKAGE_AUTOREQ diff --git a/Help/manual/cmake-cxxmodules.7.rst b/Help/manual/cmake-cxxmodules.7.rst index 840d65f..201a415 100644 --- a/Help/manual/cmake-cxxmodules.7.rst +++ b/Help/manual/cmake-cxxmodules.7.rst @@ -44,7 +44,7 @@ targets with C++ modules. .. _`P1689R5`: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html -.. note: +.. note:: CMake is focusing on correct builds before looking at performance improvements. There are known tactics within the chosen strategy which may diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 7155404..90c71b7 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -51,6 +51,14 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used to determine whether to report an error on use of deprecated macros or functions. +Policies Introduced by CMake 3.31 +================================= + +.. toctree:: + :maxdepth: 1 + + CMP0171: 'codegen' is a reserved target name. </policy/CMP0171> + Policies Introduced by CMake 3.30 ================================= diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 673bc7c..fea661a 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -430,6 +430,7 @@ Properties on Targets /prop_tgt/VS_DOTNET_STARTUP_OBJECT /prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION /prop_tgt/VS_DPI_AWARE + /prop_tgt/VS_FRAMEWORK_REFERENCES /prop_tgt/VS_GLOBAL_KEYWORD /prop_tgt/VS_GLOBAL_PROJECT_TYPES /prop_tgt/VS_GLOBAL_ROOTNAMESPACE diff --git a/Help/policy/CMP0171.rst b/Help/policy/CMP0171.rst new file mode 100644 index 0000000..c364bf4 --- /dev/null +++ b/Help/policy/CMP0171.rst @@ -0,0 +1,26 @@ +CMP0171 +------- + +.. versionadded:: 3.31 + +``codegen`` is a reserved target name. + +CMake 3.30 and earlier did not reserve ``codegen`` as a builtin target name, +leaving projects free to create their own target with that name. +CMake 3.31 and later prefer to reserve ``codegen`` as a builtin target name +to drive custom commands created with the ``CODEGEN`` option to +:command:`add_custom_command`. In order to support building the ``codegen`` +target in scripted environments, e.g., ``cmake --build . --target codegen``, +the ``codegen`` target needs to be generated even if no custom commands +use the ``CODEGEN`` option. This policy provides compatibility for projects +that have not been updated to avoid creating a target named ``codegen``. + +The ``OLD`` behavior of this policy allows projects to create a target +with the name ``codegen``. The ``NEW`` behavior halts with a fatal error +if a target with the name ``codegen`` is created. + +.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.31 +.. |WARNS_OR_DOES_NOT_WARN| replace:: warns +.. include:: STANDARD_ADVICE.txt + +.. include:: DEPRECATED.txt diff --git a/Help/prop_tgt/VS_FRAMEWORK_REFERENCES.rst b/Help/prop_tgt/VS_FRAMEWORK_REFERENCES.rst new file mode 100644 index 0000000..925ac68 --- /dev/null +++ b/Help/prop_tgt/VS_FRAMEWORK_REFERENCES.rst @@ -0,0 +1,12 @@ +VS_FRAMEWORK_REFERENCES +----------------------- + +.. versionadded:: 3.31 + +Visual Studio framework references. +Specify a :ref:`semicolon-separated list <CMake Language Lists>` of framework references +to be added to a generated Visual Studio project. For example: + +* "Microsoft.WindowsDesktop.App.WPF" for WPF applications +* "Microsoft.WindowsDesktop.App.WindowsForms" for WinForms applications +* "Microsoft.WindowsDesktop.App" for applications using both frameworks diff --git a/Help/release/dev/codegen.rst b/Help/release/dev/codegen.rst new file mode 100644 index 0000000..e8b61c9 --- /dev/null +++ b/Help/release/dev/codegen.rst @@ -0,0 +1,10 @@ +codegen +------- + +* The :ref:`Ninja Generators` and :ref:`Makefile Generators` now produce + a ``codegen`` build target. See policy :policy:`CMP0171`. It drives a + subset of the build graph sufficient to run custom commands created with + :command:`add_custom_command`'s new ``CODEGEN`` option. + +* The :command:`add_custom_command` command gained a ``CODEGEN`` option + to mark a custom commands outputs as dependencies of a ``codegen`` target. diff --git a/Help/release/dev/cpack-rpm-zstd.rst b/Help/release/dev/cpack-rpm-zstd.rst new file mode 100644 index 0000000..828d5f6 --- /dev/null +++ b/Help/release/dev/cpack-rpm-zstd.rst @@ -0,0 +1,5 @@ +cpack-rpm-zstd +-------------- + +* The :cpack_gen:`CPack RPM Generator` gained support for ``zstd`` as a + :variable:`CPACK_RPM_COMPRESSION_TYPE` value. diff --git a/Help/release/dev/vs-framework-references.rst b/Help/release/dev/vs-framework-references.rst new file mode 100644 index 0000000..1f50b50 --- /dev/null +++ b/Help/release/dev/vs-framework-references.rst @@ -0,0 +1,5 @@ +vs-framework-references +----------------------- + +* The :prop_tgt:`VS_FRAMEWORK_REFERENCES` target property was added + to tell :ref:`Visual Studio Generators` to add framework references. diff --git a/Modules/FindImageMagick.cmake b/Modules/FindImageMagick.cmake index 6baf471..50f6e46 100644 --- a/Modules/FindImageMagick.cmake +++ b/Modules/FindImageMagick.cmake @@ -93,6 +93,8 @@ Result Variables Compile options of <component>. ``ImageMagick_<component>_LIBRARIES`` + .. versionadded:: 3.31 + Full path to <component> libraries. @@ -168,6 +170,12 @@ function(FIND_IMAGEMAGICK_API component header) set(ImageMagick_${component}_INCLUDE_DIRS ${ImageMagick_${component}_INCLUDE_DIRS} PARENT_SCOPE) + set(ImageMagick_${component}_LIBRARIES + ${ImageMagick_${component}_LIBRARY} + ) + set(ImageMagick_${component}_LIBRARIES + ${ImageMagick_${component}_LIBRARIES} PARENT_SCOPE) + set(ImageMagick_${component}_COMPILE_OPTIONS ${PC_${component}_CFLAGS_OTHER}) # Add the per-component include directories to the full include dirs. @@ -185,11 +193,13 @@ function(FIND_IMAGEMAGICK_API component header) ) set(ImageMagick_COMPILE_OPTIONS ${ImageMagick_COMPILE_OPTIONS} PARENT_SCOPE) - add_library(ImageMagick::${component} UNKNOWN IMPORTED) - set_target_properties(ImageMagick::${component} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${ImageMagick_${component}_INCLUDE_DIRS}" - INTERFACE_COMPILE_OPTIONS "${ImageMagick_${component}_COMPILE_OPTIONS}" - IMPORTED_LOCATION "${ImageMagick_${component}_LIBRARY}") + if(NOT TARGET ImageMagick::${component}) + add_library(ImageMagick::${component} UNKNOWN IMPORTED) + set_target_properties(ImageMagick::${component} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${ImageMagick_${component}_INCLUDE_DIRS}" + INTERFACE_COMPILE_OPTIONS "${ImageMagick_${component}_COMPILE_OPTIONS}" + IMPORTED_LOCATION "${ImageMagick_${component}_LIBRARY}") + endif() endif() endfunction() diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake index 4a741ee..e3f8f5e 100644 --- a/Modules/Internal/CPack/CPackRPM.cmake +++ b/Modules/Internal/CPack/CPackRPM.cmake @@ -1034,27 +1034,32 @@ function(cpack_rpm_generate_package) # CPACK_RPM_COMPRESSION_TYPE # if (CPACK_RPM_COMPRESSION_TYPE) - if(CPACK_RPM_PACKAGE_DEBUG) - message("CPackRPM:Debug: User Specified RPM compression type: ${CPACK_RPM_COMPRESSION_TYPE}") - endif() - if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "lzma") - set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.lzdio") - endif() - if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "xz") - if(CPACK_THREADS GREATER "0") - set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w7T${CPACK_THREADS}.xzdio") - else() - set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w7T.xzdio") - endif() - endif() - if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "bzip2") - set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.bzdio") - endif() - if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "gzip") - set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.gzdio") - endif() + if(CPACK_RPM_PACKAGE_DEBUG) + message("CPackRPM:Debug: User Specified RPM compression type: ${CPACK_RPM_COMPRESSION_TYPE}") + endif() + if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "lzma") + set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.lzdio") + elseif(CPACK_RPM_COMPRESSION_TYPE STREQUAL "xz") + if(CPACK_THREADS GREATER "0") + set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w7T${CPACK_THREADS}.xzdio") + else() + set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w7T.xzdio") + endif() + elseif(CPACK_RPM_COMPRESSION_TYPE STREQUAL "bzip2") + set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.bzdio") + elseif(CPACK_RPM_COMPRESSION_TYPE STREQUAL "gzip") + set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.gzdio") + elseif(CPACK_RPM_COMPRESSION_TYPE STREQUAL "zstd") + if(CPACK_THREADS GREATER "0") + set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w19T${CPACK_THREADS}.zstdio") + else() + set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w19T0.zstdio") + endif() + else() + message(FATAL_ERROR "Specified CPACK_RPM_COMPRESSION_TYPE value is not supported: ${CPACK_RPM_COMPRESSION_TYPE}") + endif() else() - set(CPACK_RPM_COMPRESSION_TYPE_TMP "") + set(CPACK_RPM_COMPRESSION_TYPE_TMP "") endif() if(NOT CPACK_RPM_PACKAGE_SOURCES) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 01d1661..1b9b456 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 30) -set(CMake_VERSION_PATCH 20240627) +set(CMake_VERSION_PATCH 20240702) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index d943011..d5adba7 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -53,6 +53,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, bool command_expand_lists = false; bool depends_explicit_only = mf.IsOn("CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY"); + bool codegen = false; std::string implicit_depends_lang; cmImplicitDependsList implicit_depends; @@ -111,6 +112,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, MAKE_STATIC_KEYWORD(VERBATIM); MAKE_STATIC_KEYWORD(WORKING_DIRECTORY); MAKE_STATIC_KEYWORD(DEPENDS_EXPLICIT_ONLY); + MAKE_STATIC_KEYWORD(CODEGEN); #undef MAKE_STATIC_KEYWORD static std::unordered_set<std::string> const keywords{ keyAPPEND, @@ -135,7 +137,8 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, keyUSES_TERMINAL, keyVERBATIM, keyWORKING_DIRECTORY, - keyDEPENDS_EXPLICIT_ONLY + keyDEPENDS_EXPLICIT_ONLY, + keyCODEGEN }; for (std::string const& copy : args) { @@ -166,6 +169,8 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, command_expand_lists = true; } else if (copy == keyDEPENDS_EXPLICIT_ONLY) { depends_explicit_only = true; + } else if (copy == keyCODEGEN) { + codegen = true; } else if (copy == keyTARGET) { doing = doing_target; } else if (copy == keyARGS) { @@ -322,6 +327,28 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, return false; } + if (codegen) { + if (output.empty()) { + status.SetError("CODEGEN requires at least 1 OUTPUT."); + return false; + } + + if (append) { + status.SetError("CODEGEN may not be used with APPEND."); + return false; + } + + if (!implicit_depends.empty()) { + status.SetError("CODEGEN is not compatible with IMPLICIT_DEPENDS."); + return false; + } + + if (mf.GetPolicyStatus(cmPolicies::CMP0171) != cmPolicies::NEW) { + status.SetError("CODEGEN option requires policy CMP0171 be set to NEW!"); + return false; + } + } + // Check for an append request. if (append) { mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends, @@ -355,6 +382,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, cc->SetOutputs(output); cc->SetMainDependency(main_dependency); cc->SetDepends(depends); + cc->SetCodegen(codegen); cc->SetImplicitDepends(implicit_depends); mf.AddCustomCommandToOutput(std::move(cc)); } else { diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx index 2d55a5a..aa04018 100644 --- a/Source/cmAddDependenciesCommand.cxx +++ b/Source/cmAddDependenciesCommand.cxx @@ -30,6 +30,7 @@ bool cmAddDependenciesCommand(std::vector<std::string> const& args, // skip over target_name for (std::string const& arg : cmMakeRange(args).advance(1)) { target->AddUtility(arg, false, &mf); + target->AddCodegenDependency(arg); } } else { mf.IssueMessage( diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index 167e601..6f63d0a 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -132,6 +132,10 @@ public: const std::string& GetTarget() const; void SetTarget(const std::string& target); + /** Record if the custom command can be used for code generation. */ + bool GetCodegen() const { return Codegen; } + void SetCodegen(bool b) { Codegen = b; } + private: std::vector<std::string> Outputs; std::vector<std::string> Byproducts; @@ -153,6 +157,7 @@ private: bool StdPipesUTF8 = false; bool HasMainDependency_ = false; bool DependsExplicitOnly = false; + bool Codegen = false; // Policies are NEW for synthesized custom commands, and set by cmMakefile for // user-created custom commands. diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 019271b..bf2f0fc 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1398,6 +1398,8 @@ void cmGlobalGenerator::Configure() } } + this->ReserveGlobalTargetCodegen(); + // update the cache entry for the number of local generators, this is used // for progress this->GetCMakeInstance()->AddCacheEntry( @@ -2914,6 +2916,53 @@ void cmGlobalGenerator::AddGlobalTarget_Test( targets.push_back(std::move(gti)); } +void cmGlobalGenerator::ReserveGlobalTargetCodegen() +{ + // Read the policy value at the end of the top-level CMakeLists.txt file + // since it's a global policy that affects the whole project. + auto& mf = this->Makefiles[0]; + const auto policyStatus = mf->GetPolicyStatus(cmPolicies::CMP0171); + + this->AllowGlobalTargetCodegen = (policyStatus == cmPolicies::NEW); + + cmTarget* tgt = this->FindTarget("codegen"); + if (!tgt) { + return; + } + + MessageType messageType = MessageType::AUTHOR_WARNING; + std::ostringstream e; + bool issueMessage = false; + switch (policyStatus) { + case cmPolicies::WARN: + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0171) << "\n"; + issueMessage = true; + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + case cmPolicies::NEW: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + issueMessage = true; + messageType = MessageType::FATAL_ERROR; + break; + } + if (issueMessage) { + e << "The target name \"codegen\" is reserved."; + this->GetCMakeInstance()->IssueMessage(messageType, e.str(), + tgt->GetBacktrace()); + if (messageType == MessageType::FATAL_ERROR) { + cmSystemTools::SetFatalErrorOccurred(); + return; + } + } +} + +bool cmGlobalGenerator::CheckCMP0171() const +{ + return this->AllowGlobalTargetCodegen; +} + void cmGlobalGenerator::AddGlobalTarget_EditCache( std::vector<GlobalTargetInfo>& targets) const { diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 1ca02d9..33c9889 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -653,6 +653,8 @@ public: virtual std::string& EncodeLiteral(std::string& lit) { return lit; } + bool CheckCMP0171() const; + protected: // for a project collect all its targets by following depend // information, and also collect all the targets @@ -719,6 +721,8 @@ protected: void AddGlobalTarget_Install(std::vector<GlobalTargetInfo>& targets); void CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf); + void ReserveGlobalTargetCodegen(); + std::string FindMakeProgramFile; std::string ConfiguredFilesPath; cmake* CMakeInstance; @@ -891,4 +895,5 @@ protected: bool ToolSupportsColor; bool InstallTargetEnabled; bool ConfigureDoneCMP0026AndCMP0024; + bool AllowGlobalTargetCodegen; }; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 96c8f25..7d62fa8 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -25,6 +25,7 @@ #include "cmsys/FStream.hxx" +#include "cmCustomCommand.h" #include "cmCxxModuleMapper.h" #include "cmDyndepCollation.h" #include "cmFortranParser.h" @@ -43,6 +44,7 @@ #include "cmOutputConverter.h" #include "cmRange.h" #include "cmScanDepFormat.h" +#include "cmSourceFile.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" @@ -1627,6 +1629,90 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) std::map<std::string, DirectoryTarget> dirTargets = this->ComputeDirectoryTargets(); + // Codegen target + if (this->CheckCMP0171()) { + for (auto const& it : dirTargets) { + cmNinjaBuild build("phony"); + cmGlobalNinjaGenerator::WriteDivider(os); + std::string const& currentBinaryDir = it.first; + DirectoryTarget const& dt = it.second; + std::vector<std::string> configs = + dt.LG->GetMakefile()->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig); + + // Setup target + cmNinjaDeps configDeps; + build.Comment = cmStrCat("Folder: ", currentBinaryDir); + build.Outputs.emplace_back(); + std::string const buildDirAllTarget = + this->ConvertToNinjaPath(cmStrCat(currentBinaryDir, "/codegen")); + + cmNinjaDeps& explicitDeps = build.ExplicitDeps; + + for (auto const& config : configs) { + explicitDeps.clear(); + + for (DirectoryTarget::Target const& t : dt.Targets) { + if (this->IsExcludedFromAllInConfig(t, config)) { + continue; + } + + std::vector<cmSourceFile const*> customCommandSources; + t.GT->GetCustomCommands(customCommandSources, config); + for (cmSourceFile const* sf : customCommandSources) { + cmCustomCommand const* cc = sf->GetCustomCommand(); + if (cc->GetCodegen()) { + auto const& outputs = cc->GetOutputs(); + + std::transform(outputs.begin(), outputs.end(), + std::back_inserter(explicitDeps), + this->MapToNinjaPath()); + } + } + } + + build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config); + // Write target + this->WriteBuild(this->EnableCrossConfigBuild() && + this->CrossConfigs.count(config) + ? os + : *this->GetImplFileStream(config), + build); + } + + // Add shortcut target + if (this->IsMultiConfig()) { + for (auto const& config : configs) { + build.ExplicitDeps = { this->BuildAlias(buildDirAllTarget, config) }; + build.Outputs.front() = buildDirAllTarget; + this->WriteBuild(*this->GetConfigFileStream(config), build); + } + + if (!this->DefaultFileConfig.empty()) { + build.ExplicitDeps.clear(); + for (auto const& config : this->DefaultConfigs) { + build.ExplicitDeps.push_back( + this->BuildAlias(buildDirAllTarget, config)); + } + build.Outputs.front() = buildDirAllTarget; + this->WriteBuild(*this->GetDefaultFileStream(), build); + } + } + + // Add target for all configs + if (this->EnableCrossConfigBuild()) { + build.ExplicitDeps.clear(); + for (auto const& config : this->CrossConfigs) { + build.ExplicitDeps.push_back( + this->BuildAlias(buildDirAllTarget, config)); + } + build.Outputs.front() = this->BuildAlias(buildDirAllTarget, "codegen"); + this->WriteBuild(os, build); + } + } + } + + // All target for (auto const& it : dirTargets) { cmNinjaBuild build("phony"); cmGlobalNinjaGenerator::WriteDivider(os); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 56748a5..38cc4f6 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -23,6 +23,7 @@ #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTarget.h" #include "cmTargetDepend.h" #include "cmValue.h" #include "cmake.h" @@ -438,6 +439,10 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2( // Write directory-level rules for "all". this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "all", true, false); + // Write directory-level rules for "codegen". + this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "codegen", true, + false); + // Write directory-level rules for "preinstall". this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "preinstall", true, true); @@ -765,6 +770,17 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( depends, commands, true); } + // add the codegen rule + localName = lg.GetRelativeTargetDirectory(gtarget.get()); + depends.clear(); + commands.clear(); + makeTargetName = cmStrCat(localName, "/codegen"); + commands.push_back( + lg.GetRecursiveMakeCall(makefileName, makeTargetName)); + this->AppendCodegenTargetDepends(depends, gtarget.get()); + rootLG.WriteMakeRule(ruleFileStream, "codegen rule for target.", + makeTargetName, depends, commands, true); + // add the clean rule localName = lg.GetRelativeTargetDirectory(gtarget.get()); makeTargetName = cmStrCat(localName, "/clean"); @@ -893,6 +909,29 @@ void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends( } } +void cmGlobalUnixMakefileGenerator3::AppendCodegenTargetDepends( + std::vector<std::string>& depends, cmGeneratorTarget* target) +{ + const std::set<std::string>& codegen_depends = + target->Target->GetCodegenDeps(); + + for (cmTargetDepend const& i : this->GetTargetDirectDepends(target)) { + // Create the target-level dependency. + cmGeneratorTarget const* dep = i; + if (!dep->IsInBuildSystem()) { + continue; + } + if (codegen_depends.find(dep->GetName()) != codegen_depends.end()) { + cmLocalUnixMakefileGenerator3* lg3 = + static_cast<cmLocalUnixMakefileGenerator3*>(dep->GetLocalGenerator()); + std::string tgtName = cmStrCat( + lg3->GetRelativeTargetDirectory(const_cast<cmGeneratorTarget*>(dep)), + "/all"); + depends.push_back(tgtName); + } + } +} + void cmGlobalUnixMakefileGenerator3::WriteHelpRule( std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg) { diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index ee78351..d4fcf88 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -223,6 +223,9 @@ protected: void AppendGlobalTargetDepends(std::vector<std::string>& depends, cmGeneratorTarget* target); + void AppendCodegenTargetDepends(std::vector<std::string>& depends, + cmGeneratorTarget* target); + // Target name hooks for superclass. const char* GetAllTargetName() const override { return "all"; } const char* GetInstallTargetName() const override { return "install"; } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index aa3f28e..e6d56d3 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -4626,6 +4626,12 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg, if (cmCustomCommand* cc = sf->GetCustomCommand()) { cc->AppendCommands(commandLines); cc->AppendDepends(depends); + if (cc->GetCodegen() && !implicit_depends.empty()) { + lg.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "Cannot append IMPLICIT_DEPENDS to existing CODEGEN custom " + "command."); + } cc->AppendImplicitDepends(implicit_depends); return; } diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 7def1fe..4a776b4 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1763,6 +1763,21 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( this->WriteMakeRule(ruleFileStream, "The main all target", "all", depends, commands, true); + // Write the codegen rule. + if (this->GetGlobalGenerator()->CheckCMP0171()) { + recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/codegen"); + depends.clear(); + commands.clear(); + if (regenerate) { + depends.emplace_back("cmake_check_build_system"); + } + commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget)); + AppendEcho(commands, "Finished generating code", + cmLocalUnixMakefileGenerator3::EchoColor::EchoGenerate); + this->WriteMakeRule(ruleFileStream, "The main codegen target", "codegen", + depends, commands, true); + } + // Write the clean rule. recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/clean"); commands.clear(); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index d5c50bc..9ff0a4a 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -251,6 +251,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() std::vector<cmSourceFile const*> customCommands; this->GeneratorTarget->GetCustomCommands(customCommands, this->GetConfigName()); + std::vector<std::string> codegen_depends; + codegen_depends.reserve(customCommands.size()); for (cmSourceFile const* sf : customCommands) { if (this->CMP0113New && !this->LocalGenerator->GetCommandsVisited(this->GeneratorTarget) @@ -273,6 +275,33 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() this->LocalGenerator->MaybeRelativeToCurBinDir(byproduct)); } } + + if (ccg.GetCC().GetCodegen()) { + std::string const& output = ccg.GetOutputs().front(); + + // We always attach the actual commands to the first output. + codegen_depends.emplace_back(output); + } + } + + // Some make tools need a special dependency for an empty rule. + if (codegen_depends.empty()) { + std::string hack = this->GlobalGenerator->GetEmptyRuleHackDepends(); + if (!hack.empty()) { + codegen_depends.emplace_back(std::move(hack)); + } + } + + // Construct the codegen target. + { + std::string const codegenTarget = cmStrCat( + this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget), + "/codegen"); + + // Write the rule. + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, + codegenTarget, codegen_depends, {}, + true); } // Add byproducts from build events to the clean rules diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index d893c44..85f3293 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -525,7 +525,9 @@ class cmMakefile; 3, 30, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0170, \ "FETCHCONTENT_FULLY_DISCONNECTED requirements are enforced.", 3, 30, \ - 0, cmPolicies::WARN) + 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0171, "'codegen' is a reserved target name.", 3, 31, 0, \ + cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 8e880fd..d646cce 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1647,13 +1647,10 @@ bool cmQtAutoGenInitializer::InitRccTargets() sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On"); } - std::vector<std::string> ccOutput; - ccOutput.push_back(qrc.OutputFile); + std::vector<std::string> ccOutput{ qrc.OutputFile }; - std::vector<std::string> ccDepends; // Add the .qrc and info file to the custom command dependencies - ccDepends.push_back(qrc.QrcFile); - ccDepends.push_back(qrc.InfoFile); + std::vector<std::string> ccDepends{ qrc.QrcFile, qrc.InfoFile }; cmCustomCommandLines commandLines; AddCMakeProcessToCommandLines(qrc.InfoFile, "cmake_autorcc", commandLines); @@ -1676,13 +1673,43 @@ bool cmQtAutoGenInitializer::InitRccTargets() if (!qrc.Unique) { ccName += cmStrCat('_', qrc.QrcPathChecksum); } - - cc->SetByproducts(ccOutput); - cc->SetDepends(ccDepends); - cc->SetEscapeOldStyle(false); - cmTarget* autoRccTarget = - this->LocalGen->AddUtilityCommand(ccName, true, std::move(cc)); - + cmTarget* autoRccTarget = nullptr; + // When CMAKE_GLOBAL_AUTORCC_TARGET is ON and qrc is not generated, + // Add generate a timestamp file and a custom command to touch it. + // This will ensure that the global autorcc target is run only when the + // qrc file changes. + if (!qrc.Generated && this->Rcc.GlobalTarget) { + cm::string_view const timestampFileName = "global_rcc_timestamp"; + auto const outputFile = + cmStrCat(this->Dir.Build, "/", timestampFileName); + commandLines.push_back(cmMakeCommandLine( + { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile })); + cc->SetByproducts(ccOutput); + cc->SetDepends(ccDepends); + cc->SetEscapeOldStyle(false); + cc->SetOutputs(outputFile); + cc->SetCommandLines(commandLines); + this->LocalGen->AddCustomCommandToOutput(std::move(cc)); + this->AddGeneratedSource(outputFile, this->Rcc); + ccDepends.clear(); + ccDepends.push_back(outputFile); + + auto ccRccTarget = cm::make_unique<cmCustomCommand>(); + ccRccTarget->SetWorkingDirectory(this->Dir.Work.c_str()); + ccRccTarget->SetComment(ccComment.c_str()); + ccRccTarget->SetStdPipesUTF8(true); + ccRccTarget->SetDepends(ccDepends); + ccRccTarget->SetEscapeOldStyle(false); + + autoRccTarget = this->LocalGen->AddUtilityCommand( + ccName, true, std::move(ccRccTarget)); + } else { + cc->SetByproducts(ccOutput); + cc->SetDepends(ccDepends); + cc->SetEscapeOldStyle(false); + autoRccTarget = + this->LocalGen->AddUtilityCommand(ccName, true, std::move(cc)); + } // Create autogen generator target this->LocalGen->AddGeneratorTarget( cm::make_unique<cmGeneratorTarget>(autoRccTarget, this->LocalGen)); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 1284130..a6e6984 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -657,6 +657,7 @@ public: bool PerConfig; cmTarget::Visibility TargetVisibility; std::set<BT<std::pair<std::string, bool>>> Utilities; + std::set<std::string> CodegenDependencies; std::vector<cmCustomCommand> PreBuildCommands; std::vector<cmCustomCommand> PreLinkCommands; std::vector<cmCustomCommand> PostBuildCommands; @@ -1238,6 +1239,16 @@ void cmTarget::AddUtility(BT<std::pair<std::string, bool>> util) this->impl->Utilities.emplace(std::move(util)); } +void cmTarget::AddCodegenDependency(std::string const& name) +{ + this->impl->CodegenDependencies.emplace(name); +} + +std::set<std::string> const& cmTarget::GetCodegenDeps() const +{ + return this->impl->CodegenDependencies; +} + std::set<BT<std::pair<std::string, bool>>> const& cmTarget::GetUtilities() const { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 385dfe7..220ac13 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -173,6 +173,11 @@ public: void AddUtility(std::string const& name, bool cross, cmMakefile const* mf = nullptr); void AddUtility(BT<std::pair<std::string, bool>> util); + + void AddCodegenDependency(std::string const& name); + + std::set<std::string> const& GetCodegenDeps() const; + //! Get the utilities used by this target std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const; diff --git a/Source/cmTargetTraceDependencies.cxx b/Source/cmTargetTraceDependencies.cxx index cc91a42..f14cfbf 100644 --- a/Source/cmTargetTraceDependencies.cxx +++ b/Source/cmTargetTraceDependencies.cxx @@ -7,10 +7,12 @@ #include <cmext/algorithm> +#include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmList.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSourceFile.h" @@ -132,6 +134,8 @@ void cmTargetTraceDependencies::FollowName(std::string const& name) // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or // POST_BUILD command. this->GeneratorTarget->Target->AddUtility(t->GetName(), false); + + this->GeneratorTarget->Target->AddCodegenDependency(t->GetName()); } if (cmSourceFile* sf = i->second.Source) { // For now only follow the dependency if the source file is not a @@ -213,6 +217,11 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc) // Collect target-level dependencies referenced in command lines. for (auto const& util : ccg.GetUtilities()) { this->GeneratorTarget->Target->AddUtility(util); + + if (ccg.GetCC().GetCodegen()) { + this->GeneratorTarget->Target->AddCodegenDependency( + util.Value.first); + } } // Collect file-level dependencies referenced in DEPENDS. @@ -226,6 +235,8 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc) // The dependency does not name a target and may be a file we // know how to generate. Queue it. this->FollowName(dep); + } else { + this->GeneratorTarget->Target->AddCodegenDependency(dep); } } } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 0fb8bae..eb14e24 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -813,6 +813,7 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( this->WriteCustomCommands(e0); this->WriteAllSources(e0); this->WriteDotNetReferences(e0); + this->WriteFrameworkReferences(e0); this->WritePackageReferences(e0); this->WriteImports(e0); this->WriteEmbeddedResourceGroup(e0); @@ -1187,6 +1188,21 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference( this->WriteDotNetReferenceCustomTags(e2, ref); } +void cmVisualStudio10TargetGenerator::WriteFrameworkReferences(Elem& e0) +{ + cmList references; + if (cmValue vsFrameworkReferences = + this->GeneratorTarget->GetProperty("VS_FRAMEWORK_REFERENCES")) { + references.assign(*vsFrameworkReferences); + } + + Elem e1(e0, "ItemGroup"); + for (auto const& ref : references) { + Elem e2(e1, "FrameworkReference"); + e2.Attribute("Include", ref); + } +} + void cmVisualStudio10TargetGenerator::WriteImports(Elem& e0) { cmValue imports = diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 056f426..53eb1af 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -91,6 +91,7 @@ private: void WriteDotNetReference(Elem& e1, std::string const& ref, std::string const& hint, std::string const& config); + void WriteFrameworkReferences(Elem& e0); void WriteDotNetDocumentationFile(Elem& e0); void WriteImports(Elem& e0); void WriteDotNetReferenceCustomTags(Elem& e2, std::string const& ref); diff --git a/Tests/RunCMake/Autogen_5/RunCMakeTest.cmake b/Tests/RunCMake/Autogen_5/RunCMakeTest.cmake index 8060ec4..1f6f7d4 100644 --- a/Tests/RunCMake/Autogen_5/RunCMakeTest.cmake +++ b/Tests/RunCMake/Autogen_5/RunCMakeTest.cmake @@ -27,5 +27,21 @@ if (DEFINED with_qt_version) endblock() endforeach() endif() + if (RunCMake_GENERATOR MATCHES "Ninja") + block() + set(RunCMake_TEST_BINARY_DIR + ${RunCMake_BINARY_DIR}/RccGlobalAutoRcc-build) + run_cmake_with_options(RccExample ${RunCMake_TEST_OPTIONS} + -DCMAKE_GLOBAL_AUTORCC_TARGET=ON) + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake_TEST_VARIANT_DESCRIPTION "-First-build") + run_cmake_command(RccGlobalAutoRcc-build ${CMAKE_COMMAND} + --build . --config Debug) + set(RunCMake_TEST_VARIANT_DESCRIPTION "-Second-build-nothing-to-do") + set(RunCMake_TEST_NOT_EXPECT_stdout "Automatic RCC for data.qrc") + run_cmake_command(RccGlobalAutoRcc-build ${CMAKE_COMMAND} + --build . --config Debug) + endblock() + endif() endif() endif () diff --git a/Tests/RunCMake/CMP0171/CMP0171-NEW-result.txt b/Tests/RunCMake/CMP0171/CMP0171-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMP0171/CMP0171-NEW-stderr.txt b/Tests/RunCMake/CMP0171/CMP0171-NEW-stderr.txt new file mode 100644 index 0000000..155ddd2 --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-NEW-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at CMP0171-NEW\.cmake:[0-9]+ \(add_custom_target\): + The target name "codegen" is reserved\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/CMP0171/CMP0171-NEW.cmake b/Tests/RunCMake/CMP0171/CMP0171-NEW.cmake new file mode 100644 index 0000000..547f6c0 --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-NEW.cmake @@ -0,0 +1,6 @@ +# codegen is now a reserved name and this will cause an error since the policy is new. +add_custom_target(codegen + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.h +) diff --git a/Tests/RunCMake/CMP0171/CMP0171-OLD-result.txt b/Tests/RunCMake/CMP0171/CMP0171-OLD-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-OLD-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMP0171/CMP0171-OLD-stderr.txt b/Tests/RunCMake/CMP0171/CMP0171-OLD-stderr.txt new file mode 100644 index 0000000..1ae3318 --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-OLD-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at CMP0171-OLD\.cmake:[0-9]+ \(add_custom_command\): + add_custom_command CODEGEN option requires policy CMP0171 be set to NEW\! +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/CMP0171/CMP0171-OLD.cmake b/Tests/RunCMake/CMP0171/CMP0171-OLD.cmake new file mode 100644 index 0000000..c34b3fb --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-OLD.cmake @@ -0,0 +1,9 @@ +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp + # This will cause an error since the CODEGEN option + # requires that CMP0171 is set to NEW + CODEGEN +) diff --git a/Tests/RunCMake/CMP0171/CMP0171-WARN-stderr.txt b/Tests/RunCMake/CMP0171/CMP0171-WARN-stderr.txt new file mode 100644 index 0000000..ee79553 --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-WARN-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMP0171-WARN\.cmake:[0-9]+ \(add_custom_target\): + Policy CMP0171 is not set: 'codegen' is a reserved target name\. Run "cmake + --help-policy CMP0171" for policy details. Use the cmake_policy command to + set the policy and suppress this warning\. + + The target name "codegen" is reserved\. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. diff --git a/Tests/RunCMake/CMP0171/CMP0171-WARN.cmake b/Tests/RunCMake/CMP0171/CMP0171-WARN.cmake new file mode 100644 index 0000000..6d61723 --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-WARN.cmake @@ -0,0 +1,6 @@ +# CMake should warn the user if they have a target named codegen. +add_custom_target(codegen + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.h +) diff --git a/Tests/RunCMake/CMP0171/CMP0171-codegen-build-result.txt b/Tests/RunCMake/CMP0171/CMP0171-codegen-build-result.txt new file mode 100644 index 0000000..d197c91 --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-codegen-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/CMP0171/CMP0171-codegen.cmake b/Tests/RunCMake/CMP0171/CMP0171-codegen.cmake new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMP0171-codegen.cmake diff --git a/Tests/RunCMake/CMP0171/CMakeLists.txt b/Tests/RunCMake/CMP0171/CMakeLists.txt new file mode 100644 index 0000000..1a5755c --- /dev/null +++ b/Tests/RunCMake/CMP0171/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.29) +project(${RunCMake_TEST} LANGUAGES C) + +include(${RunCMake_TEST}.cmake) + +enable_testing() diff --git a/Tests/RunCMake/CMP0171/RunCMakeTest.cmake b/Tests/RunCMake/CMP0171/RunCMakeTest.cmake new file mode 100644 index 0000000..75941d7 --- /dev/null +++ b/Tests/RunCMake/CMP0171/RunCMakeTest.cmake @@ -0,0 +1,18 @@ +include(RunCMake) + +run_cmake("CMP0171-WARN") + +run_cmake_with_options(CMP0171-OLD "-DCMAKE_POLICY_DEFAULT_CMP0171=OLD") + +run_cmake_with_options(CMP0171-NEW "-DCMAKE_POLICY_DEFAULT_CMP0171=NEW") + +# The entire point of this test is to ensure the codegen target is not created +# unintentionally. It can only be created if CMP0171 is NEW. +block() + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0171-codegen-build) + run_cmake(CMP0171-codegen) + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake_TEST_OUTPUT_MERGE 1) + # This command will fail with either 1 or 2 depending. + run_cmake_command(CMP0171-codegen-build ${CMAKE_COMMAND} --build . --config Debug --target codegen) +endblock() diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index bfa59d6..db5ef96 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -180,6 +180,7 @@ add_RunCMake_test(CMP0163) add_RunCMake_test(CMP0165) add_RunCMake_test(CMP0169) add_RunCMake_test(CMP0170) +add_RunCMake_test(CMP0171) # The test for Policy 65 requires the use of the # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode @@ -1228,7 +1229,8 @@ add_RunCMake_test(CMakePresetsWorkflow add_RunCMake_test(VerifyHeaderSets) add_RunCMake_test(set_tests_properties) -if(${CMAKE_GENERATOR} MATCHES "Make|Ninja") +if(CMAKE_GENERATOR MATCHES "Make|Ninja") + add_RunCMake_test(Codegen) add_RunCMake_test(TransformDepfile) endif() diff --git a/Tests/RunCMake/Codegen/CMakeLists.txt b/Tests/RunCMake/Codegen/CMakeLists.txt new file mode 100644 index 0000000..f65150d --- /dev/null +++ b/Tests/RunCMake/Codegen/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.29) +project(${RunCMake_TEST} LANGUAGES C) + +# This value is read from the top level CMakeLists.txt +cmake_policy(SET CMP0171 NEW) + +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/Codegen/RunCMakeTest.cmake b/Tests/RunCMake/Codegen/RunCMakeTest.cmake new file mode 100644 index 0000000..bbd70b0 --- /dev/null +++ b/Tests/RunCMake/Codegen/RunCMakeTest.cmake @@ -0,0 +1,33 @@ +include(RunCMake) + +function(run_codegen case) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build) + + run_cmake(${case}) + + set(RunCMake_TEST_NO_CLEAN 1) + + run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --target codegen --config Debug) +endfunction() + +# Builds codegen target when there are no custom commands marked codegen +run_codegen("no-codegen") + +# We don't want codegen to drive parts of the project that are EXCLUDE_FROM_ALL +run_codegen("exclude-from-all") + +# Ensures codegen builds minimal build graphs +run_codegen("min-graph-1") +run_codegen("min-graph-2") +run_codegen("min-graph-3") + +# Handle specific cases that can affect codegen +run_codegen("add-dependencies") +run_codegen("add-custom-command-depends") +run_codegen("byproducts") + +# Error handling +run_cmake("implicit-depends") +run_cmake("implicit-depends-append-codegen") +run_cmake("append-implicit-depends") +run_cmake("no-output") diff --git a/Tests/RunCMake/Codegen/add-custom-command-depends-build-check.cmake b/Tests/RunCMake/Codegen/add-custom-command-depends-build-check.cmake new file mode 100644 index 0000000..d371d73 --- /dev/null +++ b/Tests/RunCMake/Codegen/add-custom-command-depends-build-check.cmake @@ -0,0 +1,5 @@ +set(filename "${RunCMake_TEST_BINARY_DIR}/generated.hpp") +if (NOT EXISTS "${filename}") + set(RunCMake_TEST_FAILED "expected file NOT created:\n ${filename}") + return() +endif() diff --git a/Tests/RunCMake/Codegen/add-custom-command-depends.cmake b/Tests/RunCMake/Codegen/add-custom-command-depends.cmake new file mode 100644 index 0000000..793ab5f --- /dev/null +++ b/Tests/RunCMake/Codegen/add-custom-command-depends.cmake @@ -0,0 +1,16 @@ +add_custom_target(foobar + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.h +) + +add_custom_command( + OUTPUT generated.hpp + # This test will fail if DEPENDS isn't accounted for in the codegen build graph + DEPENDS foobar + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated.h + ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp + CODEGEN +) + +add_custom_target(hpp_creator ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp) diff --git a/Tests/RunCMake/Codegen/add-dependencies-build-check.cmake b/Tests/RunCMake/Codegen/add-dependencies-build-check.cmake new file mode 100644 index 0000000..d371d73 --- /dev/null +++ b/Tests/RunCMake/Codegen/add-dependencies-build-check.cmake @@ -0,0 +1,5 @@ +set(filename "${RunCMake_TEST_BINARY_DIR}/generated.hpp") +if (NOT EXISTS "${filename}") + set(RunCMake_TEST_FAILED "expected file NOT created:\n ${filename}") + return() +endif() diff --git a/Tests/RunCMake/Codegen/add-dependencies.cmake b/Tests/RunCMake/Codegen/add-dependencies.cmake new file mode 100644 index 0000000..fbb7e99 --- /dev/null +++ b/Tests/RunCMake/Codegen/add-dependencies.cmake @@ -0,0 +1,18 @@ +add_custom_target(foobar + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.h +) + +add_custom_command( + OUTPUT generated.hpp + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated.h + ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp + CODEGEN +) + +add_custom_target(hpp_creator ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp) + +# This test will fail if add_dependencies isn't account for in the +# codegen build graph +add_dependencies(hpp_creator foobar) diff --git a/Tests/RunCMake/Codegen/append-implicit-depends-result.txt b/Tests/RunCMake/Codegen/append-implicit-depends-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Codegen/append-implicit-depends-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Codegen/append-implicit-depends-stderr.txt b/Tests/RunCMake/Codegen/append-implicit-depends-stderr.txt new file mode 100644 index 0000000..c8ef03e --- /dev/null +++ b/Tests/RunCMake/Codegen/append-implicit-depends-stderr.txt @@ -0,0 +1,2 @@ +CMake Error: + Cannot append IMPLICIT_DEPENDS to existing CODEGEN custom command\. diff --git a/Tests/RunCMake/Codegen/append-implicit-depends.cmake b/Tests/RunCMake/Codegen/append-implicit-depends.cmake new file mode 100644 index 0000000..d212fe5 --- /dev/null +++ b/Tests/RunCMake/Codegen/append-implicit-depends.cmake @@ -0,0 +1,19 @@ +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + COMMAND + ${CMAKE_COMMAND} -E + copy ${CMAKE_CURRENT_SOURCE_DIR}/error.c + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + CODEGEN +) + +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + + # ERROR out if IMPLICIT_DEPENDS is used with CODEGEN + IMPLICIT_DEPENDS C main.c + + APPEND +) diff --git a/Tests/RunCMake/Codegen/byproducts-build-check.cmake b/Tests/RunCMake/Codegen/byproducts-build-check.cmake new file mode 100644 index 0000000..d371d73 --- /dev/null +++ b/Tests/RunCMake/Codegen/byproducts-build-check.cmake @@ -0,0 +1,5 @@ +set(filename "${RunCMake_TEST_BINARY_DIR}/generated.hpp") +if (NOT EXISTS "${filename}") + set(RunCMake_TEST_FAILED "expected file NOT created:\n ${filename}") + return() +endif() diff --git a/Tests/RunCMake/Codegen/byproducts.cmake b/Tests/RunCMake/Codegen/byproducts.cmake new file mode 100644 index 0000000..ea0b6c7 --- /dev/null +++ b/Tests/RunCMake/Codegen/byproducts.cmake @@ -0,0 +1,19 @@ +add_custom_target(foobar + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.h + BYPRODUCTS + ${CMAKE_CURRENT_BINARY_DIR}/generated.h +) + +# This codegen step relies on the BYPRODUCTS of the previous command. +# If foobar isn't properly accounted for as a dependency it will fail. +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated.h + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated.h + ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp + CODEGEN +) + +add_custom_target(hpp_creator ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp) diff --git a/Tests/RunCMake/Codegen/error.c b/Tests/RunCMake/Codegen/error.c new file mode 100644 index 0000000..34cb350 --- /dev/null +++ b/Tests/RunCMake/Codegen/error.c @@ -0,0 +1 @@ +#error "This file should not be compiled" diff --git a/Tests/RunCMake/Codegen/exclude-from-all.cmake b/Tests/RunCMake/Codegen/exclude-from-all.cmake new file mode 100644 index 0000000..bcd4ac0 --- /dev/null +++ b/Tests/RunCMake/Codegen/exclude-from-all.cmake @@ -0,0 +1,11 @@ +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/generated.h + COMMAND + ${CMAKE_COMMAND} -E false + CODEGEN +) + +# We don't want codegen to drive parts of the project that are EXCLUDE_FROM_ALL. +# This tests that foobar is properly excluded from the codegen build. +add_executable(foobar EXCLUDE_FROM_ALL error.c ${CMAKE_CURRENT_BINARY_DIR}/generated.h) diff --git a/Tests/RunCMake/Codegen/generated.h.in b/Tests/RunCMake/Codegen/generated.h.in new file mode 100644 index 0000000..82ccf67 --- /dev/null +++ b/Tests/RunCMake/Codegen/generated.h.in @@ -0,0 +1 @@ +// hello diff --git a/Tests/RunCMake/Codegen/implicit-depends-append-codegen-result.txt b/Tests/RunCMake/Codegen/implicit-depends-append-codegen-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Codegen/implicit-depends-append-codegen-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Codegen/implicit-depends-append-codegen-stderr.txt b/Tests/RunCMake/Codegen/implicit-depends-append-codegen-stderr.txt new file mode 100644 index 0000000..570cf62 --- /dev/null +++ b/Tests/RunCMake/Codegen/implicit-depends-append-codegen-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at implicit-depends-append-codegen\.cmake:[0-9]+ \(add_custom_command\): + add_custom_command CODEGEN may not be used with APPEND\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/Codegen/implicit-depends-append-codegen.cmake b/Tests/RunCMake/Codegen/implicit-depends-append-codegen.cmake new file mode 100644 index 0000000..76151cc --- /dev/null +++ b/Tests/RunCMake/Codegen/implicit-depends-append-codegen.cmake @@ -0,0 +1,18 @@ +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + + # ERROR out if IMPLICIT_DEPENDS is used with CODEGEN + IMPLICIT_DEPENDS C main.c +) + +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + COMMAND + ${CMAKE_COMMAND} -E + copy ${CMAKE_CURRENT_SOURCE_DIR}/error.c + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + CODEGEN + APPEND +) diff --git a/Tests/RunCMake/Codegen/implicit-depends-result.txt b/Tests/RunCMake/Codegen/implicit-depends-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Codegen/implicit-depends-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Codegen/implicit-depends-stderr.txt b/Tests/RunCMake/Codegen/implicit-depends-stderr.txt new file mode 100644 index 0000000..b9ea8f4 --- /dev/null +++ b/Tests/RunCMake/Codegen/implicit-depends-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at implicit-depends\.cmake:[0-9]+ \(add_custom_command\): + add_custom_command CODEGEN is not compatible with IMPLICIT_DEPENDS\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/Codegen/implicit-depends.cmake b/Tests/RunCMake/Codegen/implicit-depends.cmake new file mode 100644 index 0000000..011d4b3 --- /dev/null +++ b/Tests/RunCMake/Codegen/implicit-depends.cmake @@ -0,0 +1,11 @@ +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + COMMAND + ${CMAKE_COMMAND} -E + copy ${CMAKE_CURRENT_SOURCE_DIR}/error.c + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + CODEGEN + # ERROR out if IMPLICIT_DEPENDS is used with CODEGEN + IMPLICIT_DEPENDS C main.c +) diff --git a/Tests/RunCMake/Codegen/main.c b/Tests/RunCMake/Codegen/main.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/Codegen/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/Codegen/min-graph-1-build-check.cmake b/Tests/RunCMake/Codegen/min-graph-1-build-check.cmake new file mode 100644 index 0000000..32e1557 --- /dev/null +++ b/Tests/RunCMake/Codegen/min-graph-1-build-check.cmake @@ -0,0 +1,13 @@ +set(filename "${RunCMake_TEST_BINARY_DIR}/generated.h") +if (NOT EXISTS "${filename}") + set(RunCMake_TEST_FAILED "expected file NOT created:\n ${filename}") + return() +endif() + +# foobar should be built since it was needed +# by the code generation +set(filename "${RunCMake_TEST_BINARY_DIR}/foobar.txt") +if (NOT EXISTS "${filename}") + set(RunCMake_TEST_FAILED "expected file NOT created:\n ${filename}") + return() +endif() diff --git a/Tests/RunCMake/Codegen/min-graph-1.cmake b/Tests/RunCMake/Codegen/min-graph-1.cmake new file mode 100644 index 0000000..ea47b8f --- /dev/null +++ b/Tests/RunCMake/Codegen/min-graph-1.cmake @@ -0,0 +1,26 @@ +add_executable(foobar main.c) +add_custom_command( + TARGET foobar POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/foobar.txt +) + +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/generated.h + COMMAND + ${CMAKE_COMMAND} -E + copy ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.h + COMMAND + # Generate a header file that requires foobar + foobar + CODEGEN +) + +add_library(errorlib + # If this library is built error.c will cause the build to fail + error.c + ${CMAKE_CURRENT_BINARY_DIR}/generated.h +) diff --git a/Tests/RunCMake/Codegen/min-graph-2-build-check.cmake b/Tests/RunCMake/Codegen/min-graph-2-build-check.cmake new file mode 100644 index 0000000..fab168b --- /dev/null +++ b/Tests/RunCMake/Codegen/min-graph-2-build-check.cmake @@ -0,0 +1,5 @@ +set(filename "${RunCMake_TEST_BINARY_DIR}/generated.h") +if (NOT EXISTS "${filename}") + set(RunCMake_TEST_FAILED "expected file NOT created:\n ${filename}") + return() +endif() diff --git a/Tests/RunCMake/Codegen/min-graph-2.cmake b/Tests/RunCMake/Codegen/min-graph-2.cmake new file mode 100644 index 0000000..277a901 --- /dev/null +++ b/Tests/RunCMake/Codegen/min-graph-2.cmake @@ -0,0 +1,18 @@ +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/generated.h + COMMAND + ${CMAKE_COMMAND} -E + copy ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.h + CODEGEN +) + +# This target should not be built. It has no reason +# to be part of the codegen build graph +add_custom_target(error_custom_target ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated.h + + # Cause the build to fail + COMMAND ${CMAKE_COMMAND} -E false +) diff --git a/Tests/RunCMake/Codegen/min-graph-3-build-check.cmake b/Tests/RunCMake/Codegen/min-graph-3-build-check.cmake new file mode 100644 index 0000000..734777b --- /dev/null +++ b/Tests/RunCMake/Codegen/min-graph-3-build-check.cmake @@ -0,0 +1,5 @@ +set(filename "${RunCMake_TEST_BINARY_DIR}/error_lib.c") +if (NOT EXISTS "${filename}") + set(RunCMake_TEST_FAILED "expected file NOT created:\n ${filename}") + return() +endif() diff --git a/Tests/RunCMake/Codegen/min-graph-3.cmake b/Tests/RunCMake/Codegen/min-graph-3.cmake new file mode 100644 index 0000000..c7d61dc --- /dev/null +++ b/Tests/RunCMake/Codegen/min-graph-3.cmake @@ -0,0 +1,12 @@ +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/error_lib.c + COMMAND + ${CMAKE_COMMAND} -E + copy ${CMAKE_CURRENT_SOURCE_DIR}/error.c + ${CMAKE_CURRENT_BINARY_DIR}/error_lib.c + CODEGEN +) + +# This test will fail if error_lib.c is actually compiled +add_executable(foobar ${CMAKE_CURRENT_BINARY_DIR}/error_lib.c) diff --git a/Tests/RunCMake/Codegen/no-codegen-check.cmake b/Tests/RunCMake/Codegen/no-codegen-check.cmake new file mode 100644 index 0000000..97fc46b --- /dev/null +++ b/Tests/RunCMake/Codegen/no-codegen-check.cmake @@ -0,0 +1,5 @@ +# Verify generated.hpp was NOT created +set(unexpected "${RunCMake_TEST_BINARY_DIR}/generated.hpp") +if(EXISTS "${unexpected}") + set(RunCMake_TEST_FAILED "unexpected file created:\n ${unexpected}") +endif() diff --git a/Tests/RunCMake/Codegen/no-codegen.cmake b/Tests/RunCMake/Codegen/no-codegen.cmake new file mode 100644 index 0000000..00ddd03 --- /dev/null +++ b/Tests/RunCMake/Codegen/no-codegen.cmake @@ -0,0 +1,6 @@ +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp +) diff --git a/Tests/RunCMake/Codegen/no-output-result.txt b/Tests/RunCMake/Codegen/no-output-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Codegen/no-output-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Codegen/no-output-stderr.txt b/Tests/RunCMake/Codegen/no-output-stderr.txt new file mode 100644 index 0000000..7aad679 --- /dev/null +++ b/Tests/RunCMake/Codegen/no-output-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at no-output\.cmake:[0-9]+ \(add_custom_command\): + add_custom_command CODEGEN requires at least 1 OUTPUT\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/Codegen/no-output.cmake b/Tests/RunCMake/Codegen/no-output.cmake new file mode 100644 index 0000000..61eb83c --- /dev/null +++ b/Tests/RunCMake/Codegen/no-output.cmake @@ -0,0 +1,11 @@ +add_custom_target(foobar + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in + ${CMAKE_CURRENT_BINARY_DIR}/generated.h +) + +add_custom_command(TARGET foobar POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E true + CODEGEN +) diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake index 88fd1e8..f1e8b30 100644 --- a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake +++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake @@ -17,7 +17,7 @@ function(check_files dir) list(SORT expected) file(GLOB_RECURSE actual "${dir}/*") - list(FILTER actual EXCLUDE REGEX "/CMakeFiles/|\\.ninja$|/CMakeCache\\.txt$|/target_files[^/]*\\.cmake$|/\\.ninja_[^/]*$|/cmake_install\\.cmake$|\\.ilk$|\\.manifest$|\\.odx$|\\.pdb$|\\.exp$|/install_manifest\\.txt$|/\\.qt/QtDeploySupport[^/]*\\.cmake$") + list(FILTER actual EXCLUDE REGEX "/CMakeFiles/|\\.ninja$|/CMakeCache\\.txt$|/target_files[^/]*\\.cmake$|/\\.ninja_[^/]*$|/cmake_install\\.cmake$|\\.ilk$|\\.manifest$|\\.odx$|\\.pdb$|\\.exp$|/install_manifest\\.txt$|/\\.qt/(QtDeploySupport|QtDeployTargets)[^/]*\\.cmake$") foreach(f IN LISTS _check_files_INCLUDE _check_files_EXCLUDE) if(EXISTS ${f}) list(APPEND actual ${f}) diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index e0d74cf..85fefbf 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -98,6 +98,7 @@ run_cmake(DebugInformationFormat) run_cmake(VsCLREmpty) run_cmake(VsCLRPure) run_cmake(VsCLRSafe) +run_cmake(VsFrameworkReference) if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.20) run_cmake(VsCLRNetcore) diff --git a/Tests/RunCMake/VS10Project/VsFrameworkReference-check.cmake b/Tests/RunCMake/VS10Project/VsFrameworkReference-check.cmake new file mode 100644 index 0000000..7abe8a0 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsFrameworkReference-check.cmake @@ -0,0 +1,24 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(frameworkReferenceSet FALSE) + +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "^ *<FrameworkReference Include=\"([^\"]*)\" />$") + if("${CMAKE_MATCH_1}" STREQUAL "Microsoft.WindowsDesktop.App.WPF") + message(STATUS "foo.vcxproj has FrameworkReference set") + set(frameworkReferenceSet TRUE) + else() + message(STATUS "foo.vcxproj has FrameworkReference incorrectly set to ${CMAKE_MATCH_1}") + endif() + endif() +endforeach() + +if(NOT frameworkReferenceSet) + set(RunCMake_TEST_FAILED "FrameworkReference not found or not set correctly.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsFrameworkReference.cmake b/Tests/RunCMake/VS10Project/VsFrameworkReference.cmake new file mode 100644 index 0000000..0e4d6fb --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsFrameworkReference.cmake @@ -0,0 +1,8 @@ +enable_language(CXX) + +add_executable(foo foo.cpp) + +set_target_properties(foo PROPERTIES + COMMON_LANGUAGE_RUNTIME "netcore" + DOTNET_TARGET_FRAMEWORK "net8.0-windows" + VS_FRAMEWORK_REFERENCES "Microsoft.WindowsDesktop.App.WPF") |