resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmInstallCommand.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmInstallCommand.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cstddef>
8 #include <iterator>
9 #include <map>
10 #include <set>
11 #include <sstream>
12 #include <utility>
13
14 #include <cm/memory>
15 #include <cm/optional>
16 #include <cm/string_view>
17 #include <cmext/string_view>
18
19 #include "cmsys/Glob.hxx"
20
21 #include "cmArgumentParser.h"
22 #include "cmArgumentParserTypes.h"
23 #include "cmExecutionStatus.h"
24 #include "cmExperimental.h"
25 #include "cmExportSet.h"
26 #include "cmFileSet.h"
27 #include "cmGeneratorExpression.h"
28 #include "cmGlobalGenerator.h"
29 #include "cmInstallCommandArguments.h"
30 #include "cmInstallCxxModuleBmiGenerator.h"
31 #include "cmInstallDirectoryGenerator.h"
32 #include "cmInstallExportGenerator.h"
33 #include "cmInstallFileSetGenerator.h"
34 #include "cmInstallFilesGenerator.h"
35 #include "cmInstallGenerator.h"
36 #include "cmInstallGetRuntimeDependenciesGenerator.h"
37 #include "cmInstallImportedRuntimeArtifactsGenerator.h"
38 #include "cmInstallRuntimeDependencySet.h"
39 #include "cmInstallRuntimeDependencySetGenerator.h"
40 #include "cmInstallScriptGenerator.h"
41 #include "cmInstallTargetGenerator.h"
42 #include "cmMakefile.h"
43 #include "cmMessageType.h"
44 #include "cmPolicies.h"
45 #include "cmRange.h"
46 #include "cmRuntimeDependencyArchive.h"
47 #include "cmStateTypes.h"
48 #include "cmStringAlgorithms.h"
49 #include "cmSubcommandTable.h"
50 #include "cmSystemTools.h"
51 #include "cmTarget.h"
52 #include "cmTargetExport.h"
53 #include "cmValue.h"
54
55 class cmListFileBacktrace;
56
57 namespace {
58
59 struct RuntimeDependenciesArgs
60 {
61   ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories;
62   ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes;
63   ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes;
64   ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes;
65   ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes;
66   ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles;
67   ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles;
68 };
69
70 auto const RuntimeDependenciesArgHelper =
71   cmArgumentParser<RuntimeDependenciesArgs>{}
72     .Bind("DIRECTORIES"_s, &RuntimeDependenciesArgs::Directories)
73     .Bind("PRE_INCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreIncludeRegexes)
74     .Bind("PRE_EXCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreExcludeRegexes)
75     .Bind("POST_INCLUDE_REGEXES"_s,
76           &RuntimeDependenciesArgs::PostIncludeRegexes)
77     .Bind("POST_EXCLUDE_REGEXES"_s,
78           &RuntimeDependenciesArgs::PostExcludeRegexes)
79     .Bind("POST_INCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostIncludeFiles)
80     .Bind("POST_EXCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostExcludeFiles);
81
82 class Helper
83 {
84 public:
85   Helper(cmExecutionStatus& status)
86     : Status(status)
87     , Makefile(&status.GetMakefile())
88   {
89     this->DefaultComponentName = this->Makefile->GetSafeDefinition(
90       "CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
91     if (this->DefaultComponentName.empty()) {
92       this->DefaultComponentName = "Unspecified";
93     }
94   }
95
96   void SetError(std::string const& err) { this->Status.SetError(err); }
97
98   bool MakeFilesFullPath(const char* modeName,
99                          const std::vector<std::string>& relFiles,
100                          std::vector<std::string>& absFiles);
101   bool MakeFilesFullPath(const char* modeName, const std::string& basePath,
102                          const std::vector<std::string>& relFiles,
103                          std::vector<std::string>& absFiles);
104   bool CheckCMP0006(bool& failure) const;
105
106   std::string GetDestination(const cmInstallCommandArguments* args,
107                              const std::string& varName,
108                              const std::string& guess) const;
109   std::string GetRuntimeDestination(
110     const cmInstallCommandArguments* args) const;
111   std::string GetSbinDestination(const cmInstallCommandArguments* args) const;
112   std::string GetArchiveDestination(
113     const cmInstallCommandArguments* args) const;
114   std::string GetLibraryDestination(
115     const cmInstallCommandArguments* args) const;
116   std::string GetCxxModulesBmiDestination(
117     const cmInstallCommandArguments* args) const;
118   std::string GetIncludeDestination(
119     const cmInstallCommandArguments* args) const;
120   std::string GetSysconfDestination(
121     const cmInstallCommandArguments* args) const;
122   std::string GetSharedStateDestination(
123     const cmInstallCommandArguments* args) const;
124   std::string GetLocalStateDestination(
125     const cmInstallCommandArguments* args) const;
126   std::string GetRunStateDestination(
127     const cmInstallCommandArguments* args) const;
128   std::string GetDataRootDestination(
129     const cmInstallCommandArguments* args) const;
130   std::string GetDataDestination(const cmInstallCommandArguments* args) const;
131   std::string GetInfoDestination(const cmInstallCommandArguments* args) const;
132   std::string GetLocaleDestination(
133     const cmInstallCommandArguments* args) const;
134   std::string GetManDestination(const cmInstallCommandArguments* args) const;
135   std::string GetDocDestination(const cmInstallCommandArguments* args) const;
136   std::string GetDestinationForType(const cmInstallCommandArguments* args,
137                                     const std::string& type) const;
138
139   cmExecutionStatus& Status;
140   cmMakefile* Makefile;
141   std::string DefaultComponentName;
142 };
143
144 std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
145   cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
146   cmListFileBacktrace const& backtrace, const std::string& destination,
147   bool forceOpt = false, bool namelink = false)
148 {
149   cmInstallGenerator::MessageLevel message =
150     cmInstallGenerator::SelectMessageLevel(target.GetMakefile());
151   target.SetHaveInstallRule(true);
152   const std::string& component =
153     namelink ? args.GetNamelinkComponent() : args.GetComponent();
154   auto g = cm::make_unique<cmInstallTargetGenerator>(
155     target.GetName(), destination, impLib, args.GetPermissions(),
156     args.GetConfigurations(), component, message, args.GetExcludeFromAll(),
157     args.GetOptional() || forceOpt, backtrace);
158   target.AddInstallGenerator(g.get());
159   return g;
160 }
161
162 std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
163   cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
164   cmListFileBacktrace const& backtrace, bool forceOpt = false,
165   bool namelink = false)
166 {
167   return CreateInstallTargetGenerator(target, args, impLib, backtrace,
168                                       args.GetDestination(), forceOpt,
169                                       namelink);
170 }
171
172 std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
173   cmMakefile* mf, const std::vector<std::string>& absFiles,
174   const cmInstallCommandArguments& args, bool programs,
175   const std::string& destination)
176 {
177   cmInstallGenerator::MessageLevel message =
178     cmInstallGenerator::SelectMessageLevel(mf);
179   return cm::make_unique<cmInstallFilesGenerator>(
180     absFiles, destination, programs, args.GetPermissions(),
181     args.GetConfigurations(), args.GetComponent(), message,
182     args.GetExcludeFromAll(), args.GetRename(), args.GetOptional(),
183     mf->GetBacktrace());
184 }
185
186 std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
187   cmMakefile* mf, const std::vector<std::string>& absFiles,
188   const cmInstallCommandArguments& args, bool programs)
189 {
190   return CreateInstallFilesGenerator(mf, absFiles, args, programs,
191                                      args.GetDestination());
192 }
193
194 std::unique_ptr<cmInstallFileSetGenerator> CreateInstallFileSetGenerator(
195   Helper& helper, cmTarget& target, cmFileSet* fileSet,
196   const std::string& destination, const cmInstallCommandArguments& args)
197 {
198   cmInstallGenerator::MessageLevel message =
199     cmInstallGenerator::SelectMessageLevel(helper.Makefile);
200   return cm::make_unique<cmInstallFileSetGenerator>(
201     target.GetName(), fileSet, destination, args.GetPermissions(),
202     args.GetConfigurations(), args.GetComponent(), message,
203     args.GetExcludeFromAll(), args.GetOptional(),
204     helper.Makefile->GetBacktrace());
205 }
206
207 void AddInstallRuntimeDependenciesGenerator(
208   Helper& helper, cmInstallRuntimeDependencySet* runtimeDependencySet,
209   const cmInstallCommandArguments& runtimeArgs,
210   const cmInstallCommandArguments& libraryArgs,
211   const cmInstallCommandArguments& frameworkArgs,
212   RuntimeDependenciesArgs runtimeDependenciesArgs, bool& installsRuntime,
213   bool& installsLibrary, bool& installsFramework)
214 {
215   bool dllPlatform =
216     !helper.Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
217   bool apple =
218     helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") == "Darwin";
219   auto const& runtimeDependenciesArgsRef =
220     dllPlatform ? runtimeArgs : libraryArgs;
221   std::vector<std::string> configurations =
222     runtimeDependenciesArgsRef.GetConfigurations();
223   if (apple) {
224     std::copy(frameworkArgs.GetConfigurations().begin(),
225               frameworkArgs.GetConfigurations().end(),
226               std::back_inserter(configurations));
227   }
228
229   // Create file(GET_RUNTIME_DEPENDENCIES) generator.
230   auto getRuntimeDependenciesGenerator =
231     cm::make_unique<cmInstallGetRuntimeDependenciesGenerator>(
232       runtimeDependencySet, std::move(runtimeDependenciesArgs.Directories),
233       std::move(runtimeDependenciesArgs.PreIncludeRegexes),
234       std::move(runtimeDependenciesArgs.PreExcludeRegexes),
235       std::move(runtimeDependenciesArgs.PostIncludeRegexes),
236       std::move(runtimeDependenciesArgs.PostExcludeRegexes),
237       std::move(runtimeDependenciesArgs.PostIncludeFiles),
238       std::move(runtimeDependenciesArgs.PostExcludeFiles),
239       runtimeDependenciesArgsRef.GetComponent(),
240       apple ? frameworkArgs.GetComponent() : "", true, "_CMAKE_DEPS",
241       "_CMAKE_RPATH", configurations,
242       cmInstallGenerator::SelectMessageLevel(helper.Makefile),
243       runtimeDependenciesArgsRef.GetExcludeFromAll() &&
244         (apple ? frameworkArgs.GetExcludeFromAll() : true),
245       helper.Makefile->GetBacktrace());
246   helper.Makefile->AddInstallGenerator(
247     std::move(getRuntimeDependenciesGenerator));
248
249   // Create the library dependencies generator.
250   auto libraryRuntimeDependenciesGenerator =
251     cm::make_unique<cmInstallRuntimeDependencySetGenerator>(
252       cmInstallRuntimeDependencySetGenerator::DependencyType::Library,
253       runtimeDependencySet, std::vector<std::string>{}, true, std::string{},
254       true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP",
255       dllPlatform ? helper.GetRuntimeDestination(&runtimeArgs)
256                   : helper.GetLibraryDestination(&libraryArgs),
257       runtimeDependenciesArgsRef.GetConfigurations(),
258       runtimeDependenciesArgsRef.GetComponent(),
259       runtimeDependenciesArgsRef.GetPermissions(),
260       cmInstallGenerator::SelectMessageLevel(helper.Makefile),
261       runtimeDependenciesArgsRef.GetExcludeFromAll(),
262       helper.Makefile->GetBacktrace());
263   helper.Makefile->AddInstallGenerator(
264     std::move(libraryRuntimeDependenciesGenerator));
265   if (dllPlatform) {
266     installsRuntime = true;
267   } else {
268     installsLibrary = true;
269   }
270
271   if (apple) {
272     // Create the framework dependencies generator.
273     auto frameworkRuntimeDependenciesGenerator =
274       cm::make_unique<cmInstallRuntimeDependencySetGenerator>(
275         cmInstallRuntimeDependencySetGenerator::DependencyType::Framework,
276         runtimeDependencySet, std::vector<std::string>{}, true, std::string{},
277         true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP",
278         frameworkArgs.GetDestination(), frameworkArgs.GetConfigurations(),
279         frameworkArgs.GetComponent(), frameworkArgs.GetPermissions(),
280         cmInstallGenerator::SelectMessageLevel(helper.Makefile),
281         frameworkArgs.GetExcludeFromAll(), helper.Makefile->GetBacktrace());
282     helper.Makefile->AddInstallGenerator(
283       std::move(frameworkRuntimeDependenciesGenerator));
284     installsFramework = true;
285   }
286 }
287
288 std::set<std::string> const allowedTypes{
289   "BIN",         "SBIN",       "LIB",      "INCLUDE", "SYSCONF",
290   "SHAREDSTATE", "LOCALSTATE", "RUNSTATE", "DATA",    "INFO",
291   "LOCALE",      "MAN",        "DOC",
292 };
293
294 template <typename T>
295 bool AddBundleExecutable(Helper& helper,
296                          cmInstallRuntimeDependencySet* runtimeDependencySet,
297                          T&& bundleExecutable)
298 {
299   if (!runtimeDependencySet->AddBundleExecutable(bundleExecutable)) {
300     helper.SetError(
301       "A runtime dependency set may only have one bundle executable.");
302     return false;
303   }
304   return true;
305 }
306
307 bool HandleScriptMode(std::vector<std::string> const& args,
308                       cmExecutionStatus& status)
309 {
310   Helper helper(status);
311
312   std::string component = helper.DefaultComponentName;
313   int componentCount = 0;
314   bool doing_script = false;
315   bool doing_code = false;
316   bool exclude_from_all = false;
317   bool all_components = false;
318
319   // Scan the args once for COMPONENT. Only allow one.
320   //
321   for (size_t i = 0; i < args.size(); ++i) {
322     if (args[i] == "COMPONENT" && i + 1 < args.size()) {
323       ++componentCount;
324       ++i;
325       component = args[i];
326     }
327     if (args[i] == "EXCLUDE_FROM_ALL") {
328       exclude_from_all = true;
329     } else if (args[i] == "ALL_COMPONENTS") {
330       all_components = true;
331     }
332   }
333
334   if (componentCount > 1) {
335     status.SetError("given more than one COMPONENT for the SCRIPT or CODE "
336                     "signature of the INSTALL command. "
337                     "Use multiple INSTALL commands with one COMPONENT each.");
338     return false;
339   }
340
341   if (all_components && componentCount == 1) {
342     status.SetError("ALL_COMPONENTS and COMPONENT are mutually exclusive");
343     return false;
344   }
345
346   // Scan the args again, this time adding install generators each time we
347   // encounter a SCRIPT or CODE arg:
348   //
349   for (std::string const& arg : args) {
350     if (arg == "SCRIPT") {
351       doing_script = true;
352       doing_code = false;
353     } else if (arg == "CODE") {
354       doing_script = false;
355       doing_code = true;
356     } else if (arg == "COMPONENT") {
357       doing_script = false;
358       doing_code = false;
359     } else if (doing_script) {
360       doing_script = false;
361       std::string script = arg;
362       if (!cmSystemTools::FileIsFullPath(script)) {
363         script =
364           cmStrCat(helper.Makefile->GetCurrentSourceDirectory(), '/', arg);
365       }
366       if (cmSystemTools::FileIsDirectory(script)) {
367         status.SetError("given a directory as value of SCRIPT argument.");
368         return false;
369       }
370       helper.Makefile->AddInstallGenerator(
371         cm::make_unique<cmInstallScriptGenerator>(
372           script, false, component, exclude_from_all, all_components,
373           helper.Makefile->GetBacktrace()));
374     } else if (doing_code) {
375       doing_code = false;
376       std::string const& code = arg;
377       helper.Makefile->AddInstallGenerator(
378         cm::make_unique<cmInstallScriptGenerator>(
379           code, true, component, exclude_from_all, all_components,
380           helper.Makefile->GetBacktrace()));
381     }
382   }
383
384   if (doing_script) {
385     status.SetError("given no value for SCRIPT argument.");
386     return false;
387   }
388   if (doing_code) {
389     status.SetError("given no value for CODE argument.");
390     return false;
391   }
392
393   // Tell the global generator about any installation component names
394   // specified.
395   helper.Makefile->GetGlobalGenerator()->AddInstallComponent(component);
396
397   return true;
398 }
399
400 bool HandleTargetsMode(std::vector<std::string> const& args,
401                        cmExecutionStatus& status)
402 {
403   Helper helper(status);
404
405   // This is the TARGETS mode.
406   std::vector<cmTarget*> targets;
407
408   struct ArgVectors
409   {
410     ArgumentParser::MaybeEmpty<std::vector<std::string>> Archive;
411     ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
412     ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
413     ArgumentParser::MaybeEmpty<std::vector<std::string>> Object;
414     ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
415     ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle;
416     ArgumentParser::MaybeEmpty<std::vector<std::string>> Includes;
417     ArgumentParser::MaybeEmpty<std::vector<std::string>> PrivateHeader;
418     ArgumentParser::MaybeEmpty<std::vector<std::string>> PublicHeader;
419     ArgumentParser::MaybeEmpty<std::vector<std::string>> Resource;
420     ArgumentParser::MaybeEmpty<std::vector<std::string>> CxxModulesBmi;
421     std::vector<std::vector<std::string>> FileSets;
422   };
423
424   static auto const argHelper =
425     cmArgumentParser<ArgVectors>{}
426       .Bind("ARCHIVE"_s, &ArgVectors::Archive)
427       .Bind("LIBRARY"_s, &ArgVectors::Library)
428       .Bind("RUNTIME"_s, &ArgVectors::Runtime)
429       .Bind("OBJECTS"_s, &ArgVectors::Object)
430       .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
431       .Bind("BUNDLE"_s, &ArgVectors::Bundle)
432       .Bind("INCLUDES"_s, &ArgVectors::Includes)
433       .Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader)
434       .Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader)
435       .Bind("RESOURCE"_s, &ArgVectors::Resource)
436       .Bind("FILE_SET"_s, &ArgVectors::FileSets)
437       .Bind("CXX_MODULES_BMI"_s, &ArgVectors::CxxModulesBmi);
438
439   std::vector<std::string> genericArgVector;
440   ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
441
442   // now parse the generic args (i.e. the ones not specialized on LIBRARY/
443   // ARCHIVE, RUNTIME etc. (see above)
444   // These generic args also contain the targets and the export stuff
445   ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList;
446   std::string exports;
447   cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
448     runtimeDependenciesArgVector;
449   std::string runtimeDependencySetArg;
450   std::vector<std::string> unknownArgs;
451   cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
452   genericArgs.Bind("TARGETS"_s, targetList);
453   genericArgs.Bind("EXPORT"_s, exports);
454   genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector);
455   genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
456   genericArgs.Parse(genericArgVector, &unknownArgs);
457   bool success = genericArgs.Finalize();
458
459   RuntimeDependenciesArgs runtimeDependenciesArgs =
460     runtimeDependenciesArgVector
461     ? RuntimeDependenciesArgHelper.Parse(*runtimeDependenciesArgVector,
462                                          &unknownArgs)
463     : RuntimeDependenciesArgs();
464
465   cmInstallCommandArguments archiveArgs(helper.DefaultComponentName);
466   cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
467   cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
468   cmInstallCommandArguments objectArgs(helper.DefaultComponentName);
469   cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
470   cmInstallCommandArguments bundleArgs(helper.DefaultComponentName);
471   cmInstallCommandArguments privateHeaderArgs(helper.DefaultComponentName);
472   cmInstallCommandArguments publicHeaderArgs(helper.DefaultComponentName);
473   cmInstallCommandArguments resourceArgs(helper.DefaultComponentName);
474   cmInstallCommandIncludesArgument includesArgs;
475   std::vector<cmInstallCommandFileSetArguments> fileSetArgs(
476     argVectors.FileSets.size(), { helper.DefaultComponentName });
477   cmInstallCommandArguments cxxModuleBmiArgs(helper.DefaultComponentName);
478
479   // now parse the args for specific parts of the target (e.g. LIBRARY,
480   // RUNTIME, ARCHIVE etc.
481   archiveArgs.Parse(argVectors.Archive, &unknownArgs);
482   libraryArgs.Parse(argVectors.Library, &unknownArgs);
483   runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
484   objectArgs.Parse(argVectors.Object, &unknownArgs);
485   frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
486   bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
487   privateHeaderArgs.Parse(argVectors.PrivateHeader, &unknownArgs);
488   publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs);
489   resourceArgs.Parse(argVectors.Resource, &unknownArgs);
490   includesArgs.Parse(&argVectors.Includes, &unknownArgs);
491   for (std::size_t i = 0; i < argVectors.FileSets.size(); i++) {
492     // We have to create a separate object for the parsing because
493     // cmArgumentParser<void>::Bind() binds to a specific address, but the
494     // objects in the vector can move around. So we parse in an object with a
495     // fixed address and then copy the data into the vector.
496     cmInstallCommandFileSetArguments fileSetArg(helper.DefaultComponentName);
497     fileSetArg.Parse(argVectors.FileSets[i], &unknownArgs);
498     fileSetArgs[i] = std::move(fileSetArg);
499   }
500
501   bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
502     *helper.Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
503   if (!supportCxx20FileSetTypes) {
504     std::copy(argVectors.CxxModulesBmi.begin(), argVectors.CxxModulesBmi.end(),
505               std::back_inserter(unknownArgs));
506   } else {
507     cxxModuleBmiArgs.Parse(argVectors.CxxModulesBmi, &unknownArgs);
508   }
509
510   if (!unknownArgs.empty()) {
511     // Unknown argument.
512     status.SetError(
513       cmStrCat("TARGETS given unknown argument \"", unknownArgs[0], "\"."));
514     return false;
515   }
516
517   // apply generic args
518   archiveArgs.SetGenericArguments(&genericArgs);
519   libraryArgs.SetGenericArguments(&genericArgs);
520   runtimeArgs.SetGenericArguments(&genericArgs);
521   objectArgs.SetGenericArguments(&genericArgs);
522   frameworkArgs.SetGenericArguments(&genericArgs);
523   bundleArgs.SetGenericArguments(&genericArgs);
524   privateHeaderArgs.SetGenericArguments(&genericArgs);
525   publicHeaderArgs.SetGenericArguments(&genericArgs);
526   resourceArgs.SetGenericArguments(&genericArgs);
527   for (auto& fileSetArg : fileSetArgs) {
528     fileSetArg.SetGenericArguments(&genericArgs);
529   }
530   cxxModuleBmiArgs.SetGenericArguments(&genericArgs);
531
532   success = success && archiveArgs.Finalize();
533   success = success && libraryArgs.Finalize();
534   success = success && runtimeArgs.Finalize();
535   success = success && objectArgs.Finalize();
536   success = success && frameworkArgs.Finalize();
537   success = success && bundleArgs.Finalize();
538   success = success && privateHeaderArgs.Finalize();
539   success = success && publicHeaderArgs.Finalize();
540   success = success && resourceArgs.Finalize();
541   for (auto& fileSetArg : fileSetArgs) {
542     success = success && fileSetArg.Finalize();
543   }
544   if (supportCxx20FileSetTypes) {
545     success = success && cxxModuleBmiArgs.Finalize();
546   }
547
548   if (!success) {
549     return false;
550   }
551
552   // Enforce argument rules too complex to specify for the
553   // general-purpose parser.
554   if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() ||
555       objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() ||
556       bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() ||
557       publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly() ||
558       std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
559                   [](const cmInstallCommandFileSetArguments& fileSetArg)
560                     -> bool { return fileSetArg.GetNamelinkOnly(); }) ||
561       cxxModuleBmiArgs.GetNamelinkOnly()) {
562     status.SetError(
563       "TARGETS given NAMELINK_ONLY option not in LIBRARY group.  "
564       "The NAMELINK_ONLY option may be specified only following LIBRARY.");
565     return false;
566   }
567   if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() ||
568       objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() ||
569       bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() ||
570       publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip() ||
571       std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
572                   [](const cmInstallCommandFileSetArguments& fileSetArg)
573                     -> bool { return fileSetArg.GetNamelinkSkip(); }) ||
574       cxxModuleBmiArgs.GetNamelinkSkip()) {
575     status.SetError(
576       "TARGETS given NAMELINK_SKIP option not in LIBRARY group.  "
577       "The NAMELINK_SKIP option may be specified only following LIBRARY.");
578     return false;
579   }
580   if (archiveArgs.HasNamelinkComponent() ||
581       runtimeArgs.HasNamelinkComponent() ||
582       objectArgs.HasNamelinkComponent() ||
583       frameworkArgs.HasNamelinkComponent() ||
584       bundleArgs.HasNamelinkComponent() ||
585       privateHeaderArgs.HasNamelinkComponent() ||
586       publicHeaderArgs.HasNamelinkComponent() ||
587       resourceArgs.HasNamelinkComponent() ||
588       std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
589                   [](const cmInstallCommandFileSetArguments& fileSetArg)
590                     -> bool { return fileSetArg.HasNamelinkComponent(); }) ||
591       cxxModuleBmiArgs.HasNamelinkComponent()) {
592     status.SetError(
593       "TARGETS given NAMELINK_COMPONENT option not in LIBRARY group.  "
594       "The NAMELINK_COMPONENT option may be specified only following "
595       "LIBRARY.");
596     return false;
597   }
598   if (libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip()) {
599     status.SetError("TARGETS given NAMELINK_ONLY and NAMELINK_SKIP.  "
600                     "At most one of these two options may be specified.");
601     return false;
602   }
603   if (!genericArgs.GetType().empty() || !archiveArgs.GetType().empty() ||
604       !libraryArgs.GetType().empty() || !runtimeArgs.GetType().empty() ||
605       !objectArgs.GetType().empty() || !frameworkArgs.GetType().empty() ||
606       !bundleArgs.GetType().empty() || !privateHeaderArgs.GetType().empty() ||
607       !publicHeaderArgs.GetType().empty() || !resourceArgs.GetType().empty() ||
608       std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
609                   [](const cmInstallCommandFileSetArguments& fileSetArg)
610                     -> bool { return !fileSetArg.GetType().empty(); }) ||
611       !cxxModuleBmiArgs.GetType().empty()) {
612     status.SetError(
613       "TARGETS given TYPE option. The TYPE option may only be specified in "
614       " install(FILES) and install(DIRECTORIES).");
615     return false;
616   }
617   if (std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
618                   [](const cmInstallCommandFileSetArguments& fileSetArg)
619                     -> bool { return fileSetArg.GetFileSet().empty(); })) {
620     status.SetError("TARGETS given FILE_SET option without file set name.");
621     return false;
622   }
623
624   cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
625   if (runtimeDependenciesArgVector) {
626     if (!runtimeDependencySetArg.empty()) {
627       status.SetError("TARGETS cannot have both RUNTIME_DEPENDENCIES and "
628                       "RUNTIME_DEPENDENCY_SET.");
629       return false;
630     }
631     auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
632     if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
633           system)) {
634       status.SetError(
635         cmStrCat("TARGETS RUNTIME_DEPENDENCIES is not supported on system \"",
636                  system, '"'));
637       return false;
638     }
639     if (helper.Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
640       status.SetError("TARGETS RUNTIME_DEPENDENCIES is not supported "
641                       "when cross-compiling.");
642       return false;
643     }
644     if (helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") ==
645           "Darwin" &&
646         frameworkArgs.GetDestination().empty()) {
647       status.SetError(
648         "TARGETS RUNTIME_DEPENDENCIES given no FRAMEWORK DESTINATION");
649       return false;
650     }
651     runtimeDependencySet = helper.Makefile->GetGlobalGenerator()
652                              ->CreateAnonymousRuntimeDependencySet();
653   } else if (!runtimeDependencySetArg.empty()) {
654     auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
655     if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
656           system)) {
657       status.SetError(cmStrCat(
658         "TARGETS RUNTIME_DEPENDENCY_SET is not supported on system \"", system,
659         '"'));
660       return false;
661     }
662     runtimeDependencySet =
663       helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
664         runtimeDependencySetArg);
665   }
666
667   // Select the mode for installing symlinks to versioned shared libraries.
668   cmInstallTargetGenerator::NamelinkModeType namelinkMode =
669     cmInstallTargetGenerator::NamelinkModeNone;
670   if (libraryArgs.GetNamelinkOnly()) {
671     namelinkMode = cmInstallTargetGenerator::NamelinkModeOnly;
672   } else if (libraryArgs.GetNamelinkSkip()) {
673     namelinkMode = cmInstallTargetGenerator::NamelinkModeSkip;
674   }
675
676   // Check if there is something to do.
677   if (targetList.empty()) {
678     return true;
679   }
680
681   for (std::string const& tgt : targetList) {
682
683     if (helper.Makefile->IsAlias(tgt)) {
684       status.SetError(
685         cmStrCat("TARGETS given target \"", tgt, "\" which is an alias."));
686       return false;
687     }
688     // Lookup this target in the current directory.
689     cmTarget* target = helper.Makefile->FindLocalNonAliasTarget(tgt);
690     if (!target) {
691       // If no local target has been found, find it in the global scope.
692       cmTarget* const global_target =
693         helper.Makefile->GetGlobalGenerator()->FindTarget(tgt, true);
694       if (global_target && !global_target->IsImported()) {
695         target = global_target;
696       }
697     }
698     if (target) {
699       // Found the target.  Check its type.
700       if (target->GetType() != cmStateEnums::EXECUTABLE &&
701           target->GetType() != cmStateEnums::STATIC_LIBRARY &&
702           target->GetType() != cmStateEnums::SHARED_LIBRARY &&
703           target->GetType() != cmStateEnums::MODULE_LIBRARY &&
704           target->GetType() != cmStateEnums::OBJECT_LIBRARY &&
705           target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
706         status.SetError(
707           cmStrCat("TARGETS given target \"", tgt,
708                    "\" which is not an executable, library, or module."));
709         return false;
710       }
711       // Store the target in the list to be installed.
712       targets.push_back(target);
713     } else {
714       // Did not find the target.
715       status.SetError(
716         cmStrCat("TARGETS given target \"", tgt, "\" which does not exist."));
717       return false;
718     }
719   }
720
721   // Keep track of whether we will be performing an installation of
722   // any files of the given type.
723   bool installsArchive = false;
724   bool installsLibrary = false;
725   bool installsNamelink = false;
726   bool installsRuntime = false;
727   bool installsObject = false;
728   bool installsFramework = false;
729   bool installsBundle = false;
730   bool installsPrivateHeader = false;
731   bool installsPublicHeader = false;
732   bool installsResource = false;
733   std::vector<bool> installsFileSet(fileSetArgs.size(), false);
734   bool installsCxxModuleBmi = false;
735
736   // Generate install script code to install the given targets.
737   for (cmTarget* ti : targets) {
738     // Handle each target type.
739     cmTarget& target = *ti;
740     std::unique_ptr<cmInstallTargetGenerator> archiveGenerator;
741     std::unique_ptr<cmInstallTargetGenerator> libraryGenerator;
742     std::unique_ptr<cmInstallTargetGenerator> namelinkGenerator;
743     std::unique_ptr<cmInstallTargetGenerator> runtimeGenerator;
744     std::unique_ptr<cmInstallTargetGenerator> objectGenerator;
745     std::unique_ptr<cmInstallTargetGenerator> frameworkGenerator;
746     std::unique_ptr<cmInstallTargetGenerator> bundleGenerator;
747     std::unique_ptr<cmInstallFilesGenerator> privateHeaderGenerator;
748     std::unique_ptr<cmInstallFilesGenerator> publicHeaderGenerator;
749     std::unique_ptr<cmInstallFilesGenerator> resourceGenerator;
750     std::vector<std::unique_ptr<cmInstallFileSetGenerator>> fileSetGenerators;
751     std::unique_ptr<cmInstallCxxModuleBmiGenerator> cxxModuleBmiGenerator;
752
753     // Avoid selecting default destinations for PUBLIC_HEADER and
754     // PRIVATE_HEADER if any artifacts are specified.
755     bool artifactsSpecified = false;
756
757     // Track whether this is a namelink-only rule.
758     bool namelinkOnly = false;
759
760     auto addTargetExport = [&]() -> bool {
761       // Add this install rule to an export if one was specified.
762       if (!exports.empty()) {
763         auto interfaceFileSets = target.GetAllInterfaceFileSets();
764         if (std::any_of(
765               interfaceFileSets.begin(), interfaceFileSets.end(),
766               [=](const std::string& name) -> bool {
767                 return !std::any_of(
768                   fileSetArgs.begin(), fileSetArgs.end(),
769                   [=](const cmInstallCommandFileSetArguments& fileSetArg)
770                     -> bool { return fileSetArg.GetFileSet() == name; });
771               })) {
772           status.SetError(cmStrCat("TARGETS target ", target.GetName(),
773                                    " is exported but not all of its interface "
774                                    "file sets are installed"));
775           return false;
776         }
777
778         auto te = cm::make_unique<cmTargetExport>();
779         te->TargetName = target.GetName();
780         te->ArchiveGenerator = archiveGenerator.get();
781         te->BundleGenerator = bundleGenerator.get();
782         te->FrameworkGenerator = frameworkGenerator.get();
783         te->HeaderGenerator = publicHeaderGenerator.get();
784         te->LibraryGenerator = libraryGenerator.get();
785         te->RuntimeGenerator = runtimeGenerator.get();
786         te->ObjectsGenerator = objectGenerator.get();
787         for (auto const& gen : fileSetGenerators) {
788           te->FileSetGenerators[gen->GetFileSet()] = gen.get();
789         }
790         te->CxxModuleBmiGenerator = cxxModuleBmiGenerator.get();
791         target.AddInstallIncludeDirectories(
792           *te, cmMakeRange(includesArgs.GetIncludeDirs()));
793         te->NamelinkOnly = namelinkOnly;
794         helper.Makefile->GetGlobalGenerator()
795           ->GetExportSets()[exports]
796           .AddTargetExport(std::move(te));
797       }
798       return true;
799     };
800
801     switch (target.GetType()) {
802       case cmStateEnums::SHARED_LIBRARY: {
803         // Shared libraries are handled differently on DLL and non-DLL
804         // platforms.  All windows platforms are DLL platforms including
805         // cygwin.  Currently no other platform is a DLL platform.
806         if (target.IsDLLPlatform()) {
807           // When in namelink only mode skip all libraries on Windows.
808           if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
809             namelinkOnly = true;
810             if (!addTargetExport()) {
811               return false;
812             }
813             continue;
814           }
815
816           // This is a DLL platform.
817           if (!archiveArgs.GetDestination().empty()) {
818             // The import library uses the ARCHIVE properties.
819             archiveGenerator = CreateInstallTargetGenerator(
820               target, archiveArgs, true, helper.Makefile->GetBacktrace());
821             artifactsSpecified = true;
822           }
823           if (!runtimeArgs.GetDestination().empty()) {
824             // The DLL uses the RUNTIME properties.
825             runtimeGenerator = CreateInstallTargetGenerator(
826               target, runtimeArgs, false, helper.Makefile->GetBacktrace());
827             artifactsSpecified = true;
828           }
829           if (!archiveGenerator && !runtimeGenerator) {
830             archiveGenerator = CreateInstallTargetGenerator(
831               target, archiveArgs, true, helper.Makefile->GetBacktrace(),
832               helper.GetArchiveDestination(nullptr));
833             runtimeGenerator = CreateInstallTargetGenerator(
834               target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
835               helper.GetRuntimeDestination(nullptr));
836           }
837           if (runtimeDependencySet && runtimeGenerator) {
838             runtimeDependencySet->AddLibrary(runtimeGenerator.get());
839           }
840         } else {
841           // This is a non-DLL platform.
842           // If it is marked with FRAMEWORK property use the FRAMEWORK set of
843           // INSTALL properties. Otherwise, use the LIBRARY properties.
844           if (target.IsFrameworkOnApple()) {
845             // When in namelink only mode skip frameworks.
846             if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
847               namelinkOnly = true;
848               if (!addTargetExport()) {
849                 return false;
850               }
851               continue;
852             }
853
854             // Use the FRAMEWORK properties.
855             if (!frameworkArgs.GetDestination().empty()) {
856               frameworkGenerator = CreateInstallTargetGenerator(
857                 target, frameworkArgs, false, helper.Makefile->GetBacktrace());
858             } else {
859               status.SetError(
860                 cmStrCat("TARGETS given no FRAMEWORK DESTINATION for shared "
861                          "library FRAMEWORK target \"",
862                          target.GetName(), "\"."));
863               return false;
864             }
865           } else {
866             // The shared library uses the LIBRARY properties.
867             if (!libraryArgs.GetDestination().empty()) {
868               artifactsSpecified = true;
869             }
870             if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) {
871               libraryGenerator = CreateInstallTargetGenerator(
872                 target, libraryArgs, false, helper.Makefile->GetBacktrace(),
873                 helper.GetLibraryDestination(&libraryArgs));
874               libraryGenerator->SetNamelinkMode(
875                 cmInstallTargetGenerator::NamelinkModeSkip);
876             }
877             if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) {
878               namelinkGenerator = CreateInstallTargetGenerator(
879                 target, libraryArgs, false, helper.Makefile->GetBacktrace(),
880                 helper.GetLibraryDestination(&libraryArgs), false, true);
881               namelinkGenerator->SetNamelinkMode(
882                 cmInstallTargetGenerator::NamelinkModeOnly);
883             }
884             namelinkOnly =
885               (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
886           }
887           if (runtimeDependencySet && libraryGenerator) {
888             runtimeDependencySet->AddLibrary(libraryGenerator.get());
889           }
890         }
891       } break;
892       case cmStateEnums::STATIC_LIBRARY: {
893         // If it is marked with FRAMEWORK property use the FRAMEWORK set of
894         // INSTALL properties. Otherwise, use the LIBRARY properties.
895         if (target.IsFrameworkOnApple()) {
896           // When in namelink only mode skip frameworks.
897           if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
898             namelinkOnly = true;
899             if (!addTargetExport()) {
900               return false;
901             }
902             continue;
903           }
904
905           // Use the FRAMEWORK properties.
906           if (!frameworkArgs.GetDestination().empty()) {
907             frameworkGenerator = CreateInstallTargetGenerator(
908               target, frameworkArgs, false, helper.Makefile->GetBacktrace());
909           } else {
910             status.SetError(
911               cmStrCat("TARGETS given no FRAMEWORK DESTINATION for static "
912                        "library FRAMEWORK target \"",
913                        target.GetName(), "\"."));
914             return false;
915           }
916         } else {
917           // Static libraries use ARCHIVE properties.
918           if (!archiveArgs.GetDestination().empty()) {
919             artifactsSpecified = true;
920           }
921           archiveGenerator = CreateInstallTargetGenerator(
922             target, archiveArgs, false, helper.Makefile->GetBacktrace(),
923             helper.GetArchiveDestination(&archiveArgs));
924         }
925       } break;
926       case cmStateEnums::MODULE_LIBRARY: {
927         // Modules use LIBRARY properties.
928         if (!libraryArgs.GetDestination().empty()) {
929           libraryGenerator = CreateInstallTargetGenerator(
930             target, libraryArgs, false, helper.Makefile->GetBacktrace());
931           libraryGenerator->SetNamelinkMode(namelinkMode);
932           namelinkOnly =
933             (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
934           if (runtimeDependencySet) {
935             runtimeDependencySet->AddModule(libraryGenerator.get());
936           }
937         } else {
938           status.SetError(
939             cmStrCat("TARGETS given no LIBRARY DESTINATION for module "
940                      "target \"",
941                      target.GetName(), "\"."));
942           return false;
943         }
944       } break;
945       case cmStateEnums::OBJECT_LIBRARY: {
946         // Objects use OBJECT properties.
947         if (!objectArgs.GetDestination().empty()) {
948           // Verify that we know where the objects are to install them.
949           std::string reason;
950           if (!target.HasKnownObjectFileLocation(&reason)) {
951             status.SetError(
952               cmStrCat("TARGETS given OBJECT library \"", target.GetName(),
953                        "\" whose objects may not be installed", reason, "."));
954             return false;
955           }
956
957           objectGenerator = CreateInstallTargetGenerator(
958             target, objectArgs, false, helper.Makefile->GetBacktrace());
959         } else {
960           // Installing an OBJECT library without a destination transforms
961           // it to an INTERFACE library.  It installs no files but can be
962           // exported.
963         }
964       } break;
965       case cmStateEnums::EXECUTABLE: {
966         if (target.IsAppBundleOnApple()) {
967           // Application bundles use the BUNDLE properties.
968           if (!bundleArgs.GetDestination().empty()) {
969             bundleGenerator = CreateInstallTargetGenerator(
970               target, bundleArgs, false, helper.Makefile->GetBacktrace());
971           } else if (!runtimeArgs.GetDestination().empty()) {
972             bool failure = false;
973             if (helper.CheckCMP0006(failure)) {
974               // For CMake 2.4 compatibility fallback to the RUNTIME
975               // properties.
976               bundleGenerator = CreateInstallTargetGenerator(
977                 target, runtimeArgs, false, helper.Makefile->GetBacktrace());
978             } else if (failure) {
979               return false;
980             }
981           }
982           if (!bundleGenerator) {
983             status.SetError(cmStrCat("TARGETS given no BUNDLE DESTINATION for "
984                                      "MACOSX_BUNDLE executable target \"",
985                                      target.GetName(), "\"."));
986             return false;
987           }
988           if (runtimeDependencySet) {
989             if (!AddBundleExecutable(helper, runtimeDependencySet,
990                                      bundleGenerator.get())) {
991               return false;
992             }
993           }
994         } else {
995           // Executables use the RUNTIME properties.
996           if (!runtimeArgs.GetDestination().empty()) {
997             artifactsSpecified = true;
998           }
999           runtimeGenerator = CreateInstallTargetGenerator(
1000             target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
1001             helper.GetRuntimeDestination(&runtimeArgs));
1002           if (runtimeDependencySet) {
1003             runtimeDependencySet->AddExecutable(runtimeGenerator.get());
1004           }
1005         }
1006
1007         // On DLL platforms an executable may also have an import
1008         // library.  Install it to the archive destination if it
1009         // exists.
1010         if ((target.IsDLLPlatform() || target.IsAIX()) &&
1011             !archiveArgs.GetDestination().empty() &&
1012             target.IsExecutableWithExports()) {
1013           // The import library uses the ARCHIVE properties.
1014           artifactsSpecified = true;
1015           archiveGenerator = CreateInstallTargetGenerator(
1016             target, archiveArgs, true, helper.Makefile->GetBacktrace(), true);
1017         }
1018       } break;
1019       case cmStateEnums::INTERFACE_LIBRARY:
1020         // Nothing to do. An INTERFACE_LIBRARY can be installed, but the
1021         // only effect of that is to make it exportable. It installs no
1022         // other files itself.
1023       default:
1024         // This should never happen due to the above type check.
1025         // Ignore the case.
1026         break;
1027     }
1028
1029     // These well-known sets of files are installed *automatically* for
1030     // FRAMEWORK SHARED library targets on the Mac as part of installing the
1031     // FRAMEWORK.  For other target types or on other platforms, they are not
1032     // installed automatically and so we need to create install files
1033     // generators for them.
1034     bool createInstallGeneratorsForTargetFileSets = true;
1035
1036     if (target.IsFrameworkOnApple()) {
1037       createInstallGeneratorsForTargetFileSets = false;
1038     }
1039
1040     if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) {
1041       cmValue files = target.GetProperty("PRIVATE_HEADER");
1042       if (cmNonempty(files)) {
1043         std::vector<std::string> relFiles = cmExpandedList(*files);
1044         std::vector<std::string> absFiles;
1045         if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) {
1046           return false;
1047         }
1048
1049         // Create the files install generator.
1050         if (!artifactsSpecified ||
1051             !privateHeaderArgs.GetDestination().empty()) {
1052           privateHeaderGenerator = CreateInstallFilesGenerator(
1053             helper.Makefile, absFiles, privateHeaderArgs, false,
1054             helper.GetIncludeDestination(&privateHeaderArgs));
1055         } else {
1056           std::ostringstream e;
1057           e << "Target " << target.GetName() << " has "
1058             << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION.";
1059           helper.Makefile->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
1060         }
1061       }
1062
1063       files = target.GetProperty("PUBLIC_HEADER");
1064       if (cmNonempty(files)) {
1065         std::vector<std::string> relFiles = cmExpandedList(*files);
1066         std::vector<std::string> absFiles;
1067         if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) {
1068           return false;
1069         }
1070
1071         // Create the files install generator.
1072         if (!artifactsSpecified ||
1073             !publicHeaderArgs.GetDestination().empty()) {
1074           publicHeaderGenerator = CreateInstallFilesGenerator(
1075             helper.Makefile, absFiles, publicHeaderArgs, false,
1076             helper.GetIncludeDestination(&publicHeaderArgs));
1077         } else {
1078           std::ostringstream e;
1079           e << "Target " << target.GetName() << " has "
1080             << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION.";
1081           helper.Makefile->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
1082         }
1083       }
1084
1085       files = target.GetProperty("RESOURCE");
1086       if (cmNonempty(files)) {
1087         std::vector<std::string> relFiles = cmExpandedList(*files);
1088         std::vector<std::string> absFiles;
1089         if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) {
1090           return false;
1091         }
1092
1093         // Create the files install generator.
1094         if (!resourceArgs.GetDestination().empty()) {
1095           resourceGenerator = CreateInstallFilesGenerator(
1096             helper.Makefile, absFiles, resourceArgs, false);
1097         } else if (!target.IsAppBundleOnApple()) {
1098           helper.Makefile->IssueMessage(
1099             MessageType::AUTHOR_WARNING,
1100             cmStrCat("Target ", target.GetName(),
1101                      " has RESOURCE files but no RESOURCE DESTINATION."));
1102         }
1103       }
1104     }
1105
1106     if (!namelinkOnly) {
1107       for (std::size_t i = 0; i < fileSetArgs.size(); i++) {
1108         if (auto* fileSet = target.GetFileSet(fileSetArgs[i].GetFileSet())) {
1109           auto interfaceFileSetEntries = cmExpandedList(target.GetSafeProperty(
1110             cmTarget::GetInterfaceFileSetsPropertyName(fileSet->GetType())));
1111           if (std::find(interfaceFileSetEntries.begin(),
1112                         interfaceFileSetEntries.end(),
1113                         fileSetArgs[i].GetFileSet()) !=
1114               interfaceFileSetEntries.end()) {
1115             std::string destination;
1116             if (fileSet->GetType() == "HEADERS"_s) {
1117               destination = helper.GetIncludeDestination(&fileSetArgs[i]);
1118             } else {
1119               destination = fileSetArgs[i].GetDestination();
1120               if (destination.empty()) {
1121                 status.SetError(cmStrCat(
1122                   "TARGETS given no FILE_SET DESTINATION for target \"",
1123                   target.GetName(), "\" file set \"", fileSet->GetName(),
1124                   "\"."));
1125                 return false;
1126               }
1127             }
1128             fileSetGenerators.push_back(CreateInstallFileSetGenerator(
1129               helper, target, fileSet, destination, fileSetArgs[i]));
1130             installsFileSet[i] = true;
1131           }
1132         }
1133       }
1134     }
1135
1136     if (supportCxx20FileSetTypes &&
1137         !cxxModuleBmiArgs.GetDestination().empty()) {
1138       cxxModuleBmiGenerator = cm::make_unique<cmInstallCxxModuleBmiGenerator>(
1139         target.GetName(),
1140         helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs),
1141         cxxModuleBmiArgs.GetPermissions(),
1142         cxxModuleBmiArgs.GetConfigurations(), cxxModuleBmiArgs.GetComponent(),
1143         cmInstallGenerator::SelectMessageLevel(target.GetMakefile()),
1144         cxxModuleBmiArgs.GetExcludeFromAll(), cxxModuleBmiArgs.GetOptional(),
1145         helper.Makefile->GetBacktrace());
1146       target.SetHaveInstallRule(true);
1147     }
1148
1149     // Add this install rule to an export if one was specified.
1150     if (!addTargetExport()) {
1151       return false;
1152     }
1153
1154     // Keep track of whether we're installing anything in each category
1155     installsArchive = installsArchive || archiveGenerator;
1156     installsLibrary = installsLibrary || libraryGenerator;
1157     installsNamelink = installsNamelink || namelinkGenerator;
1158     installsRuntime = installsRuntime || runtimeGenerator;
1159     installsObject = installsObject || objectGenerator;
1160     installsFramework = installsFramework || frameworkGenerator;
1161     installsBundle = installsBundle || bundleGenerator;
1162     installsPrivateHeader = installsPrivateHeader || privateHeaderGenerator;
1163     installsPublicHeader = installsPublicHeader || publicHeaderGenerator;
1164     installsResource = installsResource || resourceGenerator;
1165     installsCxxModuleBmi = installsCxxModuleBmi || cxxModuleBmiGenerator;
1166
1167     helper.Makefile->AddInstallGenerator(std::move(archiveGenerator));
1168     helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
1169     helper.Makefile->AddInstallGenerator(std::move(namelinkGenerator));
1170     helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator));
1171     helper.Makefile->AddInstallGenerator(std::move(objectGenerator));
1172     helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator));
1173     helper.Makefile->AddInstallGenerator(std::move(bundleGenerator));
1174     helper.Makefile->AddInstallGenerator(std::move(privateHeaderGenerator));
1175     helper.Makefile->AddInstallGenerator(std::move(publicHeaderGenerator));
1176     helper.Makefile->AddInstallGenerator(std::move(resourceGenerator));
1177     for (auto& gen : fileSetGenerators) {
1178       helper.Makefile->AddInstallGenerator(std::move(gen));
1179     }
1180     helper.Makefile->AddInstallGenerator(std::move(cxxModuleBmiGenerator));
1181   }
1182
1183   if (runtimeDependenciesArgVector && !runtimeDependencySet->Empty()) {
1184     AddInstallRuntimeDependenciesGenerator(
1185       helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs,
1186       std::move(runtimeDependenciesArgs), installsRuntime, installsLibrary,
1187       installsFramework);
1188   }
1189
1190   // Tell the global generator about any installation component names
1191   // specified
1192   if (installsArchive) {
1193     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1194       archiveArgs.GetComponent());
1195   }
1196   if (installsLibrary) {
1197     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1198       libraryArgs.GetComponent());
1199   }
1200   if (installsNamelink) {
1201     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1202       libraryArgs.GetNamelinkComponent());
1203   }
1204   if (installsRuntime) {
1205     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1206       runtimeArgs.GetComponent());
1207   }
1208   if (installsObject) {
1209     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1210       objectArgs.GetComponent());
1211   }
1212   if (installsFramework) {
1213     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1214       frameworkArgs.GetComponent());
1215   }
1216   if (installsBundle) {
1217     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1218       bundleArgs.GetComponent());
1219   }
1220   if (installsPrivateHeader) {
1221     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1222       privateHeaderArgs.GetComponent());
1223   }
1224   if (installsPublicHeader) {
1225     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1226       publicHeaderArgs.GetComponent());
1227   }
1228   if (installsResource) {
1229     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1230       resourceArgs.GetComponent());
1231   }
1232   for (std::size_t i = 0; i < fileSetArgs.size(); i++) {
1233     if (installsFileSet[i]) {
1234       helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1235         fileSetArgs[i].GetComponent());
1236     }
1237   }
1238   if (installsCxxModuleBmi) {
1239     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1240       cxxModuleBmiArgs.GetComponent());
1241   }
1242
1243   return true;
1244 }
1245
1246 bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
1247                                         cmExecutionStatus& status)
1248 {
1249   Helper helper(status);
1250
1251   // This is the IMPORTED_RUNTIME_ARTIFACTS mode.
1252   std::vector<cmTarget*> targets;
1253
1254   struct ArgVectors
1255   {
1256     ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
1257     ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
1258     ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
1259     ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle;
1260   };
1261
1262   static auto const argHelper = cmArgumentParser<ArgVectors>{}
1263                                   .Bind("LIBRARY"_s, &ArgVectors::Library)
1264                                   .Bind("RUNTIME"_s, &ArgVectors::Runtime)
1265                                   .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
1266                                   .Bind("BUNDLE"_s, &ArgVectors::Bundle);
1267
1268   std::vector<std::string> genericArgVector;
1269   ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
1270
1271   // now parse the generic args (i.e. the ones not specialized on LIBRARY,
1272   // RUNTIME etc. (see above)
1273   ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList;
1274   std::string runtimeDependencySetArg;
1275   std::vector<std::string> unknownArgs;
1276   cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
1277   genericArgs.Bind("IMPORTED_RUNTIME_ARTIFACTS"_s, targetList)
1278     .Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
1279   genericArgs.Parse(genericArgVector, &unknownArgs);
1280   bool success = genericArgs.Finalize();
1281
1282   cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
1283   cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
1284   cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
1285   cmInstallCommandArguments bundleArgs(helper.DefaultComponentName);
1286
1287   // now parse the args for specific parts of the target (e.g. LIBRARY,
1288   // RUNTIME etc.
1289   libraryArgs.Parse(argVectors.Library, &unknownArgs);
1290   runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
1291   frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
1292   bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
1293
1294   if (!unknownArgs.empty()) {
1295     // Unknown argument.
1296     status.SetError(
1297       cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given unknown argument \"",
1298                unknownArgs[0], "\"."));
1299     return false;
1300   }
1301
1302   // apply generic args
1303   libraryArgs.SetGenericArguments(&genericArgs);
1304   runtimeArgs.SetGenericArguments(&genericArgs);
1305   frameworkArgs.SetGenericArguments(&genericArgs);
1306   bundleArgs.SetGenericArguments(&genericArgs);
1307
1308   success = success && libraryArgs.Finalize();
1309   success = success && runtimeArgs.Finalize();
1310   success = success && frameworkArgs.Finalize();
1311   success = success && bundleArgs.Finalize();
1312
1313   if (!success) {
1314     return false;
1315   }
1316
1317   cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
1318   if (!runtimeDependencySetArg.empty()) {
1319     auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
1320     if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
1321           system)) {
1322       status.SetError(
1323         cmStrCat("IMPORTED_RUNTIME_ARTIFACTS RUNTIME_DEPENDENCY_SET is not "
1324                  "supported on system \"",
1325                  system, '"'));
1326       return false;
1327     }
1328     runtimeDependencySet =
1329       helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
1330         runtimeDependencySetArg);
1331   }
1332
1333   // Check if there is something to do.
1334   if (targetList.empty()) {
1335     return true;
1336   }
1337
1338   for (std::string const& tgt : targetList) {
1339     if (helper.Makefile->IsAlias(tgt)) {
1340       status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"",
1341                                tgt, "\" which is an alias."));
1342       return false;
1343     }
1344     // Lookup this target in the current directory.
1345     cmTarget* target = helper.Makefile->FindTargetToUse(tgt);
1346     if (!target || !target->IsImported()) {
1347       // If no local target has been found, find it in the global scope.
1348       cmTarget* const global_target =
1349         helper.Makefile->GetGlobalGenerator()->FindTarget(tgt, true);
1350       if (global_target && global_target->IsImported()) {
1351         target = global_target;
1352       }
1353     }
1354     if (target) {
1355       // Found the target.  Check its type.
1356       if (target->GetType() != cmStateEnums::EXECUTABLE &&
1357           target->GetType() != cmStateEnums::SHARED_LIBRARY &&
1358           target->GetType() != cmStateEnums::MODULE_LIBRARY) {
1359         status.SetError(
1360           cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"", tgt,
1361                    "\" which is not an executable, library, or module."));
1362         return false;
1363       }
1364       // Store the target in the list to be installed.
1365       targets.push_back(target);
1366     } else {
1367       // Did not find the target.
1368       status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"",
1369                                tgt, "\" which does not exist."));
1370       return false;
1371     }
1372   }
1373
1374   // Keep track of whether we will be performing an installation of
1375   // any files of the given type.
1376   bool installsLibrary = false;
1377   bool installsRuntime = false;
1378   bool installsFramework = false;
1379   bool installsBundle = false;
1380
1381   auto const createInstallGenerator =
1382     [helper](cmTarget& target, const cmInstallCommandArguments& typeArgs,
1383              const std::string& destination)
1384     -> std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator> {
1385     return cm::make_unique<cmInstallImportedRuntimeArtifactsGenerator>(
1386       target.GetName(), destination, typeArgs.GetPermissions(),
1387       typeArgs.GetConfigurations(), typeArgs.GetComponent(),
1388       cmInstallGenerator::SelectMessageLevel(helper.Makefile),
1389       typeArgs.GetExcludeFromAll(), typeArgs.GetOptional(),
1390       helper.Makefile->GetBacktrace());
1391   };
1392
1393   // Generate install script code to install the given targets.
1394   for (cmTarget* ti : targets) {
1395     // Handle each target type.
1396     cmTarget& target = *ti;
1397     std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
1398       libraryGenerator;
1399     std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
1400       runtimeGenerator;
1401     std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
1402       frameworkGenerator;
1403     std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
1404       bundleGenerator;
1405
1406     switch (target.GetType()) {
1407       case cmStateEnums::SHARED_LIBRARY:
1408         if (target.IsDLLPlatform()) {
1409           runtimeGenerator = createInstallGenerator(
1410             target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
1411           if (runtimeDependencySet) {
1412             runtimeDependencySet->AddLibrary(runtimeGenerator.get());
1413           }
1414         } else if (target.IsFrameworkOnApple()) {
1415           if (frameworkArgs.GetDestination().empty()) {
1416             status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given no "
1417                                      "FRAMEWORK DESTINATION for shared "
1418                                      "library FRAMEWORK target \"",
1419                                      target.GetName(), "\"."));
1420             return false;
1421           }
1422           frameworkGenerator = createInstallGenerator(
1423             target, frameworkArgs, frameworkArgs.GetDestination());
1424           if (runtimeDependencySet) {
1425             runtimeDependencySet->AddLibrary(frameworkGenerator.get());
1426           }
1427         } else {
1428           libraryGenerator = createInstallGenerator(
1429             target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
1430           if (runtimeDependencySet) {
1431             runtimeDependencySet->AddLibrary(libraryGenerator.get());
1432           }
1433         }
1434         break;
1435       case cmStateEnums::MODULE_LIBRARY:
1436         libraryGenerator = createInstallGenerator(
1437           target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
1438         if (runtimeDependencySet) {
1439           runtimeDependencySet->AddModule(libraryGenerator.get());
1440         }
1441         break;
1442       case cmStateEnums::EXECUTABLE:
1443         if (target.IsAppBundleOnApple()) {
1444           if (bundleArgs.GetDestination().empty()) {
1445             status.SetError(
1446               cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given no BUNDLE "
1447                        "DESTINATION for MACOSX_BUNDLE executable target \"",
1448                        target.GetName(), "\"."));
1449             return false;
1450           }
1451           bundleGenerator = createInstallGenerator(
1452             target, bundleArgs, bundleArgs.GetDestination());
1453           if (runtimeDependencySet) {
1454             if (!AddBundleExecutable(helper, runtimeDependencySet,
1455                                      bundleGenerator.get())) {
1456               return false;
1457             }
1458           }
1459         } else {
1460           runtimeGenerator = createInstallGenerator(
1461             target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
1462           if (runtimeDependencySet) {
1463             runtimeDependencySet->AddExecutable(runtimeGenerator.get());
1464           }
1465         }
1466         break;
1467       default:
1468         assert(false && "This should never happen");
1469         break;
1470     }
1471
1472     // Keep track of whether we're installing anything in each category
1473     installsLibrary = installsLibrary || libraryGenerator;
1474     installsRuntime = installsRuntime || runtimeGenerator;
1475     installsFramework = installsFramework || frameworkGenerator;
1476     installsBundle = installsBundle || bundleGenerator;
1477
1478     helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
1479     helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator));
1480     helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator));
1481     helper.Makefile->AddInstallGenerator(std::move(bundleGenerator));
1482   }
1483
1484   // Tell the global generator about any installation component names
1485   // specified
1486   if (installsLibrary) {
1487     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1488       libraryArgs.GetComponent());
1489   }
1490   if (installsRuntime) {
1491     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1492       runtimeArgs.GetComponent());
1493   }
1494   if (installsFramework) {
1495     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1496       frameworkArgs.GetComponent());
1497   }
1498   if (installsBundle) {
1499     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1500       bundleArgs.GetComponent());
1501   }
1502
1503   return true;
1504 }
1505
1506 bool HandleFilesMode(std::vector<std::string> const& args,
1507                      cmExecutionStatus& status)
1508 {
1509   Helper helper(status);
1510
1511   // This is the FILES mode.
1512   bool programs = (args[0] == "PROGRAMS");
1513   cmInstallCommandArguments ica(helper.DefaultComponentName);
1514   ArgumentParser::MaybeEmpty<std::vector<std::string>> files;
1515   ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
1516   std::vector<std::string> unknownArgs;
1517   ica.Parse(args, &unknownArgs);
1518
1519   if (!unknownArgs.empty()) {
1520     // Unknown argument.
1521     status.SetError(
1522       cmStrCat(args[0], " given unknown argument \"", unknownArgs[0], "\"."));
1523     return false;
1524   }
1525
1526   std::string type = ica.GetType();
1527   if (!type.empty() && allowedTypes.count(type) == 0) {
1528     status.SetError(
1529       cmStrCat(args[0], " given non-type \"", type, "\" with TYPE argument."));
1530     return false;
1531   }
1532
1533   const std::vector<std::string>& filesVector = files;
1534
1535   // Check if there is something to do.
1536   if (filesVector.empty()) {
1537     return true;
1538   }
1539
1540   if (!ica.GetRename().empty() && filesVector.size() > 1) {
1541     // The rename option works only with one file.
1542     status.SetError(
1543       cmStrCat(args[0], " given RENAME option with more than one file."));
1544     return false;
1545   }
1546
1547   std::vector<std::string> absFiles;
1548   if (!helper.MakeFilesFullPath(args[0].c_str(), filesVector, absFiles)) {
1549     return false;
1550   }
1551
1552   cmPolicies::PolicyStatus policyStatus =
1553     helper.Makefile->GetPolicyStatus(cmPolicies::CMP0062);
1554
1555   cmGlobalGenerator* gg = helper.Makefile->GetGlobalGenerator();
1556   for (std::string const& file : filesVector) {
1557     if (gg->IsExportedTargetsFile(file)) {
1558       const char* modal = nullptr;
1559       std::ostringstream e;
1560       MessageType messageType = MessageType::AUTHOR_WARNING;
1561
1562       switch (policyStatus) {
1563         case cmPolicies::WARN:
1564           e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0062) << "\n";
1565           modal = "should";
1566           CM_FALLTHROUGH;
1567         case cmPolicies::OLD:
1568           break;
1569         case cmPolicies::REQUIRED_IF_USED:
1570         case cmPolicies::REQUIRED_ALWAYS:
1571         case cmPolicies::NEW:
1572           modal = "may";
1573           messageType = MessageType::FATAL_ERROR;
1574           break;
1575       }
1576       if (modal) {
1577         e << "The file\n  " << file
1578           << "\nwas generated by the export() "
1579              "command.  It "
1580           << modal
1581           << " not be installed with the "
1582              "install() command.  Use the install(EXPORT) mechanism "
1583              "instead.  See the cmake-packages(7) manual for more.\n";
1584         helper.Makefile->IssueMessage(messageType, e.str());
1585         if (messageType == MessageType::FATAL_ERROR) {
1586           return false;
1587         }
1588       }
1589     }
1590   }
1591
1592   if (!ica.Finalize()) {
1593     return false;
1594   }
1595
1596   if (!type.empty() && !ica.GetDestination().empty()) {
1597     status.SetError(cmStrCat(args[0],
1598                              " given both TYPE and DESTINATION arguments. "
1599                              "You may only specify one."));
1600     return false;
1601   }
1602
1603   std::string destination = helper.GetDestinationForType(&ica, type);
1604   if (destination.empty()) {
1605     // A destination is required.
1606     status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
1607     return false;
1608   }
1609
1610   // Create the files install generator.
1611   helper.Makefile->AddInstallGenerator(CreateInstallFilesGenerator(
1612     helper.Makefile, absFiles, ica, programs, destination));
1613
1614   // Tell the global generator about any installation component names
1615   // specified.
1616   helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
1617     ica.GetComponent());
1618
1619   return true;
1620 }
1621
1622 bool HandleDirectoryMode(std::vector<std::string> const& args,
1623                          cmExecutionStatus& status)
1624 {
1625   Helper helper(status);
1626
1627   enum Doing
1628   {
1629     DoingNone,
1630     DoingDirs,
1631     DoingDestination,
1632     DoingPattern,
1633     DoingRegex,
1634     DoingPermsFile,
1635     DoingPermsDir,
1636     DoingPermsMatch,
1637     DoingConfigurations,
1638     DoingComponent,
1639     DoingType
1640   };
1641   Doing doing = DoingDirs;
1642   bool in_match_mode = false;
1643   bool optional = false;
1644   bool exclude_from_all = false;
1645   bool message_never = false;
1646   std::vector<std::string> dirs;
1647   const std::string* destination = nullptr;
1648   std::string permissions_file;
1649   std::string permissions_dir;
1650   std::vector<std::string> configurations;
1651   std::string component = helper.DefaultComponentName;
1652   std::string literal_args;
1653   std::string type;
1654   for (unsigned int i = 1; i < args.size(); ++i) {
1655     if (args[i] == "DESTINATION") {
1656       if (in_match_mode) {
1657         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1658                                  "\" after PATTERN or REGEX."));
1659         return false;
1660       }
1661
1662       // Switch to setting the destination property.
1663       doing = DoingDestination;
1664     } else if (args[i] == "TYPE") {
1665       if (in_match_mode) {
1666         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1667                                  "\" after PATTERN or REGEX."));
1668         return false;
1669       }
1670
1671       // Switch to setting the type.
1672       doing = DoingType;
1673     } else if (args[i] == "OPTIONAL") {
1674       if (in_match_mode) {
1675         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1676                                  "\" after PATTERN or REGEX."));
1677         return false;
1678       }
1679
1680       // Mark the rule as optional.
1681       optional = true;
1682       doing = DoingNone;
1683     } else if (args[i] == "MESSAGE_NEVER") {
1684       if (in_match_mode) {
1685         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1686                                  "\" after PATTERN or REGEX."));
1687         return false;
1688       }
1689
1690       // Mark the rule as quiet.
1691       message_never = true;
1692       doing = DoingNone;
1693     } else if (args[i] == "PATTERN") {
1694       // Switch to a new pattern match rule.
1695       doing = DoingPattern;
1696       in_match_mode = true;
1697     } else if (args[i] == "REGEX") {
1698       // Switch to a new regex match rule.
1699       doing = DoingRegex;
1700       in_match_mode = true;
1701     } else if (args[i] == "EXCLUDE") {
1702       // Add this property to the current match rule.
1703       if (!in_match_mode || doing == DoingPattern || doing == DoingRegex) {
1704         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1705                                  "\" before a PATTERN or REGEX is given."));
1706         return false;
1707       }
1708       literal_args += " EXCLUDE";
1709       doing = DoingNone;
1710     } else if (args[i] == "PERMISSIONS") {
1711       if (!in_match_mode) {
1712         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1713                                  "\" before a PATTERN or REGEX is given."));
1714         return false;
1715       }
1716
1717       // Switch to setting the current match permissions property.
1718       literal_args += " PERMISSIONS";
1719       doing = DoingPermsMatch;
1720     } else if (args[i] == "FILE_PERMISSIONS") {
1721       if (in_match_mode) {
1722         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1723                                  "\" after PATTERN or REGEX."));
1724         return false;
1725       }
1726
1727       // Switch to setting the file permissions property.
1728       doing = DoingPermsFile;
1729     } else if (args[i] == "DIRECTORY_PERMISSIONS") {
1730       if (in_match_mode) {
1731         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1732                                  "\" after PATTERN or REGEX."));
1733         return false;
1734       }
1735
1736       // Switch to setting the directory permissions property.
1737       doing = DoingPermsDir;
1738     } else if (args[i] == "USE_SOURCE_PERMISSIONS") {
1739       if (in_match_mode) {
1740         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1741                                  "\" after PATTERN or REGEX."));
1742         return false;
1743       }
1744
1745       // Add this option literally.
1746       literal_args += " USE_SOURCE_PERMISSIONS";
1747       doing = DoingNone;
1748     } else if (args[i] == "FILES_MATCHING") {
1749       if (in_match_mode) {
1750         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1751                                  "\" after PATTERN or REGEX."));
1752         return false;
1753       }
1754
1755       // Add this option literally.
1756       literal_args += " FILES_MATCHING";
1757       doing = DoingNone;
1758     } else if (args[i] == "CONFIGURATIONS") {
1759       if (in_match_mode) {
1760         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1761                                  "\" after PATTERN or REGEX."));
1762         return false;
1763       }
1764
1765       // Switch to setting the configurations property.
1766       doing = DoingConfigurations;
1767     } else if (args[i] == "COMPONENT") {
1768       if (in_match_mode) {
1769         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1770                                  "\" after PATTERN or REGEX."));
1771         return false;
1772       }
1773
1774       // Switch to setting the component property.
1775       doing = DoingComponent;
1776     } else if (args[i] == "EXCLUDE_FROM_ALL") {
1777       if (in_match_mode) {
1778         status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
1779                                  "\" after PATTERN or REGEX."));
1780         return false;
1781       }
1782       exclude_from_all = true;
1783       doing = DoingNone;
1784     } else if (doing == DoingDirs) {
1785       // Convert this directory to a full path.
1786       std::string dir = args[i];
1787       std::string::size_type gpos = cmGeneratorExpression::Find(dir);
1788       if (gpos != 0 && !cmSystemTools::FileIsFullPath(dir)) {
1789         dir =
1790           cmStrCat(helper.Makefile->GetCurrentSourceDirectory(), '/', args[i]);
1791       }
1792
1793       // Make sure the name is a directory.
1794       if (cmSystemTools::FileExists(dir) &&
1795           !cmSystemTools::FileIsDirectory(dir)) {
1796         status.SetError(cmStrCat(args[0], " given non-directory \"", args[i],
1797                                  "\" to install."));
1798         return false;
1799       }
1800
1801       // Store the directory for installation.
1802       dirs.push_back(std::move(dir));
1803     } else if (doing == DoingConfigurations) {
1804       configurations.push_back(args[i]);
1805     } else if (doing == DoingDestination) {
1806       destination = &args[i];
1807       doing = DoingNone;
1808     } else if (doing == DoingType) {
1809       if (allowedTypes.count(args[i]) == 0) {
1810         status.SetError(cmStrCat(args[0], " given non-type \"", args[i],
1811                                  "\" with TYPE argument."));
1812         return false;
1813       }
1814
1815       type = args[i];
1816       doing = DoingNone;
1817     } else if (doing == DoingPattern) {
1818       // Convert the pattern to a regular expression.  Require a
1819       // leading slash and trailing end-of-string in the matched
1820       // string to make sure the pattern matches only whole file
1821       // names.
1822       literal_args += " REGEX \"/";
1823       std::string regex = cmsys::Glob::PatternToRegex(args[i], false);
1824       cmSystemTools::ReplaceString(regex, "\\", "\\\\");
1825       literal_args += regex;
1826       literal_args += "$\"";
1827       doing = DoingNone;
1828     } else if (doing == DoingRegex) {
1829       literal_args += " REGEX \"";
1830 // Match rules are case-insensitive on some platforms.
1831 #if defined(_WIN32) || defined(__APPLE__)
1832       std::string regex = cmSystemTools::LowerCase(args[i]);
1833 #else
1834       std::string regex = args[i];
1835 #endif
1836       cmSystemTools::ReplaceString(regex, "\\", "\\\\");
1837       literal_args += regex;
1838       literal_args += "\"";
1839       doing = DoingNone;
1840     } else if (doing == DoingComponent) {
1841       component = args[i];
1842       doing = DoingNone;
1843     } else if (doing == DoingPermsFile) {
1844       // Check the requested permission.
1845       if (!cmInstallCommandArguments::CheckPermissions(args[i],
1846                                                        permissions_file)) {
1847         status.SetError(cmStrCat(args[0], " given invalid file permission \"",
1848                                  args[i], "\"."));
1849         return false;
1850       }
1851     } else if (doing == DoingPermsDir) {
1852       // Check the requested permission.
1853       if (!cmInstallCommandArguments::CheckPermissions(args[i],
1854                                                        permissions_dir)) {
1855         status.SetError(cmStrCat(
1856           args[0], " given invalid directory permission \"", args[i], "\"."));
1857         return false;
1858       }
1859     } else if (doing == DoingPermsMatch) {
1860       // Check the requested permission.
1861       if (!cmInstallCommandArguments::CheckPermissions(args[i],
1862                                                        literal_args)) {
1863         status.SetError(
1864           cmStrCat(args[0], " given invalid permission \"", args[i], "\"."));
1865         return false;
1866       }
1867     } else {
1868       // Unknown argument.
1869       status.SetError(
1870         cmStrCat(args[0], " given unknown argument \"", args[i], "\"."));
1871       return false;
1872     }
1873   }
1874
1875   // Support installing an empty directory.
1876   if (dirs.empty() && destination) {
1877     dirs.emplace_back();
1878   }
1879
1880   // Check if there is something to do.
1881   if (dirs.empty()) {
1882     return true;
1883   }
1884   std::string destinationStr;
1885   if (!destination) {
1886     if (type.empty()) {
1887       // A destination is required.
1888       status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
1889       return false;
1890     }
1891     destinationStr = helper.GetDestinationForType(nullptr, type);
1892     destination = &destinationStr;
1893   } else if (!type.empty()) {
1894     status.SetError(cmStrCat(args[0],
1895                              " given both TYPE and DESTINATION "
1896                              "arguments. You may only specify one."));
1897     return false;
1898   }
1899
1900   cmInstallGenerator::MessageLevel message =
1901     cmInstallGenerator::SelectMessageLevel(helper.Makefile, message_never);
1902
1903   // Create the directory install generator.
1904   helper.Makefile->AddInstallGenerator(
1905     cm::make_unique<cmInstallDirectoryGenerator>(
1906       dirs, *destination, permissions_file, permissions_dir, configurations,
1907       component, message, exclude_from_all, literal_args, optional,
1908       helper.Makefile->GetBacktrace()));
1909
1910   // Tell the global generator about any installation component names
1911   // specified.
1912   helper.Makefile->GetGlobalGenerator()->AddInstallComponent(component);
1913
1914   return true;
1915 }
1916
1917 bool HandleExportAndroidMKMode(std::vector<std::string> const& args,
1918                                cmExecutionStatus& status)
1919 {
1920 #ifndef CMAKE_BOOTSTRAP
1921   Helper helper(status);
1922
1923   // This is the EXPORT mode.
1924   cmInstallCommandArguments ica(helper.DefaultComponentName);
1925
1926   std::string exp;
1927   std::string name_space;
1928   bool exportOld = false;
1929   std::string filename;
1930
1931   ica.Bind("EXPORT_ANDROID_MK"_s, exp);
1932   ica.Bind("NAMESPACE"_s, name_space);
1933   ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
1934   ica.Bind("FILE"_s, filename);
1935
1936   std::vector<std::string> unknownArgs;
1937   ica.Parse(args, &unknownArgs);
1938
1939   if (!unknownArgs.empty()) {
1940     // Unknown argument.
1941     status.SetError(
1942       cmStrCat(args[0], " given unknown argument \"", unknownArgs[0], "\"."));
1943     return false;
1944   }
1945
1946   if (!ica.Finalize()) {
1947     return false;
1948   }
1949
1950   // Make sure there is a destination.
1951   if (ica.GetDestination().empty()) {
1952     // A destination is required.
1953     status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
1954     return false;
1955   }
1956
1957   // Check the file name.
1958   std::string fname = filename;
1959   if (fname.find_first_of(":/\\") != std::string::npos) {
1960     status.SetError(cmStrCat(args[0], " given invalid export file name \"",
1961                              fname,
1962                              "\".  The FILE argument may not contain a path.  "
1963                              "Specify the path in the DESTINATION argument."));
1964     return false;
1965   }
1966
1967   // Check the file extension.
1968   if (!fname.empty() &&
1969       cmSystemTools::GetFilenameLastExtension(fname) != ".mk") {
1970     status.SetError(cmStrCat(
1971       args[0], " given invalid export file name \"", fname,
1972       R"(".  The FILE argument must specify a name ending in ".mk".)"));
1973     return false;
1974   }
1975   if (fname.find_first_of(":/\\") != std::string::npos) {
1976     status.SetError(
1977       cmStrCat(args[0], " given export name \"", exp,
1978                "\".  "
1979                "This name cannot be safely converted to a file name.  "
1980                "Specify a different export name or use the FILE option to set "
1981                "a file name explicitly."));
1982     return false;
1983   }
1984   // Use the default name
1985   if (fname.empty()) {
1986     fname = "Android.mk";
1987   }
1988
1989   cmExportSet& exportSet =
1990     helper.Makefile->GetGlobalGenerator()->GetExportSets()[exp];
1991
1992   cmInstallGenerator::MessageLevel message =
1993     cmInstallGenerator::SelectMessageLevel(helper.Makefile);
1994
1995   // Create the export install generator.
1996   helper.Makefile->AddInstallGenerator(
1997     cm::make_unique<cmInstallExportGenerator>(
1998       &exportSet, ica.GetDestination(), ica.GetPermissions(),
1999       ica.GetConfigurations(), ica.GetComponent(), message,
2000       ica.GetExcludeFromAll(), fname, name_space, "", exportOld, true,
2001       helper.Makefile->GetBacktrace()));
2002
2003   return true;
2004 #else
2005   static_cast<void>(args);
2006   status.SetError("EXPORT_ANDROID_MK not supported in bootstrap cmake");
2007   return false;
2008 #endif
2009 }
2010
2011 bool HandleExportMode(std::vector<std::string> const& args,
2012                       cmExecutionStatus& status)
2013 {
2014   Helper helper(status);
2015
2016   // This is the EXPORT mode.
2017   cmInstallCommandArguments ica(helper.DefaultComponentName);
2018
2019   std::string exp;
2020   std::string name_space;
2021   bool exportOld = false;
2022   std::string filename;
2023   std::string cxx_modules_directory;
2024
2025   ica.Bind("EXPORT"_s, exp);
2026   ica.Bind("NAMESPACE"_s, name_space);
2027   ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
2028   ica.Bind("FILE"_s, filename);
2029
2030   bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
2031     *helper.Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
2032   if (supportCxx20FileSetTypes) {
2033     ica.Bind("CXX_MODULES_DIRECTORY"_s, cxx_modules_directory);
2034   }
2035
2036   std::vector<std::string> unknownArgs;
2037   ica.Parse(args, &unknownArgs);
2038
2039   if (!unknownArgs.empty()) {
2040     // Unknown argument.
2041     status.SetError(
2042       cmStrCat(args[0], " given unknown argument \"", unknownArgs[0], "\"."));
2043     return false;
2044   }
2045
2046   if (!ica.Finalize()) {
2047     return false;
2048   }
2049
2050   // Make sure there is a destination.
2051   if (ica.GetDestination().empty()) {
2052     // A destination is required.
2053     status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
2054     return false;
2055   }
2056
2057   // Check the file name.
2058   std::string fname = filename;
2059   if (fname.find_first_of(":/\\") != std::string::npos) {
2060     status.SetError(cmStrCat(args[0], " given invalid export file name \"",
2061                              fname,
2062                              "\".  "
2063                              "The FILE argument may not contain a path.  "
2064                              "Specify the path in the DESTINATION argument."));
2065     return false;
2066   }
2067
2068   // Check the file extension.
2069   if (!fname.empty() &&
2070       cmSystemTools::GetFilenameLastExtension(fname) != ".cmake") {
2071     status.SetError(
2072       cmStrCat(args[0], " given invalid export file name \"", fname,
2073                "\".  "
2074                "The FILE argument must specify a name ending in \".cmake\"."));
2075     return false;
2076   }
2077
2078   // Construct the file name.
2079   if (fname.empty()) {
2080     fname = cmStrCat(exp, ".cmake");
2081
2082     if (fname.find_first_of(":/\\") != std::string::npos) {
2083       status.SetError(cmStrCat(
2084         args[0], " given export name \"", exp,
2085         "\".  "
2086         "This name cannot be safely converted to a file name.  "
2087         "Specify a different export name or use the FILE option to set "
2088         "a file name explicitly."));
2089       return false;
2090     }
2091   }
2092
2093   cmExportSet& exportSet =
2094     helper.Makefile->GetGlobalGenerator()->GetExportSets()[exp];
2095   if (exportOld) {
2096     for (auto const& te : exportSet.GetTargetExports()) {
2097       cmTarget* tgt =
2098         helper.Makefile->GetGlobalGenerator()->FindTarget(te->TargetName);
2099       const bool newCMP0022Behavior =
2100         (tgt && tgt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
2101          tgt->GetPolicyStatusCMP0022() != cmPolicies::OLD);
2102
2103       if (!newCMP0022Behavior) {
2104         status.SetError(cmStrCat(
2105           "INSTALL(EXPORT) given keyword \""
2106           "EXPORT_LINK_INTERFACE_LIBRARIES\", but target \"",
2107           te->TargetName, "\" does not have policy CMP0022 set to NEW."));
2108         return false;
2109       }
2110     }
2111   }
2112
2113   cmInstallGenerator::MessageLevel message =
2114     cmInstallGenerator::SelectMessageLevel(helper.Makefile);
2115
2116   // Create the export install generator.
2117   helper.Makefile->AddInstallGenerator(
2118     cm::make_unique<cmInstallExportGenerator>(
2119       &exportSet, ica.GetDestination(), ica.GetPermissions(),
2120       ica.GetConfigurations(), ica.GetComponent(), message,
2121       ica.GetExcludeFromAll(), fname, name_space, cxx_modules_directory,
2122       exportOld, false, helper.Makefile->GetBacktrace()));
2123
2124   return true;
2125 }
2126
2127 bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args,
2128                                     cmExecutionStatus& status)
2129 {
2130   Helper helper(status);
2131
2132   auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
2133   if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
2134         system)) {
2135     status.SetError(cmStrCat(
2136       "RUNTIME_DEPENDENCY_SET is not supported on system \"", system, '"'));
2137     return false;
2138   }
2139
2140   // This is the RUNTIME_DEPENDENCY_SET mode.
2141   cmInstallRuntimeDependencySet* runtimeDependencySet;
2142
2143   struct ArgVectors
2144   {
2145     ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
2146     ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
2147     ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
2148   };
2149
2150   static auto const argHelper = cmArgumentParser<ArgVectors>{}
2151                                   .Bind("LIBRARY"_s, &ArgVectors::Library)
2152                                   .Bind("RUNTIME"_s, &ArgVectors::Runtime)
2153                                   .Bind("FRAMEWORK"_s, &ArgVectors::Framework);
2154
2155   std::vector<std::string> genericArgVector;
2156   ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
2157
2158   // now parse the generic args (i.e. the ones not specialized on LIBRARY,
2159   // RUNTIME, FRAMEWORK etc. (see above)
2160   // These generic args also contain the runtime dependency set
2161   std::string runtimeDependencySetArg;
2162   std::vector<std::string> runtimeDependencyArgVector;
2163   cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
2164   genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
2165   genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector);
2166   bool success = genericArgs.Finalize();
2167
2168   cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
2169   cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
2170   cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
2171
2172   // Now also parse the file(GET_RUNTIME_DEPENDENCY) args
2173   std::vector<std::string> unknownArgs;
2174   auto runtimeDependencyArgs = RuntimeDependenciesArgHelper.Parse(
2175     runtimeDependencyArgVector, &unknownArgs);
2176
2177   // now parse the args for specific parts of the target (e.g. LIBRARY,
2178   // RUNTIME, FRAMEWORK etc.
2179   libraryArgs.Parse(argVectors.Library, &unknownArgs);
2180   runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
2181   frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
2182
2183   libraryArgs.SetGenericArguments(&genericArgs);
2184   runtimeArgs.SetGenericArguments(&genericArgs);
2185   frameworkArgs.SetGenericArguments(&genericArgs);
2186
2187   success = success && libraryArgs.Finalize();
2188   success = success && runtimeArgs.Finalize();
2189   success = success && frameworkArgs.Finalize();
2190
2191   if (!success) {
2192     return false;
2193   }
2194
2195   if (!unknownArgs.empty()) {
2196     helper.SetError(
2197       cmStrCat("RUNTIME_DEPENDENCY_SET given unknown argument \"",
2198                unknownArgs.front(), "\"."));
2199     return false;
2200   }
2201
2202   if (runtimeDependencySetArg.empty()) {
2203     helper.SetError(
2204       "RUNTIME_DEPENDENCY_SET not given a runtime dependency set.");
2205     return false;
2206   }
2207
2208   runtimeDependencySet =
2209     helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
2210       runtimeDependencySetArg);
2211
2212   bool installsRuntime = false;
2213   bool installsLibrary = false;
2214   bool installsFramework = false;
2215
2216   AddInstallRuntimeDependenciesGenerator(
2217     helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs,
2218     std::move(runtimeDependencyArgs), installsRuntime, installsLibrary,
2219     installsFramework);
2220
2221   // Tell the global generator about any installation component names
2222   // specified
2223   if (installsLibrary) {
2224     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
2225       libraryArgs.GetComponent());
2226   }
2227   if (installsRuntime) {
2228     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
2229       runtimeArgs.GetComponent());
2230   }
2231   if (installsFramework) {
2232     helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
2233       frameworkArgs.GetComponent());
2234   }
2235
2236   return true;
2237 }
2238
2239 bool Helper::MakeFilesFullPath(const char* modeName,
2240                                const std::vector<std::string>& relFiles,
2241                                std::vector<std::string>& absFiles)
2242 {
2243   return this->MakeFilesFullPath(
2244     modeName, this->Makefile->GetCurrentSourceDirectory(), relFiles, absFiles);
2245 }
2246
2247 bool Helper::MakeFilesFullPath(const char* modeName,
2248                                const std::string& basePath,
2249                                const std::vector<std::string>& relFiles,
2250                                std::vector<std::string>& absFiles)
2251 {
2252   for (std::string const& relFile : relFiles) {
2253     std::string file = relFile;
2254     std::string::size_type gpos = cmGeneratorExpression::Find(file);
2255     if (gpos != 0 && !cmSystemTools::FileIsFullPath(file)) {
2256       file = cmStrCat(basePath, '/', relFile);
2257     }
2258
2259     // Make sure the file is not a directory.
2260     if (gpos == std::string::npos && !cmSystemTools::FileIsSymlink(file) &&
2261         cmSystemTools::FileIsDirectory(file)) {
2262       this->SetError(
2263         cmStrCat(modeName, " given directory \"", relFile, "\" to install."));
2264       return false;
2265     }
2266     // Store the file for installation.
2267     absFiles.push_back(std::move(file));
2268   }
2269   return true;
2270 }
2271
2272 bool Helper::CheckCMP0006(bool& failure) const
2273 {
2274   switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0006)) {
2275     case cmPolicies::WARN:
2276       this->Makefile->IssueMessage(
2277         MessageType::AUTHOR_WARNING,
2278         cmPolicies::GetPolicyWarning(cmPolicies::CMP0006));
2279       CM_FALLTHROUGH;
2280     case cmPolicies::OLD:
2281       // OLD behavior is to allow compatibility
2282       return true;
2283     case cmPolicies::NEW:
2284       // NEW behavior is to disallow compatibility
2285       break;
2286     case cmPolicies::REQUIRED_IF_USED:
2287     case cmPolicies::REQUIRED_ALWAYS:
2288       failure = true;
2289       this->Makefile->IssueMessage(
2290         MessageType::FATAL_ERROR,
2291         cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0006));
2292       break;
2293   }
2294   return false;
2295 }
2296
2297 std::string Helper::GetDestination(const cmInstallCommandArguments* args,
2298                                    const std::string& varName,
2299                                    const std::string& guess) const
2300 {
2301   if (args && !args->GetDestination().empty()) {
2302     return args->GetDestination();
2303   }
2304   std::string val = this->Makefile->GetSafeDefinition(varName);
2305   if (!val.empty()) {
2306     return val;
2307   }
2308   return guess;
2309 }
2310
2311 std::string Helper::GetRuntimeDestination(
2312   const cmInstallCommandArguments* args) const
2313 {
2314   return this->GetDestination(args, "CMAKE_INSTALL_BINDIR", "bin");
2315 }
2316
2317 std::string Helper::GetSbinDestination(
2318   const cmInstallCommandArguments* args) const
2319 {
2320   return this->GetDestination(args, "CMAKE_INSTALL_SBINDIR", "sbin");
2321 }
2322
2323 std::string Helper::GetArchiveDestination(
2324   const cmInstallCommandArguments* args) const
2325 {
2326   return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib");
2327 }
2328
2329 std::string Helper::GetLibraryDestination(
2330   const cmInstallCommandArguments* args) const
2331 {
2332   return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib");
2333 }
2334
2335 std::string Helper::GetCxxModulesBmiDestination(
2336   const cmInstallCommandArguments* args) const
2337 {
2338   if (args) {
2339     return args->GetDestination();
2340   }
2341   return {};
2342 }
2343
2344 std::string Helper::GetIncludeDestination(
2345   const cmInstallCommandArguments* args) const
2346 {
2347   return this->GetDestination(args, "CMAKE_INSTALL_INCLUDEDIR", "include");
2348 }
2349
2350 std::string Helper::GetSysconfDestination(
2351   const cmInstallCommandArguments* args) const
2352 {
2353   return this->GetDestination(args, "CMAKE_INSTALL_SYSCONFDIR", "etc");
2354 }
2355
2356 std::string Helper::GetSharedStateDestination(
2357   const cmInstallCommandArguments* args) const
2358 {
2359   return this->GetDestination(args, "CMAKE_INSTALL_SHAREDSTATEDIR", "com");
2360 }
2361
2362 std::string Helper::GetLocalStateDestination(
2363   const cmInstallCommandArguments* args) const
2364 {
2365   return this->GetDestination(args, "CMAKE_INSTALL_LOCALSTATEDIR", "var");
2366 }
2367
2368 std::string Helper::GetRunStateDestination(
2369   const cmInstallCommandArguments* args) const
2370 {
2371   return this->GetDestination(args, "CMAKE_INSTALL_RUNSTATEDIR",
2372                               this->GetLocalStateDestination(nullptr) +
2373                                 "/run");
2374 }
2375
2376 std::string Helper::GetDataRootDestination(
2377   const cmInstallCommandArguments* args) const
2378 {
2379   return this->GetDestination(args, "CMAKE_INSTALL_DATAROOTDIR", "share");
2380 }
2381
2382 std::string Helper::GetDataDestination(
2383   const cmInstallCommandArguments* args) const
2384 {
2385   return this->GetDestination(args, "CMAKE_INSTALL_DATADIR",
2386                               this->GetDataRootDestination(nullptr));
2387 }
2388
2389 std::string Helper::GetInfoDestination(
2390   const cmInstallCommandArguments* args) const
2391 {
2392   return this->GetDestination(args, "CMAKE_INSTALL_INFODIR",
2393                               this->GetDataRootDestination(nullptr) + "/info");
2394 }
2395
2396 std::string Helper::GetLocaleDestination(
2397   const cmInstallCommandArguments* args) const
2398 {
2399   return this->GetDestination(args, "CMAKE_INSTALL_LOCALEDIR",
2400                               this->GetDataRootDestination(nullptr) +
2401                                 "/locale");
2402 }
2403
2404 std::string Helper::GetManDestination(
2405   const cmInstallCommandArguments* args) const
2406 {
2407   return this->GetDestination(args, "CMAKE_INSTALL_MANDIR",
2408                               this->GetDataRootDestination(nullptr) + "/man");
2409 }
2410
2411 std::string Helper::GetDocDestination(
2412   const cmInstallCommandArguments* args) const
2413 {
2414   return this->GetDestination(args, "CMAKE_INSTALL_DOCDIR",
2415                               this->GetDataRootDestination(nullptr) + "/doc");
2416 }
2417
2418 std::string Helper::GetDestinationForType(
2419   const cmInstallCommandArguments* args, const std::string& type) const
2420 {
2421   if (args && !args->GetDestination().empty()) {
2422     return args->GetDestination();
2423   }
2424   if (type == "BIN") {
2425     return this->GetRuntimeDestination(nullptr);
2426   }
2427   if (type == "SBIN") {
2428     return this->GetSbinDestination(nullptr);
2429   }
2430   if (type == "SYSCONF") {
2431     return this->GetSysconfDestination(nullptr);
2432   }
2433   if (type == "SHAREDSTATE") {
2434     return this->GetSharedStateDestination(nullptr);
2435   }
2436   if (type == "LOCALSTATE") {
2437     return this->GetLocalStateDestination(nullptr);
2438   }
2439   if (type == "RUNSTATE") {
2440     return this->GetRunStateDestination(nullptr);
2441   }
2442   if (type == "LIB") {
2443     return this->GetLibraryDestination(nullptr);
2444   }
2445   if (type == "INCLUDE") {
2446     return this->GetIncludeDestination(nullptr);
2447   }
2448   if (type == "DATA") {
2449     return this->GetDataDestination(nullptr);
2450   }
2451   if (type == "INFO") {
2452     return this->GetInfoDestination(nullptr);
2453   }
2454   if (type == "LOCALE") {
2455     return this->GetLocaleDestination(nullptr);
2456   }
2457   if (type == "MAN") {
2458     return this->GetManDestination(nullptr);
2459   }
2460   if (type == "DOC") {
2461     return this->GetDocDestination(nullptr);
2462   }
2463   return "";
2464 }
2465
2466 } // namespace
2467
2468 bool cmInstallCommand(std::vector<std::string> const& args,
2469                       cmExecutionStatus& status)
2470 {
2471   // Allow calling with no arguments so that arguments may be built up
2472   // using a variable that may be left empty.
2473   if (args.empty()) {
2474     return true;
2475   }
2476
2477   // Enable the install target.
2478   status.GetMakefile().GetGlobalGenerator()->EnableInstallTarget();
2479
2480   static cmSubcommandTable const subcommand{
2481     { "SCRIPT"_s, HandleScriptMode },
2482     { "CODE"_s, HandleScriptMode },
2483     { "TARGETS"_s, HandleTargetsMode },
2484     { "IMPORTED_RUNTIME_ARTIFACTS"_s, HandleImportedRuntimeArtifactsMode },
2485     { "FILES"_s, HandleFilesMode },
2486     { "PROGRAMS"_s, HandleFilesMode },
2487     { "DIRECTORY"_s, HandleDirectoryMode },
2488     { "EXPORT"_s, HandleExportMode },
2489     { "EXPORT_ANDROID_MK"_s, HandleExportAndroidMKMode },
2490     { "RUNTIME_DEPENDENCY_SET"_s, HandleRuntimeDependencySetMode },
2491   };
2492
2493   return subcommand(args[0], args, status);
2494 }