|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#if NETFRAMEWORK
using System;
using Microsoft.Build.Shared.FileSystem;
using Microsoft.Build.Utilities;
#endif
using Microsoft.Build.Framework;
#nullable disable
namespace Microsoft.Build.Tasks
{
#if NETFRAMEWORK
/// <summary>
/// This class defines the "AL" XMake task, which enables using al.exe to link
/// modules and resource files into assemblies.
/// </summary>
public class AL : ToolTaskExtension, IALTaskContract
{
#region Properties
/*
Microsoft (R) Assembly Linker version 7.10.2175
for Microsoft (R) .NET Framework version 1.2
Copyright (C) Microsoft Corporation 2001-2015. All rights reserved.
Usage: al [options] [sources]
Options: ('/out' must be specified)
/? or /help Display this usage message
@<filename> Read response file for more options
/algid:<id> Algorithm used to hash files (in hexadecimal)
/base[address]:<addr> Base address for the library
/bugreport:<filename> Create a 'Bug Report' file
/comp[any]:<text> Company name
/config[uration]:<text> Configuration string
/copy[right]:<text> Copyright message
/c[ulture]:<text> Supported culture
/delay[sign][+|-] Delay sign this assembly
/descr[iption]:<text> Description
/e[vidence]:<filename> Security evidence file to embed
/fileversion:<version> Optional Win32 version (overrides assembly version)
/flags:<flags> Assembly flags (in hexadecimal)
/fullpaths Display files using fully-qualified filenames
/keyf[ile]:<filename> File containing key to sign the assembly
/keyn[ame]:<text> Key container name of key to sign assembly
/main:<method> Specifies the method name of the entry point
/nologo Suppress the startup banner and copyright message
/out:<filename> Output file name for the assembly manifest
/platform:<text> Limit which platforms this code can run on; must be
one of x86, ia64, amd64, or portable (the default)
/prod[uct]:<text> Product name
/productv[ersion]:<text> Product version
/t[arget]:lib[rary] Create a library
/t[arget]:exe Create a console executable
/t[arget]:win[exe] Create a Windows executable
/template:<filename> Specifies an assembly to get default options from
/title:<text> Title
/trade[mark]:<text> Trademark message
/v[ersion]:<version> Version (use * to auto-generate remaining numbers)
/win32icon:<filename> Use this icon for the output
/win32res:<filename> Specifies the Win32 resource file
Sources: (at least one source input is required)
<filename>[,<targetfile>] add file to assembly
/embed[resource]:<filename>[,<name>[,Private]]
embed the file as a resource in the assembly
/link[resource]:<filename>[,<name>[,<targetfile>[,Private]]]
link the file as a resource to the assembly
*/
public string AlgorithmId
{
set => Bag[nameof(AlgorithmId)] = value;
get => (string)Bag[nameof(AlgorithmId)];
}
public string BaseAddress
{
set => Bag[nameof(BaseAddress)] = value;
get => (string)Bag[nameof(BaseAddress)];
}
public string CompanyName
{
set => Bag[nameof(CompanyName)] = value;
get => (string)Bag[nameof(CompanyName)];
}
public string Configuration
{
set => Bag[nameof(Configuration)] = value;
get => (string)Bag[nameof(Configuration)];
}
public string Copyright
{
set => Bag[nameof(Copyright)] = value;
get => (string)Bag[nameof(Copyright)];
}
public string Culture
{
set => Bag[nameof(Culture)] = value;
get => (string)Bag[nameof(Culture)];
}
public bool DelaySign
{
set => Bag[nameof(DelaySign)] = value;
get => GetBoolParameterWithDefault(nameof(DelaySign), false);
}
public string Description
{
set => Bag[nameof(Description)] = value;
get => (string)Bag[nameof(Description)];
}
public string EvidenceFile
{
set => Bag[nameof(EvidenceFile)] = value;
get => (string)Bag[nameof(EvidenceFile)];
}
public string FileVersion
{
set => Bag[nameof(FileVersion)] = value;
get => (string)Bag[nameof(FileVersion)];
}
public string Flags
{
set => Bag["Flags"] = value;
get => (string)Bag["Flags"];
}
public bool GenerateFullPaths
{
set => Bag[nameof(GenerateFullPaths)] = value;
get => GetBoolParameterWithDefault(nameof(GenerateFullPaths), false);
}
public string KeyFile
{
set => Bag[nameof(KeyFile)] = value;
get => (string)Bag[nameof(KeyFile)];
}
public string KeyContainer
{
set => Bag[nameof(KeyContainer)] = value;
get => (string)Bag[nameof(KeyContainer)];
}
public string MainEntryPoint
{
set => Bag[nameof(MainEntryPoint)] = value;
get => (string)Bag[nameof(MainEntryPoint)];
}
[Output]
[Required]
public ITaskItem OutputAssembly
{
set => Bag[nameof(OutputAssembly)] = value;
get => (ITaskItem)Bag[nameof(OutputAssembly)];
}
public string Platform
{
set => Bag[nameof(Platform)] = value;
get => (string)Bag[nameof(Platform)];
}
// Map explicit platform of "AnyCPU" or the default platform (null or ""), since it is commonly understood in the
// managed build process to be equivalent to "AnyCPU", to platform "AnyCPU32BitPreferred" if the Prefer32Bit
// property is set.
internal string PlatformWith32BitPreference
{
get
{
string platform = Platform;
if ((String.IsNullOrEmpty(platform) || platform.Equals("anycpu", StringComparison.OrdinalIgnoreCase)) && Prefer32Bit)
{
platform = "anycpu32bitpreferred";
}
return platform;
}
}
public bool Prefer32Bit
{
set => Bag[nameof(Prefer32Bit)] = value;
get => GetBoolParameterWithDefault(nameof(Prefer32Bit), false);
}
public string ProductName
{
set => Bag[nameof(ProductName)] = value;
get => (string)Bag[nameof(ProductName)];
}
public string ProductVersion
{
set => Bag[nameof(ProductVersion)] = value;
get => (string)Bag[nameof(ProductVersion)];
}
public string[] ResponseFiles
{
set => Bag[nameof(ResponseFiles)] = value;
get => (string[])Bag[nameof(ResponseFiles)];
}
public string TargetType
{
set => Bag[nameof(TargetType)] = value;
get => (string)Bag[nameof(TargetType)];
}
public string TemplateFile
{
set => Bag[nameof(TemplateFile)] = value;
get => (string)Bag[nameof(TemplateFile)];
}
public string Title
{
set => Bag[nameof(Title)] = value;
get => (string)Bag[nameof(Title)];
}
public string Trademark
{
set => Bag[nameof(Trademark)] = value;
get => (string)Bag[nameof(Trademark)];
}
public string Version
{
set => Bag[nameof(Version)] = value;
get => (string)Bag[nameof(Version)];
}
public string Win32Icon
{
set => Bag[nameof(Win32Icon)] = value;
get => (string)Bag[nameof(Win32Icon)];
}
public string Win32Resource
{
set => Bag[nameof(Win32Resource)] = value;
get => (string)Bag[nameof(Win32Resource)];
}
// Input files: file[,target]
// This is not required.
public ITaskItem[] SourceModules
{
set => Bag[nameof(SourceModules)] = value;
get => (ITaskItem[])Bag[nameof(SourceModules)];
}
// Embedded resource files: file[,name[,private]]
public ITaskItem[] EmbedResources
{
set => Bag[nameof(EmbedResources)] = value;
get => (ITaskItem[])Bag[nameof(EmbedResources)];
}
// Linked resource files: file[,name[,target][,private]]]
public ITaskItem[] LinkResources
{
set => Bag[nameof(LinkResources)] = value;
get => (ITaskItem[])Bag[nameof(LinkResources)];
}
public string SdkToolsPath
{
set => Bag[nameof(SdkToolsPath)] = value;
get => (string)Bag[nameof(SdkToolsPath)];
}
#endregion
#region Tool Members
/// <summary>
/// Return the name of the tool to execute.
/// </summary>
protected override string ToolName => "al.exe";
/// <summary>
/// Return the path of the tool to execute
/// </summary>
protected override string GenerateFullPathToTool()
{
string pathToTool = null;
// If COMPLUS_InstallRoot\COMPLUS_Version are set (the dogfood world), we want to find it there, instead of
// the SDK, which may or may not be installed. The following will look there.
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("COMPLUS_InstallRoot")) || !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("COMPLUS_Version")))
{
pathToTool = ToolLocationHelper.GetPathToDotNetFrameworkFile(ToolExe, TargetDotNetFrameworkVersion.Latest);
}
if (String.IsNullOrEmpty(pathToTool) || !FileSystems.Default.FileExists(pathToTool))
{
// The bitness of al.exe should match the platform being built
// Yoda condition prevents null reference exception if Platform is null.
string archToLookFor = "x86".Equals(Platform, StringComparison.OrdinalIgnoreCase) ? Platform :
"x64".Equals(Platform, StringComparison.OrdinalIgnoreCase) ? ProcessorArchitecture.AMD64 : // x64 maps to AMD64 in GeneratePathToTool
ProcessorArchitecture.CurrentProcessArchitecture;
pathToTool = SdkToolsPathUtility.GeneratePathToTool(f => SdkToolsPathUtility.FileInfoExists(f), archToLookFor, SdkToolsPath, ToolExe, Log, true);
}
return pathToTool;
}
/// <summary>
/// Fills the provided CommandLineBuilderExtension with those switches and other information that can go into a response file.
/// </summary>
protected internal override void AddResponseFileCommands(CommandLineBuilderExtension commandLine)
{
commandLine.AppendSwitchIfNotNull("/algid:", AlgorithmId);
commandLine.AppendSwitchIfNotNull("/baseaddress:", BaseAddress);
commandLine.AppendSwitchIfNotNull("/company:", CompanyName);
commandLine.AppendSwitchIfNotNull("/configuration:", Configuration);
commandLine.AppendSwitchIfNotNull("/copyright:", Copyright);
commandLine.AppendSwitchIfNotNull("/culture:", Culture);
commandLine.AppendPlusOrMinusSwitch("/delaysign", Bag, "DelaySign");
commandLine.AppendSwitchIfNotNull("/description:", Description);
commandLine.AppendSwitchIfNotNull("/evidence:", EvidenceFile);
commandLine.AppendSwitchIfNotNull("/fileversion:", FileVersion);
commandLine.AppendSwitchIfNotNull("/flags:", Flags);
commandLine.AppendWhenTrue("/fullpaths", Bag, "GenerateFullPaths");
commandLine.AppendSwitchIfNotNull("/keyfile:", KeyFile);
commandLine.AppendSwitchIfNotNull("/keyname:", KeyContainer);
commandLine.AppendSwitchIfNotNull("/main:", MainEntryPoint);
commandLine.AppendSwitchIfNotNull("/out:", OutputAssembly?.ItemSpec);
commandLine.AppendSwitchIfNotNull("/platform:", PlatformWith32BitPreference);
commandLine.AppendSwitchIfNotNull("/product:", ProductName);
commandLine.AppendSwitchIfNotNull("/productversion:", ProductVersion);
commandLine.AppendSwitchIfNotNull("/target:", TargetType);
commandLine.AppendSwitchIfNotNull("/template:", TemplateFile);
commandLine.AppendSwitchIfNotNull("/title:", Title);
commandLine.AppendSwitchIfNotNull("/trademark:", Trademark);
commandLine.AppendSwitchIfNotNull("/version:", Version);
commandLine.AppendSwitchIfNotNull("/win32icon:", Win32Icon);
commandLine.AppendSwitchIfNotNull("/win32res:", Win32Resource);
commandLine.AppendSwitchIfNotNull("", SourceModules, ["TargetFile"]);
commandLine.AppendSwitchIfNotNull(
"/embed:",
EmbedResources,
["LogicalName", "Access"]);
commandLine.AppendSwitchIfNotNull(
"/link:",
LinkResources,
["LogicalName", "TargetFile", "Access"]);
// It's a good idea for the response file to be the very last switch passed, just
// from a predictability perspective. This is also consistent with the compiler
// tasks (Csc, etc.)
if (ResponseFiles != null)
{
foreach (string responseFile in ResponseFiles)
{
commandLine.AppendSwitchIfNotNull("@", responseFile);
}
}
}
public override bool Execute()
{
if (Culture != null)
{
// This allows subsequent tasks in the build process to know what culture each satellite
// assembly is associated with.
OutputAssembly?.SetMetadata("Culture", Culture);
}
return base.Execute();
}
#endregion
}
#else
/// <summary>
/// Stub AL task for .NET Core.
/// </summary>
public sealed class AL : TaskRequiresFramework, IALTaskContract
{
public AL()
: base(nameof(AL))
{
}
#region Properties
public string AlgorithmId { get; set; }
public string BaseAddress { get; set; }
public string CompanyName { get; set; }
public string Configuration { get; set; }
public string Copyright { get; set; }
public string Culture { get; set; }
public bool DelaySign { get; set; }
public string Description { get; set; }
public string EvidenceFile { get; set; }
public string FileVersion { get; set; }
public string Flags { get; set; }
public bool GenerateFullPaths { get; set; }
public string KeyFile { get; set; }
public string KeyContainer { get; set; }
public string MainEntryPoint { get; set; }
[Output]
public ITaskItem OutputAssembly { get; set; }
public string Platform { get; set; }
public bool Prefer32Bit { get; set; }
public string ProductName { get; set; }
public string ProductVersion { get; set; }
public string[] ResponseFiles { get; set; }
public string TargetType { get; set; }
public string TemplateFile { get; set; }
public string Title { get; set; }
public string Trademark { get; set; }
public string Version { get; set; }
public string Win32Icon { get; set; }
public string Win32Resource { get; set; }
public ITaskItem[] SourceModules { get; set; }
public ITaskItem[] EmbedResources { get; set; }
public ITaskItem[] LinkResources { get; set; }
public string SdkToolsPath { get; set; }
#endregion
}
#endif
internal interface IALTaskContract
{
#region Properties
string AlgorithmId { get; set; }
string BaseAddress { get; set; }
string CompanyName { get; set; }
string Configuration { get; set; }
string Copyright { get; set; }
string Culture { get; set; }
bool DelaySign { get; set; }
string Description { get; set; }
string EvidenceFile { get; set; }
string FileVersion { get; set; }
string Flags { get; set; }
bool GenerateFullPaths { get; set; }
string KeyFile { get; set; }
string KeyContainer { get; set; }
string MainEntryPoint { get; set; }
ITaskItem OutputAssembly { get; set; }
string Platform { get; set; }
bool Prefer32Bit { get; set; }
string ProductName { get; set; }
string ProductVersion { get; set; }
string[] ResponseFiles { get; set; }
string TargetType { get; set; }
string TemplateFile { get; set; }
string Title { get; set; }
string Trademark { get; set; }
string Version { get; set; }
string Win32Icon { get; set; }
string Win32Resource { get; set; }
ITaskItem[] SourceModules { get; set; }
ITaskItem[] EmbedResources { get; set; }
ITaskItem[] LinkResources { get; set; }
string SdkToolsPath { get; set; }
#endregion
}
}
|