1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-15 12:16:40 +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. first manually uninstall any older version.
See https://docs.firegiant.com/wix3/xsd/wix/package/ 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)"/> <Package InstallerVersion="301" Compressed="yes" InstallScope="$(var.CPACK_WIX_INSTALL_SCOPE)"/>
<?endif?> <?endif?>
<?ifndef CPACK_WIX_CAB_PER_COMPONENT?>
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/> <Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>
<?endif?>
<MajorUpgrade <MajorUpgrade
Schedule="afterInstallInitialize" Schedule="afterInstallInitialize"

View File

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

View File

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

View File

@@ -86,7 +86,8 @@ private:
std::string const& rootPath, std::string const& featureId, std::string const& rootPath, std::string const& featureId,
cmWIXDirectoriesSourceWriter& directoryDefinitions, cmWIXDirectoriesSourceWriter& directoryDefinitions,
cmWIXFilesSourceWriter& fileDefinitions, cmWIXFilesSourceWriter& fileDefinitions,
cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts); cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts,
int diskId);
bool CreateShortcuts(std::string const& cpackComponentName, bool CreateShortcuts(std::string const& cpackComponentName,
std::string const& featureId, std::string const& featureId,
@@ -122,7 +123,7 @@ private:
cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXFeaturesSourceWriter& featureDefinitions,
std::vector<std::string> const& packageExecutables, std::vector<std::string> const& packageExecutables,
std::vector<std::string> const& desktopExecutables, std::vector<std::string> const& desktopExecutables,
cmWIXShortcuts& shortcuts); cmWIXShortcuts& shortcuts, int diskId);
bool RequireOption(std::string const& name, std::string& value) const; 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 cmWIXFilesSourceWriter::EmitComponentFile(
std::string const& directoryId, std::string const& id, std::string const& directoryId, std::string const& id,
std::string const& filePath, cmWIXPatch& patch, std::string const& filePath, cmWIXPatch& patch,
cmInstalledFile const* installedFile) cmInstalledFile const* installedFile, int diskId)
{ {
std::string componentId = std::string("CM_C") + id; std::string componentId = std::string("CM_C") + id;
std::string fileId = std::string("CM_F") + id; std::string fileId = std::string("CM_F") + id;
@@ -136,6 +136,10 @@ std::string cmWIXFilesSourceWriter::EmitComponentFile(
AddAttribute("Id", componentId); AddAttribute("Id", componentId);
AddAttribute("Guid", guid); AddAttribute("Guid", guid);
if (diskId) {
AddAttribute("DiskId", std::to_string(diskId));
}
if (installedFile) { if (installedFile) {
if (installedFile->GetPropertyAsBool("CPACK_NEVER_OVERWRITE")) { if (installedFile->GetPropertyAsBool("CPACK_NEVER_OVERWRITE")) {
AddAttribute("NeverOverwrite", "yes"); AddAttribute("NeverOverwrite", "yes");

View File

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