diff options
Diffstat (limited to 'Source')
36 files changed, 1086 insertions, 329 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 7661235..c245f68 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -460,6 +460,8 @@ set(SRCS cmVariableWatch.h cmVersion.cxx cmVersion.h + cmWindowsRegistry.cxx + cmWindowsRegistry.h cmWorkerPool.cxx cmWorkerPool.h cmWorkingDirectory.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 17e5382..f3abe6f 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 23) -set(CMake_VERSION_PATCH 20220412) +set(CMake_VERSION_PATCH 20220421) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx index 92ff6df..2feca75 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx +++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx @@ -424,7 +424,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile() if (!this->Logo.empty()) { std::string srcName = cmSystemTools::GetFilenameName(this->Logo); std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName); - std::string name = "cm_logo." + suffix; + std::string name = "cm_logo" + suffix; std::string path = this->Directory + "/config/" + name; cmsys::SystemTools::CopyFileIfDifferent(this->Logo, path); xout.Element("Logo", name); @@ -461,7 +461,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile() std::string srcName = cmSystemTools::GetFilenameName(this->InstallerApplicationIcon); std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName); - std::string name = "cm_appicon." + suffix; + std::string name = "cm_appicon" + suffix; std::string path = this->Directory + "/config/" + name; cmsys::SystemTools::CopyFileIfDifferent(this->InstallerApplicationIcon, path); @@ -476,7 +476,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile() std::string srcName = cmSystemTools::GetFilenameName(this->InstallerWindowIcon); std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName); - std::string name = "cm_winicon." + suffix; + std::string name = "cm_winicon" + suffix; std::string path = this->Directory + "/config/" + name; cmsys::SystemTools::CopyFileIfDifferent(this->InstallerWindowIcon, path); xout.Element("InstallerWindowIcon", name); diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index f90b781..3c41fce 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -226,7 +226,8 @@ CMakeSetupDialog::CMakeSetupDialog() this->SourceDirectory->setCompleter(new QCMakeFileCompleter(this, true)); // fixed pitch font in output window - QFont outputFont("Courier"); + QFont outputFont("Courier New"); + outputFont.setStyleHint(QFont::Monospace); this->Output->setFont(outputFont); this->ErrorFormat.setForeground(QBrush(Qt::red)); diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx index 3922c56..0c41c68 100644 --- a/Source/cmCMakeHostSystemInformationCommand.cxx +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -9,6 +9,7 @@ #include <map> #include <string> #include <type_traits> +#include <unordered_map> #include <utility> #include <cm/optional> @@ -19,10 +20,13 @@ #include "cmsys/Glob.hxx" #include "cmsys/SystemInformation.hxx" +#include "cmArgumentParser.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmRange.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmWindowsRegistry.h" #ifdef _WIN32 # include "cmAlgorithms.h" @@ -459,6 +463,105 @@ cm::optional<std::string> GetValueChained(GetterFn current, Next... chain) } return GetValueChained(chain...); } + +template <typename Range> +bool QueryWindowsRegistry(Range args, cmExecutionStatus& status, + std::string const& variable) +{ + using View = cmWindowsRegistry::View; + static std::unordered_map<cm::string_view, cmWindowsRegistry::View> + ViewDefinitions{ + { "BOTH"_s, View::Both }, { "HOST"_s, View::Host }, + { "TARGET"_s, View::Target }, { "32"_s, View::Reg32 }, + { "64"_s, View::Reg64 }, { "32_64"_s, View::Reg32_64 }, + { "64_32"_s, View::Reg64_32 } + }; + + if (args.empty()) { + status.SetError("missing <key> specification."); + return false; + } + std::string const& key = *args.begin(); + + struct Arguments + { + std::string ValueName; + bool ValueNames = false; + bool SubKeys = false; + std::string View; + std::string Separator; + std::string ErrorVariable; + }; + cmArgumentParser<Arguments> parser; + parser.Bind("VALUE"_s, &Arguments::ValueName) + .Bind("VALUE_NAMES"_s, &Arguments::ValueNames) + .Bind("SUBKEYS"_s, &Arguments::SubKeys) + .Bind("VIEW"_s, &Arguments::View) + .Bind("SEPARATOR"_s, &Arguments::Separator) + .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable); + std::vector<std::string> invalidArgs; + std::vector<std::string> keywordsMissingValue; + + Arguments const arguments = + parser.Parse(args.advance(1), &invalidArgs, &keywordsMissingValue); + if (!invalidArgs.empty()) { + status.SetError(cmStrCat("given invalid argument(s) \"", + cmJoin(invalidArgs, ", "_s), "\".")); + return false; + } + if (!keywordsMissingValue.empty()) { + status.SetError(cmStrCat("missing expected value for argument(s) \"", + cmJoin(keywordsMissingValue, ", "_s), "\".")); + return false; + } + if ((!arguments.ValueName.empty() && + (arguments.ValueNames || arguments.SubKeys)) || + (arguments.ValueName.empty() && arguments.ValueNames && + arguments.SubKeys)) { + status.SetError("given mutually exclusive sub-options \"VALUE\", " + "\"VALUE_NAMES\" or \"SUBKEYS\"."); + return false; + } + if (!arguments.View.empty() && + ViewDefinitions.find(arguments.View) == ViewDefinitions.end()) { + status.SetError( + cmStrCat("given invalid value for \"VIEW\": ", arguments.View, '.')); + return false; + } + + auto& makefile = status.GetMakefile(); + + makefile.AddDefinition(variable, ""_s); + + auto view = + arguments.View.empty() ? View::Both : ViewDefinitions[arguments.View]; + cmWindowsRegistry registry(makefile); + if (arguments.ValueNames) { + auto result = registry.GetValueNames(key, view); + if (result) { + makefile.AddDefinition(variable, cmJoin(*result, ";"_s)); + } + } else if (arguments.SubKeys) { + auto result = registry.GetSubKeys(key, view); + if (result) { + makefile.AddDefinition(variable, cmJoin(*result, ";"_s)); + } + } else { + auto result = + registry.ReadValue(key, arguments.ValueName, view, arguments.Separator); + if (result) { + makefile.AddDefinition(variable, *result); + } + } + + // return error message if requested + if (!arguments.ErrorVariable.empty()) { + makefile.AddDefinition(arguments.ErrorVariable, registry.GetLastError()); + } + + return true; +} + // END Private functions } // anonymous namespace @@ -481,6 +584,11 @@ bool cmCMakeHostSystemInformationCommand(std::vector<std::string> const& args, return false; } + if (args[current_index + 1] == "WINDOWS_REGISTRY"_s) { + return QueryWindowsRegistry(cmMakeRange(args).advance(current_index + 2), + status, variable); + } + static cmsys::SystemInformation info; static auto initialized = false; if (!initialized) { diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx index e68f0fa..0d3a91f 100644 --- a/Source/cmCMakePresetsGraphReadJSON.cxx +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -569,7 +569,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( } // Support for TestOutputTruncation added in version 5. - if (v < 5 && preset.Output) { + if (v < 5 && preset.Output && preset.Output->TestOutputTruncation) { return ReadFileResult::TEST_OUTPUT_TRUNCATION_UNSUPPORTED; } diff --git a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx index 43eccfe..b874575 100644 --- a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx +++ b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx @@ -58,10 +58,10 @@ auto const TestPresetOptionalOutputVerbosityHelper = TestPresetOutputVerbosityHelper); ReadFileResult TestPresetOutputTruncationHelper( - cmCTestTypes::TruncationMode& out, const Json::Value* value) + cm::optional<cmCTestTypes::TruncationMode>& out, const Json::Value* value) { if (!value) { - out = cmCTestTypes::TruncationMode::Tail; + out = cm::nullopt; return ReadFileResult::READ_OK; } @@ -87,10 +87,6 @@ ReadFileResult TestPresetOutputTruncationHelper( return ReadFileResult::INVALID_PRESET; } -auto const TestPresetOptionalTruncationHelper = - cmJSONOptionalHelper<cmCTestTypes::TruncationMode, ReadFileResult>( - ReadFileResult::READ_OK, TestPresetOutputTruncationHelper); - auto const TestPresetOptionalOutputHelper = cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>( ReadFileResult::READ_OK, @@ -121,7 +117,7 @@ auto const TestPresetOptionalOutputHelper = cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) .Bind("testOutputTruncation"_s, &TestPreset::OutputOptions::TestOutputTruncation, - TestPresetOptionalTruncationHelper, false) + TestPresetOutputTruncationHelper, false) .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth, cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)); diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h index 72ab045..33c91bc 100644 --- a/Source/cmCommandLineArgument.h +++ b/Source/cmCommandLineArgument.h @@ -201,7 +201,57 @@ struct cmCommandLineArgument return (parseState == ParseMode::Valid); } + template <typename... Values> + static std::function<FunctionSignature> setToTrue(Values&&... values) + { + return ArgumentLambdaHelper<FunctionSignature>::generateSetToTrue( + std::forward<Values>(values)...); + } + + template <typename... Values> + static std::function<FunctionSignature> setToValue(Values&&... values) + { + return ArgumentLambdaHelper<FunctionSignature>::generateSetToValue( + std::forward<Values>(values)...); + } + private: + template <typename T> + class ArgumentLambdaHelper; + + template <typename... CallState> + class ArgumentLambdaHelper<bool(const std::string&, CallState...)> + { + public: + static std::function<bool(const std::string&, CallState...)> + generateSetToTrue(bool& value1) + { + return [&value1](const std::string&, CallState&&...) -> bool { + value1 = true; + return true; + }; + } + + static std::function<bool(const std::string&, CallState...)> + generateSetToTrue(bool& value1, bool& value2) + { + return [&value1, &value2](const std::string&, CallState&&...) -> bool { + value1 = true; + value2 = true; + return true; + }; + } + + static std::function<bool(const std::string&, CallState...)> + generateSetToValue(std::string& value1) + { + return [&value1](const std::string& arg, CallState&&...) -> bool { + value1 = arg; + return true; + }; + } + }; + std::string extract_single_value(std::string const& input, ParseMode& parseState) const { diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 1441925..5d0b208 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -4,6 +4,7 @@ #include <sstream> #include <utility> +#include <vector> #include <cmext/algorithm> @@ -60,7 +61,7 @@ void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode( } void cmExportBuildAndroidMKGenerator::GenerateMissingTargetsCheckCode( - std::ostream&, const std::vector<std::string>&) + std::ostream&) { } diff --git a/Source/cmExportBuildAndroidMKGenerator.h b/Source/cmExportBuildAndroidMKGenerator.h index 250564f..410d4c3 100644 --- a/Source/cmExportBuildAndroidMKGenerator.h +++ b/Source/cmExportBuildAndroidMKGenerator.h @@ -6,7 +6,6 @@ #include <iosfwd> #include <string> -#include <vector> #include "cmExportBuildFileGenerator.h" #include "cmExportFileGenerator.h" @@ -56,8 +55,7 @@ protected: std::ostream& os, const std::string& config, cmGeneratorTarget const* target, ImportPropertyMap const& properties) override; - void GenerateMissingTargetsCheckCode( - std::ostream& os, const std::vector<std::string>& missingTargets) override; + void GenerateMissingTargetsCheckCode(std::ostream& os) override; void GenerateInterfaceProperties( cmGeneratorTarget const* target, std::ostream& os, const ImportPropertyMap& properties) override; diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index a47f1e5..6ce0c98 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportBuildFileGenerator.h" +#include <algorithm> #include <map> #include <memory> #include <set> @@ -15,7 +16,6 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" -#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -76,8 +76,6 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateExpectedTargetsCode(os, expectedTargets); } - std::vector<std::string> missingTargets; - // Create all the imported targets. for (cmGeneratorTarget* gte : this->Exports) { this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte)); @@ -88,34 +86,34 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_SOURCES", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte, cmGeneratorExpression::BuildInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, properties); @@ -132,8 +130,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) gte->GetPolicyStatusCMP0022() != cmPolicies::OLD; if (newCMP0022Behavior) { this->PopulateInterfaceLinkLibrariesProperty( - gte, cmGeneratorExpression::BuildInterface, properties, - missingTargets); + gte, cmGeneratorExpression::BuildInterface, properties); } this->PopulateCompatibleInterfaceProperties(gte, properties); @@ -144,17 +141,16 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) // Generate import file content for each configuration. for (std::string const& c : this->Configurations) { - this->GenerateImportConfig(os, c, missingTargets); + this->GenerateImportConfig(os, c); } - this->GenerateMissingTargetsCheckCode(os, missingTargets); + this->GenerateMissingTargetsCheckCode(os); return true; } void cmExportBuildFileGenerator::GenerateImportTargetsConfig( - std::ostream& os, const std::string& config, std::string const& suffix, - std::vector<std::string>& missingTargets) + std::ostream& os, const std::string& config, std::string const& suffix) { for (cmGeneratorTarget* target : this->Exports) { // Collect import properties for this target. @@ -167,11 +163,10 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig( // Get the rest of the target details. if (this->GetExportTargetType(target) != cmStateEnums::INTERFACE_LIBRARY) { - this->SetImportDetailProperties(config, suffix, target, properties, - missingTargets); + this->SetImportDetailProperties(config, suffix, target, properties); this->SetImportLinkInterface(config, suffix, cmGeneratorExpression::BuildInterface, - target, properties, missingTargets); + target, properties); } // TODO: PUBLIC_HEADER_LOCATION @@ -195,7 +190,7 @@ cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType( // to support transitive usage requirements on other targets that // use the object library. if (targetType == cmStateEnums::OBJECT_LIBRARY && - !this->LG->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) { + !target->Target->HasKnownObjectFileLocation(nullptr)) { targetType = cmStateEnums::INTERFACE_LIBRARY; } return targetType; @@ -259,8 +254,8 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( } void cmExportBuildFileGenerator::HandleMissingTarget( - std::string& link_libs, std::vector<std::string>& missingTargets, - cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) + std::string& link_libs, cmGeneratorTarget const* depender, + cmGeneratorTarget* dependee) { // The target is not in the export. if (!this->AppendMode) { @@ -275,7 +270,7 @@ void cmExportBuildFileGenerator::HandleMissingTarget( missingTarget += dependee->GetExportName(); link_libs += missingTarget; - missingTargets.push_back(std::move(missingTarget)); + this->MissingTargets.emplace_back(std::move(missingTarget)); return; } // We are not appending, so all exported targets should be @@ -362,16 +357,93 @@ std::string cmExportBuildFileGenerator::InstallNameDir( return install_name_dir; } +namespace { +bool EntryIsContextSensitive( + const std::unique_ptr<cmCompiledGeneratorExpression>& cge) +{ + return cge->GetHadContextSensitiveCondition(); +} +} + std::string cmExportBuildFileGenerator::GetFileSetDirectories( - cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/) { - return cmOutputConverter::EscapeForCMake( - cmJoin(fileSet->GetDirectoryEntries(), ";")); + std::vector<std::string> resultVector; + + auto configs = + gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + auto directoryEntries = fileSet->CompileDirectoryEntries(); + + for (auto const& config : configs) { + auto directories = fileSet->EvaluateDirectoryEntries( + directoryEntries, gte->LocalGenerator, config, gte); + + bool const contextSensitive = + std::any_of(directoryEntries.begin(), directoryEntries.end(), + EntryIsContextSensitive); + + for (auto const& directory : directories) { + auto dest = cmOutputConverter::EscapeForCMake( + directory, cmOutputConverter::WrapQuotes::NoWrap); + + if (contextSensitive && configs.size() != 1) { + resultVector.push_back( + cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\"")); + } else { + resultVector.push_back(cmStrCat('"', dest, '"')); + break; + } + } + } + + return cmJoin(resultVector, " "); } -std::string cmExportBuildFileGenerator::GetFileSetFiles( - cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +std::string cmExportBuildFileGenerator::GetFileSetFiles(cmGeneratorTarget* gte, + cmFileSet* fileSet, + cmTargetExport* /*te*/) { - return cmOutputConverter::EscapeForCMake( - cmJoin(fileSet->GetFileEntries(), ";")); + std::vector<std::string> resultVector; + + auto configs = + gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + auto fileEntries = fileSet->CompileFileEntries(); + auto directoryEntries = fileSet->CompileDirectoryEntries(); + + for (auto const& config : configs) { + auto directories = fileSet->EvaluateDirectoryEntries( + directoryEntries, gte->LocalGenerator, config, gte); + + std::map<std::string, std::vector<std::string>> files; + for (auto const& entry : fileEntries) { + fileSet->EvaluateFileEntry(directories, files, entry, + gte->LocalGenerator, config, gte); + } + + bool const contextSensitive = + std::any_of(directoryEntries.begin(), directoryEntries.end(), + EntryIsContextSensitive) || + std::any_of(fileEntries.begin(), fileEntries.end(), + EntryIsContextSensitive); + + for (auto const& it : files) { + for (auto const& filename : it.second) { + auto escapedFile = cmOutputConverter::EscapeForCMake( + filename, cmOutputConverter::WrapQuotes::NoWrap); + if (contextSensitive && configs.size() != 1) { + resultVector.push_back( + cmStrCat("\"$<$<CONFIG:", config, ">:", escapedFile, ">\"")); + } else { + resultVector.push_back(cmStrCat('"', escapedFile, '"')); + } + } + } + + if (!(contextSensitive && configs.size() != 1)) { + break; + } + } + + return cmJoin(resultVector, " "); } diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index a7985c7..3db8719 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -55,13 +55,11 @@ public: protected: // Implement virtual methods from the superclass. bool GenerateMainFile(std::ostream& os) override; - void GenerateImportTargetsConfig( - std::ostream& os, const std::string& config, std::string const& suffix, - std::vector<std::string>& missingTargets) override; + void GenerateImportTargetsConfig(std::ostream& os, const std::string& config, + std::string const& suffix) override; cmStateEnums::TargetType GetExportTargetType( cmGeneratorTarget const* target) const; void HandleMissingTarget(std::string& link_libs, - std::vector<std::string>& missingTargets, cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) override; diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index dc94e76..6d6df71 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -106,9 +106,8 @@ bool cmExportFileGenerator::GenerateImportFile() return result; } -void cmExportFileGenerator::GenerateImportConfig( - std::ostream& os, const std::string& config, - std::vector<std::string>& missingTargets) +void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, + const std::string& config) { // Construct the property configuration suffix. std::string suffix = "_"; @@ -119,7 +118,7 @@ void cmExportFileGenerator::GenerateImportConfig( } // Generate the per-config target information. - this->GenerateImportTargetsConfig(os, config, suffix, missingTargets); + this->GenerateImportTargetsConfig(os, config, suffix); } void cmExportFileGenerator::PopulateInterfaceProperty( @@ -136,7 +135,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty( const std::string& propName, const std::string& outputName, cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets) + ImportPropertyMap& properties) { cmValue input = target->GetProperty(propName); if (input) { @@ -149,8 +148,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty( std::string prepro = cmGeneratorExpression::Preprocess(*input, preprocessRule); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target, - missingTargets); + this->ResolveTargetsInGeneratorExpressions(prepro, target); properties[outputName] = prepro; } } @@ -170,7 +168,7 @@ void cmExportFileGenerator::GenerateRequiredCMakeVersion( bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets) + ImportPropertyMap& properties) { if (!target->IsLinkable()) { return false; @@ -185,8 +183,8 @@ bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( std::string prepro = cmGeneratorExpression::Preprocess(*input, preprocessRule); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions( - prepro, target, missingTargets, ReplaceFreeTargets); + this->ResolveTargetsInGeneratorExpressions(prepro, target, + ReplaceFreeTargets); properties[linkIfaceProp] = prepro; hadINTERFACE_LINK_LIBRARIES = true; } @@ -343,7 +341,7 @@ static void prefixItems(std::string& exportDirs) void cmExportFileGenerator::PopulateSourcesInterface( cmGeneratorTarget const* gt, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets) + ImportPropertyMap& properties) { assert(preprocessRule == cmGeneratorExpression::InstallInterface); @@ -362,7 +360,7 @@ void cmExportFileGenerator::PopulateSourcesInterface( std::string prepro = cmGeneratorExpression::Preprocess(*input, preprocessRule, true); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets); + this->ResolveTargetsInGeneratorExpressions(prepro, gt); if (!checkInterfaceDirs(prepro, gt, propName)) { return; @@ -374,8 +372,7 @@ void cmExportFileGenerator::PopulateSourcesInterface( void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets, - cmTargetExport const& te) + ImportPropertyMap& properties, cmTargetExport const& te) { assert(preprocessRule == cmGeneratorExpression::InstallInterface); @@ -422,7 +419,7 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( std::string prepro = cmGeneratorExpression::Preprocess(includes, preprocessRule, true); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target, missingTargets); + this->ResolveTargetsInGeneratorExpressions(prepro, target); if (!checkInterfaceDirs(prepro, target, propName)) { return; @@ -434,7 +431,7 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( void cmExportFileGenerator::PopulateLinkDependsInterface( cmGeneratorTarget const* gt, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets) + ImportPropertyMap& properties) { assert(preprocessRule == cmGeneratorExpression::InstallInterface); @@ -453,7 +450,7 @@ void cmExportFileGenerator::PopulateLinkDependsInterface( std::string prepro = cmGeneratorExpression::Preprocess(*input, preprocessRule, true); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets); + this->ResolveTargetsInGeneratorExpressions(prepro, gt); if (!checkInterfaceDirs(prepro, gt, propName)) { return; @@ -465,7 +462,7 @@ void cmExportFileGenerator::PopulateLinkDependsInterface( void cmExportFileGenerator::PopulateLinkDirectoriesInterface( cmGeneratorTarget const* gt, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets) + ImportPropertyMap& properties) { assert(preprocessRule == cmGeneratorExpression::InstallInterface); @@ -484,7 +481,7 @@ void cmExportFileGenerator::PopulateLinkDirectoriesInterface( std::string prepro = cmGeneratorExpression::Preprocess(*input, preprocessRule, true); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets); + this->ResolveTargetsInGeneratorExpressions(prepro, gt); if (!checkInterfaceDirs(prepro, gt, propName)) { return; @@ -496,10 +493,10 @@ void cmExportFileGenerator::PopulateLinkDirectoriesInterface( void cmExportFileGenerator::PopulateInterfaceProperty( const std::string& propName, cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets) + ImportPropertyMap& properties) { this->PopulateInterfaceProperty(propName, propName, target, preprocessRule, - properties, missingTargets); + properties); } static void getPropertyContents(cmGeneratorTarget const* tgt, @@ -604,9 +601,9 @@ void cmExportFileGenerator::GenerateInterfaceProperties( } } -bool cmExportFileGenerator::AddTargetNamespace( - std::string& input, cmGeneratorTarget const* target, - cmLocalGenerator const* lg, std::vector<std::string>& missingTargets) +bool cmExportFileGenerator::AddTargetNamespace(std::string& input, + cmGeneratorTarget const* target, + cmLocalGenerator const* lg) { cmGeneratorTarget::TargetOrString resolved = target->ResolveTargetReference(input, lg); @@ -625,7 +622,7 @@ bool cmExportFileGenerator::AddTargetNamespace( input = this->Namespace + tgt->GetExportName(); } else { std::string namespacedTarget; - this->HandleMissingTarget(namespacedTarget, missingTargets, target, tgt); + this->HandleMissingTarget(namespacedTarget, target, tgt); if (!namespacedTarget.empty()) { input = namespacedTarget; } else { @@ -637,12 +634,11 @@ bool cmExportFileGenerator::AddTargetNamespace( void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( std::string& input, cmGeneratorTarget const* target, - std::vector<std::string>& missingTargets, FreeTargetsReplace replace) + FreeTargetsReplace replace) { cmLocalGenerator const* lg = target->GetLocalGenerator(); if (replace == NoReplaceFreeTargets) { - this->ResolveTargetsInGeneratorExpression(input, target, lg, - missingTargets); + this->ResolveTargetsInGeneratorExpression(input, target, lg); return; } std::vector<std::string> parts; @@ -655,10 +651,9 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( continue; } if (cmGeneratorExpression::Find(li) == std::string::npos) { - this->AddTargetNamespace(li, target, lg, missingTargets); + this->AddTargetNamespace(li, target, lg); } else { - this->ResolveTargetsInGeneratorExpression(li, target, lg, - missingTargets); + this->ResolveTargetsInGeneratorExpression(li, target, lg); } input += sep + li; sep = ";"; @@ -667,7 +662,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( std::string& input, cmGeneratorTarget const* target, - cmLocalGenerator const* lg, std::vector<std::string>& missingTargets) + cmLocalGenerator const* lg) { std::string::size_type pos = 0; std::string::size_type lastPos = pos; @@ -691,7 +686,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( std::string targetName = input.substr(nameStartPos, commaPos - nameStartPos); - if (this->AddTargetNamespace(targetName, target, lg, missingTargets)) { + if (this->AddTargetNamespace(targetName, target, lg)) { input.replace(nameStartPos, commaPos - nameStartPos, targetName); } lastPos = nameStartPos + targetName.size() + 1; @@ -713,7 +708,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( "literal."; break; } - if (!this->AddTargetNamespace(targetName, target, lg, missingTargets)) { + if (!this->AddTargetNamespace(targetName, target, lg)) { errorString = "$<TARGET_NAME:...> requires its parameter to be a " "reachable target."; break; @@ -734,7 +729,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( } std::string libName = input.substr(nameStartPos, endPos - nameStartPos); if (cmGeneratorExpression::IsValidTargetName(libName) && - this->AddTargetNamespace(libName, target, lg, missingTargets)) { + this->AddTargetNamespace(libName, target, lg)) { input.replace(nameStartPos, endPos - nameStartPos, libName); } lastPos = nameStartPos + libName.size() + 1; @@ -756,8 +751,7 @@ void cmExportFileGenerator::ReplaceInstallPrefix(std::string& /*unused*/) void cmExportFileGenerator::SetImportLinkInterface( const std::string& config, std::string const& suffix, cmGeneratorExpression::PreprocessContext preprocessRule, - cmGeneratorTarget const* target, ImportPropertyMap& properties, - std::vector<std::string>& missingTargets) + cmGeneratorTarget const* target, ImportPropertyMap& properties) { // Add the transitive link dependencies for this configuration. cmLinkInterface const* iface = target->GetLinkInterface(config, target); @@ -769,7 +763,7 @@ void cmExportFileGenerator::SetImportLinkInterface( // Policy CMP0022 must not be NEW. this->SetImportLinkProperty( suffix, target, "IMPORTED_LINK_INTERFACE_LIBRARIES", iface->Libraries, - properties, missingTargets, ImportLinkPropertyTargetNames::Yes); + properties, ImportLinkPropertyTargetNames::Yes); return; } @@ -808,7 +802,7 @@ void cmExportFileGenerator::SetImportLinkInterface( std::string prepro = cmGeneratorExpression::Preprocess(*propContent, preprocessRule); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target, missingTargets, + this->ResolveTargetsInGeneratorExpressions(prepro, target, ReplaceFreeTargets); properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro; } @@ -816,8 +810,7 @@ void cmExportFileGenerator::SetImportLinkInterface( void cmExportFileGenerator::SetImportDetailProperties( const std::string& config, std::string const& suffix, - cmGeneratorTarget* target, ImportPropertyMap& properties, - std::vector<std::string>& missingTargets) + cmGeneratorTarget* target, ImportPropertyMap& properties) { // Get the makefile in which to lookup target information. cmMakefile* mf = target->Makefile; @@ -848,12 +841,11 @@ void cmExportFileGenerator::SetImportDetailProperties( target->GetLinkInterface(config, target)) { this->SetImportLinkProperty( suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", iface->Languages, - properties, missingTargets, ImportLinkPropertyTargetNames::No); + properties, ImportLinkPropertyTargetNames::No); - std::vector<std::string> dummy; this->SetImportLinkProperty( suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps, - properties, dummy, ImportLinkPropertyTargetNames::Yes); + properties, ImportLinkPropertyTargetNames::Yes); if (iface->Multiplicity > 0) { std::string prop = cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix); @@ -894,8 +886,7 @@ template <typename T> void cmExportFileGenerator::SetImportLinkProperty( std::string const& suffix, cmGeneratorTarget const* target, const std::string& propName, std::vector<T> const& entries, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets, - ImportLinkPropertyTargetNames targetNames) + ImportPropertyMap& properties, ImportLinkPropertyTargetNames targetNames) { // Skip the property if there are no entries. if (entries.empty()) { @@ -914,7 +905,7 @@ void cmExportFileGenerator::SetImportLinkProperty( if (targetNames == ImportLinkPropertyTargetNames::Yes) { std::string temp = asString(l); - this->AddTargetNamespace(temp, target, lg, missingTargets); + this->AddTargetNamespace(temp, target, lg); link_entries += temp; } else { link_entries += asString(l); @@ -1124,10 +1115,9 @@ void cmExportFileGenerator::GenerateImportPropertyCode( << "\n"; } -void cmExportFileGenerator::GenerateMissingTargetsCheckCode( - std::ostream& os, const std::vector<std::string>& missingTargets) +void cmExportFileGenerator::GenerateMissingTargetsCheckCode(std::ostream& os) { - if (missingTargets.empty()) { + if (this->MissingTargets.empty()) { /* clang-format off */ os << "# This file does not depend on other imported targets which have\n" "# been exported from the same project but in a separate " @@ -1142,7 +1132,7 @@ void cmExportFileGenerator::GenerateMissingTargetsCheckCode( "foreach(_target "; /* clang-format on */ std::set<std::string> emitted; - for (std::string const& missingTarget : missingTargets) { + for (std::string const& missingTarget : this->MissingTargets) { if (emitted.insert(missingTarget).second) { os << "\"" << missingTarget << "\" "; } diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index bde6f1b..d27a555 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -66,8 +66,7 @@ protected: // Generate per-configuration target information to the given output // stream. - void GenerateImportConfig(std::ostream& os, const std::string& config, - std::vector<std::string>& missingTargets); + void GenerateImportConfig(std::ostream& os, const std::string& config); // Methods to implement export file code generation. virtual void GeneratePolicyHeaderCode(std::ostream& os); @@ -88,8 +87,7 @@ protected: ImportPropertyMap const& properties, const std::set<std::string>& importedLocations); virtual void GenerateImportedFileCheckLoop(std::ostream& os); - virtual void GenerateMissingTargetsCheckCode( - std::ostream& os, const std::vector<std::string>& missingTargets); + virtual void GenerateMissingTargetsCheckCode(std::ostream& os); virtual void GenerateExpectedTargetsCode(std::ostream& os, const std::string& expectedTargets); @@ -99,8 +97,7 @@ protected: void SetImportDetailProperties(const std::string& config, std::string const& suffix, cmGeneratorTarget* target, - ImportPropertyMap& properties, - std::vector<std::string>& missingTargets); + ImportPropertyMap& properties); enum class ImportLinkPropertyTargetNames { @@ -113,31 +110,28 @@ protected: const std::string& propName, std::vector<T> const& entries, ImportPropertyMap& properties, - std::vector<std::string>& missingTargets, ImportLinkPropertyTargetNames targetNames); /** Each subclass knows how to generate its kind of export file. */ virtual bool GenerateMainFile(std::ostream& os) = 0; /** Each subclass knows where the target files are located. */ - virtual void GenerateImportTargetsConfig( - std::ostream& os, const std::string& config, std::string const& suffix, - std::vector<std::string>& missingTargets) = 0; + virtual void GenerateImportTargetsConfig(std::ostream& os, + const std::string& config, + std::string const& suffix) = 0; /** Each subclass knows how to deal with a target that is missing from an * export set. */ virtual void HandleMissingTarget(std::string& link_libs, - std::vector<std::string>& missingTargets, cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) = 0; void PopulateInterfaceProperty(const std::string&, cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, - ImportPropertyMap& properties, - std::vector<std::string>& missingTargets); + ImportPropertyMap& properties); bool PopulateInterfaceLinkLibrariesProperty( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets); + ImportPropertyMap& properties); void PopulateInterfaceProperty(const std::string& propName, cmGeneratorTarget const* target, ImportPropertyMap& properties); @@ -149,26 +143,24 @@ protected: void PopulateIncludeDirectoriesInterface( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets, - cmTargetExport const& te); + ImportPropertyMap& properties, cmTargetExport const& te); void PopulateSourcesInterface( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets); + ImportPropertyMap& properties); void PopulateLinkDirectoriesInterface( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets); + ImportPropertyMap& properties); void PopulateLinkDependsInterface( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets); + ImportPropertyMap& properties); void SetImportLinkInterface( const std::string& config, std::string const& suffix, cmGeneratorExpression::PreprocessContext preprocessRule, - cmGeneratorTarget const* target, ImportPropertyMap& properties, - std::vector<std::string>& missingTargets); + cmGeneratorTarget const* target, ImportPropertyMap& properties); enum FreeTargetsReplace { @@ -178,7 +170,6 @@ protected: void ResolveTargetsInGeneratorExpressions( std::string& input, cmGeneratorTarget const* target, - std::vector<std::string>& missingTargets, FreeTargetsReplace replace = NoReplaceFreeTargets); virtual void GenerateRequiredCMakeVersion(std::ostream& os, @@ -216,20 +207,20 @@ protected: // The set of targets included in the export. std::set<cmGeneratorTarget*> ExportedTargets; + std::vector<std::string> MissingTargets; + private: void PopulateInterfaceProperty(const std::string&, const std::string&, cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, - ImportPropertyMap& properties, - std::vector<std::string>& missingTargets); + ImportPropertyMap& properties); bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target, - cmLocalGenerator const* lg, - std::vector<std::string>& missingTargets); + cmLocalGenerator const* lg); - void ResolveTargetsInGeneratorExpression( - std::string& input, cmGeneratorTarget const* target, - cmLocalGenerator const* lg, std::vector<std::string>& missingTargets); + void ResolveTargetsInGeneratorExpression(std::string& input, + cmGeneratorTarget const* target, + cmLocalGenerator const* lg); virtual void ReplaceInstallPrefix(std::string& input); diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx index 80f776e..4e4f8a1 100644 --- a/Source/cmExportInstallAndroidMKGenerator.cxx +++ b/Source/cmExportInstallAndroidMKGenerator.cxx @@ -5,6 +5,7 @@ #include <cstddef> #include <memory> #include <ostream> +#include <vector> #include "cmExportBuildAndroidMKGenerator.h" #include "cmExportSet.h" @@ -86,7 +87,7 @@ void cmExportInstallAndroidMKGenerator::GenerateImportPropertyCode( } void cmExportInstallAndroidMKGenerator::GenerateMissingTargetsCheckCode( - std::ostream&, const std::vector<std::string>&) + std::ostream&) { } @@ -132,7 +133,7 @@ void cmExportInstallAndroidMKGenerator::GenerateImportedFileChecksCode( } bool cmExportInstallAndroidMKGenerator::GenerateImportFileConfig( - const std::string&, std::vector<std::string>&) + const std::string&) { return true; } diff --git a/Source/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h index 40978e0..c05751a 100644 --- a/Source/cmExportInstallAndroidMKGenerator.h +++ b/Source/cmExportInstallAndroidMKGenerator.h @@ -7,7 +7,6 @@ #include <iosfwd> #include <set> #include <string> -#include <vector> #include "cmExportFileGenerator.h" #include "cmExportInstallFileGenerator.h" @@ -50,8 +49,7 @@ protected: std::ostream& os, const std::string& config, cmGeneratorTarget const* target, ImportPropertyMap const& properties) override; - void GenerateMissingTargetsCheckCode( - std::ostream& os, const std::vector<std::string>& missingTargets) override; + void GenerateMissingTargetsCheckCode(std::ostream& os) override; void GenerateInterfaceProperties( cmGeneratorTarget const* target, std::ostream& os, const ImportPropertyMap& properties) override; @@ -65,6 +63,5 @@ protected: std::ostream& os, cmGeneratorTarget* target, ImportPropertyMap const& properties, const std::set<std::string>& importedLocations) override; - bool GenerateImportFileConfig(const std::string& config, - std::vector<std::string>&) override; + bool GenerateImportFileConfig(const std::string& config) override; }; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index f232440..0c41946 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -71,8 +71,6 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) // Compute the relative import prefix for the file this->GenerateImportPrefix(os); - std::vector<std::string> missingTargets; - bool require2_8_12 = false; bool require3_0_0 = false; bool require3_1_0 = false; @@ -90,35 +88,34 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) ImportPropertyMap properties; this->PopulateIncludeDirectoriesInterface( - gt, cmGeneratorExpression::InstallInterface, properties, missingTargets, - *te); + gt, cmGeneratorExpression::InstallInterface, properties, *te); this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt, cmGeneratorExpression::InstallInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt, cmGeneratorExpression::InstallInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt, cmGeneratorExpression::InstallInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gt, cmGeneratorExpression::InstallInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt, cmGeneratorExpression::InstallInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt, cmGeneratorExpression::InstallInterface, - properties, missingTargets); + properties); this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt, cmGeneratorExpression::InstallInterface, - properties, missingTargets); + properties); this->PopulateLinkDirectoriesInterface( - gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); + gt, cmGeneratorExpression::InstallInterface, properties); this->PopulateLinkDependsInterface( - gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); + gt, cmGeneratorExpression::InstallInterface, properties); std::string errorMessage; if (!this->PopulateExportProperties(gt, properties, errorMessage)) { @@ -131,8 +128,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) gt->GetPolicyStatusCMP0022() != cmPolicies::OLD; if (newCMP0022Behavior) { if (this->PopulateInterfaceLinkLibrariesProperty( - gt, cmGeneratorExpression::InstallInterface, properties, - missingTargets) && + gt, cmGeneratorExpression::InstallInterface, properties) && !this->ExportOld) { require2_8_12 = true; } @@ -174,13 +170,13 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) // Don't do this if we only export INTERFACE_LIBRARY targets. if (requiresConfigFiles) { for (std::string const& c : this->Configurations) { - if (!this->GenerateImportFileConfig(c, missingTargets)) { + if (!this->GenerateImportFileConfig(c)) { result = false; } } } - this->GenerateMissingTargetsCheckCode(os, missingTargets); + this->GenerateMissingTargetsCheckCode(os); return result; } @@ -273,7 +269,7 @@ void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input) } bool cmExportInstallFileGenerator::GenerateImportFileConfig( - const std::string& config, std::vector<std::string>& missingTargets) + const std::string& config) { // Skip configurations not enabled for this export. if (!this->IEGen->InstallsForConfig(config)) { @@ -305,7 +301,7 @@ bool cmExportInstallFileGenerator::GenerateImportFileConfig( this->GenerateImportHeaderCode(os, config); // Generate the per-config target information. - this->GenerateImportConfig(os, config, missingTargets); + this->GenerateImportConfig(os, config); // End with the import file footer. this->GenerateImportFooterCode(os); @@ -317,8 +313,7 @@ bool cmExportInstallFileGenerator::GenerateImportFileConfig( } void cmExportInstallFileGenerator::GenerateImportTargetsConfig( - std::ostream& os, const std::string& config, std::string const& suffix, - std::vector<std::string>& missingTargets) + std::ostream& os, const std::string& config, std::string const& suffix) { // Add each target in the set to the export. for (std::unique_ptr<cmTargetExport> const& te : @@ -350,12 +345,11 @@ void cmExportInstallFileGenerator::GenerateImportTargetsConfig( if (!properties.empty()) { // Get the rest of the target details. cmGeneratorTarget* gtgt = te->Target; - this->SetImportDetailProperties(config, suffix, gtgt, properties, - missingTargets); + this->SetImportDetailProperties(config, suffix, gtgt, properties); this->SetImportLinkInterface(config, suffix, cmGeneratorExpression::InstallInterface, - gtgt, properties, missingTargets); + gtgt, properties); // TODO: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff @@ -454,8 +448,8 @@ cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType( } void cmExportInstallFileGenerator::HandleMissingTarget( - std::string& link_libs, std::vector<std::string>& missingTargets, - cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) + std::string& link_libs, cmGeneratorTarget const* depender, + cmGeneratorTarget* dependee) { const std::string name = dependee->GetName(); cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator(); @@ -466,7 +460,7 @@ void cmExportInstallFileGenerator::HandleMissingTarget( missingTarget += dependee->GetExportName(); link_libs += missingTarget; - missingTargets.push_back(std::move(missingTarget)); + this->MissingTargets.emplace_back(std::move(missingTarget)); } else { // All exported targets should be known here and should be unique. // This is probably user-error. diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index 9374c6b..86fb505 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -57,13 +57,11 @@ public: protected: // Implement virtual methods from the superclass. bool GenerateMainFile(std::ostream& os) override; - void GenerateImportTargetsConfig( - std::ostream& os, const std::string& config, std::string const& suffix, - std::vector<std::string>& missingTargets) override; + void GenerateImportTargetsConfig(std::ostream& os, const std::string& config, + std::string const& suffix) override; cmStateEnums::TargetType GetExportTargetType( cmTargetExport const* targetExport) const; void HandleMissingTarget(std::string& link_libs, - std::vector<std::string>& missingTargets, cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) override; @@ -85,8 +83,7 @@ protected: virtual void CleanupTemporaryVariables(std::ostream&); /** Generate a per-configuration file for the targets. */ - virtual bool GenerateImportFileConfig( - const std::string& config, std::vector<std::string>& missingTargets); + virtual bool GenerateImportFileConfig(const std::string& config); /** Fill in properties indicating installed file locations. */ void SetImportLocationProperty(const std::string& config, diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index 8a1fd7e..1dd8a20 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -33,12 +33,10 @@ protected: bool GenerateMainFile(std::ostream& os) override; void GenerateImportTargetsConfig(std::ostream&, const std::string&, - std::string const&, - std::vector<std::string>&) override + std::string const&) override { } - void HandleMissingTarget(std::string&, std::vector<std::string>&, - cmGeneratorTarget const*, + void HandleMissingTarget(std::string&, cmGeneratorTarget const*, cmGeneratorTarget*) override { } diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index 40e1d2e..dd0540c 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -1728,7 +1728,7 @@ Json::Value Target::DumpArtifacts() // Object libraries have only object files as artifacts. if (this->GT->GetType() == cmStateEnums::OBJECT_LIBRARY) { - if (!this->GT->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) { + if (!this->GT->Target->HasKnownObjectFileLocation(nullptr)) { return artifacts; } std::vector<cmSourceFile const*> objectSources; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 3d1cfbf..a9bc435 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1785,7 +1785,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode { std::string reason; if (!context->EvaluateForBuildsystem && - !gg->HasKnownObjectFileLocation(&reason)) { + !gt->Target->HasKnownObjectFileLocation(&reason)) { std::ostringstream e; e << "The evaluation of the TARGET_OBJECTS generator expression " "is only suitable for consumption by CMake (limited" diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f1ab85c..d8a7c39 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1213,8 +1213,10 @@ bool cmGeneratorTarget::IsInBuildSystem() const case cmStateEnums::GLOBAL_TARGET: return true; case cmStateEnums::INTERFACE_LIBRARY: - // An INTERFACE library is in the build system if it has SOURCES. - if (!this->SourceEntries.empty()) { + // An INTERFACE library is in the build system if it has SOURCES or + // HEADER_SETS. + if (!this->SourceEntries.empty() || + !this->Target->GetHeaderSetsEntries().empty()) { return true; } break; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 5965a16..dcef070 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -459,10 +459,13 @@ public: virtual bool IsNinja() const { return false; } - /** Return true if we know the exact location of object files. - If false, store the reason in the given string. - This is meaningful only after EnableLanguage has been called. */ - virtual bool HasKnownObjectFileLocation(std::string*) const { return true; } + /** Return true if we know the exact location of object files for the given + cmTarget. If false, store the reason in the given string. This is + meaningful only after EnableLanguage has been called. */ + virtual bool HasKnownObjectFileLocation(cmTarget const&, std::string*) const + { + return true; + } virtual bool UseFolderProperty() const; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 3ce3d59..d53c3d5 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1167,6 +1167,20 @@ std::string GetSourcecodeValueFromFileExtension( return sourcecode; } +template <class T> +std::string GetTargetObjectDirArch(T const& target, + const std::string& defaultVal) +{ + auto archs = cmExpandedList(target.GetSafeProperty("OSX_ARCHITECTURES")); + if (archs.size() > 1) { + return "$(CURRENT_ARCH)"; + } else if (archs.size() == 1) { + return archs.front(); + } else { + return defaultVal; + } +} + } // anonymous // Extracts the framework directory, if path matches the framework syntax @@ -4924,9 +4938,11 @@ bool cmGlobalXCodeGenerator::IsMultiConfig() const } bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation( - std::string* reason) const + cmTarget const& target, std::string* reason) const { - if (this->ObjectDirArch.find('$') != std::string::npos) { + auto objectDirArch = GetTargetObjectDirArch(target, this->ObjectDirArch); + + if (objectDirArch.find('$') != std::string::npos) { if (reason != nullptr) { *reason = " under Xcode with multiple architectures"; } @@ -4957,10 +4973,12 @@ void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory( cmGeneratorTarget* gt) const { std::string configName = this->GetCMakeCFGIntDir(); + auto objectDirArch = GetTargetObjectDirArch(*gt, this->ObjectDirArch); + std::string dir = cmStrCat(this->GetObjectsDirectory("$(PROJECT_NAME)", configName, gt, "$(OBJECT_FILE_DIR_normal:base)/"), - this->ObjectDirArch, '/'); + objectDirArch, '/'); gt->ObjectDirectory = dir; } diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 1159d1f..92e4528 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -107,7 +107,8 @@ public: bool IsXcode() const override { return true; } - bool HasKnownObjectFileLocation(std::string* reason) const override; + bool HasKnownObjectFileLocation(cmTarget const&, + std::string* reason) const override; bool IsIPOSupported() const override { return true; } diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 1ed698d..7ca5b23 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -742,9 +742,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, [=](const cmInstallCommandFileSetArguments& fileSetArg) -> bool { return fileSetArg.GetFileSet() == name; }); })) { - status.SetError(cmStrCat( - "TARGETS target ", target.GetName(), - " is exported but not all of its file sets are installed")); + status.SetError(cmStrCat("TARGETS target ", target.GetName(), + " is exported but not all of its interface " + "file sets are installed")); return false; } @@ -919,8 +919,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, if (!objectArgs.GetDestination().empty()) { // Verify that we know where the objects are to install them. std::string reason; - if (!helper.Makefile->GetGlobalGenerator() - ->HasKnownObjectFileLocation(&reason)) { + if (!target.HasKnownObjectFileLocation(&reason)) { status.SetError( cmStrCat("TARGETS given OBJECT library \"", target.GetName(), "\" whose objects may not be installed", reason, ".")); diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 434c51c..5393747 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -396,7 +396,11 @@ class cmMakefile; 24, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0132, \ "Do not set compiler environment variables on first run", 3, 24, 0, \ - cmPolicies::WARN) + cmPolicies::WARN) \ + SELECT(POLICY, CMP0133, \ + "The CPack module disables SLA by default in the CPack DragNDrop " \ + "Generator.", \ + 3, 24, 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/cmTarget.cxx b/Source/cmTarget.cxx index 5c43bc8..a01321d 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -691,6 +691,11 @@ bool cmTarget::IsAndroidGuiExecutable() const this->impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")); } +bool cmTarget::HasKnownObjectFileLocation(std::string* reason) const +{ + return this->GetGlobalGenerator()->HasKnownObjectFileLocation(*this, reason); +} + std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const { return this->impl->PreBuildCommands; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 97fdbeb..72497b3 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -220,6 +220,8 @@ public: //! Return whether this target is a GUI executable on Android. bool IsAndroidGuiExecutable() const; + bool HasKnownObjectFileLocation(std::string* reason = nullptr) const; + //! Get a backtrace from the creation of the target. cmListFileBacktrace const& GetBacktrace() const; diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index cbd241b..1a3e72e 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -4,6 +4,11 @@ #include <utility> +#if !defined(CMAKE_BOOTSTRAP) +# include <cm3p/json/reader.h> +# include <cm3p/json/value.h> +#endif + #include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" @@ -295,6 +300,87 @@ bool cmVSSetupAPIHelper::IsEWDKEnabled() return false; } +bool cmVSSetupAPIHelper::EnumerateVSInstancesWithVswhere( + std::vector<VSInstanceInfo>& VSInstances) +{ +#if !defined(CMAKE_BOOTSTRAP) + // Construct vswhere command to get installed VS instances in JSON format + std::string vswhereExe = getenv("ProgramFiles(x86)") + + std::string(R"(\Microsoft Visual Studio\Installer\vswhere.exe)"); + std::vector<std::string> vswhereCmd = { vswhereExe, "-format", "json" }; + + // Execute vswhere command and capture JSON output + std::string json_output; + int retVal = 1; + if (!cmSystemTools::RunSingleCommand(vswhereCmd, &json_output, &json_output, + &retVal, nullptr, + cmSystemTools::OUTPUT_NONE)) { + return false; + } + + // Parse JSON output and iterate over elements + Json::CharReaderBuilder builder; + auto jsonReader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); + Json::Value json; + std::string error; + + if (!jsonReader->parse(json_output.data(), + json_output.data() + json_output.size(), &json, + &error)) { + return false; + } + + for (const auto& item : json) { + VSInstanceInfo instance; + instance.Version = item["installationVersion"].asString(); + instance.VSInstallLocation = item["installationPath"].asString(); + instance.IsWin10SDKInstalled = true; + instance.IsWin81SDKInstalled = false; + cmSystemTools::ConvertToUnixSlashes(instance.VSInstallLocation); + if (LoadVSInstanceVCToolsetVersion(instance)) { + VSInstances.push_back(instance); + } + } + return true; +#else + static_cast<void>(VSInstances); + return false; +#endif +} + +bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM( + std::vector<VSInstanceInfo>& VSInstances) +{ + if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL || + setupHelper == NULL) + return false; + + SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL; + if (FAILED( + setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) || + !enumInstances) { + return false; + } + + SmartCOMPtr<ISetupInstance> instance; + while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { + SmartCOMPtr<ISetupInstance2> instance2 = NULL; + if (FAILED( + instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) || + !instance2) { + instance = NULL; + continue; + } + + VSInstanceInfo instanceInfo; + bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo); + instance = instance2 = NULL; + if (isInstalled) + VSInstances.push_back(instanceInfo); + } + return true; +} + bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() { bool isVSInstanceExists = false; @@ -321,10 +407,6 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() return true; } - if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL || - setupHelper == NULL) - return false; - std::string envVSCommonToolsDir; std::string envVSCommonToolsDirEnvName = "VS" + std::to_string(this->Version) + "0COMNTOOLS"; @@ -334,72 +416,60 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() cmSystemTools::ConvertToUnixSlashes(envVSCommonToolsDir); } - std::vector<VSInstanceInfo> vecVSInstances; - SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL; - if (FAILED( - setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) || - !enumInstances) { - return false; - } - std::string const wantVersion = std::to_string(this->Version) + '.'; bool specifiedLocationNotSpecifiedVersion = false; SmartCOMPtr<ISetupInstance> instance; - while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { - SmartCOMPtr<ISetupInstance2> instance2 = NULL; - if (FAILED( - instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) || - !instance2) { - instance = NULL; + + std::vector<VSInstanceInfo> vecVSInstancesAll; + + // Enumerate VS instances with either COM interface or Vswhere + if (!EnumerateVSInstancesWithCOM(vecVSInstancesAll) && + !EnumerateVSInstancesWithVswhere(vecVSInstancesAll)) { + return false; + } + + std::vector<VSInstanceInfo> vecVSInstances; + for (const auto& instanceInfo : vecVSInstancesAll) { + // We are looking for a specific major version. + if (instanceInfo.Version.size() < wantVersion.size() || + instanceInfo.Version.substr(0, wantVersion.size()) != wantVersion) { continue; } - VSInstanceInfo instanceInfo; - bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo); - instance = instance2 = NULL; - - if (isInstalled) { - // We are looking for a specific major version. - if (instanceInfo.Version.size() < wantVersion.size() || - instanceInfo.Version.substr(0, wantVersion.size()) != wantVersion) { - continue; + if (!this->SpecifiedVSInstallLocation.empty()) { + // We are looking for a specific instance. + std::string currentVSLocation = instanceInfo.GetInstallLocation(); + if (cmSystemTools::ComparePath(currentVSLocation, + this->SpecifiedVSInstallLocation)) { + if (this->SpecifiedVSInstallVersion.empty() || + instanceInfo.Version == this->SpecifiedVSInstallVersion) { + chosenInstanceInfo = instanceInfo; + return true; + } + specifiedLocationNotSpecifiedVersion = true; } - - if (!this->SpecifiedVSInstallLocation.empty()) { - // We are looking for a specific instance. - std::string currentVSLocation = instanceInfo.GetInstallLocation(); + } else if (!this->SpecifiedVSInstallVersion.empty()) { + // We are looking for a specific version. + if (instanceInfo.Version == this->SpecifiedVSInstallVersion) { + chosenInstanceInfo = instanceInfo; + return true; + } + } else { + // We are not looking for a specific instance. + // If we've been given a hint then use it. + if (!envVSCommonToolsDir.empty()) { + std::string currentVSLocation = + cmStrCat(instanceInfo.GetInstallLocation(), "/Common7/Tools"); if (cmSystemTools::ComparePath(currentVSLocation, - this->SpecifiedVSInstallLocation)) { - if (this->SpecifiedVSInstallVersion.empty() || - instanceInfo.Version == this->SpecifiedVSInstallVersion) { - chosenInstanceInfo = instanceInfo; - return true; - } - specifiedLocationNotSpecifiedVersion = true; - } - } else if (!this->SpecifiedVSInstallVersion.empty()) { - // We are looking for a specific version. - if (instanceInfo.Version == this->SpecifiedVSInstallVersion) { + envVSCommonToolsDir)) { chosenInstanceInfo = instanceInfo; return true; } - } else { - // We are not looking for a specific instance. - // If we've been given a hint then use it. - if (!envVSCommonToolsDir.empty()) { - std::string currentVSLocation = - cmStrCat(instanceInfo.GetInstallLocation(), "/Common7/Tools"); - if (cmSystemTools::ComparePath(currentVSLocation, - envVSCommonToolsDir)) { - chosenInstanceInfo = instanceInfo; - return true; - } - } - // Otherwise, add this to the list of candidates. - vecVSInstances.push_back(instanceInfo); } + // Otherwise, add this to the list of candidates. + vecVSInstances.push_back(instanceInfo); } } diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index 44c883b..a16f00b 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -118,6 +118,9 @@ private: int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances); bool EnumerateAndChooseVSInstance(); bool LoadSpecifiedVSInstanceFromDisk(); + bool EnumerateVSInstancesWithVswhere( + std::vector<VSInstanceInfo>& VSInstances); + bool EnumerateVSInstancesWithCOM(std::vector<VSInstanceInfo>& VSInstances); unsigned int Version; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 276eccf..cf0cb17 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -664,6 +664,14 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( } } + cmValue startupObject = + this->GeneratorTarget->GetProperty("VS_DOTNET_STARTUP_OBJECT"); + + if (startupObject && this->Managed) { + Elem e1(e0, "PropertyGroup"); + e1.Element("StartupObject", *startupObject); + } + switch (this->ProjectType) { case VsProjectType::vcxproj: { std::string const& props = @@ -927,6 +935,12 @@ void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile( break; } e1.Element("OutputType", outputType); + + cmValue startupObject = + this->GeneratorTarget->GetProperty("VS_DOTNET_STARTUP_OBJECT"); + if (startupObject) { + e1.Element("StartupObject", *startupObject); + } } for (const std::string& config : this->Configurations) { diff --git a/Source/cmWindowsRegistry.cxx b/Source/cmWindowsRegistry.cxx new file mode 100644 index 0000000..c857a3b --- /dev/null +++ b/Source/cmWindowsRegistry.cxx @@ -0,0 +1,442 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmWindowsRegistry.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) +# include <algorithm> +# include <cstdint> +# include <exception> +# include <iterator> +# include <utility> +# include <vector> + +# include <cm/memory> +# include <cmext/string_view> + +# include <windows.h> + +# include "cmsys/Encoding.hxx" +# include "cmsys/SystemTools.hxx" + +# include "cmMakefile.h" +# include "cmStringAlgorithms.h" +# include "cmValue.h" +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +namespace { +bool Is64BitWindows() +{ +# if defined(_WIN64) + // 64-bit programs run only on Win64 + return true; +# else + // 32-bit programs run on both 32-bit and 64-bit Windows, so we must check. + BOOL isWow64 = false; + return IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64; +# endif +} + +// class registry_exception +class registry_error : public std::exception +{ +public: + registry_error(std::string msg) + : What(std::move(msg)) + { + } + ~registry_error() override = default; + + const char* what() const noexcept override { return What.c_str(); } + +private: + std::string What; +}; + +// Class KeyHandler +class KeyHandler +{ +public: + using View = cmWindowsRegistry::View; + + KeyHandler(HKEY hkey) + : Handler(hkey) + { + } + ~KeyHandler() { RegCloseKey(this->Handler); } + + static KeyHandler OpenKey(cm::string_view key, View view); + + std::string ReadValue(cm::string_view name, cm::string_view separator); + + std::vector<std::string> GetValueNames(); + std::vector<std::string> GetSubKeys(); + +private: + static std::string FormatSystemError(LSTATUS status); + + HKEY Handler; +}; + +KeyHandler KeyHandler::OpenKey(cm::string_view key, View view) +{ + if (view == View::Reg64 && !Is64BitWindows()) { + throw registry_error("No 64bit registry on Windows32."); + } + + auto start = key.find_first_of("\\/"_s); + auto rootKey = key.substr(0, start); + HKEY hRootKey; + + if (rootKey == "HKCU"_s || rootKey == "HKEY_CURRENT_USER"_s) { + hRootKey = HKEY_CURRENT_USER; + } else if (rootKey == "HKLM"_s || rootKey == "HKEY_LOCAL_MACHINE"_s) { + hRootKey = HKEY_LOCAL_MACHINE; + } else if (rootKey == "HKCR"_s || rootKey == "HKEY_CLASSES_ROOT"_s) { + hRootKey = HKEY_CLASSES_ROOT; + } else if (rootKey == "HKCC"_s || rootKey == "HKEY_CURRENT_CONFIG"_s) { + hRootKey = HKEY_CURRENT_CONFIG; + } else if (rootKey == "HKU"_s || rootKey == "HKEY_USERS"_s) { + hRootKey = HKEY_USERS; + } else { + throw registry_error(cmStrCat(rootKey, ": invalid root key.")); + } + std::wstring subKey; + if (start != cm::string_view::npos) { + subKey = cmsys::Encoding::ToWide(key.substr(start + 1).data()); + } + // Update path format + std::replace(subKey.begin(), subKey.end(), L'/', L'\\'); + + REGSAM options = KEY_READ; + if (Is64BitWindows()) { + options |= view == View::Reg64 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY; + } + + HKEY hKey; + if (LSTATUS status = RegOpenKeyExW(hRootKey, subKey.c_str(), 0, options, + &hKey) != ERROR_SUCCESS) { + throw registry_error(FormatSystemError(status)); + } + + return KeyHandler(hKey); +} + +std::string KeyHandler::FormatSystemError(LSTATUS status) +{ + std::string formattedMessage; + LPWSTR message = nullptr; + DWORD size = 1024; + if (FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, + status, 0, reinterpret_cast<LPWSTR>(&message), size, nullptr) == 0) { + formattedMessage = "Windows Registry: unexpected error."; + } else { + formattedMessage = cmTrimWhitespace(cmsys::Encoding::ToNarrow(message)); + } + LocalFree(message); + + return formattedMessage; +} + +std::string KeyHandler::ReadValue(cm::string_view name, + cm::string_view separator) +{ + LSTATUS status; + DWORD size; + // pick-up maximum size for value + if ((status = RegQueryInfoKeyW(this->Handler, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, + &size, nullptr, nullptr)) != ERROR_SUCCESS) { + throw registry_error(this->FormatSystemError(status)); + } + auto data = cm::make_unique<BYTE[]>(size); + DWORD type; + auto valueName = cmsys::Encoding::ToWide(name.data()); + if ((status = RegQueryValueExW(this->Handler, valueName.c_str(), nullptr, + &type, data.get(), &size)) != ERROR_SUCCESS) { + throw registry_error(this->FormatSystemError(status)); + } + switch (type) { + case REG_SZ: + return cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(data.get())); + break; + case REG_EXPAND_SZ: { + auto expandSize = ExpandEnvironmentStringsW( + reinterpret_cast<wchar_t*>(data.get()), nullptr, 0); + auto expandData = cm::make_unique<wchar_t[]>(expandSize + 1); + if (ExpandEnvironmentStringsW(reinterpret_cast<wchar_t*>(data.get()), + expandData.get(), expandSize + 1) == 0) { + throw registry_error(this->FormatSystemError(GetLastError())); + } else { + return cmsys::Encoding::ToNarrow(expandData.get()); + } + } break; + case REG_DWORD: + return std::to_string(*reinterpret_cast<std::uint32_t*>(data.get())); + break; + case REG_QWORD: + return std::to_string(*reinterpret_cast<std::uint64_t*>(data.get())); + break; + case REG_MULTI_SZ: { + // replace separator with semicolon + auto sep = cmsys::Encoding::ToWide(separator.data())[0]; + std::replace(reinterpret_cast<wchar_t*>(data.get()), + reinterpret_cast<wchar_t*>(data.get()) + + (size / sizeof(wchar_t)) - 1, + sep, L';'); + return cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(data.get())); + } break; + default: + throw registry_error(cmStrCat(type, ": unsupported type.")); + } +} + +std::vector<std::string> KeyHandler::GetValueNames() +{ + LSTATUS status; + DWORD maxSize; + // pick-up maximum size for value names + if ((status = RegQueryInfoKeyW( + this->Handler, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &maxSize, nullptr, nullptr, nullptr)) != ERROR_SUCCESS) { + throw registry_error(this->FormatSystemError(status)); + } + // increment size for final null + auto data = cm::make_unique<wchar_t[]>(++maxSize); + DWORD index = 0; + DWORD size = maxSize; + + std::vector<std::string> valueNames; + + while ((status = RegEnumValueW(this->Handler, index, data.get(), &size, + nullptr, nullptr, nullptr, nullptr)) == + ERROR_SUCCESS) { + auto name = cmsys::Encoding::ToNarrow(data.get()); + valueNames.push_back(name.empty() ? "(default)" : name); + size = maxSize; + ++index; + } + + if (status != ERROR_NO_MORE_ITEMS) { + throw registry_error(this->FormatSystemError(status)); + } + + return valueNames; +} + +std::vector<std::string> KeyHandler::GetSubKeys() +{ + LSTATUS status; + DWORD size; + // pick-up maximum size for subkeys + if ((status = RegQueryInfoKeyW( + this->Handler, nullptr, nullptr, nullptr, nullptr, &size, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr)) != ERROR_SUCCESS) { + throw registry_error(this->FormatSystemError(status)); + } + // increment size for final null + auto data = cm::make_unique<wchar_t[]>(++size); + DWORD index = 0; + std::vector<std::string> subKeys; + + while ((status = RegEnumKeyW(this->Handler, index, data.get(), size)) == + ERROR_SUCCESS) { + subKeys.push_back(cmsys::Encoding::ToNarrow(data.get())); + ++index; + } + if (status != ERROR_NO_MORE_ITEMS) { + throw registry_error(this->FormatSystemError(status)); + } + + return subKeys; +} +} +#endif + +// class cmWindowsRegistry +cmWindowsRegistry::cmWindowsRegistry(cmMakefile& makefile) +#if !defined(_WIN32) || defined(__CYGWIN__) + : LastError("No Registry on this platform.") +#endif +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + if (cmValue targetSize = makefile.GetDefinition("CMAKE_SIZEOF_VOID_P")) { + this->TargetSize = targetSize == "8" ? 64 : 32; + } +#else + (void)makefile; +#endif +} + +cm::string_view cmWindowsRegistry::GetLastError() const +{ + return this->LastError; +} + +#if defined(_WIN32) && !defined(__CYGWIN__) +std::vector<cmWindowsRegistry::View> cmWindowsRegistry::ComputeViews(View view) +{ + switch (view) { + case View::Both: + switch (this->TargetSize) { + case 64: + return std::vector<View>{ View::Reg64, View::Reg32 }; + break; + case 32: + return Is64BitWindows() + ? std::vector<View>{ View::Reg32, View::Reg64 } + : std::vector<View>{ View::Reg32 }; + break; + default: + // No language specified, fallback to host architecture + return Is64BitWindows() + ? std::vector<View>{ View::Reg64, View::Reg32 } + : std::vector<View>{ View::Reg32 }; + break; + } + break; + case View::Target: + switch (this->TargetSize) { + case 64: + return std::vector<View>{ View::Reg64 }; + break; + case 32: + return std::vector<View>{ View::Reg32 }; + break; + default: + break; + } + CM_FALLTHROUGH; + case View::Host: + return std::vector<View>{ Is64BitWindows() ? View::Reg64 : View::Reg32 }; + break; + case View::Reg64_32: + return Is64BitWindows() ? std::vector<View>{ View::Reg64, View::Reg32 } + : std::vector<View>{ View::Reg32 }; + break; + case View::Reg32_64: + return Is64BitWindows() ? std::vector<View>{ View::Reg32, View::Reg64 } + : std::vector<View>{ View::Reg32 }; + break; + default: + return std::vector<View>{ view }; + break; + } +} +#endif + +cm::optional<std::string> cmWindowsRegistry::ReadValue( + cm::string_view key, cm::string_view name, View view, + cm::string_view separator) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + // compute list of registry views + auto views = this->ComputeViews(view); + + if (cmsys::SystemTools::Strucmp(name.data(), "(default)") == 0) { + // handle magic name for default value + name = ""_s; + } + if (separator.empty()) { + separator = "\0"_s; + } + + for (auto v : views) { + try { + this->LastError.clear(); + auto handler = KeyHandler::OpenKey(key, v); + return handler.ReadValue(name, separator); + } catch (const registry_error& e) { + this->LastError = e.what(); + continue; + } + } +#else + (void)key; + (void)name; + (void)view; + (void)separator; +#endif + return cm::nullopt; +} + +cm::optional<std::vector<std::string>> cmWindowsRegistry::GetValueNames( + cm::string_view key, View view) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + this->LastError.clear(); + // compute list of registry views + auto views = this->ComputeViews(view); + std::vector<std::string> valueNames; + bool querySuccessful = false; + + for (auto v : views) { + try { + auto handler = KeyHandler::OpenKey(key, v); + auto list = handler.GetValueNames(); + std::move(list.begin(), list.end(), std::back_inserter(valueNames)); + querySuccessful = true; + } catch (const registry_error& e) { + this->LastError = e.what(); + continue; + } + } + if (!valueNames.empty()) { + // value names must be unique and sorted + std::sort(valueNames.begin(), valueNames.end()); + valueNames.erase(std::unique(valueNames.begin(), valueNames.end()), + valueNames.end()); + } + + if (querySuccessful) { + // At least one query was successful, so clean-up any error message + this->LastError.clear(); + return valueNames; + } +#else + (void)key; + (void)view; +#endif + return cm::nullopt; +} + +cm::optional<std::vector<std::string>> cmWindowsRegistry::GetSubKeys( + cm::string_view key, View view) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + this->LastError.clear(); + // compute list of registry views + auto views = this->ComputeViews(view); + std::vector<std::string> subKeys; + bool querySuccessful = false; + + for (auto v : views) { + try { + auto handler = KeyHandler::OpenKey(key, v); + auto list = handler.GetSubKeys(); + std::move(list.begin(), list.end(), std::back_inserter(subKeys)); + querySuccessful = true; + } catch (const registry_error& e) { + this->LastError = e.what(); + continue; + } + } + if (!subKeys.empty()) { + // keys must be unique and sorted + std::sort(subKeys.begin(), subKeys.end()); + subKeys.erase(std::unique(subKeys.begin(), subKeys.end()), subKeys.end()); + } + + if (querySuccessful) { + // At least one query was successful, so clean-up any error message + this->LastError.clear(); + return subKeys; + } +#else + (void)key; + (void)view; +#endif + return cm::nullopt; +} diff --git a/Source/cmWindowsRegistry.h b/Source/cmWindowsRegistry.h new file mode 100644 index 0000000..6f10b3a --- /dev/null +++ b/Source/cmWindowsRegistry.h @@ -0,0 +1,55 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <string> +#include <vector> + +#include <cm/optional> +#include <cm/string_view> +#include <cmext/string_view> + +class cmMakefile; + +class cmWindowsRegistry +{ +public: + cmWindowsRegistry(cmMakefile&); + + enum class View + { + Both, + Target, + Host, + Reg64_32, + Reg32_64, + Reg32, + Reg64 + }; + + cm::optional<std::string> ReadValue(cm::string_view key, + View view = View::Both, + cm::string_view separator = "\0"_s) + { + return this->ReadValue(key, ""_s, view, separator); + } + cm::optional<std::string> ReadValue(cm::string_view key, + cm::string_view name, + View view = View::Both, + cm::string_view separator = "\0"_s); + + cm::optional<std::vector<std::string>> GetValueNames(cm::string_view key, + View view = View::Both); + cm::optional<std::vector<std::string>> GetSubKeys(cm::string_view key, + View view = View::Both); + + cm::string_view GetLastError() const; + +private: +#if defined(_WIN32) && !defined(__CYGWIN__) + std::vector<View> ComputeViews(View view); + + int TargetSize = 0; +#endif + std::string LastError; +}; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 5bfc4c8..1c027ad 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -565,10 +565,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) "No install directory specified for --install-prefix", CommandArgument::Values::One, PrefixLambda }, CommandArgument{ "--find-package", CommandArgument::Values::Zero, - [&](std::string const&, cmake*) -> bool { - findPackageMode = true; - return true; - } }, + CommandArgument::setToTrue(findPackageMode) }, }; for (decltype(args.size()) i = 1; i < args.size(); ++i) { std::string const& arg = args[i]; @@ -876,10 +873,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) CommandArgument{ "-P", "-P must be followed by a file name.", CommandArgument::Values::One, CommandArgument::RequiresSeparator::No, - [&](std::string const&, cmake*) -> bool { - scriptMode = true; - return true; - } }, + CommandArgument::setToTrue(scriptMode) }, CommandArgument{ "-D", "-D must be followed with VAR=VALUE.", CommandArgument::Values::One, CommandArgument::RequiresSeparator::No, diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 28be166..41c6c12 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -9,6 +9,7 @@ #include <climits> #include <cstdio> #include <cstring> +#include <functional> #include <iostream> #include <sstream> #include <string> @@ -262,37 +263,17 @@ int do_cmake(int ac, char const* const* av) return true; } }, CommandArgument{ "--system-information", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - sysinfo = true; - return true; - } }, + CommandArgument::setToTrue(sysinfo) }, CommandArgument{ "-N", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - view_only = true; - return true; - } }, + CommandArgument::setToTrue(view_only) }, CommandArgument{ "-LAH", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - list_all_cached = true; - list_help = true; - return true; - } }, + CommandArgument::setToTrue(list_all_cached, list_help) }, CommandArgument{ "-LA", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - list_all_cached = true; - return true; - } }, + CommandArgument::setToTrue(list_all_cached) }, CommandArgument{ "-LH", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - list_cached = true; - list_help = true; - return true; - } }, + CommandArgument::setToTrue(list_cached, list_help) }, CommandArgument{ "-L", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - list_cached = true; - return true; - } }, + CommandArgument::setToTrue(list_cached) }, CommandArgument{ "-P", "No script specified for argument -P", CommandArgument::Values::One, CommandArgument::RequiresSeparator::No, @@ -510,15 +491,9 @@ int do_build(int ac, char const* const* av) std::vector<CommandArgument> arguments = { CommandArgument{ "--preset", CommandArgument::Values::One, - [&](std::string const& value) -> bool { - presetName = value; - return true; - } }, + CommandArgument::setToValue(presetName) }, CommandArgument{ "--list-presets", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - listPresets = true; - return true; - } }, + CommandArgument::setToTrue(listPresets) }, CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne, CommandArgument::RequiresSeparator::No, jLambda }, CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne, @@ -527,15 +502,9 @@ int do_build(int ac, char const* const* av) CommandArgument{ "--target", CommandArgument::Values::OneOrMore, targetLambda }, CommandArgument{ "--config", CommandArgument::Values::One, - [&](std::string const& value) -> bool { - config = value; - return true; - } }, + CommandArgument::setToValue(config) }, CommandArgument{ "--clean-first", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - cleanFirst = true; - return true; - } }, + CommandArgument::setToTrue(cleanFirst) }, CommandArgument{ "--resolve-package-references", CommandArgument::Values::One, resolvePackagesLambda }, CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda }, @@ -545,10 +514,7 @@ int do_build(int ac, char const* const* av) CommandArgument{ "--use-stderr", CommandArgument::Values::Zero, [](std::string const&) -> bool { return true; } }, CommandArgument{ "--", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - nativeOptionsPassed = true; - return true; - } }, + CommandArgument::setToTrue(nativeOptionsPassed) }, }; if (ac >= 3) { @@ -831,31 +797,16 @@ int do_install(int ac, char const* const* av) std::vector<CommandArgument> arguments = { CommandArgument{ "--config", CommandArgument::Values::One, - [&](std::string const& value) -> bool { - config = value; - return true; - } }, + CommandArgument::setToValue(config) }, CommandArgument{ "--component", CommandArgument::Values::One, - [&](std::string const& value) -> bool { - component = value; - return true; - } }, - CommandArgument{ "--default-directory-permissions", - CommandArgument::Values::One, - [&](std::string const& value) -> bool { - defaultDirectoryPermissions = value; - return true; - } }, + CommandArgument::setToValue(component) }, + CommandArgument{ + "--default-directory-permissions", CommandArgument::Values::One, + CommandArgument::setToValue(defaultDirectoryPermissions) }, CommandArgument{ "--prefix", CommandArgument::Values::One, - [&](std::string const& value) -> bool { - prefix = value; - return true; - } }, + CommandArgument::setToValue(prefix) }, CommandArgument{ "--strip", CommandArgument::Values::Zero, - [&](std::string const&) -> bool { - strip = true; - return true; - } }, + CommandArgument::setToTrue(strip) }, CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda }, CommandArgument{ "--verbose", CommandArgument::Values::Zero, verboseLambda } |