cmCPackWIXGenerator.cxx 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2012-2015 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmCPackWIXGenerator.h"
  11. #include <cmSystemTools.h>
  12. #include <cmGeneratedFileStream.h>
  13. #include <cmCryptoHash.h>
  14. #include <cmInstalledFile.h>
  15. #include <CPack/cmCPackLog.h>
  16. #include <CPack/cmCPackComponentGroup.h>
  17. #include "cmWIXSourceWriter.h"
  18. #include "cmWIXDirectoriesSourceWriter.h"
  19. #include "cmWIXFeaturesSourceWriter.h"
  20. #include "cmWIXFilesSourceWriter.h"
  21. #include "cmWIXRichTextFormatWriter.h"
  22. #include <cmsys/SystemTools.hxx>
  23. #include <cmsys/Directory.hxx>
  24. #include <cmsys/Encoding.hxx>
  25. #include <cmsys/FStream.hxx>
  26. #include <rpc.h> // for GUID generation
  27. cmCPackWIXGenerator::cmCPackWIXGenerator():
  28. Patch(0)
  29. {
  30. }
  31. cmCPackWIXGenerator::~cmCPackWIXGenerator()
  32. {
  33. if(this->Patch)
  34. {
  35. delete this->Patch;
  36. }
  37. }
  38. int cmCPackWIXGenerator::InitializeInternal()
  39. {
  40. componentPackageMethod = ONE_PACKAGE;
  41. this->Patch = new cmWIXPatch(this->Logger);
  42. return this->Superclass::InitializeInternal();
  43. }
  44. bool cmCPackWIXGenerator::RunWiXCommand(std::string const& command)
  45. {
  46. std::string logFileName = this->CPackTopLevel + "/wix.log";
  47. cmCPackLogger(cmCPackLog::LOG_DEBUG,
  48. "Running WiX command: " << command << std::endl);
  49. std::string output;
  50. int returnValue = 0;
  51. bool status = cmSystemTools::RunSingleCommand(
  52. command.c_str(), &output, &output,
  53. &returnValue, 0, cmSystemTools::OUTPUT_NONE);
  54. cmsys::ofstream logFile(logFileName.c_str(), std::ios::app);
  55. logFile << command << std::endl;
  56. logFile << output;
  57. logFile.close();
  58. if(!status || returnValue)
  59. {
  60. cmCPackLogger(cmCPackLog::LOG_ERROR,
  61. "Problem running WiX candle. "
  62. "Please check '" << logFileName << "' for errors." << std::endl);
  63. return false;
  64. }
  65. return true;
  66. }
  67. bool cmCPackWIXGenerator::RunCandleCommand(
  68. std::string const& sourceFile, std::string const& objectFile)
  69. {
  70. std::string executable;
  71. if(!RequireOption("CPACK_WIX_CANDLE_EXECUTABLE", executable))
  72. {
  73. return false;
  74. }
  75. std::stringstream command;
  76. command << QuotePath(executable);
  77. command << " -nologo";
  78. command << " -arch " << GetArchitecture();
  79. command << " -out " << QuotePath(objectFile);
  80. for(extension_set_t::const_iterator i = CandleExtensions.begin();
  81. i != CandleExtensions.end(); ++i)
  82. {
  83. command << " -ext " << QuotePath(*i);
  84. }
  85. AddCustomFlags("CPACK_WIX_CANDLE_EXTRA_FLAGS", command);
  86. command << " " << QuotePath(sourceFile);
  87. return RunWiXCommand(command.str());
  88. }
  89. bool cmCPackWIXGenerator::RunLightCommand(std::string const& objectFiles)
  90. {
  91. std::string executable;
  92. if(!RequireOption("CPACK_WIX_LIGHT_EXECUTABLE", executable))
  93. {
  94. return false;
  95. }
  96. std::stringstream command;
  97. command << QuotePath(executable);
  98. command << " -nologo";
  99. command << " -out " << QuotePath(packageFileNames.at(0));
  100. for(extension_set_t::const_iterator i = this->LightExtensions.begin();
  101. i != this->LightExtensions.end(); ++i)
  102. {
  103. command << " -ext " << QuotePath(*i);
  104. }
  105. const char* const cultures = GetOption("CPACK_WIX_CULTURES");
  106. if(cultures)
  107. {
  108. command << " -cultures:" << cultures;
  109. }
  110. AddCustomFlags("CPACK_WIX_LIGHT_EXTRA_FLAGS", command);
  111. command << " " << objectFiles;
  112. return RunWiXCommand(command.str());
  113. }
  114. int cmCPackWIXGenerator::PackageFiles()
  115. {
  116. if(!PackageFilesImpl() || cmSystemTools::GetErrorOccuredFlag())
  117. {
  118. cmCPackLogger(cmCPackLog::LOG_ERROR,
  119. "Fatal WiX Generator Error" << std::endl);
  120. return false;
  121. }
  122. return true;
  123. }
  124. bool cmCPackWIXGenerator::InitializeWiXConfiguration()
  125. {
  126. if(!ReadListFile("CPackWIX.cmake"))
  127. {
  128. cmCPackLogger(cmCPackLog::LOG_ERROR,
  129. "Error while executing CPackWIX.cmake" << std::endl);
  130. return false;
  131. }
  132. if(GetOption("CPACK_WIX_PRODUCT_GUID") == 0)
  133. {
  134. std::string guid = GenerateGUID();
  135. SetOption("CPACK_WIX_PRODUCT_GUID", guid.c_str());
  136. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  137. "CPACK_WIX_PRODUCT_GUID implicitly set to " << guid << " . "
  138. << std::endl);
  139. }
  140. if(GetOption("CPACK_WIX_UPGRADE_GUID") == 0)
  141. {
  142. std::string guid = GenerateGUID();
  143. SetOption("CPACK_WIX_UPGRADE_GUID", guid.c_str());
  144. cmCPackLogger(cmCPackLog::LOG_WARNING,
  145. "CPACK_WIX_UPGRADE_GUID implicitly set to " << guid << " . "
  146. "Please refer to the documentation on how and why "
  147. "you might want to set this explicitly." << std::endl);
  148. }
  149. if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", this->CPackTopLevel))
  150. {
  151. return false;
  152. }
  153. if(GetOption("CPACK_WIX_LICENSE_RTF") == 0)
  154. {
  155. std::string licenseFilename = this->CPackTopLevel + "/License.rtf";
  156. SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename.c_str());
  157. if(!CreateLicenseFile())
  158. {
  159. return false;
  160. }
  161. }
  162. if(GetOption("CPACK_PACKAGE_VENDOR") == 0)
  163. {
  164. std::string defaultVendor = "Humanity";
  165. SetOption("CPACK_PACKAGE_VENDOR", defaultVendor.c_str());
  166. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  167. "CPACK_PACKAGE_VENDOR implicitly set to " << defaultVendor << " . "
  168. << std::endl);
  169. }
  170. if(GetOption("CPACK_WIX_UI_REF") == 0)
  171. {
  172. std::string defaultRef = "WixUI_InstallDir";
  173. if(!this->Components.empty())
  174. {
  175. defaultRef = "WixUI_FeatureTree";
  176. }
  177. SetOption("CPACK_WIX_UI_REF", defaultRef.c_str());
  178. }
  179. const char* packageContact = GetOption("CPACK_PACKAGE_CONTACT");
  180. if(packageContact != 0 &&
  181. GetOption("CPACK_WIX_PROPERTY_ARPCONTACT") == 0)
  182. {
  183. SetOption("CPACK_WIX_PROPERTY_ARPCONTACT", packageContact);
  184. }
  185. CollectExtensions("CPACK_WIX_EXTENSIONS", this->CandleExtensions);
  186. CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", this->CandleExtensions);
  187. this->LightExtensions.insert("WixUIExtension");
  188. CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions);
  189. CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions);
  190. const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
  191. if(patchFilePath)
  192. {
  193. this->Patch->LoadFragments(patchFilePath);
  194. }
  195. return true;
  196. }
  197. bool cmCPackWIXGenerator::PackageFilesImpl()
  198. {
  199. if(!InitializeWiXConfiguration())
  200. {
  201. return false;
  202. }
  203. CreateWiXVariablesIncludeFile();
  204. CreateWiXPropertiesIncludeFile();
  205. CreateWiXProductFragmentIncludeFile();
  206. if(!CreateWiXSourceFiles())
  207. {
  208. return false;
  209. }
  210. AppendUserSuppliedExtraSources();
  211. std::set<std::string> usedBaseNames;
  212. std::stringstream objectFiles;
  213. for(size_t i = 0; i < this->WixSources.size(); ++i)
  214. {
  215. std::string const& sourceFilename = this->WixSources[i];
  216. std::string baseName =
  217. cmSystemTools::GetFilenameWithoutLastExtension(sourceFilename);
  218. unsigned int counter = 0;
  219. std::string uniqueBaseName = baseName;
  220. while(usedBaseNames.find(uniqueBaseName) != usedBaseNames.end())
  221. {
  222. std::stringstream tmp;
  223. tmp << baseName << ++counter;
  224. uniqueBaseName = tmp.str();
  225. }
  226. usedBaseNames.insert(uniqueBaseName);
  227. std::string objectFilename =
  228. this->CPackTopLevel + "/" + uniqueBaseName + ".wixobj";
  229. if(!RunCandleCommand(sourceFilename, objectFilename))
  230. {
  231. return false;
  232. }
  233. objectFiles << " " << QuotePath(objectFilename);
  234. }
  235. AppendUserSuppliedExtraObjects(objectFiles);
  236. return RunLightCommand(objectFiles.str());
  237. }
  238. void cmCPackWIXGenerator::AppendUserSuppliedExtraSources()
  239. {
  240. const char *cpackWixExtraSources = GetOption("CPACK_WIX_EXTRA_SOURCES");
  241. if(!cpackWixExtraSources) return;
  242. cmSystemTools::ExpandListArgument(cpackWixExtraSources, this->WixSources);
  243. }
  244. void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream)
  245. {
  246. const char *cpackWixExtraObjects = GetOption("CPACK_WIX_EXTRA_OBJECTS");
  247. if(!cpackWixExtraObjects) return;
  248. std::vector<std::string> expandedExtraObjects;
  249. cmSystemTools::ExpandListArgument(
  250. cpackWixExtraObjects, expandedExtraObjects);
  251. for(size_t i = 0; i < expandedExtraObjects.size(); ++i)
  252. {
  253. stream << " " << QuotePath(expandedExtraObjects[i]);
  254. }
  255. }
  256. void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile()
  257. {
  258. std::string includeFilename =
  259. this->CPackTopLevel + "/cpack_variables.wxi";
  260. cmWIXSourceWriter includeFile(
  261. this->Logger, includeFilename, true);
  262. CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID");
  263. CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID");
  264. CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR");
  265. CopyDefinition(includeFile, "CPACK_PACKAGE_NAME");
  266. CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION");
  267. CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF");
  268. CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON");
  269. CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER");
  270. CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG");
  271. SetOptionIfNotSet("CPACK_WIX_PROGRAM_MENU_FOLDER",
  272. GetOption("CPACK_PACKAGE_NAME"));
  273. CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER");
  274. CopyDefinition(includeFile, "CPACK_WIX_UI_REF");
  275. }
  276. void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
  277. {
  278. std::string includeFilename =
  279. this->CPackTopLevel + "/properties.wxi";
  280. cmWIXSourceWriter includeFile(
  281. this->Logger, includeFilename, true);
  282. std::string prefix = "CPACK_WIX_PROPERTY_";
  283. std::vector<std::string> options = GetOptions();
  284. for(size_t i = 0; i < options.size(); ++i)
  285. {
  286. std::string const& name = options[i];
  287. if(name.length() > prefix.length() &&
  288. name.substr(0, prefix.length()) == prefix)
  289. {
  290. std::string id = name.substr(prefix.length());
  291. std::string value = GetOption(name.c_str());
  292. includeFile.BeginElement("Property");
  293. includeFile.AddAttribute("Id", id);
  294. includeFile.AddAttribute("Value", value);
  295. includeFile.EndElement("Property");
  296. }
  297. }
  298. if(GetOption("CPACK_WIX_PROPERTY_ARPINSTALLLOCATION") == 0)
  299. {
  300. includeFile.BeginElement("Property");
  301. includeFile.AddAttribute("Id", "INSTALL_ROOT");
  302. includeFile.AddAttribute("Secure", "yes");
  303. includeFile.BeginElement("RegistrySearch");
  304. includeFile.AddAttribute("Id", "FindInstallLocation");
  305. includeFile.AddAttribute("Root", "HKLM");
  306. includeFile.AddAttribute("Key", "Software\\Microsoft\\Windows\\"
  307. "CurrentVersion\\Uninstall\\[WIX_UPGRADE_DETECTED]");
  308. includeFile.AddAttribute("Name", "InstallLocation");
  309. includeFile.AddAttribute("Type", "raw");
  310. includeFile.EndElement("RegistrySearch");
  311. includeFile.EndElement("Property");
  312. includeFile.BeginElement("SetProperty");
  313. includeFile.AddAttribute("Id", "ARPINSTALLLOCATION");
  314. includeFile.AddAttribute("Value", "[INSTALL_ROOT]");
  315. includeFile.AddAttribute("After", "CostFinalize");
  316. includeFile.EndElement("SetProperty");
  317. }
  318. }
  319. void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile()
  320. {
  321. std::string includeFilename =
  322. this->CPackTopLevel + "/product_fragment.wxi";
  323. cmWIXSourceWriter includeFile(
  324. this->Logger, includeFilename, true);
  325. this->Patch->ApplyFragment("#PRODUCT", includeFile);
  326. }
  327. void cmCPackWIXGenerator::CopyDefinition(
  328. cmWIXSourceWriter &source, std::string const& name)
  329. {
  330. const char* value = GetOption(name.c_str());
  331. if(value)
  332. {
  333. AddDefinition(source, name, value);
  334. }
  335. }
  336. void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source,
  337. std::string const& name, std::string const& value)
  338. {
  339. std::stringstream tmp;
  340. tmp << name << "=\"" << value << '"';
  341. source.AddProcessingInstruction("define",
  342. cmWIXSourceWriter::CMakeEncodingToUtf8(tmp.str()));
  343. }
  344. bool cmCPackWIXGenerator::CreateWiXSourceFiles()
  345. {
  346. std::string directoryDefinitionsFilename =
  347. this->CPackTopLevel + "/directories.wxs";
  348. this->WixSources.push_back(directoryDefinitionsFilename);
  349. cmWIXDirectoriesSourceWriter directoryDefinitions(
  350. this->Logger, directoryDefinitionsFilename);
  351. directoryDefinitions.BeginElement("Fragment");
  352. std::string installRoot;
  353. if(!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY", installRoot))
  354. {
  355. return false;
  356. }
  357. directoryDefinitions.BeginElement("Directory");
  358. directoryDefinitions.AddAttribute("Id", "TARGETDIR");
  359. directoryDefinitions.AddAttribute("Name", "SourceDir");
  360. size_t installRootSize =
  361. directoryDefinitions.BeginInstallationPrefixDirectory(
  362. GetProgramFilesFolderId(), installRoot);
  363. std::string fileDefinitionsFilename =
  364. this->CPackTopLevel + "/files.wxs";
  365. this->WixSources.push_back(fileDefinitionsFilename);
  366. cmWIXFilesSourceWriter fileDefinitions(
  367. this->Logger, fileDefinitionsFilename);
  368. fileDefinitions.BeginElement("Fragment");
  369. std::string featureDefinitionsFilename =
  370. this->CPackTopLevel +"/features.wxs";
  371. this->WixSources.push_back(featureDefinitionsFilename);
  372. cmWIXFeaturesSourceWriter featureDefinitions(
  373. this->Logger, featureDefinitionsFilename);
  374. featureDefinitions.BeginElement("Fragment");
  375. featureDefinitions.BeginElement("Feature");
  376. featureDefinitions.AddAttribute("Id", "ProductFeature");
  377. featureDefinitions.AddAttribute("Display", "expand");
  378. featureDefinitions.AddAttribute("ConfigurableDirectory", "INSTALL_ROOT");
  379. std::string cpackPackageName;
  380. if(!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName))
  381. {
  382. return false;
  383. }
  384. featureDefinitions.AddAttribute("Title", cpackPackageName);
  385. featureDefinitions.AddAttribute("Level", "1");
  386. this->Patch->ApplyFragment("#PRODUCTFEATURE", featureDefinitions);
  387. const char* package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY");
  388. if(package)
  389. {
  390. featureDefinitions.CreateCMakePackageRegistryEntry(
  391. package, GetOption("CPACK_WIX_UPGRADE_GUID"));
  392. }
  393. if(!CreateFeatureHierarchy(featureDefinitions))
  394. {
  395. return false;
  396. }
  397. featureDefinitions.EndElement("Feature");
  398. std::set<cmWIXShortcuts::Type> emittedShortcutTypes;
  399. cmWIXShortcuts globalShortcuts;
  400. if(Components.empty())
  401. {
  402. AddComponentsToFeature(toplevel, "ProductFeature",
  403. directoryDefinitions, fileDefinitions, featureDefinitions,
  404. globalShortcuts);
  405. globalShortcuts.AddShortcutTypes(emittedShortcutTypes);
  406. }
  407. else
  408. {
  409. for(std::map<std::string, cmCPackComponent>::const_iterator
  410. i = this->Components.begin(); i != this->Components.end(); ++i)
  411. {
  412. cmCPackComponent const& component = i->second;
  413. std::string componentPath = toplevel;
  414. componentPath += "/";
  415. componentPath += component.Name;
  416. std::string componentFeatureId = "CM_C_" + component.Name;
  417. cmWIXShortcuts featureShortcuts;
  418. AddComponentsToFeature(componentPath, componentFeatureId,
  419. directoryDefinitions, fileDefinitions,
  420. featureDefinitions, featureShortcuts);
  421. featureShortcuts.AddShortcutTypes(emittedShortcutTypes);
  422. if(!CreateShortcuts(component.Name, componentFeatureId,
  423. featureShortcuts, false, fileDefinitions, featureDefinitions))
  424. {
  425. return false;
  426. }
  427. }
  428. }
  429. bool emitUninstallShortcut = emittedShortcutTypes.find(
  430. cmWIXShortcuts::START_MENU) != emittedShortcutTypes.end();
  431. if(!CreateShortcuts(std::string(), "ProductFeature",
  432. globalShortcuts, emitUninstallShortcut,
  433. fileDefinitions, featureDefinitions))
  434. {
  435. return false;
  436. }
  437. featureDefinitions.EndElement("Fragment");
  438. fileDefinitions.EndElement("Fragment");
  439. directoryDefinitions.EndInstallationPrefixDirectory(
  440. installRootSize);
  441. if(emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) !=
  442. emittedShortcutTypes.end())
  443. {
  444. directoryDefinitions.EmitStartMenuFolder(
  445. GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER"));
  446. }
  447. if(emittedShortcutTypes.find(cmWIXShortcuts::DESKTOP) !=
  448. emittedShortcutTypes.end())
  449. {
  450. directoryDefinitions.EmitDesktopFolder();
  451. }
  452. if(emittedShortcutTypes.find(cmWIXShortcuts::STARTUP) !=
  453. emittedShortcutTypes.end())
  454. {
  455. directoryDefinitions.EmitStartupFolder();
  456. }
  457. directoryDefinitions.EndElement("Directory");
  458. directoryDefinitions.EndElement("Fragment");
  459. if(!GenerateMainSourceFileFromTemplate())
  460. {
  461. return false;
  462. }
  463. return this->Patch->CheckForUnappliedFragments();
  464. }
  465. std::string cmCPackWIXGenerator::GetProgramFilesFolderId() const
  466. {
  467. if(GetArchitecture() == "x86")
  468. {
  469. return "ProgramFilesFolder";
  470. }
  471. else
  472. {
  473. return "ProgramFiles64Folder";
  474. }
  475. }
  476. bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate()
  477. {
  478. std::string wixTemplate = FindTemplate("WIX.template.in");
  479. if(GetOption("CPACK_WIX_TEMPLATE") != 0)
  480. {
  481. wixTemplate = GetOption("CPACK_WIX_TEMPLATE");
  482. }
  483. if(wixTemplate.empty())
  484. {
  485. cmCPackLogger(cmCPackLog::LOG_ERROR,
  486. "Could not find CPack WiX template file WIX.template.in" << std::endl);
  487. return false;
  488. }
  489. std::string mainSourceFilePath = this->CPackTopLevel + "/main.wxs";
  490. if(!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath .c_str()))
  491. {
  492. cmCPackLogger(cmCPackLog::LOG_ERROR,
  493. "Failed creating '" << mainSourceFilePath <<
  494. "'' from template." << std::endl);
  495. return false;
  496. }
  497. this->WixSources.push_back(mainSourceFilePath);
  498. return true;
  499. }
  500. bool cmCPackWIXGenerator::CreateFeatureHierarchy(
  501. cmWIXFeaturesSourceWriter& featureDefinitions)
  502. {
  503. for(std::map<std::string, cmCPackComponentGroup>::const_iterator
  504. i = ComponentGroups.begin(); i != ComponentGroups.end(); ++i)
  505. {
  506. cmCPackComponentGroup const& group = i->second;
  507. if(group.ParentGroup == 0)
  508. {
  509. featureDefinitions.EmitFeatureForComponentGroup(group);
  510. }
  511. }
  512. for(std::map<std::string, cmCPackComponent>::const_iterator
  513. i = this->Components.begin(); i != this->Components.end(); ++i)
  514. {
  515. cmCPackComponent const& component = i->second;
  516. if(!component.Group)
  517. {
  518. featureDefinitions.EmitFeatureForComponent(component);
  519. }
  520. }
  521. return true;
  522. }
  523. bool cmCPackWIXGenerator::AddComponentsToFeature(
  524. std::string const& rootPath,
  525. std::string const& featureId,
  526. cmWIXDirectoriesSourceWriter& directoryDefinitions,
  527. cmWIXFilesSourceWriter& fileDefinitions,
  528. cmWIXFeaturesSourceWriter& featureDefinitions,
  529. cmWIXShortcuts& shortcuts)
  530. {
  531. featureDefinitions.BeginElement("FeatureRef");
  532. featureDefinitions.AddAttribute("Id", featureId);
  533. std::vector<std::string> cpackPackageExecutablesList;
  534. const char *cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES");
  535. if(cpackPackageExecutables)
  536. {
  537. cmSystemTools::ExpandListArgument(cpackPackageExecutables,
  538. cpackPackageExecutablesList);
  539. if(cpackPackageExecutablesList.size() % 2 != 0 )
  540. {
  541. cmCPackLogger(cmCPackLog::LOG_ERROR,
  542. "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
  543. "<text label>." << std::endl);
  544. return false;
  545. }
  546. }
  547. std::vector<std::string> cpackPackageDesktopLinksList;
  548. const char *cpackPackageDesktopLinks =
  549. GetOption("CPACK_CREATE_DESKTOP_LINKS");
  550. if(cpackPackageDesktopLinks)
  551. {
  552. cmSystemTools::ExpandListArgument(cpackPackageDesktopLinks,
  553. cpackPackageDesktopLinksList);
  554. }
  555. AddDirectoryAndFileDefinitons(
  556. rootPath, "INSTALL_ROOT",
  557. directoryDefinitions, fileDefinitions, featureDefinitions,
  558. cpackPackageExecutablesList, cpackPackageDesktopLinksList,
  559. shortcuts);
  560. featureDefinitions.EndElement("FeatureRef");
  561. return true;
  562. }
  563. bool cmCPackWIXGenerator::CreateShortcuts(
  564. std::string const& cpackComponentName,
  565. std::string const& featureId,
  566. cmWIXShortcuts const& shortcuts,
  567. bool emitUninstallShortcut,
  568. cmWIXFilesSourceWriter& fileDefinitions,
  569. cmWIXFeaturesSourceWriter& featureDefinitions)
  570. {
  571. if(!shortcuts.empty(cmWIXShortcuts::START_MENU))
  572. {
  573. if(!this->CreateShortcutsOfSpecificType(cmWIXShortcuts::START_MENU,
  574. cpackComponentName, featureId, "",
  575. shortcuts, emitUninstallShortcut,
  576. fileDefinitions, featureDefinitions))
  577. {
  578. return false;
  579. }
  580. }
  581. if(!shortcuts.empty(cmWIXShortcuts::DESKTOP))
  582. {
  583. if(!this->CreateShortcutsOfSpecificType(cmWIXShortcuts::DESKTOP,
  584. cpackComponentName, featureId, "DESKTOP",
  585. shortcuts, false,
  586. fileDefinitions, featureDefinitions))
  587. {
  588. return false;
  589. }
  590. }
  591. if(!shortcuts.empty(cmWIXShortcuts::STARTUP))
  592. {
  593. if(!this->CreateShortcutsOfSpecificType(cmWIXShortcuts::STARTUP,
  594. cpackComponentName, featureId, "STARTUP",
  595. shortcuts, false,
  596. fileDefinitions, featureDefinitions))
  597. {
  598. return false;
  599. }
  600. }
  601. return true;
  602. }
  603. bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType(
  604. cmWIXShortcuts::Type type,
  605. std::string const& cpackComponentName,
  606. std::string const& featureId,
  607. std::string const& idPrefix,
  608. cmWIXShortcuts const& shortcuts,
  609. bool emitUninstallShortcut,
  610. cmWIXFilesSourceWriter& fileDefinitions,
  611. cmWIXFeaturesSourceWriter& featureDefinitions)
  612. {
  613. std::string directoryId;
  614. switch(type)
  615. {
  616. case cmWIXShortcuts::START_MENU:
  617. directoryId = "PROGRAM_MENU_FOLDER";
  618. break;
  619. case cmWIXShortcuts::DESKTOP:
  620. directoryId = "DesktopFolder";
  621. break;
  622. case cmWIXShortcuts::STARTUP:
  623. directoryId = "StartupFolder";
  624. break;
  625. default:
  626. return false;
  627. }
  628. featureDefinitions.BeginElement("FeatureRef");
  629. featureDefinitions.AddAttribute("Id", featureId);
  630. std::string cpackVendor;
  631. if(!RequireOption("CPACK_PACKAGE_VENDOR", cpackVendor))
  632. {
  633. return false;
  634. }
  635. std::string cpackPackageName;
  636. if(!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName))
  637. {
  638. return false;
  639. }
  640. std::string idSuffix;
  641. if(!cpackComponentName.empty())
  642. {
  643. idSuffix += "_";
  644. idSuffix += cpackComponentName;
  645. }
  646. std::string componentId = "CM_SHORTCUT";
  647. if(idPrefix.size())
  648. {
  649. componentId += "_" + idPrefix;
  650. }
  651. componentId += idSuffix;
  652. fileDefinitions.BeginElement("DirectoryRef");
  653. fileDefinitions.AddAttribute("Id", directoryId);
  654. fileDefinitions.BeginElement("Component");
  655. fileDefinitions.AddAttribute("Id", componentId);
  656. fileDefinitions.AddAttribute("Guid", "*");
  657. std::string registryKey = std::string("Software\\") +
  658. cpackVendor + "\\" + cpackPackageName;
  659. shortcuts.EmitShortcuts(type, registryKey,
  660. cpackComponentName, fileDefinitions);
  661. if(type == cmWIXShortcuts::START_MENU)
  662. {
  663. fileDefinitions.EmitRemoveFolder(
  664. "CM_REMOVE_PROGRAM_MENU_FOLDER" + idSuffix);
  665. }
  666. if(emitUninstallShortcut)
  667. {
  668. fileDefinitions.EmitUninstallShortcut(cpackPackageName);
  669. }
  670. fileDefinitions.EndElement("Component");
  671. fileDefinitions.EndElement("DirectoryRef");
  672. featureDefinitions.EmitComponentRef(componentId);
  673. featureDefinitions.EndElement("FeatureRef");
  674. return true;
  675. }
  676. bool cmCPackWIXGenerator::CreateLicenseFile()
  677. {
  678. std::string licenseSourceFilename;
  679. if(!RequireOption("CPACK_RESOURCE_FILE_LICENSE", licenseSourceFilename))
  680. {
  681. return false;
  682. }
  683. std::string licenseDestinationFilename;
  684. if(!RequireOption("CPACK_WIX_LICENSE_RTF", licenseDestinationFilename))
  685. {
  686. return false;
  687. }
  688. std::string extension = GetRightmostExtension(licenseSourceFilename);
  689. if(extension == ".rtf")
  690. {
  691. cmSystemTools::CopyAFile(
  692. licenseSourceFilename.c_str(),
  693. licenseDestinationFilename.c_str());
  694. }
  695. else if(extension == ".txt")
  696. {
  697. cmWIXRichTextFormatWriter rtfWriter(licenseDestinationFilename);
  698. cmsys::ifstream licenseSource(licenseSourceFilename.c_str());
  699. std::string line;
  700. while(std::getline(licenseSource, line))
  701. {
  702. rtfWriter.AddText(line);
  703. rtfWriter.AddText("\n");
  704. }
  705. }
  706. else
  707. {
  708. cmCPackLogger(cmCPackLog::LOG_ERROR,
  709. "unsupported WiX License file extension '" <<
  710. extension << "'" << std::endl);
  711. return false;
  712. }
  713. return true;
  714. }
  715. void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
  716. std::string const& topdir,
  717. std::string const& directoryId,
  718. cmWIXDirectoriesSourceWriter& directoryDefinitions,
  719. cmWIXFilesSourceWriter& fileDefinitions,
  720. cmWIXFeaturesSourceWriter& featureDefinitions,
  721. std::vector<std::string> const& packageExecutables,
  722. std::vector<std::string> const& desktopExecutables,
  723. cmWIXShortcuts& shortcuts)
  724. {
  725. cmsys::Directory dir;
  726. dir.Load(topdir.c_str());
  727. std::string relativeDirectoryPath =
  728. cmSystemTools::RelativePath(toplevel.c_str(), topdir.c_str());
  729. if(relativeDirectoryPath.empty())
  730. {
  731. relativeDirectoryPath = ".";
  732. }
  733. cmInstalledFile const* directoryInstalledFile =
  734. this->GetInstalledFile(relativeDirectoryPath);
  735. bool emptyDirectory = dir.GetNumberOfFiles() == 2;
  736. bool createDirectory = false;
  737. if(emptyDirectory)
  738. {
  739. createDirectory = true;
  740. }
  741. if(directoryInstalledFile)
  742. {
  743. if(directoryInstalledFile->HasProperty("CPACK_WIX_ACL"))
  744. {
  745. createDirectory = true;
  746. }
  747. }
  748. if(createDirectory)
  749. {
  750. std::string componentId = fileDefinitions.EmitComponentCreateFolder(
  751. directoryId, GenerateGUID(), directoryInstalledFile);
  752. featureDefinitions.EmitComponentRef(componentId);
  753. }
  754. if(emptyDirectory)
  755. {
  756. return;
  757. }
  758. for(size_t i = 0; i < dir.GetNumberOfFiles(); ++i)
  759. {
  760. std::string fileName = dir.GetFile(static_cast<unsigned long>(i));
  761. if(fileName == "." || fileName == "..")
  762. {
  763. continue;
  764. }
  765. std::string fullPath = topdir + "/" + fileName;
  766. std::string relativePath = cmSystemTools::RelativePath(
  767. toplevel.c_str(), fullPath.c_str());
  768. std::string id = PathToId(relativePath);
  769. if(cmSystemTools::FileIsDirectory(fullPath.c_str()))
  770. {
  771. std::string subDirectoryId = std::string("CM_D") + id;
  772. directoryDefinitions.BeginElement("Directory");
  773. directoryDefinitions.AddAttribute("Id", subDirectoryId);
  774. directoryDefinitions.AddAttribute("Name", fileName);
  775. AddDirectoryAndFileDefinitons(
  776. fullPath, subDirectoryId,
  777. directoryDefinitions,
  778. fileDefinitions,
  779. featureDefinitions,
  780. packageExecutables,
  781. desktopExecutables,
  782. shortcuts);
  783. this->Patch->ApplyFragment(subDirectoryId, directoryDefinitions);
  784. directoryDefinitions.EndElement("Directory");
  785. }
  786. else
  787. {
  788. cmInstalledFile const* installedFile =
  789. this->GetInstalledFile(relativePath);
  790. if(installedFile)
  791. {
  792. shortcuts.CreateFromProperties(id, directoryId, *installedFile);
  793. }
  794. std::string componentId = fileDefinitions.EmitComponentFile(
  795. directoryId, id, fullPath, *(this->Patch), installedFile);
  796. featureDefinitions.EmitComponentRef(componentId);
  797. for(size_t j = 0; j < packageExecutables.size(); ++j)
  798. {
  799. std::string const& executableName = packageExecutables[j++];
  800. std::string const& textLabel = packageExecutables[j];
  801. if(cmSystemTools::LowerCase(fileName) ==
  802. cmSystemTools::LowerCase(executableName) + ".exe")
  803. {
  804. cmWIXShortcut shortcut;
  805. shortcut.label= textLabel;
  806. shortcut.workingDirectoryId = directoryId;
  807. shortcuts.insert(cmWIXShortcuts::START_MENU, id, shortcut);
  808. if(!desktopExecutables.empty() &&
  809. std::find(desktopExecutables.begin(),
  810. desktopExecutables.end(),
  811. executableName)
  812. != desktopExecutables.end())
  813. {
  814. shortcuts.insert(cmWIXShortcuts::DESKTOP, id, shortcut);
  815. }
  816. }
  817. }
  818. }
  819. }
  820. }
  821. bool cmCPackWIXGenerator::RequireOption(
  822. std::string const& name, std::string &value) const
  823. {
  824. const char* tmp = GetOption(name.c_str());
  825. if(tmp)
  826. {
  827. value = tmp;
  828. return true;
  829. }
  830. else
  831. {
  832. cmCPackLogger(cmCPackLog::LOG_ERROR,
  833. "Required variable " << name << " not set" << std::endl);
  834. return false;
  835. }
  836. }
  837. std::string cmCPackWIXGenerator::GetArchitecture() const
  838. {
  839. std::string void_p_size;
  840. RequireOption("CPACK_WIX_SIZEOF_VOID_P", void_p_size);
  841. if(void_p_size == "8")
  842. {
  843. return "x64";
  844. }
  845. else
  846. {
  847. return "x86";
  848. }
  849. }
  850. std::string cmCPackWIXGenerator::GenerateGUID()
  851. {
  852. UUID guid;
  853. UuidCreate(&guid);
  854. unsigned short *tmp = 0;
  855. UuidToStringW(&guid, &tmp);
  856. std::string result =
  857. cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(tmp));
  858. RpcStringFreeW(&tmp);
  859. return cmSystemTools::UpperCase(result);
  860. }
  861. std::string cmCPackWIXGenerator::QuotePath(std::string const& path)
  862. {
  863. return std::string("\"") + path + '"';
  864. }
  865. std::string cmCPackWIXGenerator::GetRightmostExtension(
  866. std::string const& filename)
  867. {
  868. std::string extension;
  869. std::string::size_type i = filename.rfind(".");
  870. if(i != std::string::npos)
  871. {
  872. extension = filename.substr(i);
  873. }
  874. return cmSystemTools::LowerCase(extension);
  875. }
  876. std::string cmCPackWIXGenerator::PathToId(std::string const& path)
  877. {
  878. id_map_t::const_iterator i = PathToIdMap.find(path);
  879. if(i != PathToIdMap.end()) return i->second;
  880. std::string id = CreateNewIdForPath(path);
  881. return id;
  882. }
  883. std::string cmCPackWIXGenerator::CreateNewIdForPath(std::string const& path)
  884. {
  885. std::vector<std::string> components;
  886. cmSystemTools::SplitPath(path.c_str(), components, false);
  887. size_t replacementCount = 0;
  888. std::string identifier;
  889. std::string currentComponent;
  890. for(size_t i = 1; i < components.size(); ++i)
  891. {
  892. if(i != 1) identifier += '.';
  893. currentComponent = NormalizeComponentForId(
  894. components[i], replacementCount);
  895. identifier += currentComponent;
  896. }
  897. std::string idPrefix = "P";
  898. size_t replacementPercent = replacementCount * 100 / identifier.size();
  899. if(replacementPercent > 33 || identifier.size() > 60)
  900. {
  901. identifier = CreateHashedId(path, currentComponent);
  902. idPrefix = "H";
  903. }
  904. std::stringstream result;
  905. result << idPrefix << "_" << identifier;
  906. size_t ambiguityCount = ++IdAmbiguityCounter[identifier];
  907. if(ambiguityCount > 999)
  908. {
  909. cmCPackLogger(cmCPackLog::LOG_ERROR,
  910. "Error while trying to generate a unique Id for '" <<
  911. path << "'" << std::endl);
  912. return std::string();
  913. }
  914. else if(ambiguityCount > 1)
  915. {
  916. result << "_" << ambiguityCount;
  917. }
  918. std::string resultString = result.str();
  919. PathToIdMap[path] = resultString;
  920. return resultString;
  921. }
  922. std::string cmCPackWIXGenerator::CreateHashedId(
  923. std::string const& path, std::string const& normalizedFilename)
  924. {
  925. cmsys::auto_ptr<cmCryptoHash> sha1 = cmCryptoHash::New("SHA1");
  926. std::string hash = sha1->HashString(path.c_str());
  927. std::string identifier;
  928. identifier += hash.substr(0, 7) + "_";
  929. const size_t maxFileNameLength = 52;
  930. if(normalizedFilename.length() > maxFileNameLength)
  931. {
  932. identifier += normalizedFilename.substr(0, maxFileNameLength - 3);
  933. identifier += "...";
  934. }
  935. else
  936. {
  937. identifier += normalizedFilename;
  938. }
  939. return identifier;
  940. }
  941. std::string cmCPackWIXGenerator::NormalizeComponentForId(
  942. std::string const& component, size_t& replacementCount)
  943. {
  944. std::string result;
  945. result.resize(component.size());
  946. for(size_t i = 0; i < component.size(); ++i)
  947. {
  948. char c = component[i];
  949. if(IsLegalIdCharacter(c))
  950. {
  951. result[i] = c;
  952. }
  953. else
  954. {
  955. result[i] = '_';
  956. ++ replacementCount;
  957. }
  958. }
  959. return result;
  960. }
  961. bool cmCPackWIXGenerator::IsLegalIdCharacter(char c)
  962. {
  963. return (c >= '0' && c <= '9') ||
  964. (c >= 'a' && c <= 'z') ||
  965. (c >= 'A' && c <= 'Z') ||
  966. c == '_' || c == '.';
  967. }
  968. void cmCPackWIXGenerator::CollectExtensions(
  969. std::string const& variableName, extension_set_t& extensions)
  970. {
  971. const char *variableContent = GetOption(variableName.c_str());
  972. if(!variableContent) return;
  973. std::vector<std::string> list;
  974. cmSystemTools::ExpandListArgument(variableContent, list);
  975. extensions.insert(list.begin(), list.end());
  976. }
  977. void cmCPackWIXGenerator::AddCustomFlags(
  978. std::string const& variableName, std::ostream& stream)
  979. {
  980. const char *variableContent = GetOption(variableName.c_str());
  981. if(!variableContent) return;
  982. std::vector<std::string> list;
  983. cmSystemTools::ExpandListArgument(variableContent, list);
  984. for(std::vector<std::string>::const_iterator i = list.begin();
  985. i != list.end(); ++i)
  986. {
  987. stream << " " << QuotePath(*i);
  988. }
  989. }