| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmCPackInnoSetupGenerator.h"
- #include <algorithm>
- #include <cctype>
- #include <cstdlib>
- #include <ostream>
- #include <stack>
- #include <utility>
- #include "cmsys/RegularExpression.hxx"
- #include "cmCPackComponentGroup.h"
- #include "cmCPackLog.h"
- #include "cmDuration.h"
- #include "cmGeneratedFileStream.h"
- #include "cmList.h"
- #include "cmStringAlgorithms.h"
- #include "cmSystemTools.h"
- cmCPackInnoSetupGenerator::cmCPackInnoSetupGenerator() = default;
- cmCPackInnoSetupGenerator::~cmCPackInnoSetupGenerator() = default;
- bool cmCPackInnoSetupGenerator::CanGenerate()
- {
- // Inno Setup is only available for Windows
- #ifdef _WIN32
- return true;
- #else
- return false;
- #endif
- }
- int cmCPackInnoSetupGenerator::InitializeInternal()
- {
- if (cmIsOn(GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) {
- cmCPackLogger(cmCPackLog::LOG_WARNING,
- "Inno Setup Generator cannot work with "
- "CPACK_INCLUDE_TOPLEVEL_DIRECTORY set. "
- "This option will be reset to 0 (for this generator only)."
- << std::endl);
- SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", nullptr);
- }
- std::vector<std::string> path;
- #ifdef _WIN32
- path.push_back("C:\\Program Files (x86)\\Inno Setup 5");
- path.push_back("C:\\Program Files (x86)\\Inno Setup 6");
- #endif
- SetOptionIfNotSet("CPACK_INNOSETUP_EXECUTABLE", "ISCC");
- const std::string& isccPath = cmSystemTools::FindProgram(
- GetOption("CPACK_INNOSETUP_EXECUTABLE"), path, false);
- if (isccPath.empty()) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Cannot find Inno Setup compiler ISCC: "
- "likely it is not installed, or not in your PATH"
- << std::endl);
- return 0;
- }
- const std::string isccCmd = cmStrCat(QuotePath(isccPath), "/?");
- cmCPackLogger(cmCPackLog::LOG_VERBOSE,
- "Test Inno Setup version: " << isccCmd << std::endl);
- std::string output;
- cmSystemTools::RunSingleCommand(isccCmd, &output, &output, nullptr, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
- cmsys::RegularExpression vRex("Inno Setup ([0-9]+)");
- if (!vRex.find(output)) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem checking Inno Setup version with command: "
- << isccCmd << std::endl
- << "Have you downloaded Inno Setup from "
- "https://jrsoftware.org/isinfo.php?"
- << std::endl);
- return 0;
- }
- const int isccVersion = atoi(vRex.match(1).c_str());
- const int minIsccVersion = 6;
- cmCPackLogger(cmCPackLog::LOG_DEBUG,
- "Inno Setup Version: " << isccVersion << std::endl);
- if (isccVersion < minIsccVersion) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "CPack requires Inno Setup Version 6 or greater. "
- "Inno Setup found on the system was: "
- << isccVersion << std::endl);
- return 0;
- }
- SetOption("CPACK_INSTALLER_PROGRAM", isccPath);
- return this->Superclass::InitializeInternal();
- }
- int cmCPackInnoSetupGenerator::PackageFiles()
- {
- // Includes
- if (IsSet("CPACK_INNOSETUP_EXTRA_SCRIPTS")) {
- const cmList extraScripts(GetOption("CPACK_INNOSETUP_EXTRA_SCRIPTS"));
- for (const std::string& i : extraScripts) {
- includeDirectives.emplace_back(cmStrCat(
- "#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel))));
- }
- }
- // [Languages] section
- SetOptionIfNotSet("CPACK_INNOSETUP_LANGUAGES", "english");
- const cmList languages(GetOption("CPACK_INNOSETUP_LANGUAGES"));
- for (std::string i : languages) {
- cmCPackInnoSetupKeyValuePairs params;
- params["Name"] = Quote(i);
- if (cmSystemTools::LowerCase(i) == "english") {
- params["MessagesFile"] = "\"compiler:Default.isl\"";
- } else {
- i[0] = static_cast<char>(std::toupper(i[0]));
- params["MessagesFile"] = cmStrCat("\"compiler:Languages\\", i, ".isl\"");
- }
- languageInstructions.push_back(ISKeyValueLine(params));
- }
- if (!Components.empty() && !ProcessComponents()) {
- return false;
- }
- if (!(ProcessSetupSection() && ProcessFiles())) {
- return false;
- }
- // [Code] section
- if (IsSet("CPACK_INNOSETUP_CODE_FILES")) {
- const cmList codeFiles(GetOption("CPACK_INNOSETUP_CODE_FILES"));
- for (const std::string& i : codeFiles) {
- codeIncludes.emplace_back(cmStrCat(
- "#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel))));
- }
- }
- return ConfigureISScript() && Compile();
- }
- bool cmCPackInnoSetupGenerator::ProcessSetupSection()
- {
- if (!RequireOption("CPACK_PACKAGE_INSTALL_REGISTRY_KEY")) {
- return false;
- }
- setupDirectives["AppId"] = GetOption("CPACK_PACKAGE_INSTALL_REGISTRY_KEY");
- if (!RequireOption("CPACK_PACKAGE_NAME")) {
- return false;
- }
- setupDirectives["AppName"] = GetOption("CPACK_PACKAGE_NAME");
- setupDirectives["UninstallDisplayName"] = GetOption("CPACK_PACKAGE_NAME");
- if (!RequireOption("CPACK_PACKAGE_VERSION")) {
- return false;
- }
- setupDirectives["AppVersion"] = GetOption("CPACK_PACKAGE_VERSION");
- if (!RequireOption("CPACK_PACKAGE_VENDOR")) {
- return false;
- }
- setupDirectives["AppPublisher"] = GetOption("CPACK_PACKAGE_VENDOR");
- if (IsSet("CPACK_PACKAGE_HOMEPAGE_URL")) {
- setupDirectives["AppPublisherURL"] =
- GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
- setupDirectives["AppSupportURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
- setupDirectives["AppUpdatesURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
- }
- SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE", "OFF");
- if (IsSet("CPACK_RESOURCE_FILE_LICENSE") &&
- !GetOption("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE").IsOn()) {
- setupDirectives["LicenseFile"] = cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_RESOURCE_FILE_LICENSE"));
- }
- SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_README_PAGE", "ON");
- if (IsSet("CPACK_RESOURCE_FILE_README") &&
- !GetOption("CPACK_INNOSETUP_IGNORE_README_PAGE").IsOn()) {
- setupDirectives["InfoBeforeFile"] =
- cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_RESOURCE_FILE_README"));
- }
- SetOptionIfNotSet("CPACK_INNOSETUP_USE_MODERN_WIZARD", "OFF");
- if (GetOption("CPACK_INNOSETUP_USE_MODERN_WIZARD").IsOn()) {
- setupDirectives["WizardStyle"] = "modern";
- } else {
- setupDirectives["WizardStyle"] = "classic";
- setupDirectives["WizardSmallImageFile"] =
- "compiler:WizClassicSmallImage.bmp";
- setupDirectives["WizardImageFile"] = "compiler:WizClassicImage.bmp";
- setupDirectives["SetupIconFile"] = "compiler:SetupClassicIcon.ico";
- }
- if (IsSet("CPACK_INNOSETUP_ICON_FILE")) {
- setupDirectives["SetupIconFile"] =
- cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_INNOSETUP_ICON_FILE"));
- }
- if (IsSet("CPACK_PACKAGE_ICON")) {
- setupDirectives["WizardSmallImageFile"] =
- cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_PACKAGE_ICON"));
- }
- if (!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) {
- return false;
- }
- SetOptionIfNotSet("CPACK_INNOSETUP_INSTALL_ROOT", "{autopf}");
- setupDirectives["DefaultDirName"] =
- cmSystemTools::ConvertToWindowsOutputPath(
- cmStrCat(GetOption("CPACK_INNOSETUP_INSTALL_ROOT"), '\\',
- GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY")));
- SetOptionIfNotSet("CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY", "ON");
- if (GetOption("CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY").IsOff()) {
- setupDirectives["DisableDirPage"] = "yes";
- }
- SetOptionIfNotSet("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER",
- GetOption("CPACK_PACKAGE_NAME"));
- if (GetOption("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER") == ".") {
- setupDirectives["DisableProgramGroupPage"] = "yes";
- toplevelProgramFolder = true;
- } else {
- setupDirectives["DefaultGroupName"] =
- GetOption("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER");
- toplevelProgramFolder = false;
- }
- if (IsSet("CPACK_INNOSETUP_PASSWORD")) {
- setupDirectives["Password"] = GetOption("CPACK_INNOSETUP_PASSWORD");
- setupDirectives["Encryption"] = "yes";
- }
- /*
- * These directives can only be modified using the
- * CPACK_INNOSETUP_SETUP_<directive> variables
- */
- setupDirectives["ShowLanguageDialog"] = "auto";
- setupDirectives["AllowNoIcons"] = "yes";
- setupDirectives["Compression"] = "lzma";
- setupDirectives["SolidCompression"] = "yes";
- // Output file and directory
- if (!RequireOption("CPACK_PACKAGE_FILE_NAME")) {
- return false;
- }
- setupDirectives["OutputBaseFilename"] = GetOption("CPACK_PACKAGE_FILE_NAME");
- if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY")) {
- return false;
- }
- setupDirectives["OutputDir"] = cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_TOPLEVEL_DIRECTORY"));
- setupDirectives["SourceDir"] =
- cmSystemTools::ConvertToWindowsOutputPath(toplevel);
- // Target architecture
- if (!RequireOption("CPACK_INNOSETUP_ARCHITECTURE")) {
- return false;
- }
- cmValue const architecture = GetOption("CPACK_INNOSETUP_ARCHITECTURE");
- if (architecture != "x86" && architecture != "x64" &&
- architecture != "arm64" && architecture != "ia64") {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "CPACK_INNOSETUP_ARCHITECTURE must be either x86, x64, "
- "arm64 or ia64"
- << std::endl);
- return false;
- }
- // The following directives must not be set to target x86
- if (architecture != "x86") {
- setupDirectives["ArchitecturesAllowed"] = architecture;
- setupDirectives["ArchitecturesInstallIn64BitMode"] = architecture;
- }
- /*
- * Handle custom directives (they have higher priority than other variables,
- * so they have to be processed after all other variables)
- */
- for (const std::string& i : GetOptions()) {
- if (cmHasPrefix(i, "CPACK_INNOSETUP_SETUP_")) {
- const std::string& directive =
- i.substr(cmStrLen("CPACK_INNOSETUP_SETUP_"));
- setupDirectives[directive] = GetOption(i);
- }
- }
- return true;
- }
- bool cmCPackInnoSetupGenerator::ProcessFiles()
- {
- std::map<std::string, std::string> customFileInstructions;
- if (IsSet("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS")) {
- const cmList instructions(
- GetOption("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS"));
- if (instructions.size() % 2 != 0) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS should "
- "contain pairs of <path> and <instruction>"
- << std::endl);
- return false;
- }
- for (auto it = instructions.begin(); it != instructions.end(); ++it) {
- const std::string& key =
- QuotePath(cmSystemTools::CollapseFullPath(*it, toplevel));
- customFileInstructions[key] = *(++it);
- }
- }
- const std::string& iconsPrefix =
- toplevelProgramFolder ? "{autoprograms}\\" : "{group}\\";
- std::map<std::string, std::string> icons;
- if (IsSet("CPACK_PACKAGE_EXECUTABLES")) {
- const cmList executables(GetOption("CPACK_PACKAGE_EXECUTABLES"));
- if (executables.size() % 2 != 0) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "CPACK_PACKAGE_EXECUTABLES should should contain pairs of "
- "<executable> and <text label>"
- << std::endl);
- return false;
- }
- for (auto it = executables.begin(); it != executables.end(); ++it) {
- const std::string& key = *it;
- icons[key] = *(++it);
- }
- }
- std::vector<std::string> desktopIcons;
- if (IsSet("CPACK_CREATE_DESKTOP_LINKS")) {
- cmExpandList(GetOption("CPACK_CREATE_DESKTOP_LINKS"), desktopIcons);
- }
- std::vector<std::string> runExecutables;
- if (IsSet("CPACK_INNOSETUP_RUN_EXECUTABLES")) {
- cmExpandList(GetOption("CPACK_INNOSETUP_RUN_EXECUTABLES"), runExecutables);
- }
- for (const std::string& i : files) {
- cmCPackInnoSetupKeyValuePairs params;
- std::string toplevelDirectory;
- std::string outputDir;
- cmCPackComponent* component = nullptr;
- std::string componentParam;
- if (!Components.empty()) {
- const std::string& fileName = cmSystemTools::RelativePath(toplevel, i);
- const std::string::size_type pos = fileName.find('/');
- // Use the custom component install directory if we have one
- if (pos != std::string::npos) {
- const std::string& componentName = fileName.substr(0, pos);
- component = &Components[componentName];
- toplevelDirectory =
- cmSystemTools::CollapseFullPath(componentName, toplevel);
- outputDir = CustomComponentInstallDirectory(component);
- componentParam =
- CreateRecursiveComponentPath(component->Group, component->Name);
- if (component->IsHidden && component->IsDisabledByDefault) {
- continue;
- }
- if (component->IsHidden) {
- componentParam.clear();
- }
- } else {
- // Don't install component directories
- continue;
- }
- } else {
- toplevelDirectory = toplevel;
- outputDir = "{app}";
- }
- if (!componentParam.empty()) {
- params["Components"] = componentParam;
- }
- if (cmSystemTools::FileIsDirectory(i)) {
- // Custom instructions replace the automatic generated instructions
- if (customFileInstructions.count(QuotePath(i))) {
- dirInstructions.push_back(customFileInstructions[QuotePath(i)]);
- } else {
- std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(
- cmStrCat(outputDir, '\\',
- cmSystemTools::RelativePath(toplevelDirectory, i)));
- cmStripSuffixIfExists(destDir, '\\');
- params["Name"] = QuotePath(destDir);
- dirInstructions.push_back(ISKeyValueLine(params));
- }
- } else {
- // Custom instructions replace the automatic generated instructions
- if (customFileInstructions.count(QuotePath(i))) {
- fileInstructions.push_back(customFileInstructions[QuotePath(i)]);
- } else {
- std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(
- cmStrCat(outputDir, '\\',
- cmSystemTools::GetParentDirectory(
- cmSystemTools::RelativePath(toplevelDirectory, i))));
- cmStripSuffixIfExists(destDir, '\\');
- params["DestDir"] = QuotePath(destDir);
- if (component != nullptr && component->IsDownloaded) {
- const std::string& archiveName =
- cmSystemTools::GetFilenameWithoutLastExtension(
- component->ArchiveFile);
- const std::string& relativePath =
- cmSystemTools::RelativePath(toplevelDirectory, i);
- params["Source"] =
- QuotePath(cmStrCat("{tmp}\\", archiveName, '\\', relativePath));
- params["ExternalSize"] =
- std::to_string(cmSystemTools::FileLength(i));
- params["Flags"] = "external ignoreversion";
- params["BeforeInstall"] =
- cmStrCat("CPackExtractFile('", archiveName, "', '",
- cmRemoveQuotes(cmSystemTools::ConvertToWindowsOutputPath(
- relativePath)),
- "')");
- } else {
- params["Source"] = QuotePath(i);
- params["Flags"] = "ignoreversion";
- }
- fileInstructions.push_back(ISKeyValueLine(params));
- // Icon
- const std::string& name =
- cmSystemTools::GetFilenameWithoutLastExtension(i);
- const std::string& extension =
- cmSystemTools::GetFilenameLastExtension(i);
- if ((extension == ".exe" || extension == ".com") && // only .exe, .com
- icons.count(name)) {
- cmCPackInnoSetupKeyValuePairs iconParams;
- iconParams["Name"] = QuotePath(cmStrCat(iconsPrefix, icons[name]));
- iconParams["Filename"] =
- QuotePath(cmStrCat(destDir, '\\', name, extension));
- if (!componentParam.empty()) {
- iconParams["Components"] = componentParam;
- }
- iconInstructions.push_back(ISKeyValueLine(iconParams));
- // Desktop icon
- if (std::find(desktopIcons.begin(), desktopIcons.end(), name) !=
- desktopIcons.end()) {
- iconParams["Name"] =
- QuotePath(cmStrCat("{autodesktop}\\", icons[name]));
- iconParams["Tasks"] = "desktopicon";
- if (!componentParam.empty() &&
- std::find(desktopIconComponents.begin(),
- desktopIconComponents.end(),
- componentParam) == desktopIconComponents.end()) {
- desktopIconComponents.push_back(componentParam);
- }
- iconInstructions.push_back(ISKeyValueLine(iconParams));
- }
- // [Run] section
- if (std::find(runExecutables.begin(), runExecutables.end(), name) !=
- runExecutables.end()) {
- cmCPackInnoSetupKeyValuePairs runParams;
- runParams["Filename"] = iconParams["Filename"];
- runParams["Description"] = cmStrCat(
- "\"{cm:LaunchProgram,", PrepareForConstant(icons[name]), "}\"");
- runParams["Flags"] = "nowait postinstall skipifsilent";
- if (!componentParam.empty()) {
- runParams["Components"] = componentParam;
- }
- runInstructions.push_back(ISKeyValueLine(runParams));
- }
- }
- }
- }
- }
- // Additional icons
- static cmsys::RegularExpression urlRegex(
- "^(mailto:|(ftps?|https?|news)://).*$");
- if (IsSet("CPACK_INNOSETUP_MENU_LINKS")) {
- const cmList menuIcons(GetOption("CPACK_INNOSETUP_MENU_LINKS"));
- if (menuIcons.size() % 2 != 0) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "CPACK_INNOSETUP_MENU_LINKS should "
- "contain pairs of <shortcut target> and <shortcut label>"
- << std::endl);
- return false;
- }
- for (auto it = menuIcons.begin(); it != menuIcons.end(); ++it) {
- const std::string& target = *it;
- const std::string& label = *(++it);
- cmCPackInnoSetupKeyValuePairs params;
- params["Name"] = QuotePath(cmStrCat(iconsPrefix, label));
- if (urlRegex.find(target)) {
- params["Filename"] = Quote(target);
- } else {
- std::string dir = "{app}";
- std::string componentName;
- for (const auto& i : Components) {
- if (cmSystemTools::FileExists(cmSystemTools::CollapseFullPath(
- cmStrCat(i.second.Name, '\\', target), toplevel))) {
- dir = CustomComponentInstallDirectory(&i.second);
- componentName =
- CreateRecursiveComponentPath(i.second.Group, i.second.Name);
- if (i.second.IsHidden && i.second.IsDisabledByDefault) {
- goto continueOuterLoop;
- } else if (i.second.IsHidden) {
- componentName.clear();
- }
- break;
- }
- }
- params["Filename"] = QuotePath(cmStrCat(dir, '\\', target));
- if (!componentName.empty()) {
- params["Components"] = componentName;
- }
- }
- iconInstructions.push_back(ISKeyValueLine(params));
- continueOuterLoop:;
- }
- }
- SetOptionIfNotSet("CPACK_INNOSETUP_CREATE_UNINSTALL_LINK", "OFF");
- if (GetOption("CPACK_INNOSETUP_CREATE_UNINSTALL_LINK").IsOn()) {
- cmCPackInnoSetupKeyValuePairs params;
- params["Name"] = QuotePath(
- cmStrCat(iconsPrefix, "{cm:UninstallProgram,",
- PrepareForConstant(GetOption("CPACK_PACKAGE_NAME")), '}'));
- params["Filename"] = "\"{uninstallexe}\"";
- iconInstructions.push_back(ISKeyValueLine(params));
- }
- return true;
- }
- bool cmCPackInnoSetupGenerator::ProcessComponents()
- {
- codeIncludes.push_back("{ The following lines are required by CPack because "
- "this script uses components }");
- // Installation types
- std::vector<cmCPackInstallationType*> types(InstallationTypes.size());
- for (auto& i : InstallationTypes) {
- types[i.second.Index - 1] = &i.second;
- }
- std::vector<std::string> allTypes; // For required components
- for (cmCPackInstallationType* i : types) {
- cmCPackInnoSetupKeyValuePairs params;
- params["Name"] = Quote(i->Name);
- params["Description"] = Quote(i->DisplayName);
- allTypes.push_back(i->Name);
- typeInstructions.push_back(ISKeyValueLine(params));
- }
- // Inno Setup requires the additional "custom" type
- cmCPackInnoSetupKeyValuePairs customTypeParams;
- customTypeParams["Name"] = "\"custom\"";
- customTypeParams["Description"] =
- "\"{code:CPackGetCustomInstallationMessage}\"";
- customTypeParams["Flags"] = "iscustom";
- allTypes.push_back("custom");
- typeInstructions.push_back(ISKeyValueLine(customTypeParams));
- // Components
- std::vector<cmCPackComponent*> downloadedComponents;
- std::stack<cmCPackComponentGroup*> groups;
- for (auto& i : Components) {
- cmCPackInnoSetupKeyValuePairs params;
- cmCPackComponent* component = &i.second;
- if (component->IsHidden) {
- continue;
- }
- CreateRecursiveComponentGroups(component->Group);
- params["Name"] =
- Quote(CreateRecursiveComponentPath(component->Group, component->Name));
- params["Description"] = Quote(component->DisplayName);
- if (component->IsRequired) {
- params["Types"] = cmJoin(allTypes, " ");
- params["Flags"] = "fixed";
- } else if (!component->InstallationTypes.empty()) {
- std::vector<std::string> installationTypes;
- for (cmCPackInstallationType* j : component->InstallationTypes) {
- installationTypes.push_back(j->Name);
- }
- params["Types"] = cmJoin(installationTypes, " ");
- }
- componentInstructions.push_back(ISKeyValueLine(params));
- if (component->IsDownloaded) {
- downloadedComponents.push_back(component);
- if (component->ArchiveFile.empty()) {
- // Compute the name of the archive.
- if (!RequireOption("CPACK_TEMPORARY_DIRECTORY")) {
- return false;
- }
- std::string packagesDir =
- cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), ".dummy");
- component->ArchiveFile =
- cmStrCat(cmSystemTools::GetFilenameWithoutLastExtension(packagesDir),
- '-', component->Name, ".zip");
- } else if (!cmHasSuffix(component->ArchiveFile, ".zip")) {
- component->ArchiveFile = cmStrCat(component->ArchiveFile, ".zip");
- }
- }
- }
- // Downloaded components
- if (!downloadedComponents.empty()) {
- // Create the directory for the upload area
- cmValue userUploadDirectory = GetOption("CPACK_UPLOAD_DIRECTORY");
- std::string uploadDirectory;
- if (cmNonempty(userUploadDirectory)) {
- uploadDirectory = *userUploadDirectory;
- } else {
- if (!RequireOption("CPACK_PACKAGE_DIRECTORY")) {
- return false;
- }
- uploadDirectory =
- cmStrCat(GetOption("CPACK_PACKAGE_DIRECTORY"), "/CPackUploads");
- }
- if (!cmSystemTools::FileExists(uploadDirectory)) {
- if (!cmSystemTools::MakeDirectory(uploadDirectory)) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Unable to create Inno Setup upload directory "
- << uploadDirectory << std::endl);
- return false;
- }
- }
- if (!RequireOption("CPACK_DOWNLOAD_SITE")) {
- return false;
- }
- SetOptionIfNotSet("CPACK_INNOSETUP_VERIFY_DOWNLOADS", "ON");
- const bool verifyDownloads =
- GetOption("CPACK_INNOSETUP_VERIFY_DOWNLOADS").IsOn();
- const std::string& urlPrefix =
- cmHasSuffix(GetOption("CPACK_DOWNLOAD_SITE").GetCStr(), '/')
- ? GetOption("CPACK_DOWNLOAD_SITE")
- : cmStrCat(GetOption("CPACK_DOWNLOAD_SITE"), '/');
- std::vector<std::string> archiveUrls;
- std::vector<std::string> archiveFiles;
- std::vector<std::string> archiveHashes;
- std::vector<std::string> archiveComponents;
- for (cmCPackComponent* i : downloadedComponents) {
- std::string hash;
- if (!BuildDownloadedComponentArchive(
- i, uploadDirectory, (verifyDownloads ? &hash : nullptr))) {
- return false;
- }
- archiveUrls.push_back(Quote(cmStrCat(urlPrefix, i->ArchiveFile)));
- archiveFiles.push_back(
- Quote(cmSystemTools::GetFilenameWithoutLastExtension(i->ArchiveFile)));
- archiveHashes.push_back(Quote(hash));
- archiveComponents.push_back(
- Quote(CreateRecursiveComponentPath(i->Group, i->Name)));
- }
- SetOption("CPACK_INNOSETUP_DOWNLOAD_COUNT_INTERNAL",
- std::to_string(archiveFiles.size()));
- SetOption("CPACK_INNOSETUP_DOWNLOAD_URLS_INTERNAL",
- cmJoin(archiveUrls, ", "));
- SetOption("CPACK_INNOSETUP_DOWNLOAD_ARCHIVES_INTERNAL",
- cmJoin(archiveFiles, ", "));
- SetOption("CPACK_INNOSETUP_DOWNLOAD_HASHES_INTERNAL",
- cmJoin(archiveHashes, ", "));
- SetOption("CPACK_INNOSETUP_DOWNLOAD_COMPONENTS_INTERNAL",
- cmJoin(archiveComponents, ", "));
- static const std::string& downloadLines =
- "#define protected CPackDownloadCount "
- "@CPACK_INNOSETUP_DOWNLOAD_COUNT_INTERNAL@\n"
- "#dim protected CPackDownloadUrls[CPackDownloadCount] "
- "{@CPACK_INNOSETUP_DOWNLOAD_URLS_INTERNAL@}\n"
- "#dim protected CPackDownloadArchives[CPackDownloadCount] "
- "{@CPACK_INNOSETUP_DOWNLOAD_ARCHIVES_INTERNAL@}\n"
- "#dim protected CPackDownloadHashes[CPackDownloadCount] "
- "{@CPACK_INNOSETUP_DOWNLOAD_HASHES_INTERNAL@}\n"
- "#dim protected CPackDownloadComponents[CPackDownloadCount] "
- "{@CPACK_INNOSETUP_DOWNLOAD_COMPONENTS_INTERNAL@}";
- std::string output;
- if (!ConfigureString(downloadLines, output)) {
- return false;
- }
- codeIncludes.push_back(output);
- }
- // Add the required script
- const std::string& componentsScriptTemplate =
- FindTemplate("ISComponents.pas");
- if (componentsScriptTemplate.empty()) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Could not find additional Inno Setup script file."
- << std::endl);
- return false;
- }
- codeIncludes.push_back("#include " + QuotePath(componentsScriptTemplate) +
- "\n");
- return true;
- }
- bool cmCPackInnoSetupGenerator::ConfigureISScript()
- {
- const std::string& isScriptTemplate = FindTemplate("ISScript.template.in");
- const std::string& isScriptFile =
- cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISScript.iss");
- if (isScriptTemplate.empty()) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Could not find Inno Setup installer template file."
- << std::endl);
- return false;
- }
- // Create internal variables
- std::vector<std::string> setupSection;
- for (const auto& i : setupDirectives) {
- setupSection.emplace_back(cmStrCat(i.first, '=', TranslateBool(i.second)));
- }
- // Also create comments if the sections are empty
- const std::string& defaultMessage =
- "; CPack didn't find any entries for this section";
- if (IsSet("CPACK_CREATE_DESKTOP_LINKS") &&
- !GetOption("CPACK_CREATE_DESKTOP_LINKS").Get()->empty()) {
- cmCPackInnoSetupKeyValuePairs tasks;
- tasks["Name"] = "\"desktopicon\"";
- tasks["Description"] = "\"{cm:CreateDesktopIcon}\"";
- tasks["GroupDescription"] = "\"{cm:AdditionalIcons}\"";
- tasks["Flags"] = "unchecked";
- if (!desktopIconComponents.empty()) {
- tasks["Components"] = cmJoin(desktopIconComponents, " ");
- }
- SetOption("CPACK_INNOSETUP_TASKS_INTERNAL", ISKeyValueLine(tasks));
- } else {
- SetOption("CPACK_INNOSETUP_TASKS_INTERNAL", defaultMessage);
- }
- SetOption("CPACK_INNOSETUP_INCLUDES_INTERNAL",
- includeDirectives.empty() ? "; No extra script files specified"
- : cmJoin(includeDirectives, "\n"));
- SetOption("CPACK_INNOSETUP_SETUP_INTERNAL",
- setupSection.empty() ? defaultMessage
- : cmJoin(setupSection, "\n"));
- SetOption("CPACK_INNOSETUP_LANGUAGES_INTERNAL",
- languageInstructions.empty() ? defaultMessage
- : cmJoin(languageInstructions, "\n"));
- SetOption("CPACK_INNOSETUP_DIRS_INTERNAL",
- dirInstructions.empty() ? defaultMessage
- : cmJoin(dirInstructions, "\n"));
- SetOption("CPACK_INNOSETUP_FILES_INTERNAL",
- fileInstructions.empty() ? defaultMessage
- : cmJoin(fileInstructions, "\n"));
- SetOption("CPACK_INNOSETUP_TYPES_INTERNAL",
- typeInstructions.empty() ? defaultMessage
- : cmJoin(typeInstructions, "\n"));
- SetOption("CPACK_INNOSETUP_COMPONENTS_INTERNAL",
- componentInstructions.empty()
- ? defaultMessage
- : cmJoin(componentInstructions, "\n"));
- SetOption("CPACK_INNOSETUP_ICONS_INTERNAL",
- iconInstructions.empty() ? defaultMessage
- : cmJoin(iconInstructions, "\n"));
- SetOption("CPACK_INNOSETUP_RUN_INTERNAL",
- runInstructions.empty() ? defaultMessage
- : cmJoin(runInstructions, "\n"));
- SetOption("CPACK_INNOSETUP_CODE_INTERNAL",
- codeIncludes.empty() ? "{ No extra code files specified }"
- : cmJoin(codeIncludes, "\n"));
- cmCPackLogger(cmCPackLog::LOG_VERBOSE,
- "Configure file: " << isScriptTemplate << " to "
- << isScriptFile << std::endl);
- return ConfigureFile(isScriptTemplate, isScriptFile);
- }
- bool cmCPackInnoSetupGenerator::Compile()
- {
- const std::string& isScriptFile =
- cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISScript.iss");
- const std::string& isccLogFile =
- cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISCCOutput.log");
- std::vector<std::string> isccArgs;
- // Custom defines
- for (const std::string& i : GetOptions()) {
- if (cmHasPrefix(i, "CPACK_INNOSETUP_DEFINE_")) {
- const std::string& name = i.substr(cmStrLen("CPACK_INNOSETUP_DEFINE_"));
- isccArgs.push_back(
- cmStrCat("\"/D", name, '=', TranslateBool(GetOption(i)), '"'));
- }
- }
- if (IsSet("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS")) {
- const cmList args(GetOption("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS"));
- isccArgs.insert(isccArgs.end(), args.begin(), args.end());
- }
- const std::string& isccCmd =
- cmStrCat(QuotePath(GetOption("CPACK_INSTALLER_PROGRAM")), ' ',
- cmJoin(isccArgs, " "), ' ', QuotePath(isScriptFile));
- cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << isccCmd << std::endl);
- std::string output;
- int retVal = 1;
- const bool res = cmSystemTools::RunSingleCommand(
- isccCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
- cmDuration::zero());
- if (!res || retVal) {
- cmGeneratedFileStream ofs(isccLogFile);
- ofs << "# Run command: " << isccCmd << std::endl
- << "# Output:" << std::endl
- << output << std::endl;
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem running ISCC. Please check "
- << isccLogFile << " for errors." << std::endl);
- return false;
- }
- return true;
- }
- bool cmCPackInnoSetupGenerator::BuildDownloadedComponentArchive(
- cmCPackComponent* component, const std::string& uploadDirectory,
- std::string* hash)
- {
- // Remove the old archive, if one exists
- const std::string& archiveFile =
- uploadDirectory + '/' + component->ArchiveFile;
- cmCPackLogger(cmCPackLog::LOG_OUTPUT,
- "- Building downloaded component archive: " << archiveFile
- << std::endl);
- if (cmSystemTools::FileExists(archiveFile, true)) {
- if (!cmSystemTools::RemoveFile(archiveFile)) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Unable to remove archive file " << archiveFile
- << std::endl);
- return false;
- }
- }
- // Find a ZIP program
- if (!IsSet("ZIP_EXECUTABLE")) {
- ReadListFile("Internal/CPack/CPackZIP.cmake");
- if (!IsSet("ZIP_EXECUTABLE")) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Unable to find ZIP program" << std::endl);
- return false;
- }
- }
- if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY") ||
- !RequireOption("CPACK_TEMPORARY_DIRECTORY") ||
- !RequireOption("CPACK_ZIP_NEED_QUOTES") ||
- !RequireOption("CPACK_ZIP_COMMAND")) {
- return false;
- }
- // The directory where this component's files reside
- const std::string& dirName =
- cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), '/', component->Name);
- // Build the list of files to go into this archive
- const std::string& zipListFileName =
- cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), "/winZip.filelist");
- const bool needQuotesInFile = cmIsOn(GetOption("CPACK_ZIP_NEED_QUOTES"));
- { // the scope is needed for cmGeneratedFileStream
- cmGeneratedFileStream out(zipListFileName);
- for (const std::string& i : component->Files) {
- out << (needQuotesInFile ? Quote(i) : i) << std::endl;
- }
- }
- // Build the archive in the upload area
- std::string cmd = GetOption("CPACK_ZIP_COMMAND");
- cmsys::SystemTools::ReplaceString(cmd, "<ARCHIVE>", archiveFile.c_str());
- cmsys::SystemTools::ReplaceString(cmd, "<FILELIST>",
- zipListFileName.c_str());
- std::string output;
- int retVal = -1;
- const bool res = cmSystemTools::RunSingleCommand(
- cmd, &output, &output, &retVal, dirName.c_str(), this->GeneratorVerbose,
- cmDuration::zero());
- if (!res || retVal) {
- std::string tmpFile =
- cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/CompressZip.log");
- cmGeneratedFileStream ofs(tmpFile);
- ofs << "# Run command: " << cmd << std::endl
- << "# Output:" << std::endl
- << output << std::endl;
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem running zip command: " << cmd << std::endl
- << "Please check " << tmpFile
- << " for errors"
- << std::endl);
- return false;
- }
- // Try to get the SHA256 hash of the archive file
- if (hash == nullptr) {
- return true;
- }
- #ifdef _WIN32
- const std::string& hashCmd =
- cmStrCat("certutil -hashfile ", QuotePath(archiveFile), " SHA256");
- std::string hashOutput;
- int hashRetVal = -1;
- const bool hashRes = cmSystemTools::RunSingleCommand(
- hashCmd, &hashOutput, &hashOutput, &hashRetVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
- if (!hashRes || hashRetVal) {
- cmCPackLogger(cmCPackLog::LOG_WARNING,
- "Problem running certutil command: " << hashCmd
- << std::endl);
- }
- *hash = cmTrimWhitespace(cmTokenize(hashOutput, "\n").at(1));
- if (hash->length() != 64) {
- cmCPackLogger(cmCPackLog::LOG_WARNING,
- "Problem parsing certutil output of command: " << hashCmd
- << std::endl);
- hash->clear();
- }
- #endif
- return true;
- }
- cmValue cmCPackInnoSetupGenerator::RequireOption(const std::string& key)
- {
- cmValue value = GetOption(key);
- if (!value) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Required variable " << key << " not set" << std::endl);
- }
- return value;
- }
- std::string cmCPackInnoSetupGenerator::CustomComponentInstallDirectory(
- const cmCPackComponent* component)
- {
- cmValue outputDir = GetOption(
- cmStrCat("CPACK_INNOSETUP_", component->Name, "_INSTALL_DIRECTORY"));
- if (outputDir) {
- std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(outputDir);
- cmStripSuffixIfExists(destDir, '\\');
- /*
- * Add a dir instruction for the custom directory
- * (only once and not for Inno Setup constants ending with '}')
- */
- static std::vector<std::string> customDirectories;
- if (!cmHasSuffix(destDir, '}') &&
- std::find(customDirectories.begin(), customDirectories.end(),
- component->Name) == customDirectories.end()) {
- cmCPackInnoSetupKeyValuePairs params;
- params["Name"] = QuotePath(destDir);
- params["Components"] =
- CreateRecursiveComponentPath(component->Group, component->Name);
- dirInstructions.push_back(ISKeyValueLine(params));
- customDirectories.push_back(component->Name);
- }
- return destDir;
- }
- return "{app}";
- }
- std::string cmCPackInnoSetupGenerator::TranslateBool(const std::string& value)
- {
- if (value.empty()) {
- return value;
- }
- SetOptionIfNotSet("CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT", "ON");
- if (GetOption("CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT").IsOn()) {
- if (cmIsOn(value)) {
- return "yes";
- }
- if (cmIsOff(value)) {
- return "no";
- }
- }
- return value;
- }
- std::string cmCPackInnoSetupGenerator::ISKeyValueLine(
- const cmCPackInnoSetupKeyValuePairs& params)
- {
- /*
- * To simplify readability of the generated code, the keys are sorted.
- * Unknown keys are ignored to avoid errors during compilation.
- */
- static const char* const availableKeys[] = {
- "Source", "DestDir", "Name", "Filename",
- "Description", "GroupDescription", "MessagesFile", "Types",
- "ExternalSize", "BeforeInstall", "Flags", "Components",
- "Tasks"
- };
- std::vector<std::string> keys;
- for (const char* i : availableKeys) {
- if (params.count(i)) {
- keys.emplace_back(cmStrCat(i, ": ", params.at(i)));
- }
- }
- return cmJoin(keys, "; ");
- }
- std::string cmCPackInnoSetupGenerator::CreateRecursiveComponentPath(
- cmCPackComponentGroup* group, const std::string& path)
- {
- if (group == nullptr) {
- return path;
- }
- const std::string& newPath =
- path.empty() ? group->Name : cmStrCat(group->Name, '\\', path);
- return CreateRecursiveComponentPath(group->ParentGroup, newPath);
- }
- void cmCPackInnoSetupGenerator::CreateRecursiveComponentGroups(
- cmCPackComponentGroup* group)
- {
- if (group == nullptr) {
- return;
- }
- CreateRecursiveComponentGroups(group->ParentGroup);
- static std::vector<cmCPackComponentGroup*> processedGroups;
- if (std::find(processedGroups.begin(), processedGroups.end(), group) ==
- processedGroups.end()) {
- processedGroups.push_back(group);
- cmCPackInnoSetupKeyValuePairs params;
- params["Name"] = Quote(CreateRecursiveComponentPath(group));
- params["Description"] = Quote(group->DisplayName);
- componentInstructions.push_back(ISKeyValueLine(params));
- }
- }
- std::string cmCPackInnoSetupGenerator::Quote(const std::string& string)
- {
- if (cmHasPrefix(string, '"') && cmHasSuffix(string, '"')) {
- return Quote(string.substr(1, string.length() - 2));
- }
- // Double quote syntax
- std::string nString = string;
- cmSystemTools::ReplaceString(nString, "\"", "\"\"");
- return cmStrCat('"', nString, '"');
- }
- std::string cmCPackInnoSetupGenerator::QuotePath(const std::string& path)
- {
- return Quote(cmSystemTools::ConvertToWindowsOutputPath(path));
- }
- std::string cmCPackInnoSetupGenerator::PrepareForConstant(
- const std::string& string)
- {
- std::string nString = string;
- cmSystemTools::ReplaceString(nString, "%", "%25"); // First replacement!
- cmSystemTools::ReplaceString(nString, "\"", "%22");
- cmSystemTools::ReplaceString(nString, ",", "%2c");
- cmSystemTools::ReplaceString(nString, "|", "%7c");
- cmSystemTools::ReplaceString(nString, "}", "%7d");
- return nString;
- }
|