1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-14 19:08:07 +08:00

CPack/WiX: Implement opt-in per component .cab

By setting CPACK_WIX_CAB_PER_COMPONENT users can generate one
.cab per component instead of one .cab per installer.

WiX compresses .cab files in parallel.
This may potentially speed up installer creation.

May also allow larger installers (there is a 2GB per .cab limit).
This commit is contained in:
Nils Gladitz
2025-09-10 10:53:26 +02:00
parent 082071203f
commit 193f17102f
8 changed files with 64 additions and 13 deletions

View File

@@ -487,3 +487,12 @@ Windows using WiX.
first manually uninstall any older version.
See https://docs.firegiant.com/wix3/xsd/wix/package/
.. variable:: CPACK_WIX_CAB_PER_COMPONENT
.. versionadded:: 4.2
If this variable is set to true one `.cab` file per component is created.
The default is to create a single `.cab` file for all files in the installer.
WiX creates `.cab` files in parallel so multiple `.cab` files may be desirable for faster packaging.

View File

@@ -0,0 +1,6 @@
wix-multi-cab
-------------
* :variable:`CPACK_WIX_CAB_PER_COMPONENT` allows CPack WIX opt-in generation of one
`.cab` file per component. Having multiple `.cab` files may improve the time it takes
to generate installers and may also work around per `.cab` size constraints.

View File

@@ -19,7 +19,9 @@
<Package InstallerVersion="301" Compressed="yes" InstallScope="$(var.CPACK_WIX_INSTALL_SCOPE)"/>
<?endif?>
<?ifndef CPACK_WIX_CAB_PER_COMPONENT?>
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>
<?endif?>
<MajorUpgrade
Schedule="afterInstallInitialize"

View File

@@ -19,7 +19,9 @@
Compressed="yes"
>
<?ifndef CPACK_WIX_CAB_PER_COMPONENT?>
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>
<?endif?>
<MajorUpgrade
Schedule="afterInstallInitialize"

View File

