diff options
author | Rob Mensching <rob@firegiant.com> | 2022-03-15 14:01:07 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2022-03-15 15:51:57 -0700 |
commit | 9aa2910e79ce52144c5296077aa2444876419643 (patch) | |
tree | c29eb047af78f2324c22573b45caa7e7bc690877 | |
parent | 8ed8ca0721e08ea953f4751086c4845c98551c46 (diff) | |
download | wix-9aa2910e79ce52144c5296077aa2444876419643.tar.gz wix-9aa2910e79ce52144c5296077aa2444876419643.tar.bz2 wix-9aa2910e79ce52144c5296077aa2444876419643.zip |
Rework build command line for combining wixlibs and default output
Changes the command line handling for the "build" command to allow
creation of a .wixlib to accept compiled (but not linked)
intermediates. This will allow .wixlibs to combine separate build
commands (potentially with different "-arch" switches) into a single
.wixlib. This change also fixes the issue where by default output
was being written to the intermediate folder instead of the current
directory.
Fixes 6464
Fixes 6473
6 files changed, 277 insertions, 125 deletions
diff --git a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs index 67d2876d..f291fa8c 100644 --- a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs | |||
@@ -49,18 +49,8 @@ namespace WixToolset.Core.CommandLine | |||
49 | 49 | ||
50 | private string IntermediateFolder { get; set; } | 50 | private string IntermediateFolder { get; set; } |
51 | 51 | ||
52 | private OutputType OutputType { get; set; } | ||
53 | |||
54 | private List<string> IncludeSearchPaths { get; set; } | ||
55 | |||
56 | public string PdbFile { get; set; } | ||
57 | |||
58 | public PdbType PdbType { get; set; } | ||
59 | |||
60 | private Platform Platform { get; set; } | 52 | private Platform Platform { get; set; } |
61 | 53 | ||
62 | private string OutputFile { get; set; } | ||
63 | |||
64 | private CompressionLevel? DefaultCompressionLevel { get; set; } | 54 | private CompressionLevel? DefaultCompressionLevel { get; set; } |
65 | 55 | ||
66 | private string TrackingFile { get; set; } | 56 | private string TrackingFile { get; set; } |
@@ -75,93 +65,70 @@ namespace WixToolset.Core.CommandLine | |||
75 | 65 | ||
76 | this.IntermediateFolder = this.commandLine.CalculateIntermedateFolder(); | 66 | this.IntermediateFolder = this.commandLine.CalculateIntermedateFolder(); |
77 | 67 | ||
78 | this.OutputType = this.commandLine.CalculateOutputType(); | ||
79 | |||
80 | this.IncludeSearchPaths = this.commandLine.IncludeSearchPaths; | ||
81 | |||
82 | this.PdbFile = this.commandLine.PdbFile; | ||
83 | |||
84 | this.PdbType = this.commandLine.PdbType; | ||
85 | |||
86 | this.Platform = this.commandLine.Platform; | 68 | this.Platform = this.commandLine.Platform; |
87 | 69 | ||
88 | this.TrackingFile = this.commandLine.TrackingFile; | 70 | this.TrackingFile = this.commandLine.TrackingFile; |
89 | 71 | ||
90 | this.DefaultCompressionLevel = this.commandLine.DefaultCompressionLevel; | 72 | this.DefaultCompressionLevel = this.commandLine.DefaultCompressionLevel; |
91 | 73 | ||
92 | var preprocessorVariables = this.commandLine.GatherPreprocessorVariables(); | 74 | var preprocessorVariables = this.commandLine.CalculatePreprocessorVariables(); |
93 | |||
94 | var sourceFiles = this.commandLine.GatherSourceFiles(this.IntermediateFolder); | ||
95 | 75 | ||
96 | var filterCultures = this.commandLine.CalculateFilterCultures(); | 76 | var filterCultures = this.commandLine.CalculateFilterCultures(); |
97 | 77 | ||
98 | var creator = this.ServiceProvider.GetService<ISymbolDefinitionCreator>(); | 78 | var creator = this.ServiceProvider.GetService<ISymbolDefinitionCreator>(); |
99 | 79 | ||
100 | this.EvaluateSourceFiles(sourceFiles, creator, out var codeFiles, out var wixipl); | 80 | var inputsOutputs = this.commandLine.CalculateInputsAndOutputs(creator); |
101 | |||
102 | this.OutputFile = this.commandLine.OutputFile; | ||
103 | |||
104 | if (String.IsNullOrEmpty(this.OutputFile)) | ||
105 | { | ||
106 | if (codeFiles.Count == 1) | ||
107 | { | ||
108 | // If output type is unknown, the extension will be replaced with the right default based on output type. | ||
109 | this.OutputFile = Path.ChangeExtension(codeFiles[0].OutputPath, DefaultExtensionForOutputType(this.OutputType)); | ||
110 | } | ||
111 | else | ||
112 | { | ||
113 | this.Messaging.Write(ErrorMessages.MustSpecifyOutputWithMoreThanOneInput()); | ||
114 | } | ||
115 | } | ||
116 | 81 | ||
117 | if (this.Messaging.EncounteredError) | 82 | if (this.Messaging.EncounteredError) |
118 | { | 83 | { |
119 | return Task.FromResult(this.Messaging.LastErrorNumber); | 84 | return Task.FromResult(this.Messaging.LastErrorNumber); |
120 | } | 85 | } |
121 | 86 | ||
122 | var wixobjs = this.CompilePhase(preprocessorVariables, codeFiles, cancellationToken); | 87 | var wixobjs = this.CompilePhase(preprocessorVariables, inputsOutputs.SourcePaths, this.commandLine.IncludeSearchPaths, cancellationToken); |
123 | 88 | ||
124 | var wxls = this.LoadLocalizationFiles(this.commandLine.LocalizationFilePaths, preprocessorVariables, cancellationToken); | 89 | var wxls = this.LoadLocalizationFiles(inputsOutputs.LocalizationPaths, preprocessorVariables, this.commandLine.IncludeSearchPaths, cancellationToken); |
125 | 90 | ||
126 | if (this.Messaging.EncounteredError) | 91 | if (this.Messaging.EncounteredError) |
127 | { | 92 | { |
128 | return Task.FromResult(this.Messaging.LastErrorNumber); | 93 | return Task.FromResult(this.Messaging.LastErrorNumber); |
129 | } | 94 | } |
130 | 95 | ||
131 | if (this.OutputType == OutputType.Library) | 96 | if (inputsOutputs.OutputType == OutputType.Library) |
132 | { | 97 | { |
133 | using (new IntermediateFieldContext("wix.lib")) | 98 | using (new IntermediateFieldContext("wix.lib")) |
134 | { | 99 | { |
135 | this.LibraryPhase(wixobjs, wxls, this.commandLine.BindFiles, this.commandLine.BindPaths, cancellationToken); | 100 | this.LibraryPhase(wixobjs, wxls, inputsOutputs.LibraryPaths, creator, this.commandLine.BindFiles, this.commandLine.BindPaths, inputsOutputs.OutputPath, cancellationToken); |
136 | } | 101 | } |
137 | } | 102 | } |
138 | else | 103 | else |
139 | { | 104 | { |
140 | using (new IntermediateFieldContext("wix.link")) | 105 | using (new IntermediateFieldContext("wix.link")) |
141 | { | 106 | { |
107 | var wixipl = inputsOutputs.Wixipls.SingleOrDefault(); | ||
108 | |||
142 | if (wixipl == null) | 109 | if (wixipl == null) |
143 | { | 110 | { |
144 | wixipl = this.LinkPhase(wixobjs, this.commandLine.LibraryFilePaths, creator, cancellationToken); | 111 | wixipl = this.LinkPhase(wixobjs, inputsOutputs, creator, cancellationToken); |
145 | } | 112 | } |
146 | 113 | ||
147 | if (!this.Messaging.EncounteredError) | 114 | if (!this.Messaging.EncounteredError) |
148 | { | 115 | { |
149 | var outputExtension = Path.GetExtension(this.OutputFile); | 116 | var outputExtension = Path.GetExtension(inputsOutputs.OutputPath); |
150 | if (String.IsNullOrEmpty(outputExtension) || ".wix" == outputExtension) | 117 | if (String.IsNullOrEmpty(outputExtension) || ".wix" == outputExtension) |
151 | { | 118 | { |
152 | var entrySectionType = wixipl.Sections.Single().Type; | 119 | var entrySectionType = wixipl.Sections.Single().Type; |
153 | this.OutputFile = Path.ChangeExtension(this.OutputFile, DefaultExtensionForSectionType(entrySectionType)); | 120 | inputsOutputs.OutputPath = Path.ChangeExtension(inputsOutputs.OutputPath, DefaultExtensionForSectionType(entrySectionType)); |
154 | } | 121 | } |
155 | 122 | ||
156 | if (this.OutputType == OutputType.IntermediatePostLink) | 123 | if (inputsOutputs.OutputType == OutputType.IntermediatePostLink) |
157 | { | 124 | { |
158 | wixipl.Save(this.OutputFile); | 125 | wixipl.Save(inputsOutputs.OutputPath); |
159 | } | 126 | } |
160 | else | 127 | else |
161 | { | 128 | { |
162 | using (new IntermediateFieldContext("wix.bind")) | 129 | using (new IntermediateFieldContext("wix.bind")) |
163 | { | 130 | { |
164 | this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.BindPaths, cancellationToken); | 131 | this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.BindPaths, inputsOutputs, cancellationToken); |
165 | } | 132 | } |
166 | } | 133 | } |
167 | } | 134 | } |
@@ -176,51 +143,13 @@ namespace WixToolset.Core.CommandLine | |||
176 | return this.commandLine.TryParseArgument(argument, parser); | 143 | return this.commandLine.TryParseArgument(argument, parser); |
177 | } | 144 | } |
178 | 145 | ||
179 | private void EvaluateSourceFiles(IEnumerable<SourceFile> sourceFiles, ISymbolDefinitionCreator creator, out List<SourceFile> codeFiles, out Intermediate wixipl) | 146 | private IReadOnlyList<Intermediate> CompilePhase(IDictionary<string, string> preprocessorVariables, IEnumerable<string> sourceFiles, IReadOnlyCollection<string> includeSearchPaths, CancellationToken cancellationToken) |
180 | { | ||
181 | codeFiles = new List<SourceFile>(); | ||
182 | |||
183 | wixipl = null; | ||
184 | |||
185 | foreach (var sourceFile in sourceFiles) | ||
186 | { | ||
187 | var extension = Path.GetExtension(sourceFile.SourcePath); | ||
188 | |||
189 | if (wixipl != null || ".wxs".Equals(extension, StringComparison.OrdinalIgnoreCase)) | ||
190 | { | ||
191 | codeFiles.Add(sourceFile); | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | try | ||
196 | { | ||
197 | wixipl = Intermediate.Load(sourceFile.SourcePath, creator); | ||
198 | } | ||
199 | catch (WixException) | ||
200 | { | ||
201 | // We'll assume anything that isn't a valid intermediate is source code to compile. | ||
202 | codeFiles.Add(sourceFile); | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | |||
207 | if (wixipl == null && codeFiles.Count == 0) | ||
208 | { | ||
209 | this.Messaging.Write(ErrorMessages.NoSourceFiles()); | ||
210 | } | ||
211 | else if (wixipl != null && codeFiles.Count != 0) | ||
212 | { | ||
213 | this.Messaging.Write(ErrorMessages.WixiplSourceFileIsExclusive()); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | private IReadOnlyList<Intermediate> CompilePhase(IDictionary<string, string> preprocessorVariables, IEnumerable<SourceFile> sourceFiles, CancellationToken cancellationToken) | ||
218 | { | 147 | { |
219 | var intermediates = new List<Intermediate>(); | 148 | var intermediates = new List<Intermediate>(); |
220 | 149 | ||
221 | foreach (var sourceFile in sourceFiles) | 150 | foreach (var sourceFile in sourceFiles) |
222 | { | 151 | { |
223 | var document = this.Preprocess(preprocessorVariables, sourceFile.SourcePath, cancellationToken); | 152 | var document = this.Preprocess(preprocessorVariables, sourceFile, includeSearchPaths, cancellationToken); |
224 | 153 | ||
225 | if (this.Messaging.EncounteredError) | 154 | if (this.Messaging.EncounteredError) |
226 | { | 155 | { |
@@ -255,14 +184,21 @@ namespace WixToolset.Core.CommandLine | |||
255 | return intermediates; | 184 | return intermediates; |
256 | } | 185 | } |
257 | 186 | ||
258 | private void LibraryPhase(IReadOnlyCollection<Intermediate> intermediates, IReadOnlyCollection<Localization> localizations, bool bindFiles, IReadOnlyCollection<IBindPath> bindPaths, CancellationToken cancellationToken) | 187 | private void LibraryPhase(IReadOnlyCollection<Intermediate> intermediates, IReadOnlyCollection<Localization> localizations, IEnumerable<string> libraryFiles, ISymbolDefinitionCreator creator, bool bindFiles, IReadOnlyCollection<IBindPath> bindPaths, string outputPath, CancellationToken cancellationToken) |
259 | { | 188 | { |
189 | var libraries = this.LoadLibraries(libraryFiles, creator); | ||
190 | |||
191 | if (this.Messaging.EncounteredError) | ||
192 | { | ||
193 | return; | ||
194 | } | ||
195 | |||
260 | var context = this.ServiceProvider.GetService<ILibraryContext>(); | 196 | var context = this.ServiceProvider.GetService<ILibraryContext>(); |
261 | context.BindFiles = bindFiles; | 197 | context.BindFiles = bindFiles; |
262 | context.BindPaths = bindPaths; | 198 | context.BindPaths = bindPaths; |
263 | context.Extensions = this.ExtensionManager.GetServices<ILibrarianExtension>(); | 199 | context.Extensions = this.ExtensionManager.GetServices<ILibrarianExtension>(); |
264 | context.Localizations = localizations; | 200 | context.Localizations = localizations; |
265 | context.Intermediates = intermediates; | 201 | context.Intermediates = intermediates.Concat(libraries).ToList(); |
266 | context.CancellationToken = cancellationToken; | 202 | context.CancellationToken = cancellationToken; |
267 | 203 | ||
268 | try | 204 | try |
@@ -272,7 +208,7 @@ namespace WixToolset.Core.CommandLine | |||
272 | 208 | ||
273 | if (!this.Messaging.EncounteredError) | 209 | if (!this.Messaging.EncounteredError) |
274 | { | 210 | { |
275 | result.Library.Save(this.OutputFile); | 211 | result.Library.Save(outputPath); |
276 | 212 | ||
277 | this.LayoutFiles(this.IntermediateFolder, result.TrackedFiles, null, cancellationToken); | 213 | this.LayoutFiles(this.IntermediateFolder, result.TrackedFiles, null, cancellationToken); |
278 | } | 214 | } |
@@ -283,9 +219,9 @@ namespace WixToolset.Core.CommandLine | |||
283 | } | 219 | } |
284 | } | 220 | } |
285 | 221 | ||
286 | private Intermediate LinkPhase(IEnumerable<Intermediate> intermediates, IEnumerable<string> libraryFiles, ISymbolDefinitionCreator creator, CancellationToken cancellationToken) | 222 | private Intermediate LinkPhase(IEnumerable<Intermediate> intermediates, InputsAndOutputs inputsOutputs, ISymbolDefinitionCreator creator, CancellationToken cancellationToken) |
287 | { | 223 | { |
288 | var libraries = this.LoadLibraries(libraryFiles, creator); | 224 | var libraries = this.LoadLibraries(inputsOutputs.LibraryPaths, creator); |
289 | 225 | ||
290 | if (this.Messaging.EncounteredError) | 226 | if (this.Messaging.EncounteredError) |
291 | { | 227 | { |
@@ -295,7 +231,7 @@ namespace WixToolset.Core.CommandLine | |||
295 | var context = this.ServiceProvider.GetService<ILinkContext>(); | 231 | var context = this.ServiceProvider.GetService<ILinkContext>(); |
296 | context.Extensions = this.ExtensionManager.GetServices<ILinkerExtension>(); | 232 | context.Extensions = this.ExtensionManager.GetServices<ILinkerExtension>(); |
297 | context.ExtensionData = this.ExtensionManager.GetServices<IExtensionData>(); | 233 | context.ExtensionData = this.ExtensionManager.GetServices<IExtensionData>(); |
298 | context.ExpectedOutputType = this.OutputType; | 234 | context.ExpectedOutputType = inputsOutputs.OutputType; |
299 | context.Intermediates = intermediates.Concat(libraries).ToList(); | 235 | context.Intermediates = intermediates.Concat(libraries).ToList(); |
300 | context.SymbolDefinitionCreator = creator; | 236 | context.SymbolDefinitionCreator = creator; |
301 | context.CancellationToken = cancellationToken; | 237 | context.CancellationToken = cancellationToken; |
@@ -304,7 +240,7 @@ namespace WixToolset.Core.CommandLine | |||
304 | return linker.Link(context); | 240 | return linker.Link(context); |
305 | } | 241 | } |
306 | 242 | ||
307 | private void BindPhase(Intermediate output, IReadOnlyCollection<Localization> localizations, IReadOnlyCollection<string> filterCultures, string cabCachePath, IReadOnlyCollection<IBindPath> bindPaths, CancellationToken cancellationToken) | 243 | private void BindPhase(Intermediate output, IReadOnlyCollection<Localization> localizations, IReadOnlyCollection<string> filterCultures, string cabCachePath, IReadOnlyCollection<IBindPath> bindPaths, InputsAndOutputs inputsOutputs, CancellationToken cancellationToken) |
308 | { | 244 | { |
309 | var intermediateFolder = this.IntermediateFolder; | 245 | var intermediateFolder = this.IntermediateFolder; |
310 | if (String.IsNullOrEmpty(intermediateFolder)) | 246 | if (String.IsNullOrEmpty(intermediateFolder)) |
@@ -350,9 +286,9 @@ namespace WixToolset.Core.CommandLine | |||
350 | context.FileSystemExtensions = this.ExtensionManager.GetServices<IFileSystemExtension>(); | 286 | context.FileSystemExtensions = this.ExtensionManager.GetServices<IFileSystemExtension>(); |
351 | context.IntermediateFolder = intermediateFolder; | 287 | context.IntermediateFolder = intermediateFolder; |
352 | context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; | 288 | context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; |
353 | context.OutputPath = this.OutputFile; | 289 | context.OutputPath = inputsOutputs.OutputPath; |
354 | context.PdbType = this.PdbType; | 290 | context.PdbType = inputsOutputs.PdbType; |
355 | context.PdbPath = this.PdbType == PdbType.None ? null : this.PdbFile ?? Path.ChangeExtension(this.OutputFile, ".wixpdb"); | 291 | context.PdbPath = inputsOutputs.PdbPath; |
356 | context.CancellationToken = cancellationToken; | 292 | context.CancellationToken = cancellationToken; |
357 | 293 | ||
358 | var binder = this.ServiceProvider.GetService<IBinder>(); | 294 | var binder = this.ServiceProvider.GetService<IBinder>(); |
@@ -405,14 +341,14 @@ namespace WixToolset.Core.CommandLine | |||
405 | return Array.Empty<Intermediate>(); | 341 | return Array.Empty<Intermediate>(); |
406 | } | 342 | } |
407 | 343 | ||
408 | private IReadOnlyList<Localization> LoadLocalizationFiles(IEnumerable<string> locFiles, IDictionary<string, string> preprocessorVariables, CancellationToken cancellationToken) | 344 | private IReadOnlyList<Localization> LoadLocalizationFiles(IEnumerable<string> locFiles, IDictionary<string, string> preprocessorVariables, IReadOnlyCollection<string> includeSearchPaths, CancellationToken cancellationToken) |
409 | { | 345 | { |
410 | var localizations = new List<Localization>(); | 346 | var localizations = new List<Localization>(); |
411 | var parser = this.ServiceProvider.GetService<ILocalizationParser>(); | 347 | var parser = this.ServiceProvider.GetService<ILocalizationParser>(); |
412 | 348 | ||
413 | foreach (var loc in locFiles) | 349 | foreach (var loc in locFiles) |
414 | { | 350 | { |
415 | var document = this.Preprocess(preprocessorVariables, loc, cancellationToken); | 351 | var document = this.Preprocess(preprocessorVariables, loc, includeSearchPaths, cancellationToken); |
416 | 352 | ||
417 | if (this.Messaging.EncounteredError) | 353 | if (this.Messaging.EncounteredError) |
418 | { | 354 | { |
@@ -426,12 +362,12 @@ namespace WixToolset.Core.CommandLine | |||
426 | return localizations; | 362 | return localizations; |
427 | } | 363 | } |
428 | 364 | ||
429 | private XDocument Preprocess(IDictionary<string, string> preprocessorVariables, string sourcePath, CancellationToken cancellationToken) | 365 | private XDocument Preprocess(IDictionary<string, string> preprocessorVariables, string sourcePath, IReadOnlyCollection<string> includeSearchPaths, CancellationToken cancellationToken) |
430 | { | 366 | { |
431 | var context = this.ServiceProvider.GetService<IPreprocessContext>(); | 367 | var context = this.ServiceProvider.GetService<IPreprocessContext>(); |
432 | context.Extensions = this.ExtensionManager.GetServices<IPreprocessorExtension>(); | 368 | context.Extensions = this.ExtensionManager.GetServices<IPreprocessorExtension>(); |
433 | context.Platform = this.Platform; | 369 | context.Platform = this.Platform; |
434 | context.IncludeSearchPaths = this.IncludeSearchPaths; | 370 | context.IncludeSearchPaths = includeSearchPaths; |
435 | context.SourcePath = sourcePath; | 371 | context.SourcePath = sourcePath; |
436 | context.Variables = preprocessorVariables; | 372 | context.Variables = preprocessorVariables; |
437 | context.CancellationToken = cancellationToken; | 373 | context.CancellationToken = cancellationToken; |
@@ -519,6 +455,8 @@ namespace WixToolset.Core.CommandLine | |||
519 | 455 | ||
520 | public List<string> SourceFilePaths { get; } = new List<string>(); | 456 | public List<string> SourceFilePaths { get; } = new List<string>(); |
521 | 457 | ||
458 | public List<string> UnevaluatedInputFilePaths { get; } = new List<string>(); | ||
459 | |||
522 | public Platform Platform { get; private set; } | 460 | public Platform Platform { get; private set; } |
523 | 461 | ||
524 | public string PdbFile { get; private set; } | 462 | public string PdbFile { get; private set; } |
@@ -632,6 +570,10 @@ namespace WixToolset.Core.CommandLine | |||
632 | parser.GetNextArgumentAsFilePathOrError(arg, "library files", this.LibraryFilePaths); | 570 | parser.GetNextArgumentAsFilePathOrError(arg, "library files", this.LibraryFilePaths); |
633 | return true; | 571 | return true; |
634 | 572 | ||
573 | case "src": | ||
574 | parser.GetNextArgumentAsFilePathOrError(arg, "source code", this.SourceFilePaths); | ||
575 | return true; | ||
576 | |||
635 | case "o": | 577 | case "o": |
636 | case "out": | 578 | case "out": |
637 | this.OutputFile = parser.GetNextArgumentAsFilePathOrError(arg); | 579 | this.OutputFile = parser.GetNextArgumentAsFilePathOrError(arg); |
@@ -665,7 +607,7 @@ namespace WixToolset.Core.CommandLine | |||
665 | } | 607 | } |
666 | else | 608 | else |
667 | { | 609 | { |
668 | parser.GetArgumentAsFilePathOrError(arg, "source code", this.SourceFilePaths); | 610 | parser.GetArgumentAsFilePathOrError(arg, "input file", this.UnevaluatedInputFilePaths); |
669 | return true; | 611 | return true; |
670 | } | 612 | } |
671 | } | 613 | } |
@@ -747,7 +689,7 @@ namespace WixToolset.Core.CommandLine | |||
747 | return result; | 689 | return result; |
748 | } | 690 | } |
749 | 691 | ||
750 | public IDictionary<string, string> GatherPreprocessorVariables() | 692 | public IDictionary<string, string> CalculatePreprocessorVariables() |
751 | { | 693 | { |
752 | var variables = new Dictionary<string, string>(); | 694 | var variables = new Dictionary<string, string>(); |
753 | 695 | ||
@@ -767,19 +709,89 @@ namespace WixToolset.Core.CommandLine | |||
767 | return variables; | 709 | return variables; |
768 | } | 710 | } |
769 | 711 | ||
770 | public IEnumerable<SourceFile> GatherSourceFiles(string intermediateDirectory) | 712 | public InputsAndOutputs CalculateInputsAndOutputs(ISymbolDefinitionCreator creator) |
771 | { | 713 | { |
772 | var files = new List<SourceFile>(); | 714 | var codePaths = new List<string>(this.SourceFilePaths); |
715 | var localizationPaths = new List<string>(this.LocalizationFilePaths); | ||
716 | var libraryPaths = new List<string>(this.LibraryFilePaths); | ||
717 | var wixipls = new List<Intermediate>(); | ||
718 | string lastWixiplPath = null; | ||
773 | 719 | ||
774 | foreach (var item in this.SourceFilePaths) | 720 | var outputPath = this.OutputFile; |
721 | var outputType = this.CalculateOutputType(); | ||
722 | |||
723 | foreach (var path in this.UnevaluatedInputFilePaths) | ||
775 | { | 724 | { |
776 | var sourcePath = item; | 725 | var extension = Path.GetExtension(path); |
777 | var outputPath = Path.Combine(intermediateDirectory, Path.GetFileNameWithoutExtension(sourcePath) + ".wir"); | 726 | |
727 | if (".wxs".Equals(extension, StringComparison.OrdinalIgnoreCase)) | ||
728 | { | ||
729 | codePaths.Add(path); | ||
730 | } | ||
731 | else if (".wxl".Equals(extension, StringComparison.OrdinalIgnoreCase)) | ||
732 | { | ||
733 | localizationPaths.Add(path); | ||
734 | } | ||
735 | else if (".wixlib".Equals(extension, StringComparison.OrdinalIgnoreCase)) | ||
736 | { | ||
737 | libraryPaths.Add(path); | ||
738 | } | ||
739 | else | ||
740 | { | ||
741 | try | ||
742 | { | ||
743 | // Try to load the file as an intermediate to determine whether it is a | ||
744 | // .wixipl or a .wixlib. | ||
745 | var intermediate = Intermediate.Load(path, creator); | ||
778 | 746 | ||
779 | files.Add(new SourceFile(sourcePath, outputPath)); | 747 | if (intermediate.HasLevel(IntermediateLevels.Linked)) |
748 | { | ||
749 | wixipls.Add(intermediate); | ||
750 | lastWixiplPath = path; | ||
751 | } | ||
752 | else | ||
753 | { | ||
754 | libraryPaths.Add(path); | ||
755 | } | ||
756 | } | ||
757 | catch (WixException) | ||
758 | { | ||
759 | // We'll assume anything that isn't a valid intermediate is source code to compile. | ||
760 | codePaths.Add(path); | ||
761 | } | ||
762 | } | ||
780 | } | 763 | } |
781 | 764 | ||
782 | return files; | 765 | if (wixipls.Count > 0) |
766 | { | ||
767 | if (wixipls.Count > 1 || codePaths.Count > 0 || libraryPaths.Count > 0) | ||
768 | { | ||
769 | this.Messaging.Write(ErrorMessages.WixiplSourceFileIsExclusive()); | ||
770 | } | ||
771 | } | ||
772 | else if (codePaths.Count == 0 && libraryPaths.Count == 0) | ||
773 | { | ||
774 | this.Messaging.Write(ErrorMessages.NoSourceFiles()); | ||
775 | } | ||
776 | |||
777 | if (!this.Messaging.EncounteredError && String.IsNullOrEmpty(outputPath)) | ||
778 | { | ||
779 | var singleInputPath = codePaths.Count == 1 ? codePaths[0] : lastWixiplPath; | ||
780 | |||
781 | if (String.IsNullOrEmpty(singleInputPath)) | ||
782 | { | ||
783 | this.Messaging.Write(ErrorMessages.MustSpecifyOutputWithMoreThanOneInput()); | ||
784 | } | ||
785 | else | ||
786 | { | ||
787 | // If output type is unknown, the extension will be replaced with the right default based on output type. | ||
788 | outputPath = Path.ChangeExtension(singleInputPath, DefaultExtensionForOutputType(outputType)); | ||
789 | } | ||
790 | } | ||
791 | |||
792 | var pdbPath = this.PdbType == PdbType.None ? null : this.PdbFile ?? Path.ChangeExtension(outputPath ?? "error.above", ".wixpdb"); | ||
793 | |||
794 | return new InputsAndOutputs(codePaths, localizationPaths, libraryPaths, wixipls, outputPath, outputType, pdbPath, this.PdbType); | ||
783 | } | 795 | } |
784 | 796 | ||
785 | private bool TryParseBindPath(string bindPath, out IBindPath bp) | 797 | private bool TryParseBindPath(string bindPath, out IBindPath bp) |
@@ -807,5 +819,36 @@ namespace WixToolset.Core.CommandLine | |||
807 | return true; | 819 | return true; |
808 | } | 820 | } |
809 | } | 821 | } |
822 | |||
823 | private class InputsAndOutputs | ||
824 | { | ||
825 | public InputsAndOutputs(IReadOnlyCollection<string> sourcePaths, IReadOnlyCollection<string> localizationPaths, IReadOnlyCollection<string> libraryPaths, IReadOnlyCollection<Intermediate> wixipls, string outputPath, OutputType outputType, string pdbPath, PdbType pdbType) | ||
826 | { | ||
827 | this.SourcePaths = sourcePaths; | ||
828 | this.LocalizationPaths = localizationPaths; | ||
829 | this.LibraryPaths = libraryPaths; | ||
830 | this.Wixipls = wixipls; | ||
831 | this.OutputPath = outputPath; | ||
832 | this.OutputType = outputType; | ||
833 | this.PdbPath = pdbPath; | ||
834 | this.PdbType = pdbType; | ||
835 | } | ||
836 | |||
837 | public IReadOnlyCollection<string> SourcePaths { get; } | ||
838 | |||
839 | public IReadOnlyCollection<string> LocalizationPaths { get; } | ||
840 | |||
841 | public IReadOnlyCollection<string> LibraryPaths { get; } | ||
842 | |||
843 | public IReadOnlyCollection<Intermediate> Wixipls { get; } | ||
844 | |||
845 | public string OutputPath { get; set; } | ||
846 | |||
847 | public OutputType OutputType { get; } | ||
848 | |||
849 | public string PdbPath { get; } | ||
850 | |||
851 | public PdbType PdbType { get; } | ||
852 | } | ||
810 | } | 853 | } |
811 | } | 854 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs index 62ffe1eb..f91c0ab0 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs | |||
@@ -6,26 +6,11 @@ namespace WixToolsetTest.CoreIntegration | |||
6 | using System.IO; | 6 | using System.IO; |
7 | using WixBuildTools.TestSupport; | 7 | using WixBuildTools.TestSupport; |
8 | using WixToolset.Core.TestPackage; | 8 | using WixToolset.Core.TestPackage; |
9 | using WixToolset.Data; | ||
10 | using Xunit; | 9 | using Xunit; |
11 | 10 | ||
12 | public class BadInputFixture | 11 | public class BadInputFixture |
13 | { | 12 | { |
14 | [Fact] | 13 | [Fact] |
15 | public void SwitchIsNotConsideredAnArgument() | ||
16 | { | ||
17 | var result = WixRunner.Execute(new[] | ||
18 | { | ||
19 | "build", | ||
20 | "-bindpath", "-thisisaswitchnotanarg", | ||
21 | }); | ||
22 | |||
23 | Assert.Single(result.Messages, m => m.Id == (int)ErrorMessages.Ids.ExpectedArgument); | ||
24 | // TODO: when CantBuildSingleExeBundleWithInvalidArgument is fixed, uncomment: | ||
25 | //Assert.Equal((int)ErrorMessages.Ids.ExpectedArgument, result.ExitCode); | ||
26 | } | ||
27 | |||
28 | [Fact] | ||
29 | public void HandleInvalidIds() | 14 | public void HandleInvalidIds() |
30 | { | 15 | { |
31 | var folder = TestData.Get(@"TestData\BadInput"); | 16 | var folder = TestData.Get(@"TestData\BadInput"); |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/CommandLineFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/CommandLineFixture.cs new file mode 100644 index 00000000..1b0f9633 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/CommandLineFixture.cs | |||
@@ -0,0 +1,59 @@ | |||
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 WixToolsetTest.CoreIntegration | ||
4 | { | ||
5 | using System.IO; | ||
6 | using System.Linq; | ||
7 | using WixBuildTools.TestSupport; | ||
8 | using WixToolset.Core.TestPackage; | ||
9 | using Xunit; | ||
10 | |||
11 | public class CommandLineFixture | ||
12 | { | ||
13 | [Fact] | ||
14 | public void SwitchIsNotConsideredAnArgument() | ||
15 | { | ||
16 | var result = WixRunner.Execute(new[] | ||
17 | { | ||
18 | "build", | ||
19 | "-bindpath", "-thisisaswitchnotanarg", | ||
20 | }); | ||
21 | |||
22 | WixAssert.CompareLineByLine(new[] | ||
23 | { | ||
24 | "-bindpath is expected to be followed by a value. See -? for additional detail.", | ||
25 | "Additional argument '-bindpath' was unexpected. Remove the argument and add the '-?' switch for more information.", | ||
26 | "No source files specified." | ||
27 | }, result.Messages.Select(m => m.ToString()).ToArray()); | ||
28 | Assert.Equal(391, result.ExitCode); | ||
29 | } | ||
30 | |||
31 | [Fact] | ||
32 | public void CanBuildWithNoOutputSpecified() | ||
33 | { | ||
34 | var folder = TestData.Get(@"TestData", "SimplePackage"); | ||
35 | var bindFolder = TestData.Get(@"TestData", "SingleFile", "data"); | ||
36 | |||
37 | using (var fs = new DisposableFileSystem()) | ||
38 | { | ||
39 | var testFolder = fs.GetFolder(create: true); | ||
40 | var srcFile = Path.Combine(testFolder, "SimplePackage.wxs"); | ||
41 | var intermediateFolder = Path.Combine(testFolder, "obj"); | ||
42 | var expectedPath = Path.Combine(testFolder, "SimplePackage.msi"); | ||
43 | |||
44 | // Copy the source folder into the test working folder so the output can be written to the same folder. | ||
45 | File.Copy(Path.Combine(folder, "SimplePackage.wxs"), srcFile); | ||
46 | |||
47 | var result = WixRunner.Execute(new[] | ||
48 | { | ||
49 | "build", srcFile, | ||
50 | "-bindpath", bindFolder, | ||
51 | "-intermediateFolder", intermediateFolder | ||
52 | }); | ||
53 | |||
54 | result.AssertSuccess(); | ||
55 | Assert.True(File.Exists(expectedPath), $"Expected to build MSI to: {expectedPath}"); | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | } | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimplePackage/SimplePackage.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimplePackage/SimplePackage.wxs new file mode 100644 index 00000000..0325867c --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimplePackage/SimplePackage.wxs | |||
@@ -0,0 +1,11 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade error message." /> | ||
4 | |||
5 | <Feature Id="ProductFeature"> | ||
6 | <Component Directory="ProgramFilesFolder" Subdirectory="MsiPackage"> | ||
7 | <File Source="test.txt" /> | ||
8 | </Component> | ||
9 | </Feature> | ||
10 | </Package> | ||
11 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/WixlibMultiarch/MultiarchFile.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/WixlibMultiarch/MultiarchFile.wxs new file mode 100644 index 00000000..c74bf370 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/WixlibMultiarch/MultiarchFile.wxs | |||
@@ -0,0 +1,11 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Fragment> | ||
3 | <Directory Id="ProgramFiles3264Folder"> | ||
4 | <Directory Id="INSTALLFOLDER" Name="Foo"> | ||
5 | <Component> | ||
6 | <File Source="test.txt" /> | ||
7 | </Component> | ||
8 | </Directory> | ||
9 | </Directory> | ||
10 | </Fragment> | ||
11 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/WixlibFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/WixlibFixture.cs index 00b83de8..01b82eb3 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/WixlibFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/WixlibFixture.cs | |||
@@ -53,6 +53,49 @@ namespace WixToolsetTest.CoreIntegration | |||
53 | } | 53 | } |
54 | 54 | ||
55 | [Fact] | 55 | [Fact] |
56 | public void CanBuildMultiarchWixlib() | ||
57 | { | ||
58 | var folder = TestData.Get(@"TestData", "WixlibMultiarch"); | ||
59 | |||
60 | using (var fs = new DisposableFileSystem()) | ||
61 | { | ||
62 | var baseFolder = fs.GetFolder(); | ||
63 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
64 | var wixlibPath = Path.Combine(intermediateFolder, @"test.wixlib"); | ||
65 | |||
66 | var result = WixRunner.Execute(new[] | ||
67 | { | ||
68 | "build", | ||
69 | Path.Combine(folder, "MultiarchFile.wxs"), | ||
70 | "-intermediateFolder", intermediateFolder, | ||
71 | "-o", wixlibPath | ||
72 | }); | ||
73 | |||
74 | result.AssertSuccess(); | ||
75 | |||
76 | result = WixRunner.Execute(new[] | ||
77 | { | ||
78 | "build", | ||
79 | "-arch", "x64", | ||
80 | Path.Combine(folder, "MultiarchFile.wxs"), | ||
81 | wixlibPath, | ||
82 | "-intermediateFolder", intermediateFolder, | ||
83 | "-o", wixlibPath | ||
84 | }); | ||
85 | |||
86 | result.AssertSuccess(); | ||
87 | |||
88 | var wixlib = Intermediate.Load(wixlibPath); | ||
89 | var componentSymbols = wixlib.Sections.SelectMany(s => s.Symbols).OfType<ComponentSymbol>().ToList(); | ||
90 | WixAssert.CompareLineByLine(new[] | ||
91 | { | ||
92 | "x64 filcV1yrx0x8wJWj4qMzcH21jwkPko", | ||
93 | "x86 filcV1yrx0x8wJWj4qMzcH21jwkPko", | ||
94 | }, componentSymbols.Select(c => (c.Win64 ? "x64 " : "x86 ") + c.Id.Id).OrderBy(s => s).ToArray()); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | [Fact] | ||
56 | public void CanBuildWixlibWithBinariesFromNamedBindPaths() | 99 | public void CanBuildWixlibWithBinariesFromNamedBindPaths() |
57 | { | 100 | { |
58 | var folder = TestData.Get(@"TestData\WixlibWithBinaries"); | 101 | var folder = TestData.Get(@"TestData\WixlibWithBinaries"); |