Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NativeAOT] Support exporting methods from referenced assemblies in a formal way #83396

Merged
merged 20 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0897d10
[naot] Export methods from referenced assemblies
ivanpovazan Mar 13, 2023
ef7bf05
[naot] Adding test case
ivanpovazan Mar 14, 2023
baf20d6
[naot] Enable the feature for all configurations
ivanpovazan Mar 16, 2023
6383518
[naot] Introduce better naming
ivanpovazan Mar 16, 2023
230bfa9
[naot] Updating the test case based on the feedback
ivanpovazan Mar 16, 2023
b8ff7c7
[naot] Use the new feature to export SPC unmanaged entry points inste…
ivanpovazan Mar 16, 2023
9d73b20
[naot] Cleanup
ivanpovazan Mar 16, 2023
db91bb7
[naot] Given a more appropriate name for the unmanaged entry points r…
ivanpovazan Mar 16, 2023
18c0c59
[naot] Adjust repro.csproj to generate the new compiler switch
ivanpovazan Mar 16, 2023
0dab9ec
[naot] Skip adding System.Private.CoreLib as a UnmanagedEntryPointsRo…
ivanpovazan Mar 16, 2023
e9593b0
[naot] Test cleanup
ivanpovazan Mar 16, 2023
549ed66
[naot] Include exporting SPC entry points only if system module is no…
ivanpovazan Mar 17, 2023
dc45d4c
[naot] Switching the test to be a single executable
ivanpovazan Mar 17, 2023
ba51637
[naot] Match the ordering from .targets file
ivanpovazan Mar 17, 2023
ea71b8c
[naot] Explicitly export symbols from an executable via IlcExportUnma…
ivanpovazan Mar 17, 2023
87bac10
[naot] Enable overriding IlcExportUnmanagedEntrypoints
ivanpovazan Mar 17, 2023
5ddc135
[naot] Test cleanup
ivanpovazan Mar 17, 2023
a5a1c0a
[naot] Using more general approach to avoid adding the same module mu…
ivanpovazan Mar 17, 2023
cdbc605
[naot] Fix for including exported symbols in the dynamic symbol table…
ivanpovazan Mar 20, 2023
24a530e
[naot] Using a more appropriate condition
ivanpovazan Mar 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
<Target Name="_ComputeAssembliesToCompileToNative" DependsOnTargets="$(IlcDynamicBuildPropertyDependencies)">

<Warning Condition="Exists($(UserRuntimeConfig))" Text="The published project has a runtimeconfig.template.json that is not supported by PublishAot. Move the configuration to the project file using RuntimeHostConfigurationOption." />

<Warning Condition="'@(IlcRootedAssembliesExports)' != '' and '$(NativeLib)' == '' and '$(CustomNativeMain)' != 'true'" Text="Exporting methods from referenced assemblies is only available in the library or custom native main mode." />

<!-- Fail with descriptive error message for common mistake. -->
<Error Condition="$([MSBuild]::VersionLessThan('$(NETCoreSdkVersion)', '6.0.0'))" Text=".NET SDK 6+ is required for native compilation." />
<Error Condition="$([MSBuild]::VersionLessThan('$(TargetFrameworkVersion)', '6.0'))" Text="For native compilation, the project needs to target .NET 6 or higher." />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<IlcArg Include="@(_IlcNoSingleWarnAssemblies->'--nosinglewarnassembly:%(Filename)')" />
<IlcArg Condition="'$(TrimmerDefaultAction)' == 'copyused' or '$(TrimmerDefaultAction)' == 'copy' or '$(TrimMode)' == 'partial'" Include="--defaultrooting" />
<IlcArg Include="--resilient" />
<IlcArg Condition="'$(NativeLib)' != '' or '$(CustomNativeMain)' == 'true'" Include="@(IlcRootedAssembliesExports->'--rootedassembliesexports:%(Identity)')" />

<IlcArg Condition="$(IlcDisableReflection) == 'true'" Include="--feature:System.Reflection.IsReflectionExecutionAvailable=false" />

Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ internal sealed class ILCompilerRootCommand : RootCommand
new(new[] { "--singlemethodgenericarg" }, "Single method compilation: generic arguments to the method");
public Option<string> MakeReproPath { get; } =
new(new[] { "--make-repro-path" }, "Path where to place a repro package");
public Option<string[]> RootedAssembliesExports { get; } =
new(new[] { "--rootedassembliesexports" }, Array.Empty<string>, "Root exported methods from assemblies");

public OptimizationMode OptimizationMode { get; private set; }
public ParseResult Result;
Expand Down Expand Up @@ -232,6 +234,7 @@ public ILCompilerRootCommand(string[] args) : base(".NET Native IL Compiler")
AddOption(SingleMethodName);
AddOption(SingleMethodGenericArgs);
AddOption(MakeReproPath);
AddOption(RootedAssembliesExports);

this.SetHandler(context =>
{
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/tools/aot/ILCompiler/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,15 @@ public int Run()
}
}

if (nativeLib || SplitExeInitialization)
{
foreach (var rootedAssemblyExports in Get(_command.RootedAssembliesExports))
{
EcmaModule module = typeSystemContext.GetModuleForSimpleName(rootedAssemblyExports);
compilationRoots.Add(new ExportedMethodsRootProvider(module));
}
}

