Open insinfo opened 2 years ago
The current dll loader implementation is not compatible with NativeAOT.
thanks; do you know how to fix that? Is there an attribute we should add to functions and classes so it won't be removed by AOT compilation?
As a workaround, you may add some never reached code to call PhpExtension Registrator constructors in the extension static constructor to make sure they won't be trimmed.
Taking Zlib
as an example:
You can add a static constructor to Zlib
public static class Zlib
{
static Zlib()
{
if (DateTime.Now.Day == 33) // should not be compile-time evaluatable so the branch won't be removed
{
new Registrator();
}
}
}
Another take is to use ILLinker attributes such as DynamicallyAccessedMembers
, or embed an ILLinker root xml file. But I'm not sure whether these takes work for NativeAOT.
See https://docs.microsoft.com/en-us/dotnet/core/deploying/trimming/prepare-libraries-for-trimming#dynamicallyaccessedmembers, and https://github.com/dotnet/linker/blob/main/docs/data-formats.md#descriptor-format.
I would like to tag @MichalStrehovsky for some help.
@hez2010 What would need to be implemented in NativeAOT for this to work?
@hez2010 seems we can just embed ILLink.Descriptors.xml
resource. The compiler should do the same for compiled PHP assemblies since most of the emitted members are accessed dynamically.
ILLink.Descriptors.xml are not yet implemented in NativeAOT. Only PublishTrimmed=true
without NativeAOT supports them. We're planning to have them in NativeAOT by .NET 7.
That said, ILLink.Descriptors.xml are a subpar solution in general.
The trimming process analyzes the reflection patterns within the app. If it can reason about them statically, it makes sure not to remove things that would break the reflection pattern found in the app. If the reflection cannot be reasoned about statically, trimming generates a warning that the user can see.
If you use ILLink.Descriptors.xml, there will still be a warning at the use site that you need to suppress - otherwise the library will be reported as trimming-unfriendly. The suppression means that you're now responsible to make sure the code and ILLink.Descriptors match (i.e. you're not reflecting on more stuff without updating ILLink.Descriptors, etc.). Trimming is very hard to unit test because the act of embedding the code in a unit test framework changes the things that can be trimmed. Suppressing trimming warnings is a potential maintenance and reliability nightmare.
ILLink.Descriptors also root things unconditionally - even if the code that uses the thing you rooted in Descriptors got trimmed away, the thing rooted in descriptors will stay (trimming doesn't know what code the Descriptors entry is associated with). They limit how well the app can be trimmed.
If you're using custom attributes for discovery, could you use custom attributes to encode the reachable types?
E.g.:
public sealed class TypeConverterAttribute : Attribute
{
public TypeConverterAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.DefaultConstructor)] Type type)
{
ConverterType = type;
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.DefaultConstructor)]
public Type ConverterType { get; }
}
The DynamicallyAccessedMembers
custom attribute annotation tells trimming to make the default constructor available for reflection.
Whenever trimming sees this attribute, it will make sure to keep the constructor on the typeof
.
When you access the ConverterType
property (notice it's also annotated with DynamicallyAccessedMembers
), trimming will know that whatever can come from the property has its constructor kept and won't warn at the use site.
One can use DynamicallyAccessedMembers to annotate various System.Type instances reflected on at runtime this way.
Add support for NativeAOT as NativeAOT will be present as part of .NET 7.0. The NativeAOT ahead-of-time (AOT) toolchain can compile .NET application into a native (architecture specific) single-file executable. It can also produce standalone dynamic or static libraries that can be consumed by applications written in other programming languages.
In I intend to use libraries made with C# in Flutter/dart/ffi/rust projects
https://github.com/dotnet/runtimelab/tree/feature/NativeAOT