cmCPackGenerator.cxx 56 KB

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