foreach (var rdXmlFilePath in Get(_command.RdXmlFilePaths))
{
compilationRoots.Add(new RdXmlRootProvider(typeSystemContext, rdXmlFilePath));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project (NativeHost)
include_directories(${INC_PLATFORM_DIR})

add_library (NativeHost STATIC NativeHost.cpp)

# add the install targets
install (TARGETS NativeHost DESTINATION bin)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;

class Program
{
static int appVersion;

[UnmanagedCallersOnly(EntryPoint = "InitializeMainAssembly", CallConvs = new Type[] { typeof(CallConvCdecl) })]
static void InitializeMainAssembly(int version)
{
appVersion = version;
}

static int Main(string[] args)
{
Console.WriteLine($"MainAssembly version: {appVersion}");

var referencedAssembly1 = new ReferencedAssembly1.Configuration();
var referencedAssembly1Version = referencedAssembly1.GetAssemblyVersion();
Console.WriteLine($"ReferencedAssembly1 version: {referencedAssembly1Version}");

var referencedAssembly2 = new ReferencedAssembly2.Configuration();
var referencedAssembly2Version = referencedAssembly2.GetAssemblyVersion();
Console.WriteLine($"ReferencedAssembly2 version: {referencedAssembly2Version}");

return appVersion + referencedAssembly1Version + (referencedAssembly2Version == 0 ? 50 : 0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<CustomNativeMain>true</CustomNativeMain>
<StaticLibraryPrefix Condition="'$(TargetOS)' != 'windows'">lib</StaticLibraryPrefix>
</PropertyGroup>

<ItemGroup>
<Compile Include="ExportsFromReferencedAssemblies.cs" />
<ProjectReference Include="$(MSBuildThisFileDirectory)ReferencedAssembly1\ReferencedAssembly1.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)ReferencedAssembly2\ReferencedAssembly2.csproj" />
</ItemGroup>

<!-- Only expose methods from ReferencedAssembly1 -->
<ItemGroup>
<IlcRootedAssembliesExports Include="ReferencedAssembly1" />
</ItemGroup>

<ItemGroup>
<CMakeProjectReference Include="CMakeLists.txt" />
</ItemGroup>

<ItemGroup>
<NativeLibrary Include="$(OutputPath)$(StaticLibraryPrefix)NativeHost$(LibFileExt)" />
</ItemGroup>
</Project>
65 changes: 65 additions & 0 deletions src/tests/nativeaot/ExportsFromReferencedAssemblies/NativeHost.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#ifdef TARGET_WINDOWS
#include "windows.h"
#else
#include "dlfcn.h"
#endif
#include "stdio.h"
#include "string.h"

#ifndef TARGET_WINDOWS
#define __stdcall
#endif

// typedef for shared lib exported methods
typedef void(__stdcall *fptr)(int);

#ifdef TARGET_WINDOWS
extern "C" int __managed__Main(int argc, wchar_t* argv[]);
#else
extern "C" int __managed__Main(int argc, char* argv[]);
#endif

#ifdef TARGET_WINDOWS
int __cdecl wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
#ifdef TARGET_WINDOWS
HINSTANCE handle = GetModuleHandle(NULL);
#else
void *handle = dlopen(0, RTLD_LAZY);
#endif

if (!handle)
return 1;

#ifdef TARGET_WINDOWS
fptr main_assembly_initializer = (fptr)GetProcAddress(handle, "InitializeMainAssembly");
fptr ref1_assembly_initializer = (fptr)GetProcAddress(handle, "InitializeReferencedAssembly1");
fptr ref2_assembly_initializer = (fptr)GetProcAddress(handle, "InitializeReferencedAssembly2");
#else
fptr main_assembly_initializer = (fptr)dlsym(handle, "InitializeMainAssembly");
fptr ref1_assembly_initializer = (fptr)dlsym(handle, "InitializeReferencedAssembly1");
fptr ref2_assembly_initializer = (fptr)dlsym(handle, "InitializeReferencedAssembly2");
#endif

// method must be exposed from ExportsFromReferencedAssemblies assembly
if (!main_assembly_initializer)
return 2;
main_assembly_initializer(20);

// method must be exposed from ReferencedAssembly1 assembly
if (!ref1_assembly_initializer)
return 3;
ref1_assembly_initializer(30);

// method must not be exposed from ReferencedAssembly2 assembly
if (ref2_assembly_initializer)
return 4;

return __managed__Main(argc, argv);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace ReferencedAssembly1
{
public class Configuration
{
static int assemblyVersion;

[UnmanagedCallersOnly(EntryPoint = "InitializeReferencedAssembly1", CallConvs = new Type[] { typeof(CallConvCdecl) })]
public static void InitializeReferencedAssembly(int version)
{
assemblyVersion = version;
}

public int GetAssemblyVersion() => Configuration.assemblyVersion;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<Compile Include="ReferencedAssembly1.cs" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace ReferencedAssembly2
{
public class Configuration
{
static int assemblyVersion;

[UnmanagedCallersOnly(EntryPoint = "InitializeReferencedAssembly2", CallConvs = new Type[] { typeof(CallConvCdecl) })]
public static void InitializeReferencedAssembly(int version)
{
assemblyVersion = version;
}

public int GetAssemblyVersion() => Configuration.assemblyVersion;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<Compile Include="ReferencedAssembly2.cs" />
</ItemGroup>

</Project>