cmInstallCommand.cxx 78 KB

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