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
Rob Mensching committed
Mar 15, 2022 at 14:01 UTC
9aa2910e79ce52144c5296077aa2444876419643
6 files changed
+277
-125
src/wix/WixToolset.Core/CommandLine/BuildCommand.cs
+153
-110
@@ -49,18 +49,8 @@ namespace WixToolset.Core.CommandLine
49
50
private string IntermediateFolder { get; set; }
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
-
52
private Platform Platform { get; set; }
53
62
- private string OutputFile { get; set; }
63
-
54
private CompressionLevel? DefaultCompressionLevel { get; set; }
55
56
private string TrackingFile { get; set; }
@@ -75,93 +65,70 @@ namespace WixToolset.Core.CommandLine
65
66
this.IntermediateFolder = this.commandLine.CalculateIntermedateFolder();
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
-
68
this.Platform = this.commandLine.Platform;
69
70
this.TrackingFile = this.commandLine.TrackingFile;
71
72
this.DefaultCompressionLevel = this.commandLine.DefaultCompressionLevel;
73
92
- var preprocessorVariables = this.commandLine.GatherPreprocessorVariables();
93
-
94
- var sourceFiles = this.commandLine.GatherSourceFiles(this.IntermediateFolder);
74
+ var preprocessorVariables = this.commandLine.CalculatePreprocessorVariables();
75
76
var filterCultures = this.commandLine.CalculateFilterCultures();
77
78
var creator = this.ServiceProvider.GetService<ISymbolDefinitionCreator>();
79
100
- this.EvaluateSourceFiles(sourceFiles, creator, out var codeFiles, out var wixipl);
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
- }
80
+ var inputsOutputs = this.commandLine.CalculateInputsAndOutputs(creator);
81
82
if (this.Messaging.EncounteredError)
83
{
84
return Task.FromResult(this.Messaging.LastErrorNumber);
85
}
86
122
- var wixobjs = this.CompilePhase(preprocessorVariables, codeFiles, cancellationToken);
87
+ var wixobjs = this.CompilePhase(preprocessorVariables, inputsOutputs.SourcePaths, this.commandLine.IncludeSearchPaths, cancellationToken);
88
124
- var wxls = this.LoadLocalizationFiles(this.commandLine.LocalizationFilePaths, preprocessorVariables, cancellationToken);
89
+ var wxls = this.LoadLocalizationFiles(inputsOutputs.LocalizationPaths, preprocessorVariables, this.commandLine.IncludeSearchPaths, cancellationToken);
90
91
if (this.Messaging.EncounteredError)
92
{
93
return Task.FromResult(this.Messaging.LastErrorNumber);
94
}
95
131
- if (this.OutputType == OutputType.Library)
96
+ if (inputsOutputs.OutputType == OutputType.Library)
97
{
98
using (new IntermediateFieldContext("wix.lib"))
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);
101
}
102
}
103
else
104
{
105
using (new IntermediateFieldContext("wix.link"))
106
{
107
+ var wixipl = inputsOutputs.Wixipls.SingleOrDefault();
108
+
109
if (wixipl == null)
110
{
144
- wixipl = this.LinkPhase(wixobjs, this.commandLine.LibraryFilePaths, creator, cancellationToken);
111
+ wixipl = this.LinkPhase(wixobjs, inputsOutputs, creator, cancellationToken);
112
}
113
114
if (!this.Messaging.EncounteredError)
115
{
149
- var outputExtension = Path.GetExtension(this.OutputFile);
116
+ var outputExtension = Path.GetExtension(inputsOutputs.OutputPath);
117
if (String.IsNullOrEmpty(outputExtension) || ".wix" == outputExtension)
118
{
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));
121
}
122
156
- if (this.OutputType == OutputType.IntermediatePostLink)
123
+ if (inputsOutputs.OutputType == OutputType.IntermediatePostLink)
124
{
158
- wixipl.Save(this.OutputFile);
125
+ wixipl.Save(inputsOutputs.OutputPath);
126
}
127
else
128
{
129
using (new IntermediateFieldContext("wix.bind"))
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);
132
}
133
}
134
}
@@ -176,51 +143,13 @@ namespace WixToolset.Core.CommandLine
143
return this.commandLine.TryParseArgument(argument, parser);
144
}
145
179
- private void EvaluateSourceFiles(IEnumerable<SourceFile> sourceFiles, ISymbolDefinitionCreator creator, out List<SourceFile> codeFiles, out Intermediate wixipl)
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)
146
+ private IReadOnlyList<Intermediate> CompilePhase(IDictionary<string, string> preprocessorVariables, IEnumerable<string> sourceFiles, IReadOnlyCollection<string> includeSearchPaths, CancellationToken cancellationToken)
147
{
148
var intermediates = new List<Intermediate>();
149
150
foreach (var sourceFile in sourceFiles)
151
{
223
- var document = this.Preprocess(preprocessorVariables, sourceFile.SourcePath, cancellationToken);
152
+ var document = this.Preprocess(preprocessorVariables, sourceFile, includeSearchPaths, cancellationToken);
153
154
if (this.Messaging.EncounteredError)
155
{
@@ -255,14 +184,21 @@ namespace WixToolset.Core.CommandLine
184
return intermediates;
185
}
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)
188
{
189
+ var libraries = this.LoadLibraries(libraryFiles, creator);
190
+
191
+ if (this.Messaging.EncounteredError)
192
+ {
193
+ return;
194
+ }
195
+
196
var context = this.ServiceProvider.GetService<ILibraryContext>();
197
context.BindFiles = bindFiles;
198
context.BindPaths = bindPaths;
199
context.Extensions = this.ExtensionManager.GetServices<ILibrarianExtension>();
200
context.Localizations = localizations;
265
- context.Intermediates = intermediates;
201
+ context.Intermediates = intermediates.Concat(libraries).ToList();
202
context.CancellationToken = cancellationToken;
203
204
try
@@ -272,7 +208,7 @@ namespace WixToolset.Core.CommandLine
208
209
if (!this.Messaging.EncounteredError)
210
{
275
- result.Library.Save(this.OutputFile);
211
+ result.Library.Save(outputPath);
212
213
this.LayoutFiles(this.IntermediateFolder, result.TrackedFiles, null, cancellationToken);
214
}
@@ -283,9 +219,9 @@ namespace WixToolset.Core.CommandLine
219
}
220
}
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)
223
{
288
- var libraries = this.LoadLibraries(libraryFiles, creator);
224
+ var libraries = this.LoadLibraries(inputsOutputs.LibraryPaths, creator);
225
226
if (this.Messaging.EncounteredError)
227
{
@@ -295,7 +231,7 @@ namespace WixToolset.Core.CommandLine
231
var context = this.ServiceProvider.GetService<ILinkContext>();
232
context.Extensions = this.ExtensionManager.GetServices<ILinkerExtension>();
233
context.ExtensionData = this.ExtensionManager.GetServices<IExtensionData>();
298
- context.ExpectedOutputType = this.OutputType;
234
+ context.ExpectedOutputType = inputsOutputs.OutputType;
235
context.Intermediates = intermediates.Concat(libraries).ToList();
236
context.SymbolDefinitionCreator = creator;
237
context.CancellationToken = cancellationToken;
@@ -304,7 +240,7 @@ namespace WixToolset.Core.CommandLine
240
return linker.Link(context);
241
}
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)
244
{
245
var intermediateFolder = this.IntermediateFolder;
246
if (String.IsNullOrEmpty(intermediateFolder))
@@ -350,9 +286,9 @@ namespace WixToolset.Core.CommandLine
286
context.FileSystemExtensions = this.ExtensionManager.GetServices<IFileSystemExtension>();
287
context.IntermediateFolder = intermediateFolder;
288
context.IntermediateRepresentation = resolveResult.IntermediateRepresentation;
353
- context.OutputPath = this.OutputFile;
354
- context.PdbType = this.PdbType;
355
- context.PdbPath = this.PdbType == PdbType.None ? null : this.PdbFile ?? Path.ChangeExtension(this.OutputFile, ".wixpdb");
289
+ context.OutputPath = inputsOutputs.OutputPath;
290
+ context.PdbType = inputsOutputs.PdbType;
291
+ context.PdbPath = inputsOutputs.PdbPath;
292
context.CancellationToken = cancellationToken;
293
294
var binder = this.ServiceProvider.GetService<IBinder>();
@@ -405,14 +341,14 @@ namespace WixToolset.Core.CommandLine
341
return Array.Empty<Intermediate>();
342
}
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)
345
{
346
var localizations = new List<Localization>();
347
var parser = this.ServiceProvider.GetService<ILocalizationParser>();
348
349
foreach (var loc in locFiles)
350
{
415
- var document = this.Preprocess(preprocessorVariables, loc, cancellationToken);
351
+ var document = this.Preprocess(preprocessorVariables, loc, includeSearchPaths, cancellationToken);
352
353
if (this.Messaging.EncounteredError)
354
{
@@ -426,12 +362,12 @@ namespace WixToolset.Core.CommandLine
362
return localizations;
363
}
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)
366
{
367
var context = this.ServiceProvider.GetService<IPreprocessContext>();
368
context.Extensions = this.ExtensionManager.GetServices<IPreprocessorExtension>();
369
context.Platform = this.Platform;
434
- context.IncludeSearchPaths = this.IncludeSearchPaths;
370
+ context.IncludeSearchPaths = includeSearchPaths;
371
context.SourcePath = sourcePath;
372
context.Variables = preprocessorVariables;
373
context.CancellationToken = cancellationToken;
@@ -519,6 +455,8 @@ namespace WixToolset.Core.CommandLine
455
456
public List<string> SourceFilePaths { get; } = new List<string>();
457
458
+ public List<string> UnevaluatedInputFilePaths { get; } = new List<string>();
459
+
460
public Platform Platform { get; private set; }
461
462
public string PdbFile { get; private set; }
@@ -632,6 +570,10 @@ namespace WixToolset.Core.CommandLine
570
parser.GetNextArgumentAsFilePathOrError(arg, "library files", this.LibraryFilePaths);
571
return true;
572
573
+ case "src":
574
+ parser.GetNextArgumentAsFilePathOrError(arg, "source code", this.SourceFilePaths);
575
+ return true;
576
+
577
case "o":
578
case "out":
579
this.OutputFile = parser.GetNextArgumentAsFilePathOrError(arg);
@@ -665,7 +607,7 @@ namespace WixToolset.Core.CommandLine
607
}
608
else
609
{
668
- parser.GetArgumentAsFilePathOrError(arg, "source code", this.SourceFilePaths);
610
+ parser.GetArgumentAsFilePathOrError(arg, "input file", this.UnevaluatedInputFilePaths);
611
return true;
612
}
613
}
@@ -747,7 +689,7 @@ namespace WixToolset.Core.CommandLine
689
return result;
690
}
691
750
- public IDictionary<string, string> GatherPreprocessorVariables()
692
+ public IDictionary<string, string> CalculatePreprocessorVariables()
693
{
694
var variables = new Dictionary<string, string>();
695
@@ -767,19 +709,89 @@ namespace WixToolset.Core.CommandLine
709
return variables;
710
}
711
770
- public IEnumerable<SourceFile> GatherSourceFiles(string intermediateDirectory)
712
+ public InputsAndOutputs CalculateInputsAndOutputs(ISymbolDefinitionCreator creator)
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;
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)
724
{
776
- var sourcePath = item;
777
- var outputPath = Path.Combine(intermediateDirectory, Path.GetFileNameWithoutExtension(sourcePath) + ".wir");
725
+ var extension = Path.GetExtension(path);
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);
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
+ }
763
}
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);
795
}
796
797
private bool TryParseBindPath(string bindPath, out IBindPath bp)
@@ -807,5 +819,36 @@ namespace WixToolset.Core.CommandLine
819
return true;
820
}
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
+ }
853
}
854
}
src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs
-15
@@ -6,25 +6,10 @@ namespace WixToolsetTest.CoreIntegration
6
using System.IO;
7
using WixBuildTools.TestSupport;
8
using WixToolset.Core.TestPackage;
9
- using WixToolset.Data;
9
using Xunit;
10
11
public class BadInputFixture
12
{
14
- [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
-
13
[Fact]
14
public void HandleInvalidIds()
15
{
src/wix/test/WixToolsetTest.CoreIntegration/CommandLineFixture.cs
new
+59
@@ -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
+}
src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimplePackage/SimplePackage.wxs
new
+11
@@ -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>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/WixlibMultiarch/MultiarchFile.wxs
new
+11
@@ -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>
src/wix/test/WixToolsetTest.CoreIntegration/WixlibFixture.cs
+43
@@ -52,6 +52,49 @@ namespace WixToolsetTest.CoreIntegration
52
}
53
}
54
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]
99
public void CanBuildWixlibWithBinariesFromNamedBindPaths()
100
{