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