Spec: M4 — zixl builds WiX v4 sources #23

Closed
opened 2026-10-14 11:53:43 -05:00 by jeff · 1 comment
Owner

Problem Statement

zixl reads only WiX v3, the language msitools' wixl reads. Every WiX release since v4 has used a new language: a new namespace, <Package> in place of <Product> and <Package>, standard directories without TARGETDIR, Bitness for Win64, conditions as attributes, and from v5 on, defaults for what a source leaves out. WiX sources written today are in that language, so zixl cannot build them.

Solution

The same zixl command, and the same library and build.zig step, build WiX v4 sources: a source's <Wix> namespace says which language it is in. For WiX v4, zixl does what the current WiX documents (ADR-0007). Where the documentation is silent on something that would change the output, zixl refuses it by name with the reason, or infers a default and says so in ADR-0007.

User Stories

  1. As a packager with a WiX v4 source, I want zixl product.wxs to build it, so that I need no .NET toolchain.
  2. As a packager, I want <Package> to carry the product's name, version, manufacturer, upgrade code and code page, as WiX v4 has it.
  3. As a packager, I want v4's defaults: compressed, Windows Installer 5.0, per-machine, UTF-8, and generated product and component codes.
  4. As a packager, I want StandardDirectory, including ProgramFiles6432Folder, which follows the package's bitness.
  5. As a packager, I want Subdirectory on directories, components and component groups, so that I need not write a Directory for every level.
  6. As a packager, I want Bitness to make one component 32-bit in a 64-bit package.
  7. As a packager, I want Component/@Condition, Feature's Level children and Launch, which replace v3's Condition element.
  8. As a packager, I want MediaTemplate to lay out cabinets for me.
  9. As a packager, I want a default feature, a default INSTALLFOLDER and naked Files, as WiX v5 and later have them.
  10. As a packager, I want !(bind.Property.NAME) in a value.
  11. As a packager, I want SummaryInformation to set the package's description, comments, keywords and code page.
  12. As a packager, I want registry values, environment variables, shortcuts, icons, folders and removals, as in v3.
  13. As a packager, I want what zixl does not implement refused by name, with the reason when it is that WiX does not document it.
  14. As a packager, I want a v3 source and a v4 source in one build refused, rather than mixed.
  15. As a maintainer, I want every v4 fixture checked against a v3 twin that zixl must build into the same tables.

Implementation Decisions

  • Compiling: compiling reads either language into the same WiX document. Linking and writing do not change, except for what WiX v4 adds: per-component bitness, component conditions, generated identifiers and media templates.
  • The language is chosen by each source's namespace. A build may not mix the two.
  • Generated identifiers: Ids WiX would generate are zixl's own: a prefix and a hash of what the element is. This covers the directories Subdirectory makes, and a Directory or File with no Id. A component with no Id takes its key path's, as WiX v6 does.
  • Defaults, from the WiX schema reference:
    • Package: Compressed="yes", InstallerVersion="500", Scope="perMachine", Codepage="65001" (by number or web name), Language="0" (inferred), and a generated ProductCode;
    • Component/@Guid="*"; Feature/@Level="1";
    • MediaTemplate: cab{0}.cab, external, medium compression, 200 MB per cabinet.
  • Defaults from WiX v5 and later: a package with no feature gets DefaultFeature, holding every component; an undefined INSTALLFOLDER becomes [ProgramFiles6432Folder]Manufacturer Name; a naked File gets a component of its own.
  • Refused by name: Package/@Id, Files, access modifiers, the dual-purpose scopes, binder variables other than !(bind.Property.NAME), and !(loc.…). A package expecting the default major upgrade is warned that it has none.
  • The preprocessor adds sys.BUILDARCHSHORT (X86, X64, A64) and sys.WIXMAJORVERSION (4) for v4 sources.

Testing Decisions

  • Seam 1: unit tests in tests/database.zig cover each v4 element, attribute, default and refusal through the public interface, as for v3.
  • End to end: every v4 fixture in tests/e2e/fixtures has a WiX v3 twin in tests/e2e/fixtures/twins. zixl must build the two into the same tables, apart from what the fixture's .twin-differences file lists, each with the WiX documentation behind it. The twin stands where wixl stands for a v3 fixture, and the rest of compare.sh applies unchanged: Wine install and uninstall, .installed and .registry checks, reproducibility, and the msitools cross-check of the reader.
  • Fuzzing: the fuzz corpus gains the v4 fixtures.

Out of Scope

  • WiX localization files (.wxl) and !(loc.…).
  • Files harvesting, Package/@Id, the default major upgrade, and the dual-purpose scopes, until their behavior is documented or the file source can list directories.
  • Bundles, merge modules, patches, extensions and WixUI.
  • Converting v3 sources to v4.

Further Notes

The documentation used is the WiX schema reference, the release notes and the improvement proposals at docs.firegiant.com, each added to the references as it is used. ADR-0007 records what is inferred.

Tickets

