Skip to content

Commit

Permalink
Copy build task over from CoreRT repo (dotnet#43)
Browse files Browse the repository at this point in the history
* Copy build task over from CoreRT repo

At CoreRT commit b48a58e6facdda7f50f9256e0d9d6a209473132f.

* Hook up ILCompiler.Build.Tasks to build

Co-authored-by: dotnet-bot <dotnet-bot@microsoft.com>
  • Loading branch information
MichalStrehovsky and dotnet-bot committed Jul 31, 2020
1 parent a4b2355 commit 0a59f67
Show file tree
Hide file tree
Showing 5 changed files with 555 additions and 0 deletions.
1 change: 1 addition & 0 deletions eng/Subsets.props
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
<ProjectToBuild Include="$(CoreClrProjectRoot)src\tools\runincontext\runincontext.csproj;
$(CoreClrProjectRoot)src\tools\r2rdump\R2RDump.csproj;
$(CoreClrProjectRoot)src\tools\dotnet-pgo\dotnet-pgo.csproj;
$(CoreClrProjectRoot)src\tools\aot\ILCompiler.Build.Tasks\ILCompiler.Build.Tasks.csproj;
$(CoreClrProjectRoot)src\tools\r2rtest\R2RTest.csproj" Category="clr" BuildInParallel="true" />
<ProjectToBuild Include="$(CoreClrProjectRoot)src\tools\aot\crossgen2\crossgen2.csproj" Category="clr" />
<ProjectToBuild Include="$(CoreClrProjectRoot)src\tools\aot\ILCompiler.TypeSystem.ReadyToRun.Tests\ILCompiler.TypeSystem.ReadyToRun.Tests.csproj" Test="true" Category="clr" Condition="'$(__DistroRid)' != 'linux-musl-x64'"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;



namespace Build.Tasks
{
public class ComputeManagedAssembliesToCompileToNative : DesktopCompatibleTask
{
[Required]
public ITaskItem[] Assemblies
{
get;
set;
}

/// <summary>
/// The CoreRT-specific System.Private.* assemblies that must be used instead of the netcoreapp2.1 versions.
/// </summary>
[Required]
public ITaskItem[] SdkAssemblies
{
get;
set;
}

/// <summary>
/// The set of AOT-specific framework assemblies we currently need to use which will replace the same-named ones
/// in the app's closure.
/// </summary>
[Required]
public ITaskItem[] FrameworkAssemblies
{
get;
set;
}

/// <summary>
/// The native apphost (whose name ends up colliding with the CoreRT output binary)
/// </summary>
[Required]
public string DotNetAppHostExecutableName
{
get;
set;
}

/// <summary>
/// The CoreCLR dotnet host fixer library that can be skipped during publish
/// </summary>
[Required]
public string DotNetHostFxrLibraryName
{
get;
set;
}

/// <summary>
/// The CoreCLR dotnet host policy library that can be skipped during publish
/// </summary>
[Required]
public string DotNetHostPolicyLibraryName
{
get;
set;
}

[Output]
public ITaskItem[] ManagedAssemblies
{
get;
set;
}

[Output]
public ITaskItem[] AssembliesToSkipPublish
{
get;
set;
}

public override bool Execute()
{
var list = new List<ITaskItem>();
var assembliesToSkipPublish = new List<ITaskItem>();
var coreRTFrameworkAssembliesToUse = new HashSet<string>();

foreach (ITaskItem taskItem in SdkAssemblies)
{
coreRTFrameworkAssembliesToUse.Add(Path.GetFileName(taskItem.ItemSpec));
}

foreach (ITaskItem taskItem in FrameworkAssemblies)
{
coreRTFrameworkAssembliesToUse.Add(Path.GetFileName(taskItem.ItemSpec));
}

foreach (ITaskItem taskItem in Assemblies)
{
// In the case of disk-based assemblies, this holds the file path
string itemSpec = taskItem.ItemSpec;

// Skip the native apphost (whose name ends up colliding with the CoreRT output binary) and supporting libraries
if (itemSpec.EndsWith(DotNetAppHostExecutableName, StringComparison.OrdinalIgnoreCase) || itemSpec.Contains(DotNetHostFxrLibraryName) || itemSpec.Contains(DotNetHostPolicyLibraryName))
{
assembliesToSkipPublish.Add(taskItem);
continue;
}

// Prototype aid - remove the native CoreCLR runtime pieces from the publish folder
if (itemSpec.Contains("microsoft.netcore.app") && (itemSpec.Contains("\\native\\") || itemSpec.Contains("/native/")))
{
assembliesToSkipPublish.Add(taskItem);
continue;
}

// Remove any assemblies whose implementation we want to come from CoreRT's package.
// Currently that's System.Private.* SDK assemblies and a bunch of framework assemblies.
if (coreRTFrameworkAssembliesToUse.Contains(Path.GetFileName(itemSpec)))
{
assembliesToSkipPublish.Add(taskItem);
continue;
}

try
{
using (FileStream moduleStream = File.OpenRead(itemSpec))
using (var module = new PEReader(moduleStream))
{
if (module.HasMetadata)
{
MetadataReader moduleMetadataReader = module.GetMetadataReader();
if (moduleMetadataReader.IsAssembly)
{
string culture = moduleMetadataReader.GetString(moduleMetadataReader.GetAssemblyDefinition().Culture);

if (culture == "" || culture.Equals("neutral", StringComparison.OrdinalIgnoreCase))
{
// CoreRT doesn't consume resource assemblies yet so skip them
assembliesToSkipPublish.Add(taskItem);
list.Add(taskItem);
}
}
}
}
}
catch (BadImageFormatException)
{
}
}

ManagedAssemblies = list.ToArray();
AssembliesToSkipPublish = assembliesToSkipPublish.ToArray();

return true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;

using Microsoft.Build.Utilities;

namespace Build.Tasks
{
public abstract class DesktopCompatibleTask : Task
{
static DesktopCompatibleTask()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}

private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// apply any existing policy
AssemblyName referenceName = new AssemblyName(AppDomain.CurrentDomain.ApplyPolicy(args.Name));

string fileName = referenceName.Name + ".dll";
string assemblyPath = null;
string probingPath = null;
Assembly assm = null;

// look next to requesting assembly
assemblyPath = args.RequestingAssembly?.Location;
if (!String.IsNullOrEmpty(assemblyPath))
{
probingPath = Path.Combine(Path.GetDirectoryName(assemblyPath), fileName);
Debug.WriteLine($"Considering {probingPath} based on RequestingAssembly");
if (Probe(probingPath, referenceName.Version, out assm))
{
return assm;
}
}

// look next to the executing assembly
assemblyPath = Assembly.GetExecutingAssembly().Location;
if (!String.IsNullOrEmpty(assemblyPath))
{
probingPath = Path.Combine(Path.GetDirectoryName(assemblyPath), fileName);

Debug.WriteLine($"Considering {probingPath} based on ExecutingAssembly");
if (Probe(probingPath, referenceName.Version, out assm))
{
return assm;
}
}

// look in AppDomain base directory
probingPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
Debug.WriteLine($"Considering {probingPath} based on BaseDirectory");
if (Probe(probingPath, referenceName.Version, out assm))
{
return assm;
}

// look in current directory
Debug.WriteLine($"Considering {fileName}");
if (Probe(fileName, referenceName.Version, out assm))
{
return assm;
}

return null;
}

/// <summary>
/// Considers a path to load for satisfying an assembly ref and loads it
/// if the file exists and version is sufficient.
/// </summary>
/// <param name="filePath">Path to consider for load</param>
/// <param name="minimumVersion">Minimum version to consider</param>
/// <param name="assembly">loaded assembly</param>
/// <returns>true if assembly was loaded</returns>
private static bool Probe(string filePath, Version minimumVersion, out Assembly assembly)
{
if (File.Exists(filePath))
{
AssemblyName name = AssemblyName.GetAssemblyName(filePath);

if (name.Version >= minimumVersion)
{
assembly = Assembly.Load(name);
return true;
}
}

assembly = null;
return false;
}
}
}
Loading

0 comments on commit 0a59f67

Please sign in to comment.