// 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. namespace WixToolset.Core { using System; using System.Collections.Generic; using System.IO; using System.Linq; using WixToolset.Data; using WixToolset.Extensibility; internal class BuildCommand : ICommand { public BuildCommand(IEnumerable sources, IDictionary preprocessorVariables, IEnumerable locFiles, IEnumerable libraryFiles, string outputPath, OutputType outputType, IEnumerable cultures, bool bindFiles, IEnumerable bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile) { this.LocFiles = locFiles; this.LibraryFiles = libraryFiles; this.PreprocessorVariables = preprocessorVariables; this.SourceFiles = sources; this.OutputPath = outputPath; this.OutputType = outputType; this.Cultures = cultures; this.BindFiles = bindFiles; this.BindPaths = bindPaths; this.IntermediateFolder = intermediateFolder ?? Path.GetTempPath(); this.ContentsFile = contentsFile; this.OutputsFile = outputsFile; this.BuiltOutputsFile = builtOutputsFile; this.WixProjectFile = wixProjectFile; } public IEnumerable LocFiles { get; } public IEnumerable LibraryFiles { get; } private IEnumerable SourceFiles { get; } private IDictionary PreprocessorVariables { get; } private string OutputPath { get; } private OutputType OutputType { get; } public IEnumerable Cultures { get; } public bool BindFiles { get; } public IEnumerable BindPaths { get; } public string IntermediateFolder { get; } public string ContentsFile { get; } public string OutputsFile { get; } public string BuiltOutputsFile { get; } public string WixProjectFile { get; } public int Execute() { var intermediates = this.CompilePhase(); var tableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions()); if (this.OutputType == OutputType.Library) { this.LibraryPhase(intermediates, tableDefinitions); } else { var output = this.LinkPhase(intermediates, tableDefinitions); if (!Messaging.Instance.EncounteredError) { this.BindPhase(output, tableDefinitions); } } return Messaging.Instance.LastErrorNumber; } private IEnumerable CompilePhase() { var intermediates = new List(); var preprocessor = new Preprocessor(); var compiler = new Compiler(); foreach (var sourceFile in this.SourceFiles) { var document = preprocessor.Process(sourceFile.SourcePath, this.PreprocessorVariables); var intermediate = compiler.Compile(document); intermediates.Add(intermediate); } return intermediates; } private void LibraryPhase(IEnumerable intermediates, TableDefinitionCollection tableDefinitions) { var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList(); // If there was an error adding localization files, then bail. if (Messaging.Instance.EncounteredError) { return; } var sections = intermediates.SelectMany(i => i.Sections).ToList(); LibraryBinaryFileResolver resolver = null; if (this.BindFiles) { resolver = new LibraryBinaryFileResolver(); resolver.FileManagers = new List { new BinderFileManager() }; ; resolver.VariableResolver = new WixVariableResolver(); BinderFileManagerCore core = new BinderFileManagerCore(); core.AddBindPaths(this.BindPaths, BindStage.Normal); foreach (var fileManager in resolver.FileManagers) { fileManager.Core = core; } } var librarian = new Librarian(); var library = librarian.Combine(sections, localizations, resolver); library?.Save(this.OutputPath); } private Output LinkPhase(IEnumerable intermediates, TableDefinitionCollection tableDefinitions) { var sections = intermediates.SelectMany(i => i.Sections).ToList(); sections.AddRange(SectionsFromLibraries(tableDefinitions)); var linker = new Linker(); var output = linker.Link(sections, this.OutputType); return output; } private IEnumerable
SectionsFromLibraries(TableDefinitionCollection tableDefinitions) { var sections = new List
(); if (this.LibraryFiles != null) { foreach (var libraryFile in this.LibraryFiles) { try { var library = Library.Load(libraryFile, tableDefinitions, false); sections.AddRange(library.Sections); } catch (WixCorruptFileException e) { Messaging.Instance.OnMessage(e.Error); } catch (WixUnexpectedFileFormatException e) { Messaging.Instance.OnMessage(e.Error); } } } return sections; } private void BindPhase(Output output, TableDefinitionCollection tableDefinitions) { var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList(); var localizer = new Localizer(localizations); var resolver = new WixVariableResolver(localizer); var binder = new Binder(); binder.TempFilesLocation = this.IntermediateFolder; binder.WixVariableResolver = resolver; binder.SuppressValidation = true; binder.ContentsFile = this.ContentsFile; binder.OutputsFile = this.OutputsFile; binder.BuiltOutputsFile = this.BuiltOutputsFile; binder.WixprojectFile = this.WixProjectFile; if (this.BindPaths != null) { binder.BindPaths.AddRange(this.BindPaths); } binder.AddExtension(new BinderFileManager()); binder.Bind(output, this.OutputPath); } private IEnumerable LoadLocalizationFiles(TableDefinitionCollection tableDefinitions) { foreach (var loc in this.LocFiles) { var localization = Localizer.ParseLocalizationFile(loc, tableDefinitions); yield return localization; } } /// /// File resolution mechanism to create binary library. /// private class LibraryBinaryFileResolver : ILibraryBinaryFileResolver { public IEnumerable FileManagers { get; set; } public WixVariableResolver VariableResolver { get; set; } public string Resolve(SourceLineNumber sourceLineNumber, string table, string path) { string resolvedPath = this.VariableResolver.ResolveVariables(sourceLineNumber, path, false); foreach (IBinderFileManager fileManager in this.FileManagers) { string finalPath = fileManager.ResolveFile(resolvedPath, table, sourceLineNumber, BindStage.Normal); if (!String.IsNullOrEmpty(finalPath)) { return finalPath; } } return null; } } } }