@joebigelow / wix / commits / 184fd766

Move Directory code generation to the linker

Adding all referenced standard directories requires access to the references. However, references do no survive the linker. Which means the binder is too late to add standard directories. Fixes 6977

Rob Mensching committed Nov 4, 2022 at 12:26 UTC 184fd7663696e52fe5386f6623b3313a41e05979
5 files changed +63 -74
src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
-6
@@ -171,12 +171,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
171 command.Execute();
172 }
173
174 - if (section.Type == SectionType.Product || section.Type == SectionType.Module)
175 - {
176 - var command = new AddRequiredStandardDirectories(section, platform);
177 - command.Execute();
178 - }
179 -
174 {
175 var command = new CreateSpecialPropertiesCommand(section);
176 command.Execute();
src/wix/WixToolset.Core/Compiler.cs
+5
@@ -7131,6 +7131,11 @@ namespace WixToolset.Core
7131 this.Core.ParseExtensionElement(node, child);
7132 }
7133 }
7134 +
7135 + if (!this.Core.EncounteredError)
7136 + {
7137 + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, id);
7138 + }
7139 }
7140
7141 /// <summary>
src/wix/WixToolset.Core/Link/AddRequiredStandardDirectories.cs renamed
+40 -10
@@ -1,6 +1,6 @@
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 -namespace WixToolset.Core.WindowsInstaller.Bind
3 +namespace WixToolset.Core.Link
4 {
5 using System;
6 using System.Collections.Generic;
@@ -14,21 +14,29 @@ namespace WixToolset.Core.WindowsInstaller.Bind
14 /// </summary>
15 internal class AddRequiredStandardDirectories
16 {
17 - internal AddRequiredStandardDirectories(IntermediateSection section, Platform platform)
17 + public AddRequiredStandardDirectories(IntermediateSection section, List<WixSimpleReferenceSymbol> references)
18 {
19 this.Section = section;
20 - this.Platform = platform;
20 + this.References = references;
21 }
22
23 private IntermediateSection Section { get; }
24
25 - private Platform Platform { get; }
25 + private List<WixSimpleReferenceSymbol> References { get; }
26
27 public void Execute()
28 {
29 + var platform = this.GetPlatformFromSection();
30 +
31 var directories = this.Section.Symbols.OfType<DirectorySymbol>().ToList();
32 var directoryIds = new SortedSet<string>(directories.Select(d => d.Id.Id));
33
34 + // Ensure any standard directory references symbols are added.
35 + foreach (var directoryReference in this.References.Where(r => r.Table == "Directory"))
36 + {
37 + this.EnsureStandardDirectoryAdded(directoryIds, directoryReference.PrimaryKeys, directoryReference.SourceLineNumbers, platform);
38 + }
39 +
40 foreach (var directory in directories)
41 {
42 var parentDirectoryId = directory.ParentDirectoryRef;
@@ -42,7 +50,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
50 }
51 else
52 {
45 - this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, directory.SourceLineNumbers);
53 + this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, directory.SourceLineNumbers, platform);
54 }
55 }
56
@@ -53,11 +61,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
61 }
62 }
63
56 - private void EnsureStandardDirectoryAdded(ISet<string> directoryIds, string directoryId, SourceLineNumber sourceLineNumbers)
64 + private void EnsureStandardDirectoryAdded(ISet<string> directoryIds, string directoryId, SourceLineNumber sourceLineNumbers, Platform platform)
65 {
66 if (!directoryIds.Contains(directoryId) && WindowsInstallerStandard.TryGetStandardDirectory(directoryId, out var standardDirectory))
67 {
60 - var parentDirectoryId = this.GetStandardDirectoryParent(directoryId);
68 + var parentDirectoryId = this.GetStandardDirectoryParent(directoryId, platform);
69
70 var directory = new DirectorySymbol(sourceLineNumbers, standardDirectory.Id)
71 {
@@ -70,12 +78,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
78
79 if (!String.IsNullOrEmpty(parentDirectoryId))
80 {
73 - this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, sourceLineNumbers);
81 + this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, sourceLineNumbers, platform);
82 }
83 }
84 }
85
78 - private string GetStandardDirectoryParent(string directoryId)
86 + private string GetStandardDirectoryParent(string directoryId, Platform platform)
87 {
88 switch (directoryId)
89 {
@@ -85,11 +93,33 @@ namespace WixToolset.Core.WindowsInstaller.Bind
93 case "CommonFiles6432Folder":
94 case "ProgramFiles6432Folder":
95 case "System6432Folder":
88 - return WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directoryId, this.Platform);
96 + return WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directoryId, platform);
97
98 default:
99 return "TARGETDIR";
100 }
101 }
102 +
103 + private Platform GetPlatformFromSection()
104 + {
105 + var symbol = this.Section.Symbols.OfType<SummaryInformationSymbol>().First(p => p.PropertyId == SummaryInformationType.PlatformAndLanguage);
106 +
107 + var value = symbol.Value;
108 + var separatorIndex = value.IndexOf(';');
109 + var platformValue = separatorIndex > 0 ? value.Substring(0, separatorIndex) : value;
110 +
111 + switch (platformValue)
112 + {
113 + case "x64":
114 + return Platform.X64;
115 +
116 + case "Arm64":
117 + return Platform.ARM64;
118 +
119 + case "Intel":
120 + default:
121 + return Platform.X86;
122 + }
123 + }
124 }
125 }
src/wix/WixToolset.Core/Linker.cs
+8 -2
@@ -90,8 +90,6 @@ namespace WixToolset.Core
90 }
91 }
92
93 - //this.activeOutput = null;
94 -
93 var multipleFeatureComponents = new Hashtable();
94
95 var wixVariables = new Dictionary<string, WixVariableSymbol>();
@@ -178,6 +176,7 @@ namespace WixToolset.Core
176 // Create a new section to hold the linked content. Start with the entry section's
177 // metadata.
178 var resolvedSection = new IntermediateSection(find.EntrySection.Id, find.EntrySection.Type);
179 + var references = new List<WixSimpleReferenceSymbol>();
180
181 foreach (var section in sections)
182 {
@@ -248,6 +247,7 @@ namespace WixToolset.Core
247
248 case SymbolDefinitionType.WixSimpleReference:
249 copySymbol = false;
250 + references.Add(symbol as WixSimpleReferenceSymbol);
251 break;
252
253 case SymbolDefinitionType.WixVariable:
@@ -288,6 +288,12 @@ namespace WixToolset.Core
288 var command = new FlattenAndProcessBundleTablesCommand(resolvedSection, this.Messaging);
289 command.Execute();
290 }
291 + else if (resolvedSection.Type == SectionType.Product || resolvedSection.Type == SectionType.Module)
292 + {
293 + // Packages and modules get standard directories add.
294 + var command = new AddRequiredStandardDirectories(resolvedSection, references);
295 + command.Execute();
296 + }
297
298 if (this.Messaging.EncounteredError)
299 {
src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs
+10 -56
@@ -97,54 +97,8 @@ namespace WixToolsetTest.CoreIntegration
97 {
98 var baseFolder = fs.GetFolder();
99 var intermediateFolder = Path.Combine(baseFolder, "obj");
100 - var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
101 -
102 - var result = WixRunner.Execute(new[]
103 - {
104 - "build",
105 - Path.Combine(folder, "Directory", "DefaultName.wxs"),
106 - Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
107 - "-bindpath", Path.Combine(folder, "SingleFile", "data"),
108 - "-intermediateFolder", intermediateFolder,
109 - "-o", msiPath
110 - });
111 -
112 - result.AssertSuccess();
113 -
114 - var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
115 - var section = intermediate.Sections.Single();
116 -
117 - var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList();
118 - WixAssert.CompareLineByLine(new[]
119 - {
120 - "BinFolder\tCompanyFolder\t.",
121 - "CompanyFolder\tProgramFilesFolder\tExample Corporation",
122 - "ProgramFilesFolder\tTARGETDIR\tPFiles",
123 - "TARGETDIR\t\tSourceDir"
124 - }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => String.Join('\t', d.Id.Id, d.ParentDirectoryRef, d.Name)).ToArray());
125 -
126 - var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
127 - var directoryRows = data.Tables["Directory"].Rows;
128 - WixAssert.CompareLineByLine(new[]
129 - {
130 - "BinFolder\tCompanyFolder\t.",
131 - "CompanyFolder\tProgramFilesFolder\tu7-b4gch|Example Corporation",
132 - "ProgramFilesFolder\tTARGETDIR\tPFiles",
133 - "TARGETDIR\t\tSourceDir"
134 - }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).ToArray());
135 - }
136 - }
137 -
138 - [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6977")]
139 - public void CanGetEmptyStandardDirectory()
140 - {
141 - var folder = TestData.Get(@"TestData");
142 -
143 - using (var fs = new DisposableFileSystem())
144 - {
145 - var baseFolder = fs.GetFolder();
146 - var intermediateFolder = Path.Combine(baseFolder, "obj");
147 - var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
100 + var msiPath = Path.Combine(baseFolder, "bin", "test.msi");
101 + var wixpdbPath = Path.Combine(baseFolder, "bin", "test.wixpdb");
102
103 var result = WixRunner.Execute(new[]
104 {
@@ -158,7 +112,7 @@ namespace WixToolsetTest.CoreIntegration
112
113 result.AssertSuccess();
114
161 - var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
115 + var intermediate = Intermediate.Load(wixpdbPath);
116 var section = intermediate.Sections.Single();
117
118 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList();
@@ -166,23 +120,23 @@ namespace WixToolsetTest.CoreIntegration
120 {
121 "BinFolder\tCompanyFolder\t.",
122 "CompanyFolder\tProgramFilesFolder\tExample Corporation",
169 - "DesktopFolder\tTARGETDIR\t.",
123 + "DesktopFolder\tTARGETDIR\tDesktop",
124 "ProgramFilesFolder\tTARGETDIR\tPFiles",
171 - "ProgramMenuFolder\tTARGETDIR\t.",
125 + "ProgramMenuFolder\tTARGETDIR\tPMenu",
126 "TARGETDIR\t\tSourceDir"
173 - }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => String.Join('\t', d.Id.Id, d.ParentDirectoryRef, d.Name)).ToArray());
127 + }, dirSymbols.Select(d => String.Join('\t', d.Id.Id, d.ParentDirectoryRef, d.Name)).OrderBy(s => s).ToArray());
128
175 - var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
129 + var data = WindowsInstallerData.Load(wixpdbPath);
130 var directoryRows = data.Tables["Directory"].Rows;
131 WixAssert.CompareLineByLine(new[]
132 {
133 "BinFolder\tCompanyFolder\t.",
134 "CompanyFolder\tProgramFilesFolder\tu7-b4gch|Example Corporation",
181 - "DesktopFolder\tTARGETDIR\t.",
135 + "DesktopFolder\tTARGETDIR\tDesktop",
136 "ProgramFilesFolder\tTARGETDIR\tPFiles",
183 - "ProgramMenuFolder\tTARGETDIR\t.",
137 + "ProgramMenuFolder\tTARGETDIR\tPMenu",
138 "TARGETDIR\t\tSourceDir"
185 - }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).ToArray());
139 + }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).OrderBy(s => s).ToArray());
140 }
141 }
142