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 /src | |
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
Diffstat (limited to 'src')
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"); |