Add support for BindPaths and building .wixlibs
Rob Mensching committed
Oct 1, 2017 at 14:25 UTC
39c7e2bb0399802e65a3025c4a73db211e730479
8 files changed
+421
-170
src/WixToolset.BuildTasks/DoIt.cs
+40
-11
@@ -2,6 +2,9 @@
2
3
namespace WixToolset.BuildTasks
4
{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.Runtime.InteropServices;
8
using Microsoft.Build.Framework;
9
using Microsoft.Build.Utilities;
10
using WixToolset.Core;
@@ -40,12 +43,14 @@ namespace WixToolset.BuildTasks
43
44
public bool NoLogo { get; set; }
45
43
- public ITaskItem[] ObjectFiles { get; set; }
46
+ public ITaskItem[] LibraryFiles { get; set; }
47
48
[Output]
49
[Required]
50
public ITaskItem OutputFile { get; set; }
51
52
+ public string OutputType { get; set; }
53
+
54
public string PdbOutputFile { get; set; }
55
56
public bool Pedantic { get; set; }
@@ -84,7 +89,7 @@ namespace WixToolset.BuildTasks
89
90
public ITaskItem[] BindInputPaths { get; set; }
91
public bool BindFiles { get; set; }
87
- public ITaskItem BindContentsFile{ get; set; }
92
+ public ITaskItem BindContentsFile { get; set; }
93
public ITaskItem BindOutputsFile { get; set; }
94
public ITaskItem BindBuiltOutputsFile { get; set; }
95
@@ -102,21 +107,20 @@ namespace WixToolset.BuildTasks
107
public string[] SuppressIces { get; set; }
108
public string AdditionalCub { get; set; }
109
105
-
106
-
110
public override bool Execute()
111
{
112
try
113
{
114
this.ExecuteCore();
115
}
113
- catch (BuildException e)
114
- {
115
- this.Log.LogErrorFromException(e);
116
- }
117
- catch (WixException e)
116
+ catch (Exception e)
117
{
118
this.Log.LogErrorFromException(e);
119
+
120
+ if (e is NullReferenceException || e is SEHException)
121
+ {
122
+ throw;
123
+ }
124
}
125
126
return !this.Log.HasLoggedErrors;
@@ -129,27 +133,31 @@ namespace WixToolset.BuildTasks
133
commandLineBuilder.AppendTextUnquoted("build");
134
135
commandLineBuilder.AppendSwitchIfNotNull("-out ", this.OutputFile);
136
+ commandLineBuilder.AppendSwitchIfNotNull("-outputType ", this.OutputType);
137
+ commandLineBuilder.AppendIfTrue("-nologo", this.NoLogo);
138
commandLineBuilder.AppendSwitchIfNotNull("-cultures ", this.Cultures);
139
commandLineBuilder.AppendArrayIfNotNull("-d ", this.DefineConstants);
140
commandLineBuilder.AppendArrayIfNotNull("-I ", this.IncludeSearchPaths);
141
commandLineBuilder.AppendExtensions(this.Extensions, this.ExtensionDirectory, this.ReferencePaths);
136
- commandLineBuilder.AppendIfTrue("-nologo", this.NoLogo);
142
commandLineBuilder.AppendIfTrue("-sval", this.SuppressValidation);
143
commandLineBuilder.AppendArrayIfNotNull("-sice ", this.SuppressIces);
144
commandLineBuilder.AppendSwitchIfNotNull("-usf ", this.UnreferencedSymbolsFile);
145
commandLineBuilder.AppendSwitchIfNotNull("-cc ", this.CabinetCachePath);
146
+ commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory);
147
commandLineBuilder.AppendSwitchIfNotNull("-contentsfile ", this.BindContentsFile);
148
commandLineBuilder.AppendSwitchIfNotNull("-outputsfile ", this.BindOutputsFile);
149
commandLineBuilder.AppendSwitchIfNotNull("-builtoutputsfile ", this.BindBuiltOutputsFile);
150
commandLineBuilder.AppendSwitchIfNotNull("-wixprojectfile ", this.WixProjectFile);
151
commandLineBuilder.AppendTextIfNotWhitespace(this.AdditionalOptions);
152
153
+ commandLineBuilder.AppendArrayIfNotNull("-bindPath ", this.CalculateBindPathStrings());
154
commandLineBuilder.AppendArrayIfNotNull("-loc ", this.LocalizationFiles);
155
+ commandLineBuilder.AppendArrayIfNotNull("-lib ", this.LibraryFiles);
156
commandLineBuilder.AppendFileNamesIfNotNull(this.SourceFiles, " ");
157
158
var commandLineString = commandLineBuilder.ToString();
159
152
- this.Log.LogMessage(MessageImportance.Normal, commandLineString);
160
+ this.Log.LogMessage(MessageImportance.Normal, "wix.exe " + commandLineString);
161
162
var command = CommandLine.ParseStandardCommandLine(commandLineString);
163
command?.Execute();
@@ -160,6 +168,27 @@ namespace WixToolset.BuildTasks
168
this.Log.LogMessageFromText(e.Message, MessageImportance.Normal);
169
}
170
171
+ private IEnumerable<string> CalculateBindPathStrings()
172
+ {
173
+ if (null != this.BindInputPaths)
174
+ {
175
+ foreach (var item in this.BindInputPaths)
176
+ {
177
+ var path = item.GetMetadata("FullPath");
178
+
179
+ var bindName = item.GetMetadata("BindName");
180
+ if (!String.IsNullOrEmpty(bindName))
181
+ {
182
+ yield return String.Concat(bindName, "=", path);
183
+ }
184
+ else
185
+ {
186
+ yield return path;
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
///// <summary>
193
///// Builds a command line from options in this task.
194
///// </summary>
src/WixToolset.BuildTasks/WixCommandLineBuilder.cs
+7
-9
@@ -49,7 +49,7 @@ namespace WixToolset.BuildTasks
49
/// </summary>
50
/// <param name="switchName">Switch to append.</param>
51
/// <param name="values">Values specified by the user.</param>
52
- public void AppendArrayIfNotNull(string switchName, ITaskItem[] values)
52
+ public void AppendArrayIfNotNull(string switchName, IEnumerable<ITaskItem> values)
53
{
54
if (values != null)
55
{
@@ -65,7 +65,7 @@ namespace WixToolset.BuildTasks
65
/// </summary>
66
/// <param name="switchName">Switch to append.</param>
67
/// <param name="values">Values specified by the user.</param>
68
- public void AppendArrayIfNotNull(string switchName, string[] values)
68
+ public void AppendArrayIfNotNull(string switchName, IEnumerable<string> values)
69
{
70
if (values != null)
71
{
@@ -77,9 +77,9 @@ namespace WixToolset.BuildTasks
77
}
78
79
/// <summary>
80
- /// Build the extensions argument. Each extension is searched in the current folder, user defined search
80
+ /// Build the extensions argument. Each extension is searched in the current folder, user defined search
81
/// directories (ReferencePath), HintPath, and under Wix Extension Directory in that order.
82
- /// The order of precednce is based off of that described in Microsoft.Common.Targets's SearchPaths
82
+ /// The order of precedence is based off of that described in Microsoft.Common.Targets's SearchPaths
83
/// property for the ResolveAssemblyReferences task.
84
/// </summary>
85
/// <param name="extensions">The list of extensions to include.</param>
@@ -92,21 +92,19 @@ namespace WixToolset.BuildTasks
92
return;
93
}
94
95
- string resolvedPath;
96
-
95
foreach (ITaskItem extension in extensions)
96
{
97
string className = extension.GetMetadata("Class");
98
99
string fileName = Path.GetFileName(extension.ItemSpec);
100
103
- if (Path.GetExtension(fileName).Length == 0)
101
+ if (String.IsNullOrEmpty(Path.GetExtension(fileName)))
102
{
103
fileName += ".dll";
104
}
105
106
// First try reference paths
109
- resolvedPath = FileSearchHelperMethods.SearchFilePaths(referencePaths, fileName);
107
+ var resolvedPath = FileSearchHelperMethods.SearchFilePaths(referencePaths, fileName);
108
109
if (String.IsNullOrEmpty(resolvedPath))
110
{
@@ -118,7 +116,7 @@ namespace WixToolset.BuildTasks
116
// Now try the item itself
117
resolvedPath = extension.ItemSpec;
118
121
- if (Path.GetExtension(resolvedPath).Length == 0)
119
+ if (String.IsNullOrEmpty(Path.GetExtension(resolvedPath)))
120
{
121
resolvedPath += ".dll";
122
}
src/WixToolset.BuildTasks/wix.targets
+11
-12
@@ -646,17 +646,17 @@
646
@(_BindInputs);
647
$(MSBuildAllProjects)"
648
Outputs="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindBuiltOutputsFile);@(_BindBuiltOutputs)"
649
- Condition=" '@(Compile)' != '' and ('$(OutputType)' == 'Bundle' or '$(OutputType)' == 'Package' or '$(OutputType)' == 'PatchCreation' or '$(OutputType)' == 'Module')">
650
-
649
+ Condition=" '@(Compile)' != '' ">
650
651
<PropertyGroup>
652
+ <OutputFile>$([System.IO.Path]::GetFullPath($(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(TargetName)$(TargetExt)))</OutputFile>
653
<PdbOutputFile>$(TargetPdbDir)%(CultureGroup.OutputFolder)$(TargetPdbName)</PdbOutputFile>
654
</PropertyGroup>
655
656
<DoIt
657
SourceFiles="@(_CompileWithObjectPath)"
658
+ LibraryFiles="@(WixLibProjects);@(_ResolvedWixLibraryPaths)"
659
LocalizationFiles="@(EmbeddedResource)"
659
- ObjectFiles="@(CompileObjOutput);@(WixObject);@(WixLibProjects);@(_ResolvedWixLibraryPaths)"
660
661
Cultures="%(CultureGroup.Identity)"
662
@@ -665,7 +665,8 @@
665
666
IntermediateDirectory="$(IntermediateOutputPath)"
667
668
- OutputFile="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(TargetName)$(TargetExt)"
668
+ OutputFile="$(OutputFile)"
669
+ OutputType="$(OutputType)"
670
PdbOutputFile="$(PdbOutputFile)"
671
672
AdditionalOptions="$(CompilerAdditionalOptions) $(LinkerAdditionalOptions)"
@@ -1029,8 +1030,7 @@
1030
================================================================================================
1031
-->
1032
<Target
1032
- Name="ReadPreviousBindInputsAndBuiltOutputs"
1033
- Condition=" '$(OutputType)' == 'Bundle' or '$(OutputType)' == 'Package' or '$(OutputType)' == 'PatchCreation' or '$(OutputType)' == 'Module' ">
1033
+ Name="ReadPreviousBindInputsAndBuiltOutputs">
1034
1035
<ReadLinesFromFile File="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindContentsFile)">
1036
<Output TaskParameter="Lines" ItemName="_BindInputs" />
@@ -1169,17 +1169,16 @@
1169
================================================================================================
1170
-->
1171
<Target
1172
- Name="UpdateLinkFileWrites"
1173
- Condition=" '$(OutputType)' == 'Bundle' or '$(OutputType)' == 'Package' or '$(OutputType)' == 'PatchCreation' or '$(OutputType)' == 'Module' ">
1172
+ Name="UpdateLinkFileWrites">
1173
1174
<ReadLinesFromFile File="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindOutputsFile)">
1175
<Output TaskParameter="Lines" ItemName="FileWrites"/>
1176
</ReadLinesFromFile>
1177
1178
<ItemGroup>
1180
- <FileWrites Include="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindContentsFile)" />
1181
- <FileWrites Include="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindOutputsFile)" />
1182
- <FileWrites Include="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindBuiltOutputsFile)" />
1179
+ <FileWrites Include="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindContentsFile)" Condition=" Exists('$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindContentsFile)') " />
1180
+ <FileWrites Include="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindOutputsFile)" Condition=" Exists('$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindOutputsFile)') " />
1181
+ <FileWrites Include="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindBuiltOutputsFile)" Condition=" Exists('$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(BindBuiltOutputsFile)') " />
1182
</ItemGroup>
1183
1184
<Message Importance="low" Text="Build files after link: @(FileWrites)" />
@@ -1302,7 +1301,7 @@
1301
</ReadLinesFromFile>
1302
1303
<ItemGroup>
1305
- <_FullPathToCopy Include="$(TargetPath)" Condition=" '@(_FullPathToCopy)'=='' " />
1304
+ <_FullPathToCopy Include="$(OutputFile)" Condition=" '@(_FullPathToCopy)'=='' " />
1305
<_RelativePath Include="$([MSBuild]::MakeRelative($(FullIntermediateOutputPath), %(_FullPathToCopy.Identity)))" />
1306
</ItemGroup>
1307
src/WixToolset.Core/CommandLine/BuildCommand.cs
+171
-25
@@ -7,17 +7,24 @@ namespace WixToolset.Core
7
using System.IO;
8
using System.Linq;
9
using WixToolset.Data;
10
+ using WixToolset.Extensibility;
11
12
internal class BuildCommand : ICommand
13
{
13
- public BuildCommand(IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, string outputPath, IEnumerable<string> cultures, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile)
14
+ public BuildCommand(IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, string outputPath, OutputType outputType, IEnumerable<string> cultures, bool bindFiles, IEnumerable<BindPath> bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile)
15
{
16
this.LocFiles = locFiles;
17
+ this.LibraryFiles = libraryFiles;
18
this.PreprocessorVariables = preprocessorVariables;
19
this.SourceFiles = sources;
20
this.OutputPath = outputPath;
21
+ this.OutputType = outputType;
22
23
this.Cultures = cultures;
24
+ this.BindFiles = bindFiles;
25
+ this.BindPaths = bindPaths;
26
+
27
+ this.IntermediateFolder = intermediateFolder ?? Path.GetTempPath();
28
this.ContentsFile = contentsFile;
29
this.OutputsFile = outputsFile;
30
this.BuiltOutputsFile = builtOutputsFile;
@@ -26,14 +33,24 @@ namespace WixToolset.Core
33
34
public IEnumerable<string> LocFiles { get; }
35
36
+ public IEnumerable<string> LibraryFiles { get; }
37
+
38
private IEnumerable<SourceFile> SourceFiles { get; }
39
40
private IDictionary<string, string> PreprocessorVariables { get; }
41
42
private string OutputPath { get; }
43
44
+ private OutputType OutputType { get; }
45
+
46
public IEnumerable<string> Cultures { get; }
47
48
+ public bool BindFiles { get; }
49
+
50
+ public IEnumerable<BindPath> BindPaths { get; }
51
+
52
+ public string IntermediateFolder { get; }
53
+
54
public string ContentsFile { get; }
55
56
public string OutputsFile { get; }
@@ -44,21 +61,135 @@ namespace WixToolset.Core
61
62
public int Execute()
63
{
47
- var intermediates = CompilePhase();
64
+ var intermediates = this.CompilePhase();
65
+
66
+ var tableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions());
67
+
68
+ if (this.OutputType == OutputType.Library)
69
+ {
70
+ this.LibraryPhase(intermediates, tableDefinitions);
71
+ }
72
+ else
73
+ {
74
+ var output = this.LinkPhase(intermediates, tableDefinitions);
75
+
76
+ if (!Messaging.Instance.EncounteredError)
77
+ {
78
+ this.BindPhase(output, tableDefinitions);
79
+ }
80
+ }
81
+
82
+ return Messaging.Instance.LastErrorNumber;
83
+ }
84
+
85
+ private IEnumerable<Intermediate> CompilePhase()
86
+ {
87
+ var intermediates = new List<Intermediate>();
88
+
89
+ var preprocessor = new Preprocessor();
90
+
91
+ var compiler = new Compiler();
92
+
93
+ foreach (var sourceFile in this.SourceFiles)
94
+ {
95
+ var document = preprocessor.Process(sourceFile.SourcePath, this.PreprocessorVariables);
96
+
97
+ var intermediate = compiler.Compile(document);
98
+
99
+ intermediates.Add(intermediate);
100
+ }
101
+
102
+ return intermediates;
103
+ }
104
+
105
+ private void LibraryPhase(IEnumerable<Intermediate> intermediates, TableDefinitionCollection tableDefinitions)
106
+ {
107
+ var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList();
108
+
109
+ // If there was an error adding localization files, then bail.
110
+ if (Messaging.Instance.EncounteredError)
111
+ {
112
+ return;
113
+ }
114
115
var sections = intermediates.SelectMany(i => i.Sections).ToList();
116
117
+ LibraryBinaryFileResolver resolver = null;
118
+
119
+ if (this.BindFiles)
120
+ {
121
+ resolver = new LibraryBinaryFileResolver();
122
+ resolver.FileManagers = new List<IBinderFileManager> { new BinderFileManager() }; ;
123
+ resolver.VariableResolver = new WixVariableResolver();
124
+
125
+ BinderFileManagerCore core = new BinderFileManagerCore();
126
+ core.AddBindPaths(this.BindPaths, BindStage.Normal);
127
+
128
+ foreach (var fileManager in resolver.FileManagers)
129
+ {
130
+ fileManager.Core = core;
131
+ }
132
+ }
133
+
134
+ var librarian = new Librarian();
135
+
136
+ var library = librarian.Combine(sections, localizations, resolver);
137
+
138
+ library?.Save(this.OutputPath);
139
+ }
140
+
141
+ private Output LinkPhase(IEnumerable<Intermediate> intermediates, TableDefinitionCollection tableDefinitions)
142
+ {
143
+ var sections = intermediates.SelectMany(i => i.Sections).ToList();
144
+
145
+ sections.AddRange(SectionsFromLibraries(tableDefinitions));
146
+
147
var linker = new Linker();
148
53
- var output = linker.Link(sections, OutputType.Product);
149
+ var output = linker.Link(sections, this.OutputType);
150
+
151
+ return output;
152
+ }
153
+
154
+ private IEnumerable<Section> SectionsFromLibraries(TableDefinitionCollection tableDefinitions)
155
+ {
156
+ var sections = new List<Section>();
157
+
158
+ if (this.LibraryFiles != null)
159
+ {
160
+ foreach (var libraryFile in this.LibraryFiles)
161
+ {
162
+ try
163
+ {
164
+ var library = Library.Load(libraryFile, tableDefinitions, false);
165
+
166
+ sections.AddRange(library.Sections);
167
+ }
168
+ catch (WixCorruptFileException e)
169
+ {
170
+ Messaging.Instance.OnMessage(e.Error);
171
+ }
172
+ catch (WixUnexpectedFileFormatException e)
173
+ {
174
+ Messaging.Instance.OnMessage(e.Error);
175
+ }
176
+ }
177
+ }
178
55
- var localizer = new Localizer();
179
+ return sections;
180
+ }
181
+
182
+ private void BindPhase(Output output, TableDefinitionCollection tableDefinitions)
183
+ {
184
+ var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList();
185
+
186
+ var localizer = new Localizer(localizations);
187
+
188
+ var resolver = new WixVariableResolver(localizer);
189
190
var binder = new Binder();
58
- binder.TempFilesLocation = Path.GetTempPath();
59
- binder.WixVariableResolver = new WixVariableResolver();
60
- binder.WixVariableResolver.Localizer = localizer;
61
- binder.AddExtension(new BinderFileManager());
191
+ binder.TempFilesLocation = this.IntermediateFolder;
192
+ binder.WixVariableResolver = resolver;
193
binder.SuppressValidation = true;
194
195
binder.ContentsFile = this.ContentsFile;
@@ -66,35 +197,50 @@ namespace WixToolset.Core
197
binder.BuiltOutputsFile = this.BuiltOutputsFile;
198
binder.WixprojectFile = this.WixProjectFile;
199
69
- foreach (var loc in this.LocFiles)
200
+ if (this.BindPaths != null)
201
{
71
- var localization = Localizer.ParseLocalizationFile(loc, linker.TableDefinitions);
72
- binder.WixVariableResolver.Localizer.AddLocalization(localization);
202
+ binder.BindPaths.AddRange(this.BindPaths);
203
}
204
75
- binder.Bind(output, this.OutputPath);
205
+ binder.AddExtension(new BinderFileManager());
206
77
- return 0;
207
+ binder.Bind(output, this.OutputPath);
208
}
209
80
- private IEnumerable<Intermediate> CompilePhase()
210
+ private IEnumerable<Localization> LoadLocalizationFiles(TableDefinitionCollection tableDefinitions)
211
{
82
- var intermediates = new List<Intermediate>();
83
-
84
- var preprocessor = new Preprocessor();
212
+ foreach (var loc in this.LocFiles)
213
+ {
214
+ var localization = Localizer.ParseLocalizationFile(loc, tableDefinitions);
215
86
- var compiler = new Compiler();
216
+ yield return localization;
217
+ }
218
+ }
219
88
- foreach (var sourceFile in this.SourceFiles)
89
- {
90
- var document = preprocessor.Process(sourceFile.SourcePath, this.PreprocessorVariables);
220
+ /// <summary>
221
+ /// File resolution mechanism to create binary library.
222
+ /// </summary>
223
+ private class LibraryBinaryFileResolver : ILibraryBinaryFileResolver
224
+ {
225
+ public IEnumerable<IBinderFileManager> FileManagers { get; set; }
226
92
- var intermediate = compiler.Compile(document);
227
+ public WixVariableResolver VariableResolver { get; set; }
228
94
- intermediates.Add(intermediate);
229
+ public string Resolve(SourceLineNumber sourceLineNumber, string table, string path)
230
+ {
231
+ string resolvedPath = this.VariableResolver.ResolveVariables(sourceLineNumber, path, false);
232
+
233
+ foreach (IBinderFileManager fileManager in this.FileManagers)
234
+ {
235
+ string finalPath = fileManager.ResolveFile(resolvedPath, table, sourceLineNumber, BindStage.Normal);
236
+ if (!String.IsNullOrEmpty(finalPath))
237
+ {
238
+ return finalPath;
239
+ }
240
+ }
241
+
242
+ return null;
243
}
96
-
97
- return intermediates;
244
}
245
}
246
}
src/WixToolset.Core/CommandLine/CommandLine.cs
+95
-20
@@ -57,14 +57,20 @@ namespace WixToolset.Core
57
var showVersion = false;
58
var outputFolder = String.Empty;
59
var outputFile = String.Empty;
60
- var sourceFile = String.Empty;
60
+ var outputType = String.Empty;
61
var verbose = false;
62
var files = new List<string>();
63
var defines = new List<string>();
64
var includePaths = new List<string>();
65
var locFiles = new List<string>();
66
+ var libraryFiles = new List<string>();
67
var suppressedWarnings = new List<int>();
68
69
+ var bindFiles = false;
70
+ var bindPaths = new List<string>();
71
+
72
+ var intermediateFolder = String.Empty;
73
+
74
var cultures = new List<string>();
75
var contentsFile = String.Empty;
76
var outputsFile = String.Empty;
@@ -84,6 +90,14 @@ namespace WixToolset.Core
90
cmdline.ShowHelp = true;
91
return true;
92
93
+ case "bindfiles":
94
+ bindFiles = true;
95
+ return true;
96
+
97
+ case "bindpath":
98
+ cmdline.GetNextArgumentOrError(bindPaths);
99
+ return true;
100
+
101
case "cultures":
102
cmdline.GetNextArgumentOrError(cultures);
103
return true;
@@ -110,15 +124,27 @@ namespace WixToolset.Core
124
cmdline.GetNextArgumentOrError(includePaths);
125
return true;
126
127
+ case "intermediatefolder":
128
+ cmdline.GetNextArgumentOrError(ref intermediateFolder);
129
+ return true;
130
+
131
case "loc":
132
cmdline.GetNextArgumentAsFilePathOrError(locFiles, "localization files");
133
return true;
134
135
+ case "lib":
136
+ cmdline.GetNextArgumentAsFilePathOrError(libraryFiles, "library files");
137
+ return true;
138
+
139
case "o":
140
case "out":
141
cmdline.GetNextArgumentOrError(ref outputFile);
142
return true;
143
144
+ case "outputtype":
145
+ cmdline.GetNextArgumentOrError(ref outputType);
146
+ return true;
147
+
148
case "nologo":
149
showLogo = false;
150
return true;
@@ -143,6 +169,8 @@ namespace WixToolset.Core
169
}
170
});
171
172
+ Messaging.Instance.ShowVerboseMessages = verbose;
173
+
174
if (showVersion)
175
{
176
return new VersionCommand();
@@ -164,8 +192,10 @@ namespace WixToolset.Core
192
{
193
var sourceFiles = GatherSourceFiles(files, outputFolder);
194
var variables = GatherPreprocessorVariables(defines);
195
+ var bindPathList = GatherBindPaths(bindPaths);
196
var extensions = cli.ExtensionManager;
168
- return new BuildCommand(sourceFiles, variables, locFiles, outputFile, cultures, contentsFile, outputsFile, builtOutputsFile, wixProjectFile);
197
+ var type = CalculateOutputType(outputType, outputFile);
198
+ return new BuildCommand(sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile, wixProjectFile);
199
}
200
201
case Commands.Compile:
@@ -179,6 +209,46 @@ namespace WixToolset.Core
209
return null;
210
}
211
212
+ private static OutputType CalculateOutputType(string outputType, string outputFile)
213
+ {
214
+ if (String.IsNullOrEmpty(outputType))
215
+ {
216
+ outputType = Path.GetExtension(outputFile);
217
+ }
218
+
219
+ switch (outputType.ToLowerInvariant())
220
+ {
221
+ case "bundle":
222
+ case ".exe":
223
+ return OutputType.Bundle;
224
+
225
+ case "library":
226
+ case ".wixlib":
227
+ return OutputType.Library;
228
+
229
+ case "module":
230
+ case ".msm":
231
+ return OutputType.Module;
232
+
233
+ case "patch":
234
+ case ".msp":
235
+ return OutputType.Patch;
236
+
237
+ case ".pcp":
238
+ return OutputType.PatchCreation;
239
+
240
+ case "product":
241
+ case ".msi":
242
+ return OutputType.Product;
243
+
244
+ case "transform":
245
+ case ".mst":
246
+ return OutputType.Transform;
247
+ }
248
+
249
+ return OutputType.Unknown;
250
+ }
251
+
252
private static CommandLine Parse(string commandLineString, Func<CommandLine, string, bool> parseArgument)
253
{
254
var arguments = CommandLine.ParseArgumentsToArray(commandLineString).ToArray();
@@ -239,6 +309,26 @@ namespace WixToolset.Core
309
return variables;
310
}
311
312
+ private static IEnumerable<BindPath> GatherBindPaths(IEnumerable<string> bindPaths)
313
+ {
314
+ var result = new List<BindPath>();
315
+
316
+ foreach (var bindPath in bindPaths)
317
+ {
318
+ BindPath bp = BindPath.Parse(bindPath);
319
+
320
+ if (Directory.Exists(bp.Path))
321
+ {
322
+ result.Add(bp);
323
+ }
324
+ else if (File.Exists(bp.Path))
325
+ {
326
+ Messaging.Instance.OnMessage(WixErrors.ExpectedDirectoryGotFile("-bindpath", bp.Path));
327
+ }
328
+ }
329
+
330
+ return result;
331
+ }
332
333
/// <summary>
334
/// Get a set of files that possibly have a search pattern in the path (such as '*').
@@ -361,7 +451,7 @@ namespace WixToolset.Core
451
452
private static bool TryDequeue(Queue<string> q, out string arg)
453
{
364
- if (q.Count> 0)
454
+ if (q.Count > 0)
455
{
456
arg = q.Dequeue();
457
return true;
@@ -469,11 +559,6 @@ namespace WixToolset.Core
559
return false;
560
}
561
472
- /// <summary>
473
- /// Parses a response file.
474
- /// </summary>
475
- /// <param name="responseFile">The file to parse.</param>
476
- /// <returns>The array of arguments.</returns>
562
private static List<string> ParseResponseFile(string responseFile)
563
{
564
string arguments;
@@ -486,11 +571,6 @@ namespace WixToolset.Core
571
return CommandLine.ParseArgumentsToArray(arguments);
572
}
573
489
- /// <summary>
490
- /// Parses an argument string into an argument array based on whitespace and quoting.
491
- /// </summary>
492
- /// <param name="arguments">Argument string.</param>
493
- /// <returns>Argument array.</returns>
574
private static List<string> ParseArgumentsToArray(string arguments)
575
{
576
// Scan and parse the arguments string, dividing up the arguments based on whitespace.
@@ -526,7 +606,7 @@ namespace WixToolset.Core
606
// Add the argument to the list if it's not empty.
607
if (arg.Length > 0)
608
{
529
- argsList.Add(CommandLine.ExpandEnvVars(arg.ToString()));
609
+ argsList.Add(CommandLine.ExpandEnvironmentVariables(arg.ToString()));
610
arg.Length = 0;
611
}
612
}
@@ -557,12 +637,7 @@ namespace WixToolset.Core
637
return argsList;
638
}
639
560
- /// <summary>
561
- /// Expand enxironment variables contained in the passed string
562
- /// </summary>
563
- /// <param name="arguments"></param>
564
- /// <returns></returns>
565
- private static string ExpandEnvVars(string arguments)
640
+ private static string ExpandEnvironmentVariables(string arguments)
641
{
642
var id = Environment.GetEnvironmentVariables();
643
src/WixToolset.Core/Librarian.cs
+67
-50
@@ -4,8 +4,8 @@ namespace WixToolset
4
{
5
using System;
6
using System.Collections.Generic;
7
+ using System.Linq;
8
using WixToolset.Data;
8
- using WixToolset.Extensibility;
9
using WixToolset.Link;
10
11
/// <summary>
@@ -13,70 +13,27 @@ namespace WixToolset
13
/// </summary>
14
public sealed class Librarian
15
{
16
- /// <summary>
17
- /// Instantiate a new Librarian class.
18
- /// </summary>
19
- public Librarian()
20
- {
21
- this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions());
22
- }
23
-
24
- /// <summary>
25
- /// Gets table definitions used by this librarian.
26
- /// </summary>
27
- /// <value>Table definitions.</value>
28
- public TableDefinitionCollection TableDefinitions { get; private set; }
29
-
30
- /// <summary>
31
- /// Adds an extension's data.
32
- /// </summary>
33
- /// <param name="extension">The extension data to add.</param>
34
- public void AddExtensionData(IExtensionData extension)
35
- {
36
- if (null != extension.TableDefinitions)
37
- {
38
- foreach (TableDefinition tableDefinition in extension.TableDefinitions)
39
- {
40
- try
41
- {
42
- this.TableDefinitions.Add(tableDefinition);
43
- }
44
- catch (ArgumentException)
45
- {
46
- Messaging.Instance.OnMessage(WixErrors.DuplicateExtensionTable(extension.GetType().ToString(), tableDefinition.Name));
47
- }
48
- }
49
- }
50
- }
51
-
16
/// <summary>
17
/// Create a library by combining several intermediates (objects).
18
/// </summary>
19
/// <param name="sections">The sections to combine into a library.</param>
20
/// <returns>Returns the new library.</returns>
57
- public Library Combine(IEnumerable<Section> sections)
21
+ public Library Combine(IEnumerable<Section> sections, IEnumerable<Localization> localizations, ILibraryBinaryFileResolver resolver)
22
{
59
- Library library = new Library(sections);
23
+ var localizationsByCulture = CollateLocalizations(localizations);
24
61
- this.Validate(library);
25
+ var embedFilePaths = ResolveFilePathsToEmbed(sections, resolver);
26
63
- return (Messaging.Instance.EncounteredError ? null : library);
64
- }
27
+ var library = new Library(sections, localizationsByCulture, embedFilePaths);
28
66
- /// <summary>
67
- /// Sends a message to the message delegate if there is one.
68
- /// </summary>
69
- /// <param name="mea">Message event arguments.</param>
70
- public void OnMessage(MessageEventArgs e)
71
- {
72
- Messaging.Instance.OnMessage(e);
29
+ return this.Validate(library);
30
}
31
32
/// <summary>
33
/// Validate that a library contains one entry section and no duplicate symbols.
34
/// </summary>
35
/// <param name="library">Library to validate.</param>
79
- private void Validate(Library library)
36
+ private Library Validate(Library library)
37
{
38
FindEntrySectionAndLoadSymbolsCommand find = new FindEntrySectionAndLoadSymbolsCommand(library.Sections);
39
find.Execute();
@@ -90,6 +47,66 @@ namespace WixToolset
47
// ReportDuplicateResolvedSymbolErrorsCommand reportDupes = new ReportDuplicateResolvedSymbolErrorsCommand(find.SymbolsWithDuplicates, resolve.ResolvedSections);
48
// reportDupes.Execute();
49
// }
50
+
51
+ return (Messaging.Instance.EncounteredError ? null : library);
52
+ }
53
+
54
+ private static Dictionary<string, Localization> CollateLocalizations(IEnumerable<Localization> localizations)
55
+ {
56
+ var localizationsByCulture = new Dictionary<string, Localization>(StringComparer.OrdinalIgnoreCase);
57
+
58
+ foreach (var localization in localizations)
59
+ {
60
+ if (localizationsByCulture.TryGetValue(localization.Culture, out var existingCulture))
61
+ {
62
+ existingCulture.Merge(localization);
63
+ }
64
+ else
65
+ {
66
+ localizationsByCulture.Add(localization.Culture, localization);
67
+ }
68
+ }
69
+
70
+ return localizationsByCulture;
71
+ }
72
+
73
+ private static List<string> ResolveFilePathsToEmbed(IEnumerable<Section> sections, ILibraryBinaryFileResolver resolver)
74
+ {
75
+ var embedFilePaths = new List<string>();
76
+
77
+ // Resolve paths to files that are to be embedded in the library.
78
+ if (null != resolver)
79
+ {
80
+ foreach (Table table in sections.SelectMany(s => s.Tables))
81
+ {
82
+ foreach (Row row in table.Rows)
83
+ {
84
+ foreach (ObjectField objectField in row.Fields.OfType<ObjectField>())
85
+ {
86
+ if (null != objectField.Data)
87
+ {
88
+ string file = resolver.Resolve(row.SourceLineNumbers, table.Name, (string)objectField.Data);
89
+ if (!String.IsNullOrEmpty(file))
90
+ {
91
+ // File was successfully resolved so track the embedded index as the embedded file index.
92
+ objectField.EmbeddedFileIndex = embedFilePaths.Count;
93
+ embedFilePaths.Add(file);
94
+ }
95
+ else
96
+ {
97
+ Messaging.Instance.OnMessage(WixDataErrors.FileNotFound(row.SourceLineNumbers, (string)objectField.Data, table.Name));
98
+ }
99
+ }
100
+ else // clear out embedded file id in case there was one there before.
101
+ {
102
+ objectField.EmbeddedFileIndex = null;
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ return embedFilePaths;
110
}
111
}
112
}
src/WixToolset.Core/Localizer.cs
+24
-29
@@ -23,11 +23,32 @@ namespace WixToolset
23
/// <summary>
24
/// Instantiate a new Localizer.
25
/// </summary>
26
- public Localizer()
26
+ public Localizer(IEnumerable<Localization> localizations)
27
{
28
this.Codepage = -1;
29
- this.variables = new Dictionary<string,WixVariableRow>();
29
+ this.variables = new Dictionary<string, WixVariableRow>();
30
this.localizedControls = new Dictionary<string, LocalizedControl>();
31
+
32
+ foreach (var localization in localizations)
33
+ {
34
+ if (-1 == this.Codepage)
35
+ {
36
+ this.Codepage = localization.Codepage;
37
+ }
38
+
39
+ foreach (WixVariableRow wixVariableRow in localization.Variables)
40
+ {
41
+ Localizer.AddWixVariable(this.variables, wixVariableRow);
42
+ }
43
+
44
+ foreach (KeyValuePair<string, LocalizedControl> localizedControl in localization.LocalizedControls)
45
+ {
46
+ if (!this.localizedControls.ContainsKey(localizedControl.Key))
47
+ {
48
+ this.localizedControls.Add(localizedControl.Key, localizedControl.Value);
49
+ }
50
+ }
51
+ }
52
}
53
54
/// <summary>
@@ -75,31 +96,6 @@ namespace WixToolset
96
return localization;
97
}
98
78
- /// <summary>
79
- /// Add a localization file.
80
- /// </summary>
81
- /// <param name="localization">The localization file to add.</param>
82
- public void AddLocalization(Localization localization)
83
- {
84
- if (-1 == this.Codepage)
85
- {
86
- this.Codepage = localization.Codepage;
87
- }
88
-
89
- foreach (WixVariableRow wixVariableRow in localization.Variables)
90
- {
91
- Localizer.AddWixVariable(this.variables, wixVariableRow);
92
- }
93
-
94
- foreach (KeyValuePair<string, LocalizedControl> localizedControl in localization.LocalizedControls)
95
- {
96
- if (!this.localizedControls.ContainsKey(localizedControl.Key))
97
- {
98
- this.localizedControls.Add(localizedControl.Key, localizedControl.Value);
99
- }
100
- }
101
- }
102
-
99
/// <summary>
100
/// Get a localized data value.
101
/// </summary>
@@ -107,8 +103,7 @@ namespace WixToolset
103
/// <returns>The localized data value or null if it wasn't found.</returns>
104
public string GetLocalizedValue(string id)
105
{
110
- WixVariableRow wixVariableRow;
111
- return this.variables.TryGetValue(id, out wixVariableRow) ? wixVariableRow.Value : null;
106
+ return this.variables.TryGetValue(id, out var wixVariableRow) ? wixVariableRow.Value : null;
107
}
108
109
/// <summary>
src/WixToolset.Core/WixVariableResolver.cs
+6
-14
@@ -3,7 +3,6 @@
3
namespace WixToolset
4
{
5
using System;
6
- using System.Collections;
6
using System.Collections.Generic;
7
using System.Diagnostics.CodeAnalysis;
8
using System.Globalization;
@@ -17,34 +16,27 @@ namespace WixToolset
16
/// </summary>
17
public sealed class WixVariableResolver
18
{
20
- private Localizer localizer;
19
private Dictionary<string, string> wixVariables;
20
21
/// <summary>
22
/// Instantiate a new WixVariableResolver.
23
/// </summary>
26
- public WixVariableResolver()
24
+ public WixVariableResolver(Localizer localizer = null)
25
{
26
this.wixVariables = new Dictionary<string, string>();
27
+ this.Localizer = localizer;
28
}
29
30
/// <summary>
31
/// Gets or sets the localizer.
32
/// </summary>
33
/// <value>The localizer.</value>
35
- public Localizer Localizer
36
- {
37
- get { return this.localizer; }
38
- set { this.localizer = value; }
39
- }
34
+ public Localizer Localizer { get; private set; }
35
36
/// <summary>
37
/// Gets the count of variables added to the resolver.
38
/// </summary>
44
- public int VariableCount
45
- {
46
- get { return this.wixVariables.Count; }
47
- }
39
+ public int VariableCount => this.wixVariables.Count;
40
41
/// <summary>
42
/// Add a variable.
@@ -198,9 +190,9 @@ namespace WixToolset
190
Messaging.Instance.OnMessage(WixWarnings.DeprecatedLocalizationVariablePrefix(sourceLineNumbers, variableId));
191
}
192
201
- if (null != this.localizer)
193
+ if (null != this.Localizer)
194
{
203
- resolvedValue = this.localizer.GetLocalizedValue(variableId);
195
+ resolvedValue = this.Localizer.GetLocalizedValue(variableId);
196
}
197
}
198
else if (!localizationOnly && "wix" == variableNamespace)