Skip to content

Compose partially implementation both .NET language and IL assembler into a single assembly.

License

Notifications You must be signed in to change notification settings

kekyo/ILCompose

Repository files navigation

ILCompose

ILCompose

Project Status: Active – The project has reached a stable, usable state and is being actively developed. NuGet ILCompose CI build (main)


What is this?

Compose partially implementation both .NET language and IL assembler. An improved implementation of the principles of ILSupport. If you are looking for an inline assembler for CIL/MSIL, here is a realistic solution.

In sample.cs:

namespace IL2C.BasicTypes
{
    public class System_Boolean
    {
        // Refer IL assembly
        [MethodImpl(MethodImplOptions.ForwardRef)]
        public static extern void ValueTypeTest();
    }
}

In sample.il:

.class public IL2C.BasicTypes.System_Boolean
{
    .method public static void ValueTypeTest() cil managed
    {
        .maxstack 2
        ldc.i4.s 123
        box bool

        ; ...

        ret
    }
}

These source code compose into one assembly by ILCompose. Semantically, it is similar to the C# partial class definition, but it does this at the CIL level.

Diagram

All CIL assemble source code (*.il) are automatically assembled by official dotnet IL assembler ILAsm.

Only you have to do install the NuGet package ILCompose and ready to use!


Environments

Supported target platforms:

  • .NET 8, 7, 6, 5
  • .NET Core 3.1 to 2.0 (maybe to 1.0)
  • .NET Standard 2.1, 2.0 (maybe to 1.0)
  • .NET Framework 4.8 to 2.0 (maybe to 1.0)

Supported building platforms:

  • dotnet SDK 8, 7, 6, 5, 3.1, 2.2 and 2.1 (on Windows and Linux)
  • .NET Framework 4.8 to 4.6.2 on Windows (With dotnet SDK installation)

How to use

In short example:

$ dotnet new console
$ dotnet add package ILCompose

[Then write your code both *.cs and *.il ...]

See fully sample code:


Choose IL assembler

You can choose IL assembler between:

  • ILAsm.Managed: Defaulted, no need to action.
  • CoreCLR ILAsm: Optional, need to set <ILComposeUsingILAsmManaged>false</ILComposeUsingILAsmManaged> into <PropertyGroup>.
  • Your own ilasm.exe: Optional, need to set <ILComposeILAsmToolPath> and <ILComposeILAsmToolOptions>.

Why ILAsm.Managed is defaulted instead CoreCLR one?

Because CoreCLR ILAsm package contains many different sub packages included native binary each OS distributions. And standard dynamic reference script technique has a problem, could not effect MSBuild script conditions at running dotnet restore and nuget restore time except using Visual Studio IDE.

If you are concerned about the stock ILAsm, and in fact ILAsm.Managed fails to compile, you can accept the above problem and use it.


Insight

ILSupport is cumbersome because it requires custom build scripts to be incorporated into the your project. However, ILCompose is simply installation the NuGet package and builds everything automatically.

When you install the NuGet package, the CIL (*.il) file will have the ILComposeTargetIL build action set as follows:

ILComposeTargetIL

Basically, it can be used in the same way as ILSupport.

ILSupport is realized using ILDasm and a string substitution technique. While ILCompose is realized using cecil, so the internal implementations are completely different.

Here is where the problem was in ILSupport. The following C# code with the forwardref attribute applied cannot apply the additional custom attributes (they must be written on the IL assembly source code side):

// Refer IL assembly, all additional custom attribute will silently remove by ILSupport.
[MethodImpl(MethodImplOptions.ForwardRef)]
public static extern void ValueTypeTest();

It allows you to apply custom attributes normally, as shown below:

// Refer IL assembly with custom attributes
[Test]
[Description("A value type test.")]
[MethodImpl(MethodImplOptions.ForwardRef)]
public static extern void ValueTypeTest();

Automatic adjusting assembly references.

When assembling your loose IL source code with implicit referenced assemblies, ILAsm will cause these warnings below.

ILAsm.Managed:

Warning -- Reference to undeclared extern assembly 'netstandard', adding.
Warning -- Reference to undeclared extern assembly 'System.Runtime', adding.
Warning -- Reference to undeclared extern assembly 'mscorlib', adding.

CoreCLR ILAsm:

warning : Reference to undeclared extern assembly 'netstandard'. Attempting autodetect
warning : Reference to undeclared extern assembly 'System.Runtime'. Attempting autodetect
warning : Reference to undeclared extern assembly 'mscorlib'. Attempting autodetect

...

See also: dotnet/runtime: ilasm cannot compile against different corlib names

ILCompose has no control these warning on ILAsm, but ILCompose will resolve these inconsistent references in the final composite assembly. Finally, the primary assembly (the original output assembly of the project) is aggregated into referenced assemblies. For example, mscorlib.dll for net48 and System.Runtime.dll for net6.0.

This feature is disabled <ILComposeAdjustAssemblyReferences>false</ILComposeAdjustAssemblyReferences> in <PropertyGroup> element.


Limitation

  • <DebugType> embedded is not supported.
  • If no corresponding forwardref method is defined for a CIL method on the source code, that CIL method will not be composed.

Background

This project was created in IL2C, there was a need for IL code management. In IL2C, CIL unit test code was composed into .NET assemblies using ILSupport, but:

  • The portion of NUnit that relies on Custom attributes extensions has caused problems on the JetBrains Rider's test explorer, and I wanted to eliminate this. I was thinking of stopping the use of custom attributes extensions.
  • In that case, needed to resolve a problem with custom attributes being removed by the forwardref attribute in ILSupport.
  • To begin with, the ILSupport script was being used with considerable modifications, which caused maintainability problems.

Related: IL2C issue #100: Will upgrade basis environments.

Therefore, I developed this package as a general-purpose package.


License

Copyright (c) Kouji Matsui (@kozy_kekyo, @kekyo@mastodon.cloud)

License under Apache-v2.

About

Compose partially implementation both .NET language and IL assembler into a single assembly.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published