@@ -430,6 +430,7 @@ void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile()
CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER");
CopyDefinition(includeFile, "CPACK_WIX_UI_REF");
CopyDefinition(includeFile, "CPACK_WIX_INSTALL_SCOPE");
CopyDefinition(includeFile, "CPACK_WIX_CAB_PER_COMPONENT");
}
void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
@@ -492,6 +493,22 @@ void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile()
cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT);
InjectXmlNamespaces(includeFile);
bool perComponentCab = GetOption("CPACK_WIX_CAB_PER_COMPONENT").IsOn();
if (perComponentCab) {
std::size_t cabCount = std::max<std::size_t>(1, this->Components.size());
for (std::size_t i = 0; i < cabCount; ++i) {
std::string diskId = std::to_string(i + 1);
includeFile.BeginElement("Media");
includeFile.AddAttribute("Id", diskId);
includeFile.AddAttribute("Cabinet", "media" + diskId + ".cab");
includeFile.AddAttribute("EmbedCab", "yes");
includeFile.EndElement("Media");
}
}
this->Patch->ApplyFragment("#PRODUCT", includeFile);
}
@@ -617,11 +634,17 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
if (Components.empty()) {
AddComponentsToFeature(toplevel, "ProductFeature", directoryDefinitions,
fileDefinitions, featureDefinitions,
globalShortcuts);
globalShortcuts, 0);
globalShortcuts.AddShortcutTypes(emittedShortcutTypes);
} else {
bool perComponentCab = GetOption("CPACK_WIX_CAB_PER_COMPONENT").IsOn();
std::size_t componentDiskId = 0;
for (auto const& i : this->Components) {
++componentDiskId;
cmCPackComponent const& component = i.second;
std::string componentPath = cmStrCat(toplevel, '/', component.Name);
@@ -631,7 +654,8 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
cmWIXShortcuts featureShortcuts;
AddComponentsToFeature(componentPath, componentFeatureId,
directoryDefinitions, fileDefinitions,
featureDefinitions, featureShortcuts);
featureDefinitions, featureShortcuts,
perComponentCab ? componentDiskId : 0);
featureShortcuts.AddShortcutTypes(emittedShortcutTypes);
@@ -779,7 +803,8 @@ bool cmCPackWIXGenerator::AddComponentsToFeature(
std::string const& rootPath, std::string const& featureId,
cmWIXDirectoriesSourceWriter& directoryDefinitions,
cmWIXFilesSourceWriter& fileDefinitions,
cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts)
cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts,
int diskId)
{
featureDefinitions.BeginElement("FeatureRef");
featureDefinitions.AddAttribute("Id", featureId);
@@ -807,7 +832,7 @@ bool cmCPackWIXGenerator::AddComponentsToFeature(
AddDirectoryAndFileDefinitions(
rootPath, "INSTALL_ROOT", directoryDefinitions, fileDefinitions,
featureDefinitions, cpackPackageExecutablesList,
cpackPackageDesktopLinksList, shortcuts);
cpackPackageDesktopLinksList, shortcuts, diskId);
featureDefinitions.EndElement("FeatureRef");
@@ -995,7 +1020,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitions(
cmWIXFeaturesSourceWriter& featureDefinitions,
std::vector<std::string> const& packageExecutables,
std::vector<std::string> const& desktopExecutables,
cmWIXShortcuts& shortcuts)
cmWIXShortcuts& shortcuts, int diskId)
{
cmsys::Directory dir;
dir.Load(topdir.c_str());
@@ -1054,9 +1079,10 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitions(
directoryDefinitions.AddAttribute("Name", fileName);
this->Patch->ApplyFragment(subDirectoryId, directoryDefinitions);
AddDirectoryAndFileDefinitions(
fullPath, subDirectoryId, directoryDefinitions, fileDefinitions,
featureDefinitions, packageExecutables, desktopExecutables, shortcuts);
AddDirectoryAndFileDefinitions(fullPath, subDirectoryId,
directoryDefinitions, fileDefinitions,
featureDefinitions, packageExecutables,
desktopExecutables, shortcuts, diskId);
directoryDefinitions.EndElement("Directory");
} else {
@@ -1068,7 +1094,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitions(
}
std::string componentId = fileDefinitions.EmitComponentFile(
directoryId, id, fullPath, *(this->Patch), installedFile);
directoryId, id, fullPath, *(this->Patch), installedFile, diskId);
featureDefinitions.EmitComponentRef(componentId);

View File

@@ -86,7 +86,8 @@ private:
std::string const& rootPath, std::string const& featureId,
cmWIXDirectoriesSourceWriter& directoryDefinitions,
cmWIXFilesSourceWriter& fileDefinitions,
cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts);
cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts,
int diskId);
bool CreateShortcuts(std::string const& cpackComponentName,
std::string const& featureId,
@@ -122,7 +123,7 @@ private:
cmWIXFeaturesSourceWriter& featureDefinitions,
std::vector<std::string> const& packageExecutables,
std::vector<std::string> const& desktopExecutables,
cmWIXShortcuts& shortcuts);
cmWIXShortcuts& shortcuts, int diskId);
bool RequireOption(std::string const& name, std::string& value) const;

View File

@@ -122,7 +122,7 @@ std::string cmWIXFilesSourceWriter::EmitComponentCreateFolder(
std::string cmWIXFilesSourceWriter::EmitComponentFile(
std::string const& directoryId, std::string const& id,
std::string const& filePath, cmWIXPatch& patch,
cmInstalledFile const* installedFile)
cmInstalledFile const* installedFile, int diskId)
{
std::string componentId = std::string("CM_C") + id;
std::string fileId = std::string("CM_F") + id;
@@ -136,6 +136,10 @@ std::string cmWIXFilesSourceWriter::EmitComponentFile(
AddAttribute("Id", componentId);
AddAttribute("Guid", guid);
if (diskId) {
AddAttribute("DiskId", std::to_string(diskId));
}
if (installedFile) {
if (installedFile->GetPropertyAsBool("CPACK_NEVER_OVERWRITE")) {
AddAttribute("NeverOverwrite", "yes");

View File

@@ -35,5 +35,6 @@ public:
std::string EmitComponentFile(std::string const& directoryId,
std::string const& id,
std::string const& filePath, cmWIXPatch& patch,
cmInstalledFile const* installedFile);
cmInstalledFile const* installedFile,
int diskId);
};