Lokad / ILPack

Serialize .NET Core assemblies
MIT License
306 stars 39 forks source link

Exported Net core lib is referencing System.Private.CorLib instead of System.Runtime #139

Closed Karolis2011 closed 2 years ago

Karolis2011 commented 3 years ago

This is same as issue #13 image

vermorel commented 3 years ago

Thanks @Karolis2011 for reporting the problem. I don't have the resources to tackle this issue right now, but if you submit a pull request, I will be reviewing it.

lukekaalim commented 3 years ago

Hi, I'm also taking a look at this issue since I ran into it too. I'm not super knowledgeable about the underlying mechanics of assembly loading or really most of the guts of this library, but I gave it my best shot.

The issue that I ran into similarly, is the references to System.Private.Corelib, which I can see when I crack open my generated dll with ILSpy.

For some background, I found this library while I was searching for an alternative for AssemblyBuilder.Save when I realized it wasn't included in .NET 5. I had assumed at the time that this library would be a valid alternative, but later I would realize that this library is specifically for .Net Core (3?). @vermorel correct me if I'm wrong, but I don't see anything that explicitly indicates that it should be used with .NET 5.

After some hacking about in the source code, I realized that in "./ILPack/src/Metadata/AssemblyMetadata.cs"

// HACK: [vermorel] 2019-07-25. 'GetReferencedAssemblies()' does not capture all assemblies,
// only those that are explicitly referenced. Thus, we end-up  manually adding the assembly.

var corlib_name = Assembly.GetAssembly(typeof(object)).GetName();
for (int x = 0; x < assemblies.Count; x++) {
    if (assemblies[x].Name.Equals(corlib_name.Name)) /* string ref (coreclr ptr) not equal */
        assemblies.RemoveAt(x--);

corelib_name is evaluating to "System.Private.Corelib" when running in .NET 5. I'm guessing that this wasn't the case in core? But I don't know too much about that, I def don't know the "proper" library to reference.

But in my specific case, I wanted to build a .NET 5 program that could generate netstandard2.0 libs for use in Unity, so building a smaller test project to manually create a similar DLL reveals that the proper value for corelib_name should be "netstandard".

I can get a runnable (to my limited testing) DLL in .NET by editing the code to

var corlib_name = Assembly.Load("netstandard").GetName();
for (int x = 0; x < assemblies.Count; x++) {
    if (assemblies[x].Name.Equals("System.Private.CoreLib"))
        assemblies.RemoveAt(x--);
}

which deletes references to private core lib, and prepends the "netstandard" assembly name reference. However, I'm feel like this may break some netframework 4x and netcore use cases, though surprisingly it only breaks 5 rewrite tests (for reasons I am uncertain of).

I know you mentioned you don't have a lot of time @vermorel, but I would appreciate some guidance on what would be the most appropriate approach, as I'm not a professional dotnet developer. Should I try fix those test cases, and assume that this change is fine working in core and framework, or should I fork this project/make a new entrypoint for .NET5 based projects if making this change is out of the scope of this library?

lukekaalim commented 3 years ago

Actually nvm that I got the tests passing on netcore2 and .net5; I'm pretty sure it will work on 4x as well, so I'll pop open a PR in a sec

bferullo commented 3 years ago

Hi! Just running into this issue now myself -- it looks like the fix was added in 159b49e10f9b8e629f94e571d756d759993e785b, though there is a comment on a related PR concerning its compatibilty; even so, can a new (prerelease?) nuget package version be pushed containing this commit when convenient?

vermorel commented 3 years ago

@bferullo I have just published the version ILPack 0.1.7 which includes the commit 159b49e. Hope it helps.

OlegRa commented 2 years ago

The proposed fix is already committed and published on NuGet. Maybe we need more flexibility with these assembly "replacement" process but this issue can be closed as resolved for now.

Niczob commented 1 year ago

Hi, I'm having the same issue with the last version (0.2.0). My assembly should target netstandard 2 (or net6.0 ?) and it targets .Net Framework v4.0 with a reference to System.Private.CoreLib.dll.

When I debug the code in Assembly.Metadata.cs, I've never have the isReplaceCorLibWithNetStandardEnabled var to true, then the System.Private.CoreLib is never removed and NetStandard never added; besides, I'm wondering what's the purpose of the "Lokad.ILPack.AssemblyGenerator.ReplaceCoreLibWithNetStandard" switch in AppContext.TryGetSwitch( "Lokad.ILPack.AssemblyGenerator.ReplaceCoreLibWithNetStandard", out var isReplaceCorLibWithNetStandardEnabled);.

If I hack the code and force the remove of System.Private.CoreLib and add of NetStandard, my saved assembly runs as expected.

Should I re-open the issue ?

Edit : I think I mess the AppContext SetSwitch purpose ... If I set the switch ReplaceCoreLibWithNetStandard, my assembly is rightly generated.

mainmind83 commented 9 months ago

Edit : I think I mess the AppContext SetSwitch purpose ... If I set the switch ReplaceCoreLibWithNetStandard, my assembly is rightly generated.

Hi @Niczob where and how do you establish this option?

UPDATED and solved: (tested with .NET 8)

var assembly = Assembly.GetAssembly(MyCustomType);
var generator = new Lokad.ILPack.AssemblyGenerator();
string dest= AppDomain.CurrentDomain.SetupInformation.ApplicationBase + strAssemblyName + "." + customTXT + ".dll";

AppContext.SetSwitch("Lokad.ILPack.AssemblyGenerator.ReplaceCoreLibWithNetStandard", true);
AppContext.TryGetSwitch("Lokad.ILPack.AssemblyGenerator.ReplaceCoreLibWithNetStandard", out var isReplaceCorLibWithNetStandardEnabled);

generator.GenerateAssembly(assembly, dest);