cmCPackGenerator.cxx 64 KB

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