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