/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file LICENSE.rst or https://cmake.org/licensing for details. */ #include "cmInstallCommand.h" #include #include #include #include #include #include #include #include #include #include #include "cmsys/Glob.hxx" #include "cmArgumentParser.h" #include "cmArgumentParserTypes.h" #include "cmCMakePath.h" #include "cmComputeLinkInformation.h" #include "cmDiagnosticContext.h" #include "cmDiagnostics.h" #include "cmExecutionStatus.h" #include "cmExperimental.h" #include "cmExportSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmInstallAndroidMKExportGenerator.h" #include "cmInstallCMakeConfigExportGenerator.h" #include "cmInstallCommandArguments.h" #include "cmInstallCxxModuleBmiGenerator.h" #include "cmInstallDirectoryGenerator.h" #include "cmInstallDirs.h" #include "cmInstallFileSetGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" #include "cmInstallGetRuntimeDependenciesGenerator.h" #include "cmInstallImportedRuntimeArtifactsGenerator.h" #include "cmInstallPackageInfoExportGenerator.h" #include "cmInstallRuntimeDependencySet.h" #include "cmInstallRuntimeDependencySetGenerator.h" #include "cmInstallSbomGenerator.h" #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPackageInfoArguments.h" #include "cmPolicies.h" #include "cmRange.h" #include "cmRuntimeDependencyArchive.h" #include "cmSbomArguments.h" #include "cmStringAlgorithms.h" #include "cmSubcommandTable.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetExport.h" #include "cmTargetTypes.h" #include "cmUnreachable.h" #include "cmValue.h" class cmListFileBacktrace; namespace { enum class RuntimeOnly { No, Yes, }; struct InstallCategoryFlags { bool Archive = false; bool Library = false; bool Namelink = false; bool Importlink = false; bool Runtime = false; bool Object = false; bool Framework = false; bool Bundle = false; bool PrivateHeader = false; bool PublicHeader = false; bool Resource = false; std::vector FileSet; bool CxxModuleBmi = false; }; struct InstallContext { std::unique_ptr GenericArgs; std::unique_ptr ArchiveArgs; std::unique_ptr LibraryArgs; std::unique_ptr RuntimeArgs; std::unique_ptr ObjectArgs; std::unique_ptr FrameworkArgs; std::unique_ptr BundleArgs; std::unique_ptr PrivateHeaderArgs; std::unique_ptr PublicHeaderArgs; std::unique_ptr ResourceArgs; std::unique_ptr CxxModuleBmiArgs; cmInstallCommandIncludesArgument IncludesArgs; std::vector FileSetArgs; cmInstallTargetGenerator::NamelinkModeType NamelinkMode = cmInstallTargetGenerator::NamelinkModeNone; cmInstallTargetGenerator::NamelinkModeType ImportlinkMode = cmInstallTargetGenerator::NamelinkModeNone; std::string Exports; cmInstallRuntimeDependencySet* RuntimeDependencySet = nullptr; void BindGenericArguments() { cmInstallCommandArguments* generic = this->GenericArgs.get(); this->ArchiveArgs->SetGenericArguments(generic); this->LibraryArgs->SetGenericArguments(generic); this->RuntimeArgs->SetGenericArguments(generic); this->ObjectArgs->SetGenericArguments(generic); this->FrameworkArgs->SetGenericArguments(generic); this->BundleArgs->SetGenericArguments(generic); this->PrivateHeaderArgs->SetGenericArguments(generic); this->PublicHeaderArgs->SetGenericArguments(generic); this->ResourceArgs->SetGenericArguments(generic); this->CxxModuleBmiArgs->SetGenericArguments(generic); for (auto& fileSetArg : this->FileSetArgs) { fileSetArg.SetGenericArguments(generic); } } }; void CollectEvaluatedTransitiveSharedModuleTargets( cmLocalGenerator& lg, std::vector const& rootNames, std::set& out, std::string const& config) { std::set visited; std::vector stack; std::set const rootNameSet(rootNames.begin(), rootNames.end()); auto consider = [&](cmGeneratorTarget const* dep) { if (!dep || dep->IsImported()) { return; } if (!visited.insert(dep).second) { return; } cm::TargetType type = dep->GetType(); if (type == cm::TargetType::SHARED_LIBRARY) { if (rootNameSet.find(dep->GetName()) == rootNameSet.end()) { out.insert(dep->Target); } stack.push_back(dep); } }; auto enqueue = [&](cmGeneratorTarget const* current) { cmComputeLinkInformation* linkInfo = current->GetLinkInformation(config); std::set const& sharedTargets = linkInfo->GetSharedLibrariesLinked(); for (cmGeneratorTarget const* dep : sharedTargets) { consider(dep); } }; for (std::string const& name : rootNames) { cmGeneratorTarget* root = lg.FindGeneratorTargetToUse(name); if (!root) { root = lg.GetGlobalGenerator()->FindGeneratorTarget(name); } if (!root) { continue; } visited.insert(root); enqueue(root); } while (!stack.empty()) { cmGeneratorTarget const* current = stack.back(); stack.pop_back(); enqueue(current); } } struct RuntimeDependenciesArgs { ArgumentParser::MaybeEmpty> Directories; ArgumentParser::MaybeEmpty> PreIncludeRegexes; ArgumentParser::MaybeEmpty> PreExcludeRegexes; ArgumentParser::MaybeEmpty> PostIncludeRegexes; ArgumentParser::MaybeEmpty> PostExcludeRegexes; ArgumentParser::MaybeEmpty> PostIncludeFiles; ArgumentParser::MaybeEmpty> PostExcludeFiles; }; auto const RuntimeDependenciesArgHelper = cmArgumentParser{} .Bind("DIRECTORIES"_s, &RuntimeDependenciesArgs::Directories) .Bind("PRE_INCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreIncludeRegexes) .Bind("PRE_EXCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreExcludeRegexes) .Bind("POST_INCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PostIncludeRegexes) .Bind("POST_EXCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PostExcludeRegexes) .Bind("POST_INCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostIncludeFiles) .Bind("POST_EXCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostExcludeFiles); class Helper { public: Helper(cmExecutionStatus& status) : Status(status) , Makefile(&status.GetMakefile()) { this->DefaultComponentName = this->Makefile->GetSafeDefinition( "CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"); if (this->DefaultComponentName == "") { cmValue projectName = this->Makefile->GetDefinition("PROJECT_NAME"); if (!projectName->empty()) { this->DefaultComponentName = projectName; } else { this->DefaultComponentName = "Unspecified"; } } if (this->DefaultComponentName.empty()) { this->DefaultComponentName = "Unspecified"; } } cmDiagnosticContext CaptureContext() const { return cmInstallGenerator::CaptureContext(this->Makefile); } void SetError(std::string const& err) { this->Status.SetError(err); } bool MakeFilesFullPath(char const* modeName, std::vector const& relFiles, std::vector& absFiles); bool MakeFilesFullPath(char const* modeName, std::string const& basePath, std::vector const& relFiles, std::vector& absFiles); std::string GetRuntimeDestination( cmInstallCommandArguments const* args) const; std::string GetArchiveDestination( cmInstallCommandArguments const* args) const; std::string GetLibraryDestination( cmInstallCommandArguments const* args) const; std::string GetCxxModulesBmiDestination( cmInstallCommandArguments const* args) const; std::string GetIncludeDestination( cmInstallCommandArguments const* args) const; std::string GetDestinationForType(cmInstallCommandArguments const* args, std::string const& type) const; cmExecutionStatus& Status; cmMakefile* Makefile; std::string DefaultComponentName; }; std::vector const& SelectConfigurations( cmInstallCommandArguments const& args, cm::optional> const& configurations) { return configurations ? *configurations : args.GetConfigurations(); } std::unique_ptr CreateInstallTargetGenerator( cmTarget& target, cmInstallCommandArguments const& args, bool impLib, cmDiagnosticContext context, std::string const& destination, bool forceOpt = false, bool namelink = false, cm::optional> const& configurations = {}) { cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(target.GetMakefile()); target.SetHaveInstallRule(true); std::string const& component = namelink ? args.GetNamelinkComponent() : args.GetComponent(); auto g = cm::make_unique( target.GetName(), destination, impLib, args.GetPermissions(), SelectConfigurations(args, configurations), component, message, args.GetExcludeFromAll(), args.GetOptional() || forceOpt, std::move(context)); target.AddInstallGenerator(g.get()); return g; } std::unique_ptr CreateInstallTargetGenerator( cmTarget& target, cmInstallCommandArguments const& args, bool impLib, cmDiagnosticContext context, bool forceOpt = false, bool namelink = false, cm::optional> const& configurations = {}) { return CreateInstallTargetGenerator(target, args, impLib, std::move(context), args.GetDestination(), forceOpt, namelink, configurations); } std::unique_ptr CreateInstallFilesGenerator( cmMakefile* mf, std::vector const& absFiles, cmInstallCommandArguments const& args, bool programs, std::string const& destination, cm::optional> const& configurations = {}) { cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(mf); return cm::make_unique( absFiles, destination, programs, args.GetPermissions(), SelectConfigurations(args, configurations), args.GetComponent(), message, args.GetExcludeFromAll(), args.GetRename(), args.GetOptional(), cmInstallGenerator::CaptureContext(mf)); } std::unique_ptr CreateInstallFileSetGenerator( Helper& helper, cmTarget& target, cmInstallCommandFileSetArguments const& args, cm::optional> const& configurations = {}) { cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(helper.Makefile); return cm::make_unique( target.GetName(), args.GetFileSet(), args.GetDestination(), args.GetPermissions(), SelectConfigurations(args, configurations), args.GetComponent(), message, args.GetExcludeFromAll(), args.GetOptional(), helper.CaptureContext()); } void AddInstallRuntimeDependenciesGenerator( Helper& helper, cmInstallRuntimeDependencySet* runtimeDependencySet, cmInstallCommandArguments const& runtimeArgs, cmInstallCommandArguments const& libraryArgs, cmInstallCommandArguments const& frameworkArgs, RuntimeDependenciesArgs runtimeDependenciesArgs, bool& installsRuntime, bool& installsLibrary, bool& installsFramework) { bool dllPlatform = !helper.Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); bool apple = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") == "Darwin"; auto const& runtimeDependenciesArgsRef = dllPlatform ? runtimeArgs : libraryArgs; std::vector configurations = runtimeDependenciesArgsRef.GetConfigurations(); if (apple) { std::copy(frameworkArgs.GetConfigurations().begin(), frameworkArgs.GetConfigurations().end(), std::back_inserter(configurations)); } // Create file(GET_RUNTIME_DEPENDENCIES) generator. auto getRuntimeDependenciesGenerator = cm::make_unique( runtimeDependencySet, std::move(runtimeDependenciesArgs.Directories), std::move(runtimeDependenciesArgs.PreIncludeRegexes), std::move(runtimeDependenciesArgs.PreExcludeRegexes), std::move(runtimeDependenciesArgs.PostIncludeRegexes), std::move(runtimeDependenciesArgs.PostExcludeRegexes), std::move(runtimeDependenciesArgs.PostIncludeFiles), std::move(runtimeDependenciesArgs.PostExcludeFiles), runtimeDependenciesArgsRef.GetComponent(), apple ? frameworkArgs.GetComponent() : "", true, "_CMAKE_DEPS", "_CMAKE_RPATH", configurations, cmInstallGenerator::SelectMessageLevel(helper.Makefile), runtimeDependenciesArgsRef.GetExcludeFromAll() && (apple ? frameworkArgs.GetExcludeFromAll() : true), helper.Makefile->GetBacktrace(), helper.Makefile->GetPolicyStatus(cmPolicies::CMP0207)); helper.Makefile->AddInstallGenerator( std::move(getRuntimeDependenciesGenerator)); // Create the library dependencies generator. auto libraryRuntimeDependenciesGenerator = cm::make_unique( cmInstallRuntimeDependencySetGenerator::DependencyType::Library, runtimeDependencySet, std::vector{}, true, std::string{}, true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP", dllPlatform ? helper.GetRuntimeDestination(&runtimeArgs) : helper.GetLibraryDestination(&libraryArgs), runtimeDependenciesArgsRef.GetConfigurations(), runtimeDependenciesArgsRef.GetComponent(), runtimeDependenciesArgsRef.GetPermissions(), cmInstallGenerator::SelectMessageLevel(helper.Makefile), runtimeDependenciesArgsRef.GetExcludeFromAll(), helper.CaptureContext()); helper.Makefile->AddInstallGenerator( std::move(libraryRuntimeDependenciesGenerator)); if (dllPlatform) { installsRuntime = true; } else { installsLibrary = true; } if (apple) { // Create the framework dependencies generator. auto frameworkRuntimeDependenciesGenerator = cm::make_unique( cmInstallRuntimeDependencySetGenerator::DependencyType::Framework, runtimeDependencySet, std::vector{}, true, std::string{}, true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP", frameworkArgs.GetDestination(), frameworkArgs.GetConfigurations(), frameworkArgs.GetComponent(), frameworkArgs.GetPermissions(), cmInstallGenerator::SelectMessageLevel(helper.Makefile), frameworkArgs.GetExcludeFromAll(), helper.CaptureContext()); helper.Makefile->AddInstallGenerator( std::move(frameworkRuntimeDependenciesGenerator)); installsFramework = true; } } std::set const allowedTypes{ "BIN", "SBIN", "LIB", "INCLUDE", "SYSCONF", "SHAREDSTATE", "LOCALSTATE", "RUNSTATE", "DATA", "INFO", "LOCALE", "MAN", "DOC", "LIBEXEC", }; template bool AddBundleExecutable(Helper& helper, cmInstallRuntimeDependencySet* runtimeDependencySet, T&& bundleExecutable) { if (!runtimeDependencySet->AddBundleExecutable(bundleExecutable)) { helper.SetError( "A runtime dependency set may only have one bundle executable."); return false; } return true; } void RegisterInstallComponents(cmMakefile* makefile, InstallContext const& ctx, InstallCategoryFlags const& flags) { cmGlobalGenerator* gg = makefile->GetGlobalGenerator(); // Tell the global generator about any installation component names // specified if (flags.Archive) { gg->AddInstallComponent(ctx.ArchiveArgs->GetComponent()); } if (flags.Library) { gg->AddInstallComponent(ctx.LibraryArgs->GetComponent()); } if (flags.Namelink) { gg->AddInstallComponent(ctx.LibraryArgs->GetNamelinkComponent()); } if (flags.Importlink) { gg->AddInstallComponent(ctx.ArchiveArgs->GetNamelinkComponent()); } if (flags.Runtime) { gg->AddInstallComponent(ctx.RuntimeArgs->GetComponent()); } if (flags.Object) { gg->AddInstallComponent(ctx.ObjectArgs->GetComponent()); } if (flags.Framework) { gg->AddInstallComponent(ctx.FrameworkArgs->GetComponent()); } if (flags.Bundle) { gg->AddInstallComponent(ctx.BundleArgs->GetComponent()); } if (flags.PrivateHeader) { gg->AddInstallComponent(ctx.PrivateHeaderArgs->GetComponent()); } if (flags.PublicHeader) { gg->AddInstallComponent(ctx.PublicHeaderArgs->GetComponent()); } if (flags.Resource) { gg->AddInstallComponent(ctx.ResourceArgs->GetComponent()); } for (std::size_t i = 0; i < ctx.FileSetArgs.size(); ++i) { if (flags.FileSet[i]) { gg->AddInstallComponent(ctx.FileSetArgs[i].GetComponent()); } } if (flags.CxxModuleBmi) { gg->AddInstallComponent(ctx.CxxModuleBmiArgs->GetComponent()); } } bool CreateInstallGeneratorsForTarget( Helper& helper, cmTarget& target, InstallContext const& ctx, InstallCategoryFlags& flags, std::string& error, cm::optional> configurations = {}, RuntimeOnly runtimeOnly = RuntimeOnly::No) { cmInstallCommandArguments const& archiveArgs = *ctx.ArchiveArgs; cmInstallCommandArguments const& libraryArgs = *ctx.LibraryArgs; cmInstallCommandArguments const& runtimeArgs = *ctx.RuntimeArgs; cmInstallCommandArguments const& objectArgs = *ctx.ObjectArgs; cmInstallCommandArguments const& frameworkArgs = *ctx.FrameworkArgs; cmInstallCommandArguments const& bundleArgs = *ctx.BundleArgs; cmInstallCommandArguments const& privateHeaderArgs = *ctx.PrivateHeaderArgs; cmInstallCommandArguments const& publicHeaderArgs = *ctx.PublicHeaderArgs; cmInstallCommandArguments const& resourceArgs = *ctx.ResourceArgs; cmInstallCommandArguments const& cxxModuleBmiArgs = *ctx.CxxModuleBmiArgs; cmInstallCommandIncludesArgument const& includesArgs = ctx.IncludesArgs; std::vector const& fileSetArgs = ctx.FileSetArgs; cmInstallTargetGenerator::NamelinkModeType const namelinkMode = ctx.NamelinkMode; cmInstallTargetGenerator::NamelinkModeType const importlinkMode = ctx.ImportlinkMode; std::string const& exports = ctx.Exports; cmInstallRuntimeDependencySet* runtimeDependencySet = ctx.RuntimeDependencySet; auto fail = [&](std::string const& msg) -> bool { error = msg; helper.SetError(msg); return false; }; std::unique_ptr archiveGenerator; std::unique_ptr libraryGenerator; std::unique_ptr namelinkGenerator; std::unique_ptr importlinkGenerator; std::unique_ptr runtimeGenerator; std::unique_ptr objectGenerator; std::unique_ptr frameworkGenerator; std::unique_ptr bundleGenerator; std::unique_ptr privateHeaderGenerator; std::unique_ptr publicHeaderGenerator; std::unique_ptr resourceGenerator; std::vector> fileSetGenerators; std::unique_ptr cxxModuleBmiGenerator; // Avoid selecting default destinations for PUBLIC_HEADER and // PRIVATE_HEADER if any artifacts are specified. bool artifactsSpecified = false; // Track whether this is a namelink-only rule. bool namelinkOnly = false; auto addTargetExport = [&]() -> bool { // Add this install rule to an export if one was specified. if (!exports.empty()) { auto interfaceFileSets = target.GetAllInterfaceFileSets(); if (std::any_of( interfaceFileSets.begin(), interfaceFileSets.end(), [&](std::string const& name) -> bool { return !std::any_of( fileSetArgs.begin(), fileSetArgs.end(), [&](cmInstallCommandFileSetArguments const& fileSetArg) -> bool { return fileSetArg.GetFileSet() == name; }); })) { return fail(cmStrCat("TARGETS target ", target.GetName(), " is exported but not all of its interface " "file sets are installed")); } auto te = cm::make_unique(); te->TargetName = target.GetName(); te->ArchiveGenerator = archiveGenerator.get(); te->BundleGenerator = bundleGenerator.get(); te->FrameworkGenerator = frameworkGenerator.get(); te->HeaderGenerator = publicHeaderGenerator.get(); te->LibraryGenerator = libraryGenerator.get(); te->RuntimeGenerator = runtimeGenerator.get(); te->ObjectsGenerator = objectGenerator.get(); for (auto const& gen : fileSetGenerators) { te->FileSetGenerators[gen->GetFileSetName()] = gen.get(); } te->CxxModuleBmiGenerator = cxxModuleBmiGenerator.get(); target.AddInstallIncludeDirectories( *te, cmMakeRange(includesArgs.GetIncludeDirs())); te->NamelinkOnly = namelinkOnly; helper.Makefile->GetGlobalGenerator() ->GetExportSets()[exports] .AddTargetExport(std::move(te)); } return true; }; switch (target.GetType()) { case cm::TargetType::SHARED_LIBRARY: { // Shared libraries are handled differently on DLL and non-DLL // platforms. All windows platforms are DLL platforms including // cygwin. Currently no other platform is a DLL platform. if (target.IsDLLPlatform()) { // When in namelink only mode skip all libraries on Windows. if (runtimeOnly == RuntimeOnly::No && namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; return addTargetExport(); } // This is a DLL platform. if (runtimeOnly == RuntimeOnly::No && !archiveArgs.GetDestination().empty()) { // The import library uses the ARCHIVE properties. archiveGenerator = CreateInstallTargetGenerator( target, archiveArgs, true, helper.CaptureContext(), false, false, configurations); artifactsSpecified = true; } if (runtimeOnly == RuntimeOnly::Yes || !runtimeArgs.GetDestination().empty()) { // The DLL uses the RUNTIME properties. runtimeGenerator = CreateInstallTargetGenerator( target, runtimeArgs, false, helper.CaptureContext(), helper.GetRuntimeDestination(&runtimeArgs), false, false, configurations); artifactsSpecified = true; } if (runtimeOnly == RuntimeOnly::No && !archiveGenerator && !runtimeGenerator) { archiveGenerator = CreateInstallTargetGenerator( target, archiveArgs, true, helper.CaptureContext(), helper.GetArchiveDestination(nullptr), false, false, configurations); runtimeGenerator = CreateInstallTargetGenerator( target, runtimeArgs, false, helper.CaptureContext(), helper.GetRuntimeDestination(nullptr), false, false, configurations); } if (runtimeDependencySet && runtimeGenerator) { runtimeDependencySet->AddLibrary(runtimeGenerator.get()); } } else { // This is a non-DLL platform. // If it is marked with FRAMEWORK property use the FRAMEWORK set of // INSTALL properties. Otherwise, use the LIBRARY properties. if (target.IsFrameworkOnApple()) { // When in namelink only mode skip frameworks. if (runtimeOnly == RuntimeOnly::No && namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; return addTargetExport(); } // Use the FRAMEWORK properties. if (!frameworkArgs.GetDestination().empty()) { frameworkGenerator = CreateInstallTargetGenerator( target, frameworkArgs, false, helper.CaptureContext(), false, false, configurations); } else { return fail( cmStrCat("TARGETS given no FRAMEWORK DESTINATION for shared " "library FRAMEWORK target \"", target.GetName(), "\".")); } } else { // The shared library uses the LIBRARY properties. if (!libraryArgs.GetDestination().empty()) { artifactsSpecified = true; } if (runtimeOnly == RuntimeOnly::Yes || namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) { libraryGenerator = CreateInstallTargetGenerator( target, libraryArgs, false, helper.CaptureContext(), helper.GetLibraryDestination(&libraryArgs), false, false, configurations); libraryGenerator->SetNamelinkMode( cmInstallTargetGenerator::NamelinkModeSkip); } if (runtimeOnly == RuntimeOnly::No && namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) { namelinkGenerator = CreateInstallTargetGenerator( target, libraryArgs, false, helper.CaptureContext(), helper.GetLibraryDestination(&libraryArgs), false, true, configurations); namelinkGenerator->SetNamelinkMode( cmInstallTargetGenerator::NamelinkModeOnly); } namelinkOnly = runtimeOnly == RuntimeOnly::No && (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); if (runtimeOnly == RuntimeOnly::No && target.GetMakefile()->PlatformSupportsAppleTextStubs() && target.IsSharedLibraryWithExports()) { // Apple .tbd files use the ARCHIVE properties if (!archiveArgs.GetDestination().empty()) { artifactsSpecified = true; } if (importlinkMode != cmInstallTargetGenerator::NamelinkModeOnly) { archiveGenerator = CreateInstallTargetGenerator( target, archiveArgs, true, helper.CaptureContext(), helper.GetLibraryDestination(&archiveArgs), false, false, configurations); archiveGenerator->SetImportlinkMode( cmInstallTargetGenerator::NamelinkModeSkip); } if (importlinkMode != cmInstallTargetGenerator::NamelinkModeSkip) { importlinkGenerator = CreateInstallTargetGenerator( target, archiveArgs, true, helper.CaptureContext(), helper.GetLibraryDestination(&archiveArgs), false, true, configurations); importlinkGenerator->SetImportlinkMode( cmInstallTargetGenerator::NamelinkModeOnly); } namelinkOnly = (importlinkMode == cmInstallTargetGenerator::NamelinkModeOnly); } } if (runtimeDependencySet && libraryGenerator) { runtimeDependencySet->AddLibrary(libraryGenerator.get()); } } } break; case cm::TargetType::STATIC_LIBRARY: { if (runtimeOnly == RuntimeOnly::Yes) { break; } // If it is marked with FRAMEWORK property use the FRAMEWORK set of // INSTALL properties. Otherwise, use the LIBRARY properties. if (target.IsFrameworkOnApple()) { // When in namelink only mode skip frameworks. if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; return addTargetExport(); } // Use the FRAMEWORK properties. if (!frameworkArgs.GetDestination().empty()) { frameworkGenerator = CreateInstallTargetGenerator( target, frameworkArgs, false, helper.CaptureContext(), false, false, configurations); } else { return fail( cmStrCat("TARGETS given no FRAMEWORK DESTINATION for static " "library FRAMEWORK target \"", target.GetName(), "\".")); } } else { // Static libraries use ARCHIVE properties. if (!archiveArgs.GetDestination().empty()) { artifactsSpecified = true; } archiveGenerator = CreateInstallTargetGenerator( target, archiveArgs, false, helper.CaptureContext(), helper.GetArchiveDestination(&archiveArgs), false, false, configurations); } } break; case cm::TargetType::MODULE_LIBRARY: { // Modules use LIBRARY properties. std::string moduleDest; if (!libraryArgs.GetDestination().empty()) { moduleDest = libraryArgs.GetDestination(); } else if (target.IsDLLPlatform()) { moduleDest = helper.GetRuntimeDestination(nullptr); } else { moduleDest = helper.GetLibraryDestination(nullptr); } libraryGenerator = CreateInstallTargetGenerator( target, libraryArgs, false, helper.CaptureContext(), moduleDest, false, false, configurations); libraryGenerator->SetNamelinkMode( runtimeOnly == RuntimeOnly::Yes ? cmInstallTargetGenerator::NamelinkModeNone : namelinkMode); namelinkOnly = runtimeOnly == RuntimeOnly::No && (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); if (runtimeDependencySet) { runtimeDependencySet->AddModule(libraryGenerator.get()); } } break; case cm::TargetType::OBJECT_LIBRARY: { if (runtimeOnly == RuntimeOnly::Yes) { break; } // Objects use OBJECT properties. if (!objectArgs.GetDestination().empty()) { // Verify that we know where the objects are to install them. std::string reason; if (!target.HasKnownObjectFileLocation(&reason)) { return fail( cmStrCat("TARGETS given OBJECT library \"", target.GetName(), "\" whose objects may not be installed", reason, '.')); } objectGenerator = CreateInstallTargetGenerator( target, objectArgs, false, helper.CaptureContext(), false, false, configurations); } else { // Installing an OBJECT library without a destination transforms // it to an INTERFACE library. It installs no files but can be // exported. } } break; case cm::TargetType::EXECUTABLE: { if (runtimeOnly == RuntimeOnly::Yes) { break; } if (target.IsAppBundleOnApple()) { // Application bundles use the BUNDLE properties. if (!bundleArgs.GetDestination().empty()) { bundleGenerator = CreateInstallTargetGenerator( target, bundleArgs, false, helper.CaptureContext(), false, false, configurations); } if (!bundleGenerator) { return fail(cmStrCat("TARGETS given no BUNDLE DESTINATION for " "MACOSX_BUNDLE executable target \"", target.GetName(), "\".")); } if (runtimeDependencySet) { if (!AddBundleExecutable(helper, runtimeDependencySet, bundleGenerator.get())) { error = helper.Status.GetError(); return false; } } } else { // Executables use the RUNTIME properties. if (!runtimeArgs.GetDestination().empty()) { artifactsSpecified = true; } runtimeGenerator = CreateInstallTargetGenerator( target, runtimeArgs, false, helper.CaptureContext(), helper.GetRuntimeDestination(&runtimeArgs), false, false, configurations); if (runtimeDependencySet) { runtimeDependencySet->AddExecutable(runtimeGenerator.get()); } } // On DLL platforms an executable may also have an import // library. Install it to the archive destination if it // exists. if ((target.IsDLLPlatform() || target.IsAIX()) && !archiveArgs.GetDestination().empty() && target.IsExecutableWithExports()) { // The import library uses the ARCHIVE properties. artifactsSpecified = true; archiveGenerator = CreateInstallTargetGenerator( target, archiveArgs, true, helper.CaptureContext(), true, false, configurations); } } break; case cm::TargetType::INTERFACE_LIBRARY: // Nothing to do. An INTERFACE_LIBRARY can be installed, but the // only effect of that is to make it exportable. It installs no // other files itself. default: // This should never happen due to the above type check. // Ignore the case. break; } // These well-known sets of files are installed *automatically* for // FRAMEWORK SHARED library targets on the Mac as part of installing the // FRAMEWORK. For other target types or on other platforms, they are not // installed automatically and so we need to create install files // generators for them. bool createInstallGeneratorsForTargetFileSets = runtimeOnly == RuntimeOnly::No; if (target.IsFrameworkOnApple()) { createInstallGeneratorsForTargetFileSets = false; } if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) { cmValue files = target.GetProperty("PRIVATE_HEADER"); if (cmNonempty(files)) { cmList relFiles{ *files }; std::vector absFiles; if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) { error = helper.Status.GetError(); return false; } // Create the files install generator. if (!artifactsSpecified || !privateHeaderArgs.GetDestination().empty()) { privateHeaderGenerator = CreateInstallFilesGenerator( helper.Makefile, absFiles, privateHeaderArgs, false, helper.GetIncludeDestination(&privateHeaderArgs), configurations); } else { helper.Makefile->IssueDiagnostic( cmDiagnostics::CMD_AUTHOR, cmStrCat("Target ", target.GetName(), " has PRIVATE_HEADER files" " but no PRIVATE_HEADER DESTINATION.")); } } files = target.GetProperty("PUBLIC_HEADER"); if (cmNonempty(files)) { cmList relFiles{ *files }; std::vector absFiles; if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) { error = helper.Status.GetError(); return false; } // Create the files install generator. if (!artifactsSpecified || !publicHeaderArgs.GetDestination().empty()) { publicHeaderGenerator = CreateInstallFilesGenerator( helper.Makefile, absFiles, publicHeaderArgs, false, helper.GetIncludeDestination(&publicHeaderArgs), configurations); } else { helper.Makefile->IssueDiagnostic( cmDiagnostics::CMD_AUTHOR, cmStrCat("Target ", target.GetName(), " has PUBLIC_HEADER files" " but no PUBLIC_HEADER DESTINATION.")); } } files = target.GetProperty("RESOURCE"); if (cmNonempty(files)) { cmList relFiles{ *files }; std::vector absFiles; if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) { error = helper.Status.GetError(); return false; } // Create the files install generator. if (!resourceArgs.GetDestination().empty()) { resourceGenerator = CreateInstallFilesGenerator( helper.Makefile, absFiles, resourceArgs, false, resourceArgs.GetDestination(), configurations); } else if (!target.IsAppBundleOnApple()) { helper.Makefile->IssueDiagnostic( cmDiagnostics::CMD_AUTHOR, cmStrCat("Target ", target.GetName(), " has RESOURCE files but no RESOURCE DESTINATION.")); } } } if (runtimeOnly == RuntimeOnly::No && !namelinkOnly) { for (std::size_t i = 0; i < fileSetArgs.size(); i++) { fileSetGenerators.push_back(CreateInstallFileSetGenerator( helper, target, fileSetArgs[i], configurations)); flags.FileSet[i] = true; } } if (runtimeOnly == RuntimeOnly::No && !cxxModuleBmiArgs.GetDestination().empty()) { cxxModuleBmiGenerator = cm::make_unique( target.GetName(), helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs), cxxModuleBmiArgs.GetPermissions(), SelectConfigurations(cxxModuleBmiArgs, configurations), cxxModuleBmiArgs.GetComponent(), cmInstallGenerator::SelectMessageLevel(target.GetMakefile()), cxxModuleBmiArgs.GetExcludeFromAll(), cxxModuleBmiArgs.GetOptional(), helper.CaptureContext()); target.SetHaveInstallRule(true); } // Add this install rule to an export if one was specified. // Transitive runtime artifacts from RUNTIME_DEPENDENCY_TARGETS are // included; skip if this call created no runtime install generators. bool const hasRuntimeArtifact = libraryGenerator || runtimeGenerator || frameworkGenerator || bundleGenerator; if ((runtimeOnly == RuntimeOnly::No || hasRuntimeArtifact) && !addTargetExport()) { return false; } // Keep track of whether we're installing anything in each category flags.Archive = flags.Archive || archiveGenerator; flags.Library = flags.Library || libraryGenerator; flags.Namelink = flags.Namelink || namelinkGenerator; flags.Importlink = flags.Importlink || importlinkGenerator; flags.Runtime = flags.Runtime || runtimeGenerator; flags.Object = flags.Object || objectGenerator; flags.Framework = flags.Framework || frameworkGenerator; flags.Bundle = flags.Bundle || bundleGenerator; flags.PrivateHeader = flags.PrivateHeader || privateHeaderGenerator; flags.PublicHeader = flags.PublicHeader || publicHeaderGenerator; flags.Resource = flags.Resource || resourceGenerator; flags.CxxModuleBmi = flags.CxxModuleBmi || cxxModuleBmiGenerator; helper.Makefile->AddInstallGenerator(std::move(archiveGenerator)); helper.Makefile->AddInstallGenerator(std::move(libraryGenerator)); helper.Makefile->AddInstallGenerator(std::move(namelinkGenerator)); helper.Makefile->AddInstallGenerator(std::move(importlinkGenerator)); helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator)); helper.Makefile->AddInstallGenerator(std::move(objectGenerator)); helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator)); helper.Makefile->AddInstallGenerator(std::move(bundleGenerator)); helper.Makefile->AddInstallGenerator(std::move(privateHeaderGenerator)); helper.Makefile->AddInstallGenerator(std::move(publicHeaderGenerator)); helper.Makefile->AddInstallGenerator(std::move(resourceGenerator)); for (auto& gen : fileSetGenerators) { helper.Makefile->AddInstallGenerator(std::move(gen)); } helper.Makefile->AddInstallGenerator(std::move(cxxModuleBmiGenerator)); return true; } bool InstallTargetsGroupedByConfig( Helper& helper, InstallContext const& ctx, InstallCategoryFlags& flags, cmLocalGenerator& lg, std::map> const& byConfig, std::vector const& configs) { std::map hits; for (std::pair> const& e : byConfig) { for (cmTarget* t : e.second) { ++hits[t]; } } std::set common; std::size_t const n = configs.size(); for (std::pair const& h : hits) { if (h.second == n) { common.insert(h.first); } } auto installDep = [&](cmTarget& dep, cm::optional> configurations) -> bool { std::string error; if (!CreateInstallGeneratorsForTarget(helper, dep, ctx, flags, error, configurations, RuntimeOnly::Yes)) { lg.IssueMessage(MessageType::FATAL_ERROR, error); return false; } return true; }; for (cmTarget* dep : common) { if (!installDep(*dep, cm::nullopt)) { return false; } } std::map> configSpecific; for (std::string const& config : configs) { auto it = byConfig.find(config); if (it == byConfig.end()) { continue; } for (cmTarget* dep : it->second) { if (common.find(dep) == common.end()) { configSpecific[dep].push_back(config); } } } return std::all_of( configSpecific.begin(), configSpecific.end(), [&](std::pair> const& e) { return installDep(*e.first, e.second); }); } void CheckAbsoluteDestination(Helper& helper, std::string const& destination) { // Check for an absolute destination. if (cmGeneratorExpression::Find(destination) == std::string::npos && cmSystemTools::FileIsFullPath(destination)) { helper.Makefile->IssueDiagnostic( cmDiagnostics::CMD_INSTALL_ABSOLUTE_DESTINATION, cmStrCat("INSTALL command given absolute DESTINATION path:\n ", destination)); } } bool HandleScriptMode(std::vector const& args, cmExecutionStatus& status) { struct Arguments : ArgumentParser::ParseResult { struct Script { std::string Value; bool IsCode; }; ArgumentParser::Continue AddScript(cm::string_view keyword, cm::string_view value) { this->Scripts.push_back({ std::string(value), keyword == "CODE"_s }); return ArgumentParser::Continue::No; } std::vector