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"); |
