Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ascpixi committed Jul 11, 2024
0 parents commit 23df24e
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.sln
bin/
obj/
14 changes: 14 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# dotnet-ilc
`dotnet-ilc` is a simple .NET tool wrapper over the `ilc` compiler provided by .NET 7.0 and higher, which is used for Native AOT (NAOT) compilation.

This tool is available under the NuGet package name `ilc`. In order to install it, use the following command:
```
dotnet tool install -g ilc
```

The tool will automatically retrieve the right versions based on the .NET runtime that is used to invoke the tool. This means that you might experience a measurable delay the first time you launch the tool with a new .NET version.

## Why a wrapper?
The internal NuGet packages used to store `ilc` - `runtime.<rid>.microsoft.dotnet.ilcompiler` - are meant to be used as project dependencies. These packages also supply various build specification files, which reference the stored `ilc` binary.

This wrapper removes the need for scripts to manually locate the NuGet global packages folder, or to use hacks such as creating a temporary project just to install the internal package. It automatically determines the host system runtime ID and .NET version, and retrieves the right package. In case of an non-major .NET version upgrade, the tool will automatically retrieve new files.
37 changes: 37 additions & 0 deletions src/ILC.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>

<!-- The earliest version that has ILCompiler packages is .NET 7.0. -->
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
<AssemblyName>ilc-wrapper</AssemblyName>
<ToolCommandName>ilc</ToolCommandName>
<PackAsTool>true</PackAsTool>
</PropertyGroup>

<PropertyGroup>
<PackageId>ilc</PackageId>
<Authors>dotnetframework</Authors>
<Description>Provides a .NET tool wrapper to access ilc (the IL compiler), used for native AOT (NAOT) compilation.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/ascpixi/dotnet-ilc</PackageProjectUrl>
<Tags>ilc;ilcompiler;compiler;nativeaot;naot;native;aot</Tags>
<RepositoryUrl>https://github.com/ascpixi/dotnet-ilc</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageIcon>icon.png</PackageIcon>
<PackageReadmeFile>readme.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<None Include="./icon.png" Pack="true" PackagePath="/" />
<None Include="../readme.md" Pack="true" PackagePath="/" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions src/InvocationForwarder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Diagnostics;

namespace ILC;

/// <summary>
/// Forwards command-line invocations.
/// </summary>
public class InvocationForwarder
{
public static int Run(string target, string[] args)
{
var psi = new ProcessStartInfo() {
WorkingDirectory = Directory.GetCurrentDirectory(),
FileName = target
};

foreach (var arg in args) {
psi.ArgumentList.Add(arg);
}

var process = Process.Start(psi)!;
process.WaitForExit();
return process.ExitCode;
}
}
54 changes: 54 additions & 0 deletions src/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.IO.Compression;
using System.Reflection;
using System.Runtime.InteropServices;
using ILC;

var dotnetVer = RuntimeInformation.FrameworkDescription[5..];

var selfDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
var pkgDir = Path.Combine(selfDir, "pkg", dotnetVer);
var ilcPath = Path.Combine(pkgDir, "tools", OperatingSystem.IsWindows() ? "ilc.exe" : "ilc");

if (File.Exists(ilcPath))
return InvocationForwarder.Run(ilcPath, args);

var platform =
RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux"
: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win"
: RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx"
: null;

if (platform == null) {
Console.Error.WriteLine($"wrapper error: unknown platform ({RuntimeInformation.RuntimeIdentifier}) - please report this to https://github.com/ascpixi/dotnet-ilc");
return 1;
}

var rid = $"{platform}-{RuntimeInformation.OSArchitecture.ToString().ToLower()}";

Console.WriteLine($"wrapper: retrieving ilc for .NET {dotnetVer} via NuGet...");

var pkgName = $"runtime.{rid}.microsoft.dotnet.ilcompiler";

using var http = new HttpClient();
var res = await http.GetAsync($"https://api.nuget.org/v3-flatcontainer/{pkgName}/{dotnetVer}/{pkgName}.{dotnetVer}.nupkg");
if (!res.IsSuccessStatusCode) {
Console.Error.WriteLine($"wrapper error: retrieval failed! HTTP {(int)res.StatusCode} ({res.StatusCode}) for package '{pkgName}' with version '{dotnetVer}'");
return 1;
}

Directory.CreateDirectory(Path.GetDirectoryName(pkgDir)!);

var pkg = new ZipArchive(await res.Content.ReadAsStreamAsync(), ZipArchiveMode.Read);
pkg.ExtractToDirectory(pkgDir, overwriteFiles: true);

if (!File.Exists(ilcPath)) {
Console.Error.WriteLine("wrapper error: the package was retrieved, but the ilc binary is missing");
Console.Error.WriteLine($"wrapper error: package contents can be found in '{pkgDir}'");
return 1;
}

if (OperatingSystem.IsLinux()) {
File.SetUnixFileMode(ilcPath, File.GetUnixFileMode(ilcPath) | UnixFileMode.UserExecute);
}

return InvocationForwarder.Run(ilcPath, args);
Binary file added src/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 23df24e

Please sign in to comment.