## Problem Statement zixl reads only WiX v3, the language msitools' wixl reads. Every WiX release since v4 has used a new language: a new namespace, `<Package>` in place of `<Product>` and `<Package>`, standard directories without `TARGETDIR`, `Bitness` for `Win64`, conditions as attributes, and from v5 on, defaults for what a source leaves out. WiX sources written today are in that language, so zixl cannot build them. ## Solution The same `zixl` command, and the same library and `build.zig` step, build WiX v4 sources: a source's `<Wix>` namespace says which language it is in. For WiX v4, zixl does what the current WiX documents (ADR-0007). Where the documentation is silent on something that would change the output, zixl refuses it by name with the reason, or infers a default and says so in ADR-0007. ## User Stories 1. As a packager with a WiX v4 source, I want `zixl product.wxs` to build it, so that I need no .NET toolchain. 2. As a packager, I want `<Package>` to carry the product's name, version, manufacturer, upgrade code and code page, as WiX v4 has it. 3. As a packager, I want v4's defaults: compressed, Windows Installer 5.0, per-machine, UTF-8, and generated product and component codes. 4. As a packager, I want `StandardDirectory`, including `ProgramFiles6432Folder`, which follows the package's bitness. 5. As a packager, I want `Subdirectory` on directories, components and component groups, so that I need not write a `Directory` for every level. 6. As a packager, I want `Bitness` to make one component 32-bit in a 64-bit package. 7. As a packager, I want `Component/@Condition`, `Feature`'s `Level` children and `Launch`, which replace v3's `Condition` element. 8. As a packager, I want `MediaTemplate` to lay out cabinets for me. 9. As a packager, I want a default feature, a default `INSTALLFOLDER` and naked `File`s, as WiX v5 and later have them. 10. As a packager, I want `!(bind.Property.NAME)` in a value. 11. As a packager, I want `SummaryInformation` to set the package's description, comments, keywords and code page. 12. As a packager, I want registry values, environment variables, shortcuts, icons, folders and removals, as in v3. 13. As a packager, I want what zixl does not implement refused by name, with the reason when it is that WiX does not document it. 14. As a packager, I want a v3 source and a v4 source in one build refused, rather than mixed. 15. As a maintainer, I want every v4 fixture checked against a v3 twin that zixl must build into the same tables. ## Implementation Decisions - **Compiling:** compiling reads either language into the same WiX document. Linking and writing do not change, except for what WiX v4 adds: per-component bitness, component conditions, generated identifiers and media templates. - **The language** is chosen by each source's namespace. A build may not mix the two. - **Generated identifiers:** Ids WiX would generate are zixl's own: a prefix and a hash of what the element is. This covers the directories `Subdirectory` makes, and a `Directory` or `File` with no `Id`. A component with no `Id` takes its key path's, as WiX v6 does. - **Defaults, from the WiX schema reference:** - `Package`: `Compressed="yes"`, `InstallerVersion="500"`, `Scope="perMachine"`, `Codepage="65001"` (by number or web name), `Language="0"` (inferred), and a generated `ProductCode`; - `Component/@Guid="*"`; `Feature/@Level="1"`; - `MediaTemplate`: `cab{0}.cab`, external, medium compression, 200 MB per cabinet. - **Defaults from WiX v5 and later:** a package with no feature gets `DefaultFeature`, holding every component; an undefined `INSTALLFOLDER` becomes `[ProgramFiles6432Folder]Manufacturer Name`; a naked `File` gets a component of its own. - **Refused by name:** `Package/@Id`, `Files`, access modifiers, the dual-purpose scopes, binder variables other than `!(bind.Property.NAME)`, and `!(loc.…)`. A package expecting the default major upgrade is warned that it has none. - **The preprocessor** adds `sys.BUILDARCHSHORT` (`X86`, `X64`, `A64`) and `sys.WIXMAJORVERSION` (4) for v4 sources. ## Testing Decisions - **Seam 1:** unit tests in `tests/database.zig` cover each v4 element, attribute, default and refusal through the public interface, as for v3. - **End to end:** every v4 fixture in `tests/e2e/fixtures` has a WiX v3 twin in `tests/e2e/fixtures/twins`. zixl must build the two into the same tables, apart from what the fixture's `.twin-differences` file lists, each with the WiX documentation behind it. The twin stands where wixl stands for a v3 fixture, and the rest of `compare.sh` applies unchanged: Wine install and uninstall, `.installed` and `.registry` checks, reproducibility, and the msitools cross-check of the reader. - **Fuzzing:** the fuzz corpus gains the v4 fixtures. ## Out of Scope - WiX localization files (`.wxl`) and `!(loc.…)`. - `Files` harvesting, `Package/@Id`, the default major upgrade, and the dual-purpose scopes, until their behavior is documented or the file source can list directories. - Bundles, merge modules, patches, extensions and WixUI. - Converting v3 sources to v4. ## Further Notes The documentation used is the WiX schema reference, the release notes and the improvement proposals at `docs.firegiant.com`, each added to the references as it is used. ADR-0007 records what is inferred. ## Tickets - [ ] #24 - [ ] #25 - [ ] #26 - [ ] #27
Author
Owner

Every ticket is done: #24 (323c9f9), #25 (e34d153), #26 (5479149), #27 (31e85de). Every v4 fixture has a v3 twin and a .twin-differences file, and 5d54f16 added the last three v4 fixtures (compressed4, media4, upgrade4) to the fuzz corpus.

Every ticket is done: #24 (323c9f9), #25 (e34d153), #26 (5479149), #27 (31e85de). Every v4 fixture has a v3 twin and a .twin-differences file, and 5d54f16 added the last three v4 fixtures (compressed4, media4, upgrade4) to the fuzz corpus.
jeff closed this issue 2026-10-16 13:08:02 -05:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jeff/zixl#23
No description provided.