cmCPackGenerator.cxx 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include "cmCPackGenerator.h"
  4. #include <algorithm>
  5. #include <iterator>
  6. #include <memory>
  7. #include <utility>
  8. #include <cmext/string_view>
  9. #include "cmsys/FStream.hxx"
  10. #include "cmsys/Glob.hxx"
  11. #include "cmsys/RegularExpression.hxx"
  12. #include "cmCPackComponentGroup.h"
  13. #include "cmCPackLog.h"
  14. #include "cmCryptoHash.h"
  15. #include "cmDuration.h"
  16. #include "cmFSPermissions.h"
  17. #include "cmFileTimes.h"
  18. #include "cmGeneratedFileStream.h"
  19. #include "cmGlobalGenerator.h"
  20. #include "cmList.h"
  21. #include "cmMakefile.h"
  22. #include "cmState.h"
  23. #include "cmStateSnapshot.h"
  24. #include "cmStringAlgorithms.h"
  25. #include "cmSystemTools.h"
  26. #include "cmValue.h"
  27. #include "cmVersion.h"
  28. #include "cmWorkingDirectory.h"
  29. #include "cmXMLSafe.h"
  30. #include "cmake.h"
  31. #if defined(__HAIKU__)
  32. # include <FindDirectory.h>
  33. # include <StorageDefs.h>
  34. #endif
  35. cmCPackGenerator::cmCPackGenerator()
  36. {
  37. this->GeneratorVerbose = cmSystemTools::OUTPUT_NONE;
  38. this->MakefileMap = nullptr;
  39. this->Logger = nullptr;
  40. this->componentPackageMethod = ONE_PACKAGE_PER_GROUP;
  41. }
  42. cmCPackGenerator::~cmCPackGenerator()
  43. {
  44. this->MakefileMap = nullptr;
  45. }
  46. void cmCPackGenerator::DisplayVerboseOutput(std::string const& msg,
  47. float /*unused*/)
  48. {
  49. cmCPackLogger(cmCPackLog::LOG_VERBOSE, msg << std::endl);
  50. }
  51. int cmCPackGenerator::PrepareNames()
  52. {
  53. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Create temp directory." << std::endl);
  54. // checks CPACK_SET_DESTDIR support
  55. if (this->IsOn("CPACK_SET_DESTDIR")) {
  56. if (SETDESTDIR_UNSUPPORTED == this->SupportsSetDestdir()) {
  57. cmCPackLogger(cmCPackLog::LOG_ERROR,
  58. "CPACK_SET_DESTDIR is set to ON but the '"
  59. << this->Name << "' generator does NOT support it."
  60. << std::endl);
  61. return 0;
  62. }
  63. if (SETDESTDIR_SHOULD_NOT_BE_USED == this->SupportsSetDestdir()) {
  64. cmCPackLogger(cmCPackLog::LOG_WARNING,
  65. "CPACK_SET_DESTDIR is set to ON but it is "
  66. << "usually a bad idea to do that with '" << this->Name
  67. << "' generator. Use at your own risk." << std::endl);
  68. }
  69. }
  70. // Determine package-directory.
  71. cmValue pkgDirectory = this->GetOption("CPACK_PACKAGE_DIRECTORY");
  72. if (!pkgDirectory) {
  73. cmCPackLogger(cmCPackLog::LOG_ERROR,
  74. "CPACK_PACKAGE_DIRECTORY not specified" << std::endl);
  75. return 0;
  76. }
  77. // Determine base-filename of the package.
  78. cmValue pkgBaseFileName = this->GetOption("CPACK_PACKAGE_FILE_NAME");
  79. if (!pkgBaseFileName) {
  80. cmCPackLogger(cmCPackLog::LOG_ERROR,
  81. "CPACK_PACKAGE_FILE_NAME not specified" << std::endl);
  82. return 0;
  83. }
  84. // Determine filename of the package.
  85. if (!this->GetOutputExtension()) {
  86. cmCPackLogger(cmCPackLog::LOG_ERROR,
  87. "No output extension specified" << std::endl);
  88. return 0;
  89. }
  90. std::string pkgFileName =
  91. cmStrCat(pkgBaseFileName, this->GetOutputExtension());
  92. // Determine path to the package.
  93. std::string pkgFilePath = cmStrCat(pkgDirectory, '/', pkgFileName);
  94. // Determine top-level directory for packaging.
  95. std::string topDirectory = cmStrCat(pkgDirectory, "/_CPack_Packages/");
  96. {
  97. cmValue toplevelTag = this->GetOption("CPACK_TOPLEVEL_TAG");
  98. if (toplevelTag) {
  99. topDirectory += cmStrCat(toplevelTag, '/');
  100. }
  101. }
  102. topDirectory += *this->GetOption("CPACK_GENERATOR");
  103. // Determine temporary packaging-directory.
  104. std::string tmpDirectory = cmStrCat(topDirectory, '/', pkgBaseFileName);
  105. // Determine path to temporary package file.
  106. std::string tmpPkgFilePath = topDirectory + "/" + pkgFileName;
  107. // Set CPack variables which are not set already.
  108. this->SetOptionIfNotSet("CPACK_REMOVE_TOPLEVEL_DIRECTORY", "1");
  109. this->SetOptionIfNotSet("CPACK_TOPLEVEL_DIRECTORY", topDirectory);
  110. this->SetOptionIfNotSet("CPACK_TEMPORARY_DIRECTORY", tmpDirectory);
  111. this->SetOptionIfNotSet("CPACK_TEMPORARY_INSTALL_DIRECTORY", tmpDirectory);
  112. this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PREFIX", pkgDirectory);
  113. this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_NAME", pkgFileName);
  114. this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PATH", pkgFilePath);
  115. this->SetOptionIfNotSet("CPACK_TEMPORARY_PACKAGE_FILE_NAME", tmpPkgFilePath);
  116. this->SetOptionIfNotSet("CPACK_INSTALL_DIRECTORY", this->GetInstallPath());
  117. this->SetOptionIfNotSet(
  118. "CPACK_NATIVE_INSTALL_DIRECTORY",
  119. cmsys::SystemTools::ConvertToOutputPath(this->GetInstallPath()));
  120. // Determine description of the package and set as CPack variable,
  121. // if not already set.
  122. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  123. "Look for: CPACK_PACKAGE_DESCRIPTION_FILE" << std::endl);
  124. cmValue descFileName = this->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
  125. if (descFileName && !this->GetOption("CPACK_PACKAGE_DESCRIPTION")) {
  126. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  127. "Look for: " << *descFileName << std::endl);
  128. if (!cmSystemTools::FileExists(*descFileName)) {
  129. cmCPackLogger(cmCPackLog::LOG_ERROR,
  130. "Cannot find description file name: ["
  131. << *descFileName << "]" << std::endl);
  132. return 0;
  133. }
  134. cmsys::ifstream ifs(descFileName->c_str());
  135. if (!ifs) {
  136. cmCPackLogger(cmCPackLog::LOG_ERROR,
  137. "Cannot open description file name: " << *descFileName
  138. << std::endl);
  139. return 0;
  140. }
  141. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  142. "Read description file: " << *descFileName << std::endl);
  143. std::ostringstream ostr;
  144. std::string line;
  145. while (ifs && cmSystemTools::GetLineFromStream(ifs, line)) {
  146. ostr << cmXMLSafe(line) << std::endl;
  147. }
  148. this->SetOption("CPACK_PACKAGE_DESCRIPTION", ostr.str());
  149. cmValue defFileName =
  150. this->GetOption("CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE");
  151. if (defFileName && (*defFileName == *descFileName)) {
  152. this->SetOption("CPACK_USED_DEFAULT_PACKAGE_DESCRIPTION_FILE", "ON");
  153. }
  154. }
  155. if (!this->GetOption("CPACK_PACKAGE_DESCRIPTION")) {
  156. cmCPackLogger(
  157. cmCPackLog::LOG_ERROR,
  158. "Project description not specified. Please specify "
  159. "CPACK_PACKAGE_DESCRIPTION or CPACK_PACKAGE_DESCRIPTION_FILE."
  160. << std::endl);
  161. return 0;
  162. }
  163. // Check algorithms for calculating the checksum of the package.
  164. cmValue algoSignatures = this->GetOption("CPACK_PACKAGE_CHECKSUM");
  165. if (cmNonempty(algoSignatures)) {
  166. cmList algoList{ algoSignatures };
  167. // Workout unique algorithms and duplicates for diagnostic purposes
  168. algoList.sort();
  169. // Store a copy since std::unique modifies the sequence
  170. cmList const sortedAlgoList = algoList;
  171. auto const newEnd = std::unique(algoList.begin(), algoList.end());
  172. if (newEnd != algoList.end()) {
  173. cmList duplicatesAlgoList;
  174. std::set_difference(sortedAlgoList.begin(), sortedAlgoList.end(),
  175. algoList.begin(), newEnd,
  176. std::back_inserter(duplicatesAlgoList));
  177. // Make sure to output duplicates a single time even if these appear more
  178. // than two times. Exploit the already sorted sequence to determine the
  179. // unique elements.
  180. duplicatesAlgoList.erase(
  181. std::unique(duplicatesAlgoList.begin(), duplicatesAlgoList.end()),
  182. duplicatesAlgoList.end());
  183. cmCPackLogger(cmCPackLog::LOG_WARNING,
  184. "Algorithm specified multiple times: "
  185. << duplicatesAlgoList.join(", ") << std::endl);
  186. }
  187. algoList.erase(newEnd, algoList.end());
  188. for (std::string const& algo : algoList) {
  189. if (!cmCryptoHash::New(algo)) {
  190. cmCPackLogger(cmCPackLog::LOG_ERROR,
  191. "Cannot recognize algorithm: " << algo << std::endl);
  192. return 0;
  193. }
  194. }
  195. }
  196. return 1;
  197. }
  198. int cmCPackGenerator::InstallProject()
  199. {
  200. cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Install projects" << std::endl);
  201. this->CleanTemporaryDirectory();
  202. std::string bareTempInstallDirectory =
  203. this->GetOption("CPACK_TEMPORARY_DIRECTORY");
  204. std::string tempInstallDirectory = bareTempInstallDirectory;
  205. cmValue v = this->GetOption("CPACK_SET_DESTDIR");
  206. bool setDestDir = v.IsOn() || cmIsInternallyOn(v);
  207. if (!setDestDir) {
  208. tempInstallDirectory += this->GetPackagingInstallPrefix();
  209. }
  210. int res = 1;
  211. if (!cmsys::SystemTools::MakeDirectory(bareTempInstallDirectory)) {
  212. cmCPackLogger(
  213. cmCPackLog::LOG_ERROR,
  214. "Problem creating temporary directory: "
  215. << (!tempInstallDirectory.empty() ? tempInstallDirectory : "(NULL)")
  216. << std::endl);
  217. return 0;
  218. }
  219. if (setDestDir) {
  220. std::string destDir = cmStrCat("DESTDIR=", tempInstallDirectory);
  221. cmSystemTools::PutEnv(destDir);
  222. } else {
  223. // Make sure there is no destdir
  224. cmSystemTools::PutEnv("DESTDIR=");
  225. }
  226. // prepare default created directory permissions
  227. mode_t default_dir_mode_v = 0;
  228. mode_t* default_dir_mode = nullptr;
  229. cmValue default_dir_install_permissions =
  230. this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
  231. if (cmNonempty(default_dir_install_permissions)) {
  232. cmList items{ default_dir_install_permissions };
  233. for (auto const& arg : items) {
  234. if (!cmFSPermissions::stringToModeT(arg, default_dir_mode_v)) {
  235. cmCPackLogger(cmCPackLog::LOG_ERROR,
  236. "Invalid permission value '"
  237. << arg
  238. << "'."
  239. " CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
  240. "value is invalid."
  241. << std::endl);
  242. return 0;
  243. }
  244. }
  245. default_dir_mode = &default_dir_mode_v;
  246. }
  247. // If the CPackConfig file sets CPACK_INSTALL_COMMANDS then run them
  248. // as listed
  249. if (!this->InstallProjectViaInstallCommands(setDestDir,
  250. tempInstallDirectory)) {
  251. return 0;
  252. }
  253. // If the CPackConfig file sets CPACK_INSTALL_SCRIPT(S) then run them
  254. // as listed
  255. if (!this->InstallProjectViaInstallScript(setDestDir,
  256. tempInstallDirectory)) {
  257. return 0;
  258. }
  259. // If the CPackConfig file sets CPACK_INSTALLED_DIRECTORIES
  260. // then glob it and copy it to CPACK_TEMPORARY_DIRECTORY
  261. // This is used in Source packaging
  262. if (!this->InstallProjectViaInstalledDirectories(
  263. setDestDir, tempInstallDirectory, default_dir_mode)) {
  264. return 0;
  265. }
  266. // If the project is a CMAKE project then run pre-install
  267. // and then read the cmake_install script to run it
  268. if (!this->InstallProjectViaInstallCMakeProjects(
  269. setDestDir, bareTempInstallDirectory, default_dir_mode)) {
  270. return 0;
  271. }
  272. // Run pre-build actions
  273. cmValue preBuildScripts = this->GetOption("CPACK_PRE_BUILD_SCRIPTS");
  274. if (preBuildScripts) {
  275. cmList const scripts{ preBuildScripts };
  276. for (auto const& script : scripts) {
  277. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  278. "Executing pre-build script: " << script << std::endl);
  279. if (!this->MakefileMap->ReadListFile(script)) {
  280. cmCPackLogger(cmCPackLog::LOG_ERROR,
  281. "The pre-build script not found: " << script
  282. << std::endl);
  283. return 0;
  284. }
  285. }
  286. }
  287. if (setDestDir) {
  288. cmSystemTools::PutEnv("DESTDIR=");
  289. }
  290. return res;
  291. }
  292. int cmCPackGenerator::InstallProjectViaInstallCommands(
  293. bool setDestDir, std::string const& tempInstallDirectory)
  294. {
  295. (void)setDestDir;
  296. cmValue installCommands = this->GetOption("CPACK_INSTALL_COMMANDS");
  297. if (cmNonempty(installCommands)) {
  298. std::string tempInstallDirectoryEnv =
  299. cmStrCat("CMAKE_INSTALL_PREFIX=", tempInstallDirectory);
  300. cmSystemTools::PutEnv(tempInstallDirectoryEnv);
  301. cmList installCommandsVector{ installCommands };
  302. for (std::string const& ic : installCommandsVector) {
  303. cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ic << std::endl);
  304. std::string output;
  305. int retVal = 1;
  306. bool resB = cmSystemTools::RunSingleCommand(
  307. ic, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
  308. cmDuration::zero());
  309. if (!resB || retVal) {
  310. std::string tmpFile = cmStrCat(
  311. this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/InstallOutput.log");
  312. cmGeneratedFileStream ofs(tmpFile);
  313. ofs << "# Run command: " << ic << std::endl
  314. << "# Output:" << std::endl
  315. << output << std::endl;
  316. cmCPackLogger(cmCPackLog::LOG_ERROR,
  317. "Problem running install command: "
  318. << ic << std::endl
  319. << "Please check " << tmpFile << " for errors"
  320. << std::endl);
  321. return 0;
  322. }
  323. }
  324. }
  325. return 1;
  326. }
  327. int cmCPackGenerator::InstallProjectViaInstalledDirectories(
  328. bool setDestDir, std::string const& tempInstallDirectory,
  329. mode_t const* default_dir_mode)
  330. {
  331. (void)setDestDir;
  332. (void)tempInstallDirectory;
  333. std::vector<cmsys::RegularExpression> ignoreFilesRegex;
  334. cmValue cpackIgnoreFiles = this->GetOption("CPACK_IGNORE_FILES");
  335. if (cpackIgnoreFiles) {
  336. cmList ignoreFilesRegexString{ cpackIgnoreFiles };
  337. for (std::string const& ifr : ignoreFilesRegexString) {
  338. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  339. "Create ignore files regex for: " << ifr << std::endl);
  340. ignoreFilesRegex.emplace_back(ifr);
  341. }
  342. }
  343. cmValue installDirectories = this->GetOption("CPACK_INSTALLED_DIRECTORIES");
  344. if (cmNonempty(installDirectories)) {
  345. cmList installDirectoriesList{ installDirectories };
  346. if (installDirectoriesList.size() % 2 != 0) {
  347. cmCPackLogger(
  348. cmCPackLog::LOG_ERROR,
  349. "CPACK_INSTALLED_DIRECTORIES should contain pairs of <directory> "
  350. "and "
  351. "<subdirectory>. The <subdirectory> can be '.' to be installed in "
  352. "the toplevel directory of installation."
  353. << std::endl);
  354. return 0;
  355. }
  356. cmList::iterator it;
  357. std::string const& tempDir = tempInstallDirectory;
  358. for (it = installDirectoriesList.begin();
  359. it != installDirectoriesList.end(); ++it) {
  360. std::vector<std::pair<std::string, std::string>> symlinkedFiles;
  361. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl);
  362. cmsys::Glob gl;
  363. std::string top = *it;
  364. ++it;
  365. std::string subdir = *it;
  366. std::string findExpr = cmStrCat(top, "/*");
  367. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  368. "- Install directory: " << top << std::endl);
  369. gl.RecurseOn();
  370. gl.SetRecurseListDirs(true);
  371. gl.SetRecurseThroughSymlinks(false);
  372. if (!gl.FindFiles(findExpr)) {
  373. cmCPackLogger(cmCPackLog::LOG_ERROR,
  374. "Cannot find any files in the installed directory"
  375. << std::endl);
  376. return 0;
  377. }
  378. this->files = gl.GetFiles();
  379. for (std::string const& gf : this->files) {
  380. bool skip = false;
  381. std::string inFile = gf;
  382. if (cmSystemTools::FileIsDirectory(gf) &&
  383. !cmSystemTools::FileIsSymlink(gf)) {
  384. inFile += '/';
  385. }
  386. for (cmsys::RegularExpression& reg : ignoreFilesRegex) {
  387. if (reg.find(inFile)) {
  388. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  389. "Ignore file: " << inFile << std::endl);
  390. skip = true;
  391. }
  392. }
  393. if (skip) {
  394. continue;
  395. }
  396. std::string filePath = cmStrCat(tempDir, '/', subdir, '/',
  397. cmSystemTools::RelativePath(top, gf));
  398. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  399. "Copy file: " << inFile << " -> " << filePath
  400. << std::endl);
  401. /* If the file is a symlink we will have to re-create it */
  402. if (cmSystemTools::FileIsSymlink(inFile)) {
  403. std::string targetFile;
  404. std::string inFileRelative =
  405. cmSystemTools::RelativePath(top, inFile);
  406. cmSystemTools::ReadSymlink(inFile, targetFile);
  407. symlinkedFiles.emplace_back(std::move(targetFile),
  408. std::move(inFileRelative));
  409. }
  410. /* If it is not a symlink then do a plain copy */
  411. else if (!(cmSystemTools::CopyFileIfDifferent(inFile, filePath) &&
  412. cmFileTimes::Copy(inFile, filePath))) {
  413. cmCPackLogger(cmCPackLog::LOG_ERROR,
  414. "Problem copying file: " << inFile << " -> "
  415. << filePath << std::endl);
  416. return 0;
  417. }
  418. }
  419. /* rebuild symlinks in the installed tree */
  420. if (!symlinkedFiles.empty()) {
  421. std::string goToDir = cmStrCat(tempDir, '/', subdir);
  422. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  423. "Change dir to: " << goToDir << std::endl);
  424. cmWorkingDirectory workdir(goToDir);
  425. if (workdir.Failed()) {
  426. cmCPackLogger(cmCPackLog::LOG_ERROR,
  427. workdir.GetError() << std::endl);
  428. return 0;
  429. }
  430. for (auto const& symlinked : symlinkedFiles) {
  431. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  432. "Will create a symlink: " << symlinked.second << "--> "
  433. << symlinked.first
  434. << std::endl);
  435. // make sure directory exists for symlink
  436. std::string destDir =
  437. cmSystemTools::GetFilenamePath(symlinked.second);
  438. if (!destDir.empty() &&
  439. !cmSystemTools::MakeDirectory(destDir, default_dir_mode)) {
  440. cmCPackLogger(cmCPackLog::LOG_ERROR,
  441. "Cannot create dir: "
  442. << destDir << "\nTrying to create symlink: "
  443. << symlinked.second << "--> " << symlinked.first
  444. << std::endl);
  445. }
  446. if (!cmSystemTools::CreateSymlink(symlinked.first,
  447. symlinked.second)) {
  448. cmCPackLogger(cmCPackLog::LOG_ERROR,
  449. "Cannot create symlink: "
  450. << symlinked.second << "--> " << symlinked.first
  451. << std::endl);
  452. return 0;
  453. }
  454. }
  455. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  456. "Going back to: " << workdir.GetOldDirectory()
  457. << std::endl);
  458. }
  459. }
  460. }
  461. return 1;
  462. }
  463. int cmCPackGenerator::InstallProjectViaInstallScript(
  464. bool setDestDir, std::string const& tempInstallDirectory)
  465. {
  466. cmValue cmakeScripts = this->GetOption("CPACK_INSTALL_SCRIPTS");
  467. {
  468. cmValue const cmakeScript = this->GetOption("CPACK_INSTALL_SCRIPT");
  469. if (cmakeScript && cmakeScripts) {
  470. cmCPackLogger(
  471. cmCPackLog::LOG_WARNING,
  472. "Both CPACK_INSTALL_SCRIPTS and CPACK_INSTALL_SCRIPT are set, "
  473. "the latter will be ignored."
  474. << std::endl);
  475. } else if (cmakeScript && !cmakeScripts) {
  476. cmakeScripts = cmakeScript;
  477. }
  478. }
  479. if (cmakeScripts && !cmakeScripts->empty()) {
  480. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  481. "- Install scripts: " << cmakeScripts << std::endl);
  482. cmList cmakeScriptsVector{ cmakeScripts };
  483. for (std::string const& installScript : cmakeScriptsVector) {
  484. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  485. "- Install script: " << installScript << std::endl);
  486. if (setDestDir) {
  487. // For DESTDIR based packaging, use the *project*
  488. // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
  489. // value of the project's CMAKE_INSTALL_PREFIX is sent in here as the
  490. // value of the CPACK_INSTALL_PREFIX variable.
  491. std::string dir;
  492. if (this->GetOption("CPACK_INSTALL_PREFIX")) {
  493. dir += *this->GetOption("CPACK_INSTALL_PREFIX");
  494. }
  495. this->SetOption("CMAKE_INSTALL_PREFIX", dir);
  496. cmCPackLogger(
  497. cmCPackLog::LOG_DEBUG,
  498. "- Using DESTDIR + CPACK_INSTALL_PREFIX... (this->SetOption)"
  499. << std::endl);
  500. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  501. "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
  502. << std::endl);
  503. } else {
  504. this->SetOption("CMAKE_INSTALL_PREFIX", tempInstallDirectory);
  505. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  506. "- Using non-DESTDIR install... (this->SetOption)"
  507. << std::endl);
  508. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  509. "- Setting CMAKE_INSTALL_PREFIX to '"
  510. << tempInstallDirectory << "'" << std::endl);
  511. }
  512. this->SetOptionIfNotSet("CMAKE_CURRENT_BINARY_DIR",
  513. tempInstallDirectory);
  514. this->SetOptionIfNotSet("CMAKE_CURRENT_SOURCE_DIR",
  515. tempInstallDirectory);
  516. bool res = this->MakefileMap->ReadListFile(installScript);
  517. if (cmSystemTools::GetErrorOccurredFlag() || !res) {
  518. return 0;
  519. }
  520. }
  521. }
  522. return 1;
  523. }
  524. int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
  525. bool setDestDir, std::string const& baseTempInstallDirectory,
  526. mode_t const* default_dir_mode)
  527. {
  528. cmValue cmakeProjects = this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS");
  529. cmValue cmakeGenerator = this->GetOption("CPACK_CMAKE_GENERATOR");
  530. std::string absoluteDestFiles;
  531. if (cmNonempty(cmakeProjects)) {
  532. if (!cmakeGenerator) {
  533. cmCPackLogger(cmCPackLog::LOG_ERROR,
  534. "CPACK_INSTALL_CMAKE_PROJECTS is specified, but "
  535. "CPACK_CMAKE_GENERATOR is not. CPACK_CMAKE_GENERATOR "
  536. "is required to install the project."
  537. << std::endl);
  538. return 0;
  539. }
  540. cmList cmakeProjectsList{ cmakeProjects };
  541. cmList::iterator it;
  542. for (it = cmakeProjectsList.begin(); it != cmakeProjectsList.end(); ++it) {
  543. if (it + 1 == cmakeProjectsList.end() ||
  544. it + 2 == cmakeProjectsList.end() ||
  545. it + 3 == cmakeProjectsList.end()) {
  546. cmCPackLogger(
  547. cmCPackLog::LOG_ERROR,
  548. "Not enough items on list: CPACK_INSTALL_CMAKE_PROJECTS. "
  549. "CPACK_INSTALL_CMAKE_PROJECTS should hold quadruplet of install "
  550. "directory, install project name, install component, and install "
  551. "subdirectory."
  552. << std::endl);
  553. return 0;
  554. }
  555. std::string installDirectory = *it;
  556. ++it;
  557. std::string installProjectName = *it;
  558. ++it;
  559. cmCPackInstallCMakeProject project;
  560. project.Directory = installDirectory;
  561. project.ProjectName = installProjectName;
  562. project.Component = *it;
  563. ++it;
  564. project.SubDirectory = *it;
  565. cmList componentsList;
  566. bool componentInstall = false;
  567. /*
  568. * We do a component install iff
  569. * - the CPack generator support component
  570. * - the user did not request Monolithic install
  571. * (this works at CPack time too)
  572. */
  573. if (this->SupportsComponentInstallation() &&
  574. !(this->IsOn("CPACK_MONOLITHIC_INSTALL"))) {
  575. // Determine the installation types for this project (if provided).
  576. std::string installTypesVar = "CPACK_" +
  577. cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES";
  578. cmValue installTypes = this->GetOption(installTypesVar);
  579. if (!installTypes.IsEmpty()) {
  580. cmList installTypesList{ installTypes };
  581. for (std::string const& installType : installTypesList) {
  582. project.InstallationTypes.push_back(
  583. this->GetInstallationType(project.ProjectName, installType));
  584. }
  585. }
  586. // Determine the set of components that will be used in this project
  587. std::string componentsVar =
  588. "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(project.Component);
  589. cmValue components = this->GetOption(componentsVar);
  590. if (!components.IsEmpty()) {
  591. componentsList.assign(components);
  592. for (auto const& comp : componentsList) {
  593. project.Components.push_back(
  594. this->GetComponent(project.ProjectName, comp));
  595. }
  596. componentInstall = true;
  597. }
  598. }
  599. if (componentsList.empty()) {
  600. componentsList.push_back(project.Component);
  601. }
  602. cmList buildConfigs;
  603. // Try get configuration names given via `-C` CLI option
  604. buildConfigs.assign(this->GetOption("CPACK_BUILD_CONFIG"));
  605. // Remove duplicates
  606. std::sort(buildConfigs.begin(), buildConfigs.end());
  607. buildConfigs.erase(std::unique(buildConfigs.begin(), buildConfigs.end()),
  608. buildConfigs.end());
  609. // Ensure we have at least one configuration.
  610. if (buildConfigs.empty()) {
  611. buildConfigs.emplace_back();
  612. }
  613. std::unique_ptr<cmGlobalGenerator> globalGenerator =
  614. this->MakefileMap->GetCMakeInstance()->CreateGlobalGenerator(
  615. *cmakeGenerator);
  616. if (!globalGenerator) {
  617. cmCPackLogger(cmCPackLog::LOG_ERROR,
  618. "Specified package generator not found. "
  619. "CPACK_CMAKE_GENERATOR value is invalid."
  620. << std::endl);
  621. return 0;
  622. }
  623. // set the global flag for unix style paths on cmSystemTools as
  624. // soon as the generator is set. This allows gmake to be used
  625. // on windows.
  626. cmSystemTools::SetForceUnixPaths(globalGenerator->GetForceUnixPaths());
  627. // Run the installation for the selected build configurations
  628. for (auto const& buildConfig : buildConfigs) {
  629. if (!this->RunPreinstallTarget(project.ProjectName, project.Directory,
  630. globalGenerator.get(), buildConfig)) {
  631. return 0;
  632. }
  633. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  634. "- Install project: " << project.ProjectName << " ["
  635. << buildConfig << ']'
  636. << std::endl);
  637. // Run the installation for each component
  638. for (std::string const& component : componentsList) {
  639. if (!this->InstallCMakeProject(
  640. setDestDir, project.Directory, baseTempInstallDirectory,
  641. default_dir_mode, component, componentInstall,
  642. project.SubDirectory, buildConfig, absoluteDestFiles)) {
  643. return 0;
  644. }
  645. }
  646. }
  647. this->CMakeProjects.emplace_back(std::move(project));
  648. }
  649. }
  650. this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES", absoluteDestFiles);
  651. return 1;
  652. }
  653. int cmCPackGenerator::RunPreinstallTarget(
  654. std::string const& installProjectName, std::string const& installDirectory,
  655. cmGlobalGenerator* globalGenerator, std::string const& buildConfig)
  656. {
  657. // Does this generator require pre-install?
  658. if (char const* preinstall = globalGenerator->GetPreinstallTargetName()) {
  659. std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
  660. preinstall, buildConfig, "", "", false);
  661. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  662. "- Install command: " << buildCommand << std::endl);
  663. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  664. "- Run preinstall target for: " << installProjectName
  665. << std::endl);
  666. std::string output;
  667. int retVal = 1;
  668. bool resB = cmSystemTools::RunSingleCommand(
  669. buildCommand, &output, &output, &retVal, installDirectory.c_str(),
  670. this->GeneratorVerbose, cmDuration::zero());
  671. if (!resB || retVal) {
  672. std::string tmpFile = cmStrCat(
  673. this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/PreinstallOutput.log");
  674. cmGeneratedFileStream ofs(tmpFile);
  675. ofs << "# Run command: " << buildCommand << std::endl
  676. << "# Directory: " << installDirectory << std::endl
  677. << "# Output:" << std::endl
  678. << output << std::endl;
  679. cmCPackLogger(cmCPackLog::LOG_ERROR,
  680. "Problem running install command: "
  681. << buildCommand << std::endl
  682. << "Please check " << tmpFile << " for errors"
  683. << std::endl);
  684. return 0;
  685. }
  686. }
  687. return 1;
  688. }
  689. int cmCPackGenerator::InstallCMakeProject(
  690. bool setDestDir, std::string const& installDirectory,
  691. std::string const& baseTempInstallDirectory, mode_t const* default_dir_mode,
  692. std::string const& component, bool componentInstall,
  693. std::string const& installSubDirectory, std::string const& buildConfig,
  694. std::string& absoluteDestFiles)
  695. {
  696. std::string tempInstallDirectory = baseTempInstallDirectory;
  697. std::string installFile = installDirectory + "/cmake_install.cmake";
  698. if (componentInstall) {
  699. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  700. "- Install component: " << component << std::endl);
  701. }
  702. cmake cm(cmake::RoleScript, cmState::CPack);
  703. cm.GetCurrentSnapshot().SetDefaultDefinitions();
  704. cm.AddCMakePaths();
  705. cm.SetProgressCallback([this](std::string const& msg, float prog) {
  706. this->DisplayVerboseOutput(msg, prog);
  707. });
  708. cm.SetTrace(this->Trace);
  709. cm.SetTraceExpand(this->TraceExpand);
  710. cmGlobalGenerator gg(&cm);
  711. cmMakefile mf(&gg, cm.GetCurrentSnapshot());
  712. if (!installSubDirectory.empty() && installSubDirectory != "/" &&
  713. installSubDirectory != ".") {
  714. tempInstallDirectory += installSubDirectory;
  715. }
  716. if (componentInstall) {
  717. tempInstallDirectory += "/";
  718. // Some CPack generators would rather chose
  719. // the local installation directory suffix.
  720. // Some (e.g. RPM) use
  721. // one install directory for each component **GROUP**
  722. // instead of the default
  723. // one install directory for each component.
  724. tempInstallDirectory += this->GetComponentInstallDirNameSuffix(component);
  725. if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
  726. tempInstallDirectory += "/";
  727. tempInstallDirectory += *this->GetOption("CPACK_PACKAGE_FILE_NAME");
  728. }
  729. }
  730. cmValue default_dir_inst_permissions =
  731. this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
  732. if (cmNonempty(default_dir_inst_permissions)) {
  733. mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS",
  734. default_dir_inst_permissions);
  735. }
  736. if (!setDestDir) {
  737. tempInstallDirectory += this->GetPackagingInstallPrefix();
  738. }
  739. if (setDestDir) {
  740. // For DESTDIR based packaging, use the *project*
  741. // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
  742. // value of the project's CMAKE_INSTALL_PREFIX is sent in here as
  743. // the value of the CPACK_INSTALL_PREFIX variable.
  744. //
  745. // If DESTDIR has been 'internally set ON' this means that
  746. // the underlying CPack specific generator did ask for that
  747. // In this case we may override CPACK_INSTALL_PREFIX with
  748. // CPACK_PACKAGING_INSTALL_PREFIX
  749. // I know this is tricky and awkward but it's the price for
  750. // CPACK_SET_DESTDIR backward compatibility.
  751. if (cmIsInternallyOn(this->GetOption("CPACK_SET_DESTDIR"))) {
  752. this->SetOption("CPACK_INSTALL_PREFIX",
  753. this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"));
  754. }
  755. std::string dir;
  756. if (this->GetOption("CPACK_INSTALL_PREFIX")) {
  757. dir += *this->GetOption("CPACK_INSTALL_PREFIX");
  758. }
  759. mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir);
  760. cmCPackLogger(
  761. cmCPackLog::LOG_DEBUG,
  762. "- Using DESTDIR + CPACK_INSTALL_PREFIX... (mf.AddDefinition)"
  763. << std::endl);
  764. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  765. "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
  766. << std::endl);
  767. // Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory
  768. // exists:
  769. //
  770. if (cmHasLiteralPrefix(dir, "/")) {
  771. dir = tempInstallDirectory + dir;
  772. } else {
  773. dir = tempInstallDirectory + "/" + dir;
  774. }
  775. /*
  776. * We must re-set DESTDIR for each component
  777. * We must not add the CPACK_INSTALL_PREFIX part because
  778. * it will be added using the override of CMAKE_INSTALL_PREFIX
  779. * The main reason for this awkward trick is that
  780. * are using DESTDIR for 2 different reasons:
  781. * - Because it was asked by the CPack Generator or the user
  782. * using CPACK_SET_DESTDIR
  783. * - Because it was already used for component install
  784. * in order to put things in subdirs...
  785. */
  786. cmSystemTools::PutEnv("DESTDIR=" + tempInstallDirectory);
  787. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  788. "- Creating directory: '" << dir << "'" << std::endl);
  789. if (!cmsys::SystemTools::MakeDirectory(dir, default_dir_mode)) {
  790. cmCPackLogger(cmCPackLog::LOG_ERROR,
  791. "Problem creating temporary directory: " << dir
  792. << std::endl);
  793. return 0;
  794. }
  795. } else {
  796. mf.AddDefinition("CMAKE_INSTALL_PREFIX", tempInstallDirectory);
  797. if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory,
  798. default_dir_mode)) {
  799. cmCPackLogger(cmCPackLog::LOG_ERROR,
  800. "Problem creating temporary directory: "
  801. << tempInstallDirectory << std::endl);
  802. return 0;
  803. }
  804. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  805. "- Using non-DESTDIR install... (mf.AddDefinition)"
  806. << std::endl);
  807. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  808. "- Setting CMAKE_INSTALL_PREFIX to '" << tempInstallDirectory
  809. << "'" << std::endl);
  810. }
  811. if (!buildConfig.empty()) {
  812. mf.AddDefinition("BUILD_TYPE", buildConfig);
  813. }
  814. std::string installComponentLowerCase = cmSystemTools::LowerCase(component);
  815. if (installComponentLowerCase != "all") {
  816. mf.AddDefinition("CMAKE_INSTALL_COMPONENT", component);
  817. }
  818. // strip on TRUE, ON, 1, one or several file names, but not on
  819. // FALSE, OFF, 0 and an empty string
  820. if (!this->GetOption("CPACK_STRIP_FILES").IsOff()) {
  821. mf.AddDefinition("CMAKE_INSTALL_DO_STRIP", "1");
  822. }
  823. // Remember the list of files before installation
  824. // of the current component (if we are in component install)
  825. std::string const& InstallPrefix = tempInstallDirectory;
  826. std::vector<std::string> filesBefore;
  827. std::string findExpr = tempInstallDirectory;
  828. if (componentInstall) {
  829. cmsys::Glob glB;
  830. findExpr += "/*";
  831. glB.RecurseOn();
  832. glB.SetRecurseListDirs(true);
  833. glB.SetRecurseThroughSymlinks(false);
  834. glB.FindFiles(findExpr);
  835. filesBefore = glB.GetFiles();
  836. std::sort(filesBefore.begin(), filesBefore.end());
  837. }
  838. // If CPack was asked to warn on ABSOLUTE INSTALL DESTINATION
  839. // then forward request to cmake_install.cmake script
  840. if (this->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")) {
  841. mf.AddDefinition("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
  842. }
  843. // If current CPack generator does not support
  844. // ABSOLUTE INSTALL DESTINATION or CPack has been asked for
  845. // then ask cmake_install.cmake script to error out
  846. // as soon as it occurs (before installing file)
  847. if (!this->SupportsAbsoluteDestination() ||
  848. this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) {
  849. mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
  850. }
  851. cmList custom_variables{ this->MakefileMap->GetDefinition(
  852. "CPACK_CUSTOM_INSTALL_VARIABLES") };
  853. for (auto const& custom_variable : custom_variables) {
  854. std::string value;
  855. auto i = custom_variable.find('=');
  856. if (i != std::string::npos) {
  857. value = custom_variable.substr(i + 1);
  858. }
  859. mf.AddDefinition(custom_variable.substr(0, i), value);
  860. }
  861. // do installation
  862. bool res = mf.ReadListFile(installFile);
  863. // forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
  864. // to CPack (may be used by generators like CPack RPM or DEB)
  865. // in order to transparently handle ABSOLUTE PATH
  866. if (cmValue def = mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
  867. mf.AddDefinition("CPACK_ABSOLUTE_DESTINATION_FILES", *def);
  868. }
  869. // Now rebuild the list of files after installation
  870. // of the current component (if we are in component install)
  871. if (componentInstall) {
  872. cmsys::Glob glA;
  873. glA.RecurseOn();
  874. glA.SetRecurseListDirs(true);
  875. glA.SetRecurseThroughSymlinks(false);
  876. glA.FindFiles(findExpr);
  877. std::vector<std::string> filesAfter = glA.GetFiles();
  878. std::sort(filesAfter.begin(), filesAfter.end());
  879. std::vector<std::string>::iterator diff;
  880. std::vector<std::string> result(filesAfter.size());
  881. diff = std::set_difference(filesAfter.begin(), filesAfter.end(),
  882. filesBefore.begin(), filesBefore.end(),
  883. result.begin());
  884. std::vector<std::string>::iterator fit;
  885. std::string localFileName;
  886. // Populate the File field of each component
  887. for (fit = result.begin(); fit != diff; ++fit) {
  888. localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit);
  889. localFileName =
  890. localFileName.substr(localFileName.find_first_not_of('/'));
  891. this->Components[component].Files.push_back(localFileName);
  892. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  893. "Adding file <" << localFileName << "> to component <"
  894. << component << ">" << std::endl);
  895. }
  896. }
  897. if (cmValue d = mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
  898. if (!absoluteDestFiles.empty()) {
  899. absoluteDestFiles += ";";
  900. }
  901. absoluteDestFiles += *d;
  902. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  903. "Got some ABSOLUTE DESTINATION FILES: " << absoluteDestFiles
  904. << std::endl);
  905. // define component specific var
  906. if (componentInstall) {
  907. std::string absoluteDestFileComponent =
  908. std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
  909. this->GetComponentInstallSuffix(component);
  910. if (cmValue v = this->GetOption(absoluteDestFileComponent)) {
  911. std::string absoluteDestFilesListComponent = cmStrCat(*v, ';', *d);
  912. this->SetOption(absoluteDestFileComponent,
  913. absoluteDestFilesListComponent);
  914. } else {
  915. this->SetOption(absoluteDestFileComponent,
  916. mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"));
  917. }
  918. }
  919. }
  920. if (cmSystemTools::GetErrorOccurredFlag() || !res) {
  921. return 0;
  922. }
  923. return 1;
  924. }
  925. bool cmCPackGenerator::GenerateChecksumFile(cmCryptoHash& crypto,
  926. cm::string_view filename) const
  927. {
  928. std::string packageFileName =
  929. cmStrCat(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"), '/', filename);
  930. std::string hashFile = cmStrCat(
  931. packageFileName, "." + cmSystemTools::LowerCase(crypto.GetHashAlgoName()));
  932. cmsys::ofstream outF(hashFile.c_str());
  933. if (!outF) {
  934. cmCPackLogger(cmCPackLog::LOG_ERROR,
  935. "Cannot create checksum file: " << hashFile << std::endl);
  936. return false;
  937. }
  938. outF << crypto.HashFile(packageFileName) << " " << filename << "\n";
  939. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  940. "- checksum file: " << hashFile << " generated." << std::endl);
  941. return true;
  942. }
  943. bool cmCPackGenerator::CopyPackageFile(std::string const& srcFilePath,
  944. cm::string_view filename) const
  945. {
  946. std::string destFilePath =
  947. cmStrCat(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"), '/', filename);
  948. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  949. "Copy final package(s): "
  950. << (!srcFilePath.empty() ? srcFilePath : "(NULL)") << " to "
  951. << (!destFilePath.empty() ? destFilePath : "(NULL)")
  952. << std::endl);
  953. if (!cmSystemTools::CopyFileIfDifferent(srcFilePath, destFilePath)) {
  954. cmCPackLogger(
  955. cmCPackLog::LOG_ERROR,
  956. "Problem copying the package: "
  957. << (!srcFilePath.empty() ? srcFilePath : "(NULL)") << " to "
  958. << (!destFilePath.empty() ? destFilePath : "(NULL)") << std::endl);
  959. return false;
  960. }
  961. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  962. "- package: " << destFilePath << " generated." << std::endl);
  963. return true;
  964. }
  965. bool cmCPackGenerator::ReadListFile(char const* moduleName)
  966. {
  967. bool retval;
  968. std::string fullPath = this->MakefileMap->GetModulesFile(moduleName);
  969. retval = this->MakefileMap->ReadListFile(fullPath);
  970. // include FATAL_ERROR and ERROR in the return status
  971. retval = retval && (!cmSystemTools::GetErrorOccurredFlag());
  972. return retval;
  973. }
  974. template <typename ValueType>
  975. void cmCPackGenerator::StoreOptionIfNotSet(std::string const& op,
  976. ValueType value)
  977. {
  978. cmValue def = this->MakefileMap->GetDefinition(op);
  979. if (cmNonempty(def)) {
  980. return;
  981. }
  982. this->StoreOption(op, value);
  983. }
  984. void cmCPackGenerator::SetOptionIfNotSet(std::string const& op,
  985. char const* value)
  986. {
  987. this->StoreOptionIfNotSet(op, value);
  988. }
  989. void cmCPackGenerator::SetOptionIfNotSet(std::string const& op, cmValue value)
  990. {
  991. this->StoreOptionIfNotSet(op, value);
  992. }
  993. template <typename ValueType>
  994. void cmCPackGenerator::StoreOption(std::string const& op, ValueType value)
  995. {
  996. if (!value) {
  997. this->MakefileMap->RemoveDefinition(op);
  998. return;
  999. }
  1000. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  1001. this->GetNameOfClass() << "::SetOption(" << op << ", " << value
  1002. << ")" << std::endl);
  1003. this->MakefileMap->AddDefinition(op, value);
  1004. }
  1005. void cmCPackGenerator::SetOption(std::string const& op, char const* value)
  1006. {
  1007. this->StoreOption(op, value);
  1008. }
  1009. void cmCPackGenerator::SetOption(std::string const& op, cmValue value)
  1010. {
  1011. this->StoreOption(op, value);
  1012. }
  1013. int cmCPackGenerator::DoPackage()
  1014. {
  1015. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  1016. "Create package using " << this->Name << std::endl);
  1017. // Prepare CPack internal name and check
  1018. // values for many CPACK_xxx vars
  1019. if (!this->PrepareNames()) {
  1020. return 0;
  1021. }
  1022. // Digest Component grouping specification
  1023. if (!this->PrepareGroupingKind()) {
  1024. return 0;
  1025. }
  1026. // Possibly remove the top-level packaging-directory.
  1027. if (this->GetOption("CPACK_REMOVE_TOPLEVEL_DIRECTORY").IsOn()) {
  1028. cmValue toplevelDirectory = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
  1029. if (toplevelDirectory && cmSystemTools::FileExists(*toplevelDirectory)) {
  1030. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  1031. "Remove toplevel directory: " << *toplevelDirectory
  1032. << std::endl);
  1033. if (!cmSystemTools::RepeatedRemoveDirectory(*toplevelDirectory)) {
  1034. cmCPackLogger(cmCPackLog::LOG_ERROR,
  1035. "Problem removing toplevel directory: "
  1036. << *toplevelDirectory << std::endl);
  1037. return 0;
  1038. }
  1039. }
  1040. }
  1041. // Install the project (to the temporary install-directory).
  1042. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  1043. "About to install project " << std::endl);
  1044. if (!this->InstallProject()) {
  1045. return 0;
  1046. }
  1047. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Done install project " << std::endl);
  1048. // Determine the temporary directory whose content shall be packaged.
  1049. cmValue tempDirectory = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
  1050. // Determine and store internally the list of files to be installed.
  1051. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl);
  1052. {
  1053. cmsys::Glob gl;
  1054. std::string findExpr = cmStrCat(tempDirectory, "/*");
  1055. gl.RecurseOn();
  1056. gl.SetRecurseListDirs(true);
  1057. gl.SetRecurseThroughSymlinks(false);
  1058. if (!gl.FindFiles(findExpr)) {
  1059. cmCPackLogger(cmCPackLog::LOG_ERROR,
  1060. "Cannot find any files in the packaging tree"
  1061. << std::endl);
  1062. return 0;
  1063. }
  1064. this->files = gl.GetFiles();
  1065. }
  1066. // Determine and store internally the directory that shall be packaged.
  1067. if (this->GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY").IsOn()) {
  1068. tempDirectory = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
  1069. }
  1070. this->toplevel = *tempDirectory;
  1071. cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Create package" << std::endl);
  1072. // Determine and store internally the list of packages to create.
  1073. // Note: Initially, this only contains a single package.
  1074. {
  1075. cmValue tempPackageFileName =
  1076. this->GetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME");
  1077. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  1078. "Package files to: "
  1079. << (tempPackageFileName ? *tempPackageFileName : "(NULL)")
  1080. << std::endl);
  1081. if (tempPackageFileName &&
  1082. cmSystemTools::FileExists(*tempPackageFileName)) {
  1083. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  1084. "Remove old package file" << std::endl);
  1085. cmSystemTools::RemoveFile(*tempPackageFileName);
  1086. }
  1087. this->packageFileNames.clear();
  1088. /* Put at least one file name into the list of
  1089. * wanted packageFileNames. The specific generator
  1090. * may update this during PackageFiles.
  1091. * (either putting several names or updating the provided one)
  1092. */
  1093. this->packageFileNames.emplace_back(tempPackageFileName);
  1094. }
  1095. // Do package the files (using the derived CPack generators.
  1096. { // scope that enables package generators to run internal scripts with
  1097. // latest CMake policies enabled
  1098. cmMakefile::ScopePushPop pp{ this->MakefileMap };
  1099. this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion(),
  1100. std::string());
  1101. if (!this->PackageFiles() || cmSystemTools::GetErrorOccurredFlag()) {
  1102. cmCPackLogger(cmCPackLog::LOG_ERROR,
  1103. "Problem compressing the directory" << std::endl);
  1104. return 0;
  1105. }
  1106. }
  1107. // Run post-build actions
  1108. cmValue postBuildScripts = this->GetOption("CPACK_POST_BUILD_SCRIPTS");
  1109. if (postBuildScripts) {
  1110. this->MakefileMap->AddDefinition(
  1111. "CPACK_PACKAGE_FILES", cmList::to_string(this->packageFileNames));
  1112. cmList const scripts{ postBuildScripts };
  1113. for (auto const& script : scripts) {
  1114. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  1115. "Executing post-build script: " << script << std::endl);
  1116. if (!this->MakefileMap->ReadListFile(script)) {
  1117. cmCPackLogger(cmCPackLog::LOG_ERROR,
  1118. "The post-build script not found: " << script
  1119. << std::endl);
  1120. return 0;
  1121. }
  1122. }
  1123. }
  1124. /* Prepare checksum algorithm*/
  1125. cmValue algoSignatures = this->GetOption("CPACK_PACKAGE_CHECKSUM");
  1126. std::vector<std::unique_ptr<cmCryptoHash>> crypto;
  1127. if (cmNonempty(algoSignatures)) {
  1128. cmList algoList{ algoSignatures };
  1129. // Keep unique algorithms since generating the same checksum multiple times
  1130. // is not meaningful.
  1131. algoList.remove_duplicates();
  1132. crypto.reserve(algoList.size());
  1133. for (std::string const& algo : algoList) {
  1134. if (std::unique_ptr<cmCryptoHash> hash = cmCryptoHash::New(algo)) {
  1135. crypto.push_back(std::move(hash));
  1136. }
  1137. }
  1138. }
  1139. /*
  1140. * Copy the generated packages to final destination
  1141. * - there may be several of them
  1142. * - the initially provided name may have changed
  1143. * (because the specific generator did 'normalize' it)
  1144. */
  1145. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  1146. "Copying final package(s) [" << this->packageFileNames.size()
  1147. << "]:" << std::endl);
  1148. /* now copy package one by one */
  1149. for (std::string const& pkgFileName : this->packageFileNames) {
  1150. std::string filename(cmSystemTools::GetFilenameName(pkgFileName));
  1151. if (!this->CopyPackageFile(pkgFileName, filename)) {
  1152. return 0;
  1153. }
  1154. /* Generate checksum files */
  1155. for (std::unique_ptr<cmCryptoHash> const& hash : crypto) {
  1156. if (!this->GenerateChecksumFile(*hash, filename)) {
  1157. return 0;
  1158. }
  1159. }
  1160. }
  1161. return 1;
  1162. }
  1163. int cmCPackGenerator::Initialize(std::string const& name, cmMakefile* mf)
  1164. {
  1165. this->MakefileMap = mf;
  1166. this->Name = name;
  1167. // set the running generator name
  1168. this->SetOption("CPACK_GENERATOR", this->Name);
  1169. // Load the project specific config file
  1170. cmValue config = this->GetOption("CPACK_PROJECT_CONFIG_FILE");
  1171. if (config) {
  1172. if (!mf->ReadListFile(*config)) {
  1173. cmCPackLogger(cmCPackLog::LOG_WARNING,
  1174. "CPACK_PROJECT_CONFIG_FILE not found: " << *config
  1175. << std::endl);
  1176. }
  1177. }
  1178. int result = this->InitializeInternal();
  1179. if (cmSystemTools::GetErrorOccurredFlag()) {
  1180. return 0;
  1181. }
  1182. // If a generator subclass did not already set this option in its
  1183. // InitializeInternal implementation, and the project did not already set
  1184. // it, the default value should be:
  1185. this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/");
  1186. // Special handling for CPACK_TEMPORARY[_INSTALL]_DIRECTORY.
  1187. // Note: Make sure that if only one of these variables is already set, the
  1188. // other will be set to the same value. If they are set to different
  1189. // values, however, we cannot proceed.
  1190. cmValue val1 =
  1191. this->MakefileMap->GetDefinition("CPACK_TEMPORARY_INSTALL_DIRECTORY");
  1192. cmValue val2 = this->MakefileMap->GetDefinition("CPACK_TEMPORARY_DIRECTORY");
  1193. if (val1 != val2) {
  1194. // One variable is set but not the other?
  1195. // Then set the other variable to the same value (even if it is invalid).
  1196. if (val1.Get() && !val2.Get()) {
  1197. cmCPackLogger(cmCPackLog::LOG_WARNING,
  1198. "Variable CPACK_TEMPORARY_INSTALL_DIRECTORY is set, which "
  1199. "is not recommended. For backwards-compatibility we will "
  1200. "also set CPACK_TEMPORARY_DIRECTORY to the same value and "
  1201. "proceed. However, better set neither of them!"
  1202. << std::endl);
  1203. this->MakefileMap->AddDefinition("CPACK_TEMPORARY_DIRECTORY", val1);
  1204. } else if (!val1.Get() && val2.Get()) {
  1205. cmCPackLogger(
  1206. cmCPackLog::LOG_WARNING,
  1207. "Variable CPACK_TEMPORARY_DIRECTORY is set, which is not recommended."
  1208. << std::endl);
  1209. cmCPackLogger(
  1210. cmCPackLog::LOG_DEBUG,
  1211. "For backwards-compatibility we will set "
  1212. "CPACK_TEMPORARY_INSTALL_DIRECTORY to the same value as "
  1213. "CPACK_TEMPORARY_DIRECTORY. However, better set neither of them!"
  1214. << std::endl);
  1215. this->MakefileMap->AddDefinition("CPACK_TEMPORARY_INSTALL_DIRECTORY",
  1216. val2);
  1217. } else {
  1218. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  1219. "CPACK_TEMPORARY_INSTALL_DIRECTORY is already set to: "
  1220. << val1 << std::endl);
  1221. cmCPackLogger(
  1222. cmCPackLog::LOG_VERBOSE,
  1223. "CPACK_TEMPORARY_DIRECTORY is already set to: " << val2 << std::endl);
  1224. cmCPackLogger(cmCPackLog::LOG_ERROR,
  1225. "Variables CPACK_TEMPORARY_DIRECTORY and "
  1226. "CPACK_TEMPORARY_INSTALL_DIRECTORY are both set but to "
  1227. "different values. This is not supported!"
  1228. << std::endl);
  1229. return 0;
  1230. }
  1231. } else if (val1.Get() && val2.Get()) {
  1232. cmCPackLogger(cmCPackLog::LOG_WARNING,
  1233. "Variables CPACK_TEMPORARY_DIRECTORY and "
  1234. "CPACK_TEMPORARY_INSTALL_DIRECTORY are both set. Because "
  1235. "they are set to the same value we can still proceed. "
  1236. "However, better set neither of them!"
  1237. << std::endl);
  1238. }
  1239. return result;
  1240. }
  1241. int cmCPackGenerator::InitializeInternal()
  1242. {
  1243. return 1;
  1244. }
  1245. bool cmCPackGenerator::IsSet(std::string const& name) const
  1246. {
  1247. return this->MakefileMap->IsSet(name);
  1248. }
  1249. cmValue cmCPackGenerator::GetOptionIfSet(std::string const& name) const
  1250. {
  1251. cmValue ret = this->MakefileMap->GetDefinition(name);
  1252. if (!ret || ret->empty() || cmIsNOTFOUND(*ret)) {
  1253. return {};
  1254. }
  1255. return ret;
  1256. }
  1257. bool cmCPackGenerator::IsOn(std::string const& name) const
  1258. {
  1259. return this->GetOption(name).IsOn();
  1260. }
  1261. bool cmCPackGenerator::IsSetToOff(std::string const& op) const
  1262. {
  1263. cmValue ret = this->MakefileMap->GetDefinition(op);
  1264. if (cmNonempty(ret)) {
  1265. return ret.IsOff();
  1266. }
  1267. return false;
  1268. }
  1269. bool cmCPackGenerator::IsSetToEmpty(std::string const& op) const
  1270. {
  1271. cmValue ret = this->MakefileMap->GetDefinition(op);
  1272. if (ret) {
  1273. return ret->empty();
  1274. }
  1275. return false;
  1276. }
  1277. cmValue cmCPackGenerator::GetOption(std::string const& op) const
  1278. {
  1279. cmValue ret = this->MakefileMap->GetDefinition(op);
  1280. if (!ret) {
  1281. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  1282. "Warning, GetOption return NULL for: " << op << std::endl);
  1283. }
  1284. return ret;
  1285. }
  1286. std::vector<std::string> cmCPackGenerator::GetOptions() const
  1287. {
  1288. return this->MakefileMap->GetDefinitions();
  1289. }
  1290. int cmCPackGenerator::PackageFiles()
  1291. {
  1292. return 0;
  1293. }
  1294. char const* cmCPackGenerator::GetInstallPath()
  1295. {
  1296. if (!this->InstallPath.empty()) {
  1297. return this->InstallPath.c_str();
  1298. }
  1299. #if defined(_WIN32) && !defined(__CYGWIN__)
  1300. std::string prgfiles;
  1301. std::string sysDrive;
  1302. if (cmsys::SystemTools::GetEnv("ProgramFiles", prgfiles)) {
  1303. this->InstallPath = prgfiles;
  1304. } else if (cmsys::SystemTools::GetEnv("SystemDrive", sysDrive)) {
  1305. this->InstallPath = cmStrCat(sysDrive, "/Program Files");
  1306. } else {
  1307. this->InstallPath = "c:/Program Files";
  1308. }
  1309. this->InstallPath += "/";
  1310. this->InstallPath += this->GetOption("CPACK_PACKAGE_NAME");
  1311. this->InstallPath += "-";
  1312. this->InstallPath += this->GetOption("CPACK_PACKAGE_VERSION");
  1313. #elif defined(__HAIKU__)
  1314. char dir[B_PATH_NAME_LENGTH];
  1315. if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
  1316. B_OK) {
  1317. this->InstallPath = dir;
  1318. } else {
  1319. this->InstallPath = "/boot/system";
  1320. }
  1321. #else
  1322. this->InstallPath = "/usr/local/";
  1323. #endif
  1324. return this->InstallPath.c_str();
  1325. }
  1326. char const* cmCPackGenerator::GetPackagingInstallPrefix()
  1327. {
  1328. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  1329. "GetPackagingInstallPrefix: '"
  1330. << this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX") << "'"
  1331. << std::endl);
  1332. return this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX")->c_str();
  1333. }
  1334. std::string cmCPackGenerator::FindTemplate(cm::string_view name,
  1335. cm::optional<cm::string_view> alt)
  1336. {
  1337. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  1338. "Look for template: " << name << std::endl);
  1339. // Search CMAKE_MODULE_PATH for a custom template.
  1340. std::string ffile = this->MakefileMap->GetModulesFile(name);
  1341. if (ffile.empty()) {
  1342. // Fall back to our internal builtin default.
  1343. ffile = cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/Internal/CPack/",
  1344. alt ? *alt : ""_s, name);
  1345. cmSystemTools::ConvertToUnixSlashes(ffile);
  1346. if (!cmSystemTools::FileExists(ffile)) {
  1347. ffile.clear();
  1348. }
  1349. }
  1350. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  1351. "Found template: " << ffile << std::endl);
  1352. return ffile;
  1353. }
  1354. bool cmCPackGenerator::ConfigureString(std::string const& inString,
  1355. std::string& outString)
  1356. {
  1357. this->MakefileMap->ConfigureString(inString, outString, true, false);
  1358. return true;
  1359. }
  1360. bool cmCPackGenerator::ConfigureFile(std::string const& inName,
  1361. std::string const& outName,
  1362. bool copyOnly /* = false */)
  1363. {
  1364. return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
  1365. false) == 1;
  1366. }
  1367. int cmCPackGenerator::CleanTemporaryDirectory()
  1368. {
  1369. std::string tempInstallDirectory =
  1370. this->GetOption("CPACK_TEMPORARY_DIRECTORY");
  1371. if (cmsys::SystemTools::FileExists(tempInstallDirectory)) {
  1372. cmCPackLogger(cmCPackLog::LOG_OUTPUT,
  1373. "- Clean temporary : " << tempInstallDirectory << std::endl);
  1374. if (!cmSystemTools::RepeatedRemoveDirectory(tempInstallDirectory)) {
  1375. cmCPackLogger(cmCPackLog::LOG_ERROR,
  1376. "Problem removing temporary directory: "
  1377. << tempInstallDirectory << std::endl);
  1378. return 0;
  1379. }
  1380. }
  1381. return 1;
  1382. }
  1383. cmInstalledFile const* cmCPackGenerator::GetInstalledFile(
  1384. std::string const& name) const
  1385. {
  1386. cmake const* cm = this->MakefileMap->GetCMakeInstance();
  1387. return cm->GetInstalledFile(name);
  1388. }
  1389. int cmCPackGenerator::PrepareGroupingKind()
  1390. {
  1391. // find a component package method specified by the user
  1392. ComponentPackageMethod method = UNKNOWN_COMPONENT_PACKAGE_METHOD;
  1393. if (this->GetOption("CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE")) {
  1394. method = ONE_PACKAGE;
  1395. }
  1396. if (this->GetOption("CPACK_COMPONENTS_IGNORE_GROUPS")) {
  1397. method = ONE_PACKAGE_PER_COMPONENT;
  1398. }
  1399. if (this->GetOption("CPACK_COMPONENTS_ONE_PACKAGE_PER_GROUP")) {
  1400. method = ONE_PACKAGE_PER_GROUP;
  1401. }
  1402. // Second way to specify grouping
  1403. std::string groupingType = *this->GetOption("CPACK_COMPONENTS_GROUPING");
  1404. if (!groupingType.empty()) {
  1405. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  1406. "[" << this->Name << "]"
  1407. << " requested component grouping = " << groupingType
  1408. << std::endl);
  1409. if (groupingType == "ALL_COMPONENTS_IN_ONE") {
  1410. method = ONE_PACKAGE;
  1411. } else if (groupingType == "IGNORE") {
  1412. method = ONE_PACKAGE_PER_COMPONENT;
  1413. } else if (groupingType == "ONE_PER_GROUP") {
  1414. method = ONE_PACKAGE_PER_GROUP;
  1415. } else {
  1416. cmCPackLogger(
  1417. cmCPackLog::LOG_WARNING,
  1418. "[" << this->Name << "]"
  1419. << " requested component grouping type <" << groupingType
  1420. << "> UNKNOWN not in (ALL_COMPONENTS_IN_ONE,IGNORE,ONE_PER_GROUP)"
  1421. << std::endl);
  1422. }
  1423. }
  1424. // Some components were defined but NO group
  1425. // fallback to default if not group based
  1426. if (method == ONE_PACKAGE_PER_GROUP && this->ComponentGroups.empty() &&
  1427. !this->Components.empty()) {
  1428. if (this->componentPackageMethod == ONE_PACKAGE) {
  1429. method = ONE_PACKAGE;
  1430. } else {
  1431. method = ONE_PACKAGE_PER_COMPONENT;
  1432. }
  1433. cmCPackLogger(
  1434. cmCPackLog::LOG_WARNING,
  1435. "[" << this->Name << "]"
  1436. << " One package per component group requested, "
  1437. << "but NO component groups exist: Ignoring component group."
  1438. << std::endl);
  1439. }
  1440. // if user specified packaging method, override the default packaging
  1441. // method
  1442. if (method != UNKNOWN_COMPONENT_PACKAGE_METHOD) {
  1443. this->componentPackageMethod = method;
  1444. }
  1445. char const* method_names[] = { "ALL_COMPONENTS_IN_ONE", "IGNORE",
  1446. "ONE_PER_GROUP", "UNKNOWN" };
  1447. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  1448. "[" << this->Name << "]"
  1449. << " requested component grouping = "
  1450. << method_names[this->componentPackageMethod]
  1451. << std::endl);
  1452. return 1;
  1453. }
  1454. std::string cmCPackGenerator::GetSanitizedDirOrFileName(
  1455. std::string const& name, bool isFullName) const
  1456. {
  1457. if (isFullName) {
  1458. #ifdef _WIN32
  1459. // Given name matches a reserved name (on Windows)?
  1460. // Then return it prepended with an underscore.
  1461. // See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
  1462. cmsys::RegularExpression reserved_pattern("^("
  1463. "[Cc][Oo][Nn]|"
  1464. "[Pp][Rr][Nn]|"
  1465. "[Aa][Uu][Xx]|"
  1466. "[Nn][Uu][Ll]|"
  1467. "[Cc][Oo][Mm][1-9]|"
  1468. "[Ll][Pp][Tt][1-9]"
  1469. ")[.]?$");
  1470. if (reserved_pattern.find(name)) {
  1471. return "_" + name;
  1472. }
  1473. // Given name ends in a dot (on Windows)?
  1474. // Then return it appended with an underscore.
  1475. if (name.back() == '.') {
  1476. return name + '_';
  1477. }
  1478. #endif
  1479. }
  1480. #ifndef _WIN32
  1481. constexpr char const* prohibited_chars = "<>\"/\\|?*`";
  1482. #else
  1483. // Note: Windows also excludes the colon.
  1484. constexpr char const* prohibited_chars = "<>\"/\\|?*`:";
  1485. #endif
  1486. // Given name contains non-supported character?
  1487. // Then return its MD5 hash.
  1488. if (name.find_first_of(prohibited_chars) != std::string::npos) {
  1489. cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
  1490. return hasher.HashString(name);
  1491. }
  1492. // Otherwise return unmodified.
  1493. return name;
  1494. }
  1495. std::string cmCPackGenerator::GetComponentInstallSuffix(
  1496. std::string const& componentName)
  1497. {
  1498. return componentName;
  1499. }
  1500. std::string cmCPackGenerator::GetComponentInstallDirNameSuffix(
  1501. std::string const& componentName)
  1502. {
  1503. return this->GetSanitizedDirOrFileName(
  1504. this->GetComponentInstallSuffix(componentName));
  1505. }
  1506. std::string cmCPackGenerator::GetComponentPackageFileName(
  1507. std::string const& initialPackageFileName,
  1508. std::string const& groupOrComponentName, bool isGroupName)
  1509. {
  1510. /*
  1511. * the default behavior is to use the
  1512. * component [group] name as a suffix
  1513. */
  1514. std::string suffix = "-" + groupOrComponentName;
  1515. /* check if we should use DISPLAY name */
  1516. std::string dispNameVar =
  1517. "CPACK_" + this->Name + "_USE_DISPLAY_NAME_IN_FILENAME";
  1518. if (this->IsOn(dispNameVar)) {
  1519. /* the component Group case */
  1520. if (isGroupName) {
  1521. std::string groupDispVar = "CPACK_COMPONENT_GROUP_" +
  1522. cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
  1523. cmValue groupDispName = this->GetOption(groupDispVar);
  1524. if (groupDispName) {
  1525. suffix = "-" + *groupDispName;
  1526. }
  1527. }
  1528. /* the [single] component case */
  1529. else {
  1530. std::string dispVar = "CPACK_COMPONENT_" +
  1531. cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
  1532. cmValue dispName = this->GetOption(dispVar);
  1533. if (dispName) {
  1534. suffix = "-" + *dispName;
  1535. }
  1536. }
  1537. }
  1538. return initialPackageFileName + suffix;
  1539. }
  1540. enum cmCPackGenerator::CPackSetDestdirSupport
  1541. cmCPackGenerator::SupportsSetDestdir() const
  1542. {
  1543. return cmCPackGenerator::SETDESTDIR_SUPPORTED;
  1544. }
  1545. bool cmCPackGenerator::SupportsAbsoluteDestination() const
  1546. {
  1547. return true;
  1548. }
  1549. bool cmCPackGenerator::SupportsComponentInstallation() const
  1550. {
  1551. return false;
  1552. }
  1553. bool cmCPackGenerator::WantsComponentInstallation() const
  1554. {
  1555. return (!this->IsOn("CPACK_MONOLITHIC_INSTALL") &&
  1556. this->SupportsComponentInstallation()
  1557. // check that we have at least one group or component
  1558. && (!this->ComponentGroups.empty() || !this->Components.empty()));
  1559. }
  1560. cmCPackInstallationType* cmCPackGenerator::GetInstallationType(
  1561. std::string const& projectName, std::string const& name)
  1562. {
  1563. (void)projectName;
  1564. bool hasInstallationType = this->InstallationTypes.count(name) != 0;
  1565. cmCPackInstallationType* installType = &this->InstallationTypes[name];
  1566. if (!hasInstallationType) {
  1567. // Define the installation type
  1568. std::string macroPrefix =
  1569. "CPACK_INSTALL_TYPE_" + cmsys::SystemTools::UpperCase(name);
  1570. installType->Name = name;
  1571. cmValue displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
  1572. if (cmNonempty(displayName)) {
  1573. installType->DisplayName = *displayName;
  1574. } else {
  1575. installType->DisplayName = installType->Name;
  1576. }
  1577. installType->Index = static_cast<unsigned>(this->InstallationTypes.size());
  1578. }
  1579. return installType;
  1580. }
  1581. cmCPackComponent* cmCPackGenerator::GetComponent(
  1582. std::string const& projectName, std::string const& name)
  1583. {
  1584. bool hasComponent = this->Components.count(name) != 0;
  1585. cmCPackComponent* component = &this->Components[name];
  1586. if (!hasComponent) {
  1587. // Define the component
  1588. std::string macroPrefix =
  1589. "CPACK_COMPONENT_" + cmsys::SystemTools::UpperCase(name);
  1590. component->Name = name;
  1591. cmValue displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
  1592. if (cmNonempty(displayName)) {
  1593. component->DisplayName = *displayName;
  1594. } else {
  1595. component->DisplayName = component->Name;
  1596. }
  1597. component->IsHidden = this->IsOn(macroPrefix + "_HIDDEN");
  1598. component->IsRequired = this->IsOn(macroPrefix + "_REQUIRED");
  1599. component->IsDisabledByDefault = this->IsOn(macroPrefix + "_DISABLED");
  1600. component->IsDownloaded = this->IsOn(macroPrefix + "_DOWNLOADED") ||
  1601. this->GetOption("CPACK_DOWNLOAD_ALL").IsOn();
  1602. cmValue archiveFile = this->GetOption(macroPrefix + "_ARCHIVE_FILE");
  1603. if (cmNonempty(archiveFile)) {
  1604. component->ArchiveFile = *archiveFile;
  1605. }
  1606. cmValue plist = this->GetOption(macroPrefix + "_PLIST");
  1607. if (cmNonempty(plist)) {
  1608. component->Plist = *plist;
  1609. }
  1610. cmValue groupName = this->GetOption(macroPrefix + "_GROUP");
  1611. if (cmNonempty(groupName)) {
  1612. component->Group = this->GetComponentGroup(projectName, *groupName);
  1613. component->Group->Components.push_back(component);
  1614. } else {
  1615. component->Group = nullptr;
  1616. }
  1617. cmValue description = this->GetOption(macroPrefix + "_DESCRIPTION");
  1618. if (cmNonempty(description)) {
  1619. component->Description = *description;
  1620. }
  1621. // Determine the installation types.
  1622. cmValue installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES");
  1623. if (cmNonempty(installTypes)) {
  1624. cmList installTypesList{ installTypes };
  1625. for (auto const& installType : installTypesList) {
  1626. component->InstallationTypes.push_back(
  1627. this->GetInstallationType(projectName, installType));
  1628. }
  1629. }
  1630. // Determine the component dependencies.
  1631. cmValue depends = this->GetOption(macroPrefix + "_DEPENDS");
  1632. if (cmNonempty(depends)) {
  1633. cmList dependsList{ depends };
  1634. for (auto const& depend : dependsList) {
  1635. cmCPackComponent* child = this->GetComponent(projectName, depend);
  1636. component->Dependencies.push_back(child);
  1637. child->ReverseDependencies.push_back(component);
  1638. }
  1639. }
  1640. }
  1641. return component;
  1642. }
  1643. cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup(
  1644. std::string const& projectName, std::string const& name)
  1645. {
  1646. (void)projectName;
  1647. std::string macroPrefix =
  1648. "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(name);
  1649. bool hasGroup = this->ComponentGroups.count(name) != 0;
  1650. cmCPackComponentGroup* group = &this->ComponentGroups[name];
  1651. if (!hasGroup) {
  1652. // Define the group
  1653. group->Name = name;
  1654. cmValue displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
  1655. if (cmNonempty(displayName)) {
  1656. group->DisplayName = *displayName;
  1657. } else {
  1658. group->DisplayName = group->Name;
  1659. }
  1660. cmValue description = this->GetOption(macroPrefix + "_DESCRIPTION");
  1661. if (cmNonempty(description)) {
  1662. group->Description = *description;
  1663. }
  1664. group->IsBold = this->IsOn(macroPrefix + "_BOLD_TITLE");
  1665. group->IsExpandedByDefault = this->IsOn(macroPrefix + "_EXPANDED");
  1666. cmValue parentGroupName = this->GetOption(macroPrefix + "_PARENT_GROUP");
  1667. if (cmNonempty(parentGroupName)) {
  1668. group->ParentGroup =
  1669. this->GetComponentGroup(projectName, *parentGroupName);
  1670. group->ParentGroup->Subgroups.push_back(group);
  1671. } else {
  1672. group->ParentGroup = nullptr;
  1673. }
  1674. }
  1675. return group;
  1676. }