-
Notifications
You must be signed in to change notification settings - Fork 52
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
[Hello-NativeAOTFromJNI] Add NativeAOT sample #1153
Commits on Oct 24, 2023
-
[Hello-NativeAOTFromJNI] Add NativeAOT sample
Instead of a managed app creating a Java VM and calling into Java, do the opposite: have a Java app call into Native Library built using NativeAOT, using `[UnmanagedCallersOnly]` to provide the entry points.
Configuration menu - View commit details
-
Copy full SHA for 007317b - Browse repository at this point
Copy the full SHA 007317bView commit details
Commits on Oct 25, 2023
-
BROKEN BROKEN BROKEN BROKEN What do we want? To create a `JreRuntime` instance! …which is shockingly difficult. But first, *why* do we want to create a `JreRuntime` instance? (It's not like we've needed it so far!) Force the issue by changing `NativeAOTInit.sayHello()` to return a `String` instance, thus requiring that for `NativeAOTInit.sayHello()` to return a non-`null` value, it needs a `JreRuntime` instance! This is where everything falls apart. `JreRuntime` and `JreRuntimeOptions` were not designed with this scenario in mind! Update `JreRuntime` & co so that it doesn't require `JvmLibraryPath` when `InvocationPointer` isn't null, and don't require that `JreRuntimeOptions.ClassPath` contain the path to `java-interop.jar` when `InvocationPointer` isn't null. This allows us to create the `JreRuntimeOptions` instance. Yay! The next problem is that setting `%(ProjectReference.AdditionalProperties)` to include `Standalone=true` doesn't appear to work, in that the `Java.Interop.dll` that is included still contains P/Invokes instead of the `JniNativeMethods` class. Update `Java.Interop.csproj` so that `$(Standalone)`=true is now the default. (This *shouldn't* break anybody, but… it now means the P/Invoke backend is getting NO testing. ¯\_(ツ)_/¯ ) The next part is where it blows up GOOD: `options.CreateJreVM()` throws, which aborts everything: % (cd bin/Release/osx-x64/publish ; java -cp hello-from-java.jar:java-interop.jar com/microsoft/hello_from_jni/App) Hello from Java! # jonp: JNI_OnLoad: vm=10a9c0b00 # jonp: JNI_OnLoad: created options… # jonp: builder.InvocationPointer=10a9c0b00 JNI_OnLoad: error: System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property. ---> System.NotSupportedException: 'Java.Interop.ManagedPeer+ConstructMarshalMethod' is missing delegate marshalling data. This can happen for code that is not compatible with AOT. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility at Internal.Runtime.CompilerHelpers.RuntimeInteropData.GetDelegateMarshallingStub(RuntimeTypeHandle, Boolean) + 0x78 at System.Runtime.InteropServices.PInvokeMarshal.AllocateThunk(Delegate del) + 0x6b at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValueLocked(TKey, ConditionalWeakTable`2.CreateValueCallback) + 0x27 at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValue(TKey, ConditionalWeakTable`2.CreateValueCallback) + 0x41 at System.Runtime.InteropServices.PInvokeMarshal.GetFunctionPointerForDelegate(Delegate) + 0xd5 at libHello-NativeAOTFromJNI!<BaseAddress>+0x8adeb at Java.Interop.JniEnvironment.Types._RegisterNatives(JniObjectReference, JniNativeMethodRegistration[], Int32) + 0x90 at Java.Interop.JniEnvironment.Types.RegisterNatives(JniObjectReference, JniNativeMethodRegistration[], Int32) + 0x65 at Java.Interop.JniType.RegisterNativeMethods(JniNativeMethodRegistration[]) + 0x30 at Java.Interop.ManagedPeer..cctor() + 0x175 at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xb4 --- End of inner exception stack trace --- at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x147 at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext*, Object) + 0x9 at Java.Interop.JniRuntime..ctor(JniRuntime.CreationOptions) + 0x5a2 at Java.Interop.JreRuntime..ctor(JreRuntimeOptions) + 0x22 at Hello_NativeAOTFromJNI.JNIEnvInit.JNI_OnLoad(IntPtr, IntPtr) + 0x9e Exception in thread "main" java.lang.UnsatisfiedLinkError: unsupported JNI version 0x00000000 required by /Volumes/Xamarin-Work/src/xamarin/Java.Interop/samples/Hello-NativeAOTFromJNI/bin/Release/osx-x64/publish/libHello-NativeAOTFromJNI.dylib at java.base/jdk.internal.loader.NativeLibraries.load(Native Method) at java.base/jdk.internal.loader.NativeLibraries$NativeLibraryImpl.open(NativeLibraries.java:388) at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:232) at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:174) at java.base/jdk.internal.loader.NativeLibraries.findFromPaths(NativeLibraries.java:315) at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:287) at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2427) at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:818) at java.base/java.lang.System.loadLibrary(System.java:1989) at com.microsoft.hello_from_jni.NativeAOTInit.<clinit>(NativeAOTInit.java:5) at com.microsoft.hello_from_jni.App.main(App.java:7) Within the `JniRuntime` constructor, we're hitting: #if !XA_JI_EXCLUDE ManagedPeer.Init (); #endif // !XA_JI_EXCLUDE This invokes the `ManagedPeer` static constructor, which attempts to call `JniType.RegisterNativeMethods()`, which attempts to call `JNIEnv::RegisterNatives()`, but before it can get that far it needs to marshal things: 1. The `JniNativeMethodRegistration` struct, which in turn requires 2. The `JniNativeMethodRegistration.Marshaler` delegate field. This apparently isn't supported by NativeAOT, at least not without additional work that I am not currently privy to. Given that `JniNativeMethodRegistration` structure marshaling is how *all* JNI method registration is done in .NET Android, this is a bit of a blocker for this sample. TODO? Figure out how to allow NativeAOT to marshal `JniNativeMethodRegistration` with a minimum of effort? TODO? *Require* `jnimarshalmethod-gen`, and update it so that it emits `[UnmanagedCallersOnlyAttribute]` on all generated marshal methods *and* emits `UnmanagedCallersOnlyAttribute.EntryPoint` to a `Java_…` symbol name so that we *don't* hit the `JniNativeMethodRegistration` struct marshaling codepath. (See also 77800dd). [0]:https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#RegisterNatives
Configuration menu - View commit details
-
Copy full SHA for db84cc3 - Browse repository at this point
Copy the full SHA db84cc3View commit details -
icanhaz blittable method registration?
Commit db84cc3 "didn't work" because the "traditional" form of method registration through `JNIEnv::RegisterNatives()` used a `System.Delegate` instance to refer to a C# method to invoke, but this fails under NativeAOT because the NativeAOT infrastructure needs to be able to produce "stubs" for the methods based on compile-time scans, and it doesn't represent our code pattern and/or our pattern is not supportable with how NativeAOT works. Oops. "Ecosystem-wise", I'm not sure how to solve this, other than handy-wavy ideas such as "rely on `jnimarshalmethod-gen`!". Short-term, we can at least resolve `ManagedPeer`. Create a new `JniBlittableNativeMethodRegistration` struct which contains only blittable types, vs. `JniNativeMethodRegistration` which contains `string` fields and `Delegate` fields and is not easily supportable by NativeAOT. public partial struct JniBlittableNativeMethodRegistration { public JniBlittableNativeMethodRegistration (IntPtr name, IntPtr signature, IntPtr marshaler); // To support `new JniBlittableNativeMethodRegistration("name"u8, "signature"u8, marshaler)` public JniBlittableNativeMethodRegistration (ReadOnlySpan<byte> name, ReadOnlySpan<byte> signature, IntPtr marshaler); } "Plumb through" use of `JniBlittableNativeMethodRegistration` to `JniEnvironment.Types.RegisterNatives()` overloads: partial class JniEnvironment { partial class Types { public static void RegisterNatives(JniObjectReference type, ReadOnlySpan<JniBlittableNativeMethodRegistration> methods); } } This in turn requires updating `jnienv-gen` so that `RegisterNatives()` is bound with the `const JNINativeMethod *methods` parameter bound as an `IntPtr` instead of a `JniNativeMethodRegistration[]`. Update the `ManagedPeer` static constructor to use `[UnmanagedCallersOnly]` methods and native function pointers to register the marshal methods that `ManagedPeer` requires.
Configuration menu - View commit details
-
Copy full SHA for a32e244 - Browse repository at this point
Copy the full SHA a32e244View commit details -
Configuration menu - View commit details
-
Copy full SHA for 4c30ab5 - Browse repository at this point
Copy the full SHA 4c30ab5View commit details -
Configuration menu - View commit details
-
Copy full SHA for a08dce8 - Browse repository at this point
Copy the full SHA a08dce8View commit details -
Use [UnmanagedFunctionPointer]
Commit db84cc3 noted that the sample failed to run because NativeAOT didn't know how to produce the required "stubs" to allow a `System.Delegate` field to be marshaled. Commit a32e244 was an attempt to "fix" this by introducing a `JniBlittableNativeMethodRegistration` and using C#9 function pointers to register `ManagedPeer` marshal methods instead of delegates. While this works, this is an extensive change, and leaves various "corner cases" in how things fit together, such as the `JniNativeMethodRegistrationArguments` struct used as part of `jnimarshalmethod-gen`-based method registration. @lambdageek found an easier solution: place `[UnmanagedFunctionPointer]` onto the delegate declaration. This appears to tell NativeAOT to generate the required stubs, with significantly fewer changes. This also could fit nicely into a future `generator` change to place `[UnmanagedFunctionPointer]` on all the `_JniMarshal_*` declarations (56955d9).
Configuration menu - View commit details
-
Copy full SHA for da9f188 - Browse repository at this point
Copy the full SHA da9f188View commit details
Commits on Nov 2, 2023
-
What `Hello-NativeAOTFromJNI` previously did was quite minimal: 1. Use `[UnmanagedCallersOnly]` to provide a `JNI_OnLoad()` method which 2. Initialized the Java.Interop runtime, allowing 3. An `[UnmanagedCallersOnly]`-provided `Java_…` method which is called from Java. All quite low level, all miles away from .NET Android. Expand the sample to: 1. Contain a `Java.Lang.Object` subclass, which contains a `[JavaCallable]` method. 2. Call `jcw-gen` to generate Java Callable Wrappers for (1), containing the `[JavaCallable]` method. 3. Call `jnimarshalmethod-gen` to generate marshal methods for (1), as NativeAOT doesn't support System.Reflection.Emit. 4. Instantiate (1) *from Java*, and invoke the `[JavaCallable]` method. *Now* we're (kinda) getting something that looks like .NET Android. But first, we need to make that *work*: Update `Java.Interop.Tools.JavaCallableWrappers` so that it will emit `native` method declarations for `[JavaCallable]` methods, not just method overrides and `[Export]` methods. Update `Java.Interop.Tools.Expressions` so that the `_JniMarshal_*` delegate types have `[UnmanagedFunctionPointer(CallingConvention.Winapi)]`, as this is what allows NativeAOT to emit appropriate "stubs"; see also da9f188. Update `Java.Interop.Tools.Expressions.ExpressionAssemblyBuilder` to no longer attempt to "remove and fixup" `System.Private.CoreLib`. So long as `ExpressionAssemblyBuilder` output is *only* used in "completed" apps (not distributed in NuGet packages in some "intermediate" form), referencing `System.Private.CoreLib` is "fine". Additionally, trying to remove `System.Private.CoreLib` broke things when adding `[UnmanagedFunctionPointer]`, as `CallingConvention` could not be resolved, resulting in `jnimarshalmethod-gen` erroring out with: error JM4006: jnimarshalmethod-gen: Unable to process assembly '/Volumes/Xamarin-Work/src/xamarin/Java.Interop/samples/Hello-NativeAOTFromJNI/bin/Debug/Hello-NativeAOTFromJNI.dll' Failed to resolve System.Runtime.InteropServices.CallingConvention Mono.Cecil.ResolutionException: Failed to resolve System.Runtime.InteropServices.CallingConvention at Mono.Cecil.Mixin.CheckedResolve(TypeReference self) at Mono.Cecil.SignatureWriter.WriteCustomAttributeEnumValue(TypeReference enum_type, Object value) … (This is because `CallingConvention` is in `System.Runtime.InteropServices.dll`, which isn't referenced.) We could "fix" this by explicitly adding a reference to `System.Runtime.InteropServices.dll`, but this is just one of an unknown number of corner cases. Give up for now. Update `jnimarshalmethod-gen` assembly location probing: it was given the *full assembly name* of `Java.Base`: # jonp: resolving assembly: Java.Base, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null …and failing to find `Java.Base.dll`, because it was looking for `Java.Base, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null.dll`. Oops. Use `AssemblyName` to parse the string and extract out the assembly name., so that `Java.Base.dll` is probed for and found. With all that…it still fails: % (cd bin/Release/osx-x64/publish ; java -cp hello-from-java.jar:java-interop.jar com/microsoft/hello_from_jni/App) Hello from Java! C# init() Hello from .NET NativeAOT! String returned to Java: Hello from .NET NativeAOT! Exception in thread "main" com.xamarin.java_interop.internal.JavaProxyThrowable: System.IO.FileNotFoundException: Could not resolve assembly 'Hello-NativeAOTFromJNI'. at System.Reflection.TypeNameParser.ResolveAssembly(String) + 0x97 at System.Reflection.TypeNameParser.GetType(String, ReadOnlySpan`1, String) + 0x32 at System.Reflection.TypeNameParser.NamespaceTypeName.ResolveType(TypeNameParser&, String) + 0x17 at System.Reflection.TypeNameParser.GetType(String, Func`2, Func`4, Boolean, Boolean, Boolean, String) + 0x99 at Java.Interop.ManagedPeer.RegisterNativeMembers(IntPtr jnienv, IntPtr klass, IntPtr n_nativeClass, IntPtr n_assemblyQualifiedName, IntPtr n_methods) + 0x103 at com.xamarin.java_interop.ManagedPeer.registerNativeMembers(Native Method) at example.ManagedType.<clinit>(ManagedType.java:15) at com.microsoft.hello_from_jni.App.main(App.java:13) `App.main()` has `new example.ManagedType()`, which hits the `ManagedType` static constructor of: public /* partial */ class ManagedType extends java.lang.Object implements com.xamarin.java_interop.GCUserPeerable { /** @hide */ public static final String __md_methods; static { __md_methods = "n_GetString:()Ljava/lang/String;:__export__\n" + ""; com.xamarin.java_interop.ManagedPeer.registerNativeMembers (ManagedType.class, "Example.ManagedType, Hello-NativeAOTFromJNI", __md_methods); } } The `ManagedPeer.registerNativeMembers()` call is what is needed to register the native `ManagedPeer.getString()` method, so that it can be called. This is good. (Though `__md_methods` containing *anything* is not desired, but that's a different problem.) `ManagedPeer.RegisterNativeMembers()` is given the assembly-qualified name `Example.ManagedType, Hello-NativeAOTFromJNI`, and tries to: Type.GetType ("Example.ManagedType, Hello-NativeAOTFromJNI", throwOnError: true); …which then proceeds to throw, because in NativeAOT *there are no assemblies*, and thus `Type.GetType()` *cannot work*. Oops. Thus, the only way to make something remotely like .NET Android infrastructure work is to *require* the use of `Java_…` native method names and `[UnmanagedCallersOnly]` on marshal methods. (In .NET Android parlance, the experimental `$(AndroidEnableMarshalMethods)`=True is required.)
Configuration menu - View commit details
-
Copy full SHA for 69c90ba - Browse repository at this point
Copy the full SHA 69c90baView commit details -
Configuration menu - View commit details
-
Copy full SHA for 1fc0af5 - Browse repository at this point
Copy the full SHA 1fc0af5View commit details -
Configuration menu - View commit details
-
Copy full SHA for a499a1d - Browse repository at this point
Copy the full SHA a499a1dView commit details -
Commit 69c90ba expanded into a "Full(er)" sample, with just one issue: it didn't fully work: Exception in thread "main" com.xamarin.java_interop.internal.JavaProxyThrowable: System.IO.FileNotFoundException: Could not resolve assembly 'Hello-NativeAOTFromJNI'. at System.Reflection.TypeNameParser.ResolveAssembly(String) + 0x97 at System.Reflection.TypeNameParser.GetType(String, ReadOnlySpan`1, String) + 0x32 at System.Reflection.TypeNameParser.NamespaceTypeName.ResolveType(TypeNameParser&, String) + 0x17 at System.Reflection.TypeNameParser.GetType(String, Func`2, Func`4, Boolean, Boolean, Boolean, String) + 0x99 at Java.Interop.ManagedPeer.RegisterNativeMembers(IntPtr jnienv, IntPtr klass, IntPtr n_nativeClass, IntPtr n_assemblyQualifiedName, IntPtr n_methods) + 0x103 at com.xamarin.java_interop.ManagedPeer.registerNativeMembers(Native Method) at example.ManagedType.<clinit>(ManagedType.java:15) at com.microsoft.hello_from_jni.App.main(App.java:13) The problem is that `ManagedPeer.RegisterNativeMembers()` calls `Type.GetType("Example.ManagedType, Hello-NativeAOTFromJNI")`, which throws `FileNotFoundException`. Let's attempt to fix that: Update `MangedPeer.RegisterNativeMembers()` to call the (new!) method: partial class JniRuntime { partial class JniTypeManager { public virtual void RegisterNativeMembers ( JniType nativeClass, ReadOnlySpan<char> assmblyQualifiedTypeName, ReadOnlySpan<char> methods); } } which allows a subclass to *avoid* the `Type.GetType()` call. Add a `NativeAotTypeManager` class which subclasses `JniRuntime.JniTypeManager`, overriding `RegisterNativeMembers()` so as to avoid the `Type.GetType()` call. (It also "fakes" its own "typemap" implementation…) Add `Hello-NativeAOTFromJNI.xml`, a Linker Descriptor, to preserve the `JavaException` constructors, which are needed when things break horrifically. TODO: figure out the appropriate `DynamicDependencyAttribute` incantations to replace `Hello-NativeAOTFromJNI.xml`. Update the `_AddMarshalMethods` build task to *also* update `$(IntermediateOutputPath)$(TargetFileName)`, as the copy in `$(IntermediateOutputPath)` is used by the `IlcCompile` target. *Not* updating the copy in `$(IntermediateOutputPath)` means that we don't get *any* marshal methods, and things break. Rename `ExpressionAssemblyBuilder.CreateRegistrationMethod()` to Rename `ExpressionAssemblyBuilder.AddRegistrationMethod()`, so that the `EmitConsoleWriteLine()` invocation can provide the *full* type name of the `__RegisterNativeMembers()` method, which helps when there is more than one such method running around… Various changes to `JniRuntime.JniTypeManager.cs`, to increase logging verbosity, and to make the optimization effort in `TryLoadJniMarshalMethods()` actually work; `Type.GetRuntimeMethod()` *will not find* non-public methods, and `__RegisterNativeMembers()` is rarely/never public. Thus, it was basically dead code, and we'd always fallback to the "look at all methods and see which ones have `[JniAddNativeMethodRegistration]`" codepath, which is by definition slower. Use `Type.GetMethod()` instead. Update `jnimarshalmethod-gen` & co so that they're consistent with the output of `jcw-gen`. Without these changes, the JCW would declare `n_GetString()`, while `jnimarshalmethod-gen` would try to register `getString`, and Java would thrown an exception because there is no `getString` member to register. Doh! Finally, and the one thing that keeps this from being "perfect", add an "activation constructor" `Example.ManagedType(ref JniObjectReference, JniObjectReferenceOptions)`. This constructor is currently needed because "JavaInterop1"-style Java Callable Wrappers don't contain constructors (?!), so no `Example.ManagedType` instance is created *until* the `ManagedType.n_GetString()` marshal method is executed and attempts to invoke the `ManagedType.GetString()` method. We'll need to update `jcw-gen` & related to address this. Current output: % (cd bin/Release/osx-x64/publish ; java -cp hello-from-java.jar:java-interop.jar com/microsoft/hello_from_jni/App) Hello from Java! C# init() Hello from .NET NativeAOT! String returned to Java: Hello from .NET NativeAOT! C# RegisterNativeMembers(JniType(Name='example/ManagedType' PeerReference=0x7fe545812ed8/G), "Example.ManagedType, Hello-NativeAOTFromJNI", "n_GetString:()Ljava/lang/String;:__export__ ") # jonp: called `Example.ManagedType/__<$>_jni_marshal_methods.__RegisterNativeMembers()` w/ 1 methods to register. mt.getString()=Hello from C#, via Java.Interop!
Configuration menu - View commit details
-
Copy full SHA for e1822f0 - Browse repository at this point
Copy the full SHA e1822f0View commit details
Commits on Nov 7, 2023
-
A funny thing happened on the way through CI: `Java.Interop.Export-Tests` *with* `jnimarshalmethod-gen` failed! Failed AddExportMethods [169 ms] Error Message: Java.Interop.JavaException : Could not initialize class com.xamarin.interop.export.ExportType Stack Trace: at Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(JniObjectReference type, String name, String signature) in /Users/runner/work/1/s/src/Java.Interop/obj/Release/net7.0/JniEnvironment.g.cs:line 21407 at Java.Interop.JniType.GetStaticMethod(String name, String signature) in /Users/runner/work/1/s/src/Java.Interop/Java.Interop/JniType.cs:line 315 at Java.InteropTests.MarshalMemberBuilderTest.AddExportMethods() at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) --- End of managed Java.Interop.JavaException stack trace --- java.lang.NoClassDefFoundError: Could not initialize class com.xamarin.interop.export.ExportType The cause? e1822f0 updated `jnimarshalmethod-gen`: - registrations.Add (new ExpressionMethodRegistration (name, signature, mmDef)); + // Assume that `JavaCallableAttribute.Name` is "public" JCW name, and JCW's declare `n_`-prefixed `native` methods… + registrations.Add (new ExpressionMethodRegistration ("n_" + method.Name, signature, mmDef)); That is, instead of attempting to register e.g. `ExportType.action()V` (via `[JavaCallable("action")]`), it was instead attempting to register `ExportType.n_action()V`, because of the introduced `"n_" + method.Name` change. The "problem" is that `jnimarshalmethod-gen` was written in the context of Java.Interop, *not* .NET Android, and the existing `Java.Interop.Export-Tests` unit tests assume that there is no `n_`-prefix on native method declarations. There are two plausible solutions: update the unit tests to conform to existing .NET Android convention, and use an `n_` prefix on `native` method declarations. Or update `jcw-gen` so that when using `jcw-gen --codegen-target=JavaInterop1`, the `JavaCallableAttribute.Name` value is used for the `native` method declaration. Because @jonpryor is a glutton for punishment and "cleanliness", let's try the latter. `JavaCallableWrapperGenerator` already has a `.CodeGenerationTarget` property, How Hard Could It Be™? Turns out, harder than expected: `JavaCallableWrapperGenerator` was doing *lots* of work in its constructor, including the all important bit of populating `Signature` values, and the constructor runs *before* the `.CodeGenerationTarget` property is set. This is a somewhat straightforward fix: turn most of the `JavaCallableWrapperGenerator` constructor into a `Initialize()` method, and call `Initialize()` from the public methods. This creates a semantic change: some exceptions which were thrown by the constructor are now thrown from the public methods. We deem this as acceptable because all known uses of `JavaCallableWrapperGenerator` ~immediately call `.Generate()` after creating the instance, so the exception will still be thrown from a site near where it previously would have been thrown. The more annoying aspect is `Signature` initialization: we need to pass in `.CodeGenerationTarget`, which is Yet Another Constructor Parameter, and we already have A Lot™. Attempt to bring sanity to this mess by introducing a new `SignatureOptions` type to hold the `Signature` parameters. Update `jnimarshalmethod-gen` to undo the change which broke `Java.Interop.Export-Tests`. Update `tests/Java.Interop.Tools.JavaCallableWrappers-Tests` to add a test for `.CodeGenerationTarget==JavaInterop1`. Add `$(NoWarn)` to `Java.Interop.Tools.JavaCallableWrappers-Tests.csproj` in order to "work around" the warnings-as-errors: …/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportFieldAttribute.cs(19,63): error CA1019: Remove the property setter from Name or reduce its accessibility because it corresponds to positional argument name …/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs(53,4): error CA1019: Remove the property setter from Name or reduce its accessibility because it corresponds to positional argument name …/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportFieldAttribute.cs(12,16): error CA1813: Avoid unsealed attributes … This is "weird"; the warnings/errors appear to come in because `Java.Interop.Tools.JavaCallableWrappers-Tests.csproj` now has: <Compile Include="..\..\src\Java.Interop\Java.Interop\JniTypeSignatureAttribute.cs" /> which appears to pull in `src/Java.Interop/.editorconfig`, which makes CA1019 and CA1813 errors. (insert massively confused face here. Like, wat?)
Configuration menu - View commit details
-
Copy full SHA for 9027591 - Browse repository at this point
Copy the full SHA 9027591View commit details -
Merge remote-tracking branch 'origin/main' into dev/jonp/jonp-hello-f…
…rom-jni All hail the new interface invokers in 1adb796!
Configuration menu - View commit details
-
Copy full SHA for 1d422da - Browse repository at this point
Copy the full SHA 1d422daView commit details -
9027591 tried to fix Java.Interop.Export-Tests, and in the process broke Java.Base-Tests! A total of 1 test files matched the specified pattern. Failed InterfaceInvokerMethod [100 ms] Error Message: Java.Interop.JavaException : 'void example.MyIntConsumer.accept(int)' Stack Trace: at Java.Interop.JniEnvironment.InstanceMethods.CallVoidMethod(JniObjectReference instance, JniMethodInfo method, JniArgumentValue* args) in /Users/runner/work/1/s/src/Java.Interop/obj/Release/net7.0/JniEnvironment.g.cs:line 20370 at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 47 at Java.Lang.IRunnableInvoker.Run() in /Users/runner/work/1/s/src/Java.Base/obj/Release-net7.0/mcw/Java.Lang.IRunnable.cs:line 34 at Java.BaseTests.JavaToManagedTests.InterfaceInvokerMethod() in /Users/runner/work/1/s/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs:line 28 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) --- End of managed Java.Interop.JavaException stack trace --- java.lang.UnsatisfiedLinkError: 'void example.MyIntConsumer.accept(int)' at example.MyIntConsumer.accept(Native Method) at com.microsoft.java_base_tests.Invoker$1.run(Invoker.java:15) The problem? That pesky `n_`! Or rather, the lack thereof this time. The issue is that `JreTypeManager`/etc. and `jcw-gen` need to be consistent. 9027591 altered the consistency, breaking Java.Base tests. Commit this to verify that things work on CI, not just locally. Assuming it works on CI, next step will be to largely revert 9027591, and then fix `Java.Interop.Export-Tests` to use an `n_` prefix on all `native` method declarations. That bit is hand-written; it can change. Keeping the tooling consistent is more important.
Configuration menu - View commit details
-
Copy full SHA for 902fe28 - Browse repository at this point
Copy the full SHA 902fe28View commit details -
Invoking the Java-side constructor should invoke the C#-side constructor too! And now it does! Hello from Java! C# init() Hello from .NET NativeAOT! String returned to Java: Hello from .NET NativeAOT! C# RegisterNativeMembers(JniType(Name='example/ManagedType' PeerReference=0x7f9392713098/G), "Example.ManagedType, Hello-NativeAOTFromJNI", "getString:()Ljava/lang/String;:__export__ ") # jonp: called `Example.ManagedType/__<$>_jni_marshal_methods.__RegisterNativeMembers()` w/ 1 methods to register. # jonp: ActivatePeer( False, 0x700001bc6a70/I, Void .ctor(), System.Object[]) mt.getString()=Hello from C#, via Java.Interop!
Configuration menu - View commit details
-
Copy full SHA for 0392169 - Browse repository at this point
Copy the full SHA 0392169View commit details -
Allow marking constructors as callable from Java.
Continuing on the "activation constructor" train, we want to allow Java to pass parameters to a constructor. In .NET Android parlance: class Example : Java.Lang.Object { [Export] public Example (int value) {} } Commit 9027591 updated `JavaCallableAttribute` to allow it to be placed on constructors, but if we try that with `samples/Hello-NativeAOTFromJNI`, the Java Callable Wrapper doesn't build: // JCW /* partial */ class Example extends java.lang.Object { public Example (int p0) { super (p0); if (getClass () == Example.class) ManagedPeer.construct(…); } } To make this work, we need `ExportAttribute.SuperArgumentsString`. We *could* add this to `JavaCallableAttribute`, but that means we'd have a property which can only be used from constructors. (Yes, `ExportAttribute` has this "wonkiness", but that doens't mean we should continue it!) Add a new `JavaCallableConstructorAttribute`, which has a new `SuperConstructorExpression` property, along with `jcw-gen` support. This allows things to compile: // C# class Example : Java.Lang.Object { [JavaCallableConstructor (SuperConstructorExpression="")] public Example (int value) {} } // JCW /* partial */ class Example extends java.lang.Object { public Example (int p0) { super (); if (getClass () == Example.class) ManagedPeer.construct(…); } } …but it's not quite right yet, because the wrong constructor is invoked! ManagedPeer.construct ( /* self */ this, /* aqn */ "Namespace.Example, Assembly", /* ctor sig */ "", /* arguments */ new java.lang.Object[] { p0 } ); Oops! Update the `Signature`/`SignatureOptions` creation within `JavaCallableWrapperGenerator.cs` so that `ManagedParameters` is set for *all* constructor codepaths. ManagedPeer.construct ( /* self */ this, /* aqn */ "Namespace.Example, Assembly", /* ctor sig */ "System.Int32, System.Runtime", /* arguments */ new java.lang.Object[] { p0 } ); This appears to fix a long-standing bug/"thinko" in JCW generation!
Configuration menu - View commit details
-
Copy full SHA for 93a901a - Browse repository at this point
Copy the full SHA 93a901aView commit details
Commits on Nov 8, 2023
-
Remember 902fe28? > Assuming it works on CI, next step will be to largely revert > 9027591, and then fix > `Java.Interop.Export-Tests` to use an `n_` prefix on all `native` > method declarations. That bit is hand-written; it can change. > Keeping the tooling consistent is more important. Let's Do It! Revert most of the `JavaCallableWrapperGenerator` bits of 9027591. Update the `JavaInterop1` JCW output to conform, using `n_`-prefixed native method declarations. *Retain the constructor signature fix* in 93a901a.. Revert the `JreTypeManager` change in 902fe28. Update `jnimarshalmethod-gen` to register `n_`-prefixed names. Update `Java.Interop.Export-Tests` so that native method declarations now have `n_` prefixes, so that all is in sync.
Configuration menu - View commit details
-
Copy full SHA for a50457b - Browse repository at this point
Copy the full SHA a50457bView commit details
Commits on Nov 9, 2023
-
Rethink
Type.GetType()
alternativesRemember the one-off comment in 93a901a? > (Possible "quick hack": replace `Type.GetType()` use with calls to something > on `JniRuntime.JniTypeManager`, allowing a subclass to provide its own > mapping? This feels "duplicative" of dotnet/runtime, though.) The more I think about it, the saner this feels. Add `JniRuntime.JniTypeManager.GetTypeFromAssemblyQualifiedName()`, and use that instead of `Type.GetType()`. This allows `NativeAotTypeManager` to provide its equivalent functionality. This in turn allows `ManagedType` to provide a constructor which takes parameters, which previously broke because that codepath hit `Type.GetType()`!
Configuration menu - View commit details
-
Copy full SHA for ce850ca - Browse repository at this point
Copy the full SHA ce850caView commit details -
Configuration menu - View commit details
-
Copy full SHA for 6920e6c - Browse repository at this point
Copy the full SHA 6920e6cView commit details
Commits on Nov 13, 2023
-
Configuration menu - View commit details
-
Copy full SHA for 4ceaa34 - Browse repository at this point
Copy the full SHA 4ceaa34View commit details
Commits on Nov 14, 2023
-
Configuration menu - View commit details
-
Copy full SHA for cf73d77 - Browse repository at this point
Copy the full SHA cf73d77View commit details -
Configuration menu - View commit details
-
Copy full SHA for 986f0c4 - Browse repository at this point
Copy the full SHA 986f0c4View commit details
Commits on Nov 15, 2023
-
The Hello-NativeAOTFromJNI sample previously built and worked on .NET 8 RC2 on macOS+x64, but when I tried things on .NET 8 GA on macOS+arm64, things failed "inexplicably" % dotnet publish -c Release -r osx-x64 EXEC : error JM4006: jnimarshalmethod-gen: Unable to process assembly '/Users/jon/Developer/src/xamarin/java.interop/samples/Hello-NativeAOTFromJNI/bin/Release/osx-x64/Hello-NativeAOTFromJNI.dll' [/Users/jon/Developer/src/xamarin/java.interop/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj] Could not load file or assembly 'Hello-NativeAOTFromJNI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. System.IO.FileLoadException: Could not load file or assembly 'Hello-NativeAOTFromJNI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. at System.Runtime.Loader.AssemblyLoadContext.InternalLoad(ReadOnlySpan`1 arrAssembly, ReadOnlySpan`1 arrSymbols) at Xamarin.Android.Tools.JniMarshalMethodGenerator.App.CreateMarshalMethodAssembly(String path) in /Users/jon/Developer/src/xamarin/java.interop/tools/jnimarshalmethod-gen/App.cs:line 445 at Xamarin.Android.Tools.JniMarshalMethodGenerator.App.ProcessAssemblies(List`1 assemblies) in /Users/jon/Developer/src/xamarin/java.interop/tools/jnimarshalmethod-gen/App.cs:line 272 After a few days of pulling my hair out, @lambdageek suggested: > so maybe coreclr on arm64 refuses to load a PE32+ image that is x86-64? This turns out to be the case, presenting two "workarounds": 1. Build with an rid that matches the host platform, e.g. this worked: dotnet publish -c Release -r osx-arm64 2. Setting `$(PlatformTarget)`=AnyCPU also works, as the resulting assembly isn't tied to a specific rid. Update `Hello-NativeAOTFromJNI.csproj` to set `$(PlatformTarget)`=AnyCPU, so that I can at least *build* osx-x64 from osx-arm64. (I can't *run* it, but I can build it!) Also update `jnimarshalmethod-gen` to not load assemblies from directories containing `/ref/`, as reference assemblies cannot be loaded for execution: System.ArgumentException: A BadImageFormatException has been thrown while parsing the signature. This is likely due to lack of a generic context. Ensure genericTypeArguments and genericMethodArguments are provided and contain enough context. ---> System.BadImageFormatException: Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Reference assemblies cannot be loaded for execution. (0x80131058) File name: 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' ---> System.BadImageFormatException: Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL'. Reference assemblies cannot be loaded for execution. (0x80131058) File name: 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL' ---> System.BadImageFormatException: Cannot load a reference assembly for execution. at System.Runtime.Loader.AssemblyLoadContext.<LoadFromPath>g____PInvoke|5_0(IntPtr ptrNativeAssemblyBinder, UInt16* ilPath, UInt16* niPath, ObjectHandleOnStack retAssembly) at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath) at System.Reflection.Assembly.LoadFile(String path)
Configuration menu - View commit details
-
Copy full SHA for 17a4403 - Browse repository at this point
Copy the full SHA 17a4403View commit details
Commits on Nov 16, 2023
-
Use
net.dot.jni
package prefixIt's shorter! It avoids `_1` in Java method names!
Configuration menu - View commit details
-
Copy full SHA for 1b86f9a - Browse repository at this point
Copy the full SHA 1b86f9aView commit details -
Configuration menu - View commit details
-
Copy full SHA for f71cadb - Browse repository at this point
Copy the full SHA f71cadbView commit details -
I'm not sure that `GetTypeFromAssemblyQualifiedName()` is actually a good idea or not, so I'd rather not add it as public API, yet it's required in order to make the sample work? How do we square this circle? With build configs (redux!). Commit c6c487b added the "Standalone" build config, while commit db84cc3 noted that it didn't quite work right, because "just" using `AdditionalProperties="Standalone=true"` didn't result in a `Java.Interop.dll` which had the right build config. Figure this out. The magic voodoo is that the output directories need to differ for each build config, because reusing the same output path leads to "madness" (parallel builds overwrite files, resulting in possible build breaks, etc., etc.). The key properties that need to differ based on "build config" are: * `$(IntermediateOutputPath)`, which contains intermediate files like AssemblyInfo! * `$(OutputPath)`, which is where the final assemblies are written. Update `Java.Interop.csproj` to treat `$(UseNativeAot)` as a "distinct" build config, which also sets `FEATURE_NATIVE_AOT`. This allows `GetTypeFromAssemblyQualifiedName()` to be `internal` by default, and only public when used by/built from the Hello-NativeAOTFromJNI sample. The next new public API is `JniRuntime.UseMarshalMemberBuilder`. We can make that `internal` for now by making `Java.Runtime.Environment.dll` a "friend" assembly to `Java.Interop.dll` via `[InternalsVisibleTo]`, then fix up the resulting build errors (as both assemblies had `NativeMethods` types). Remove the inclusion of `ManagedValueManager.cs` from `Hello-NativeAOTFromJNI.csproj`. It's no longer needed as of commit 6920e6c.
Configuration menu - View commit details
-
Copy full SHA for b5fc4cf - Browse repository at this point
Copy the full SHA b5fc4cfView commit details -
Configuration menu - View commit details
-
Copy full SHA for 4741dc9 - Browse repository at this point
Copy the full SHA 4741dc9View commit details -
Configuration menu - View commit details
-
Copy full SHA for 8eb2850 - Browse repository at this point
Copy the full SHA 8eb2850View commit details
Commits on Nov 23, 2023
-
Configuration menu - View commit details
-
Copy full SHA for c3e4870 - Browse repository at this point
Copy the full SHA c3e4870View commit details
Commits on Nov 24, 2023
-
Configuration menu - View commit details
-
Copy full SHA for aeed449 - Browse repository at this point
Copy the full SHA aeed449View commit details -
Remove GetTypeFromAssemblyQualifiedName()
Fixes: #1165 Context: #1157 If we more strongly rely on JNI signatures, we can remove the need for Java Callable Wrappers to contain assembly-qualified type names, thus removing the need for `ManagedPeer` to use `Type.GetType()` entirely, removing the [IL2057][0] warnings. Furthermore, if we add `[DynamicallyAccessedMembers]` to `JniRuntime.JniTypeManager.GetType()`, we can fix some [IL2075][1] warnings which appeared after fixing the IL2057 warnings. Aside: Excising assembly-qualified type names from Java Callable Wrappers had some "interesting" knock-on effects in the unit tests, requiring that more typemap information be explicitly provided. (This same information was *implicitly* provided before, via the provision of assembly-qualified type names everywhere…) [0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-warnings/IL2057 [1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-warnings/il2075
Configuration menu - View commit details
-
Copy full SHA for 1e71988 - Browse repository at this point
Copy the full SHA 1e71988View commit details
Commits on Dec 2, 2023
-
Configuration menu - View commit details
-
Copy full SHA for 1b7be6c - Browse repository at this point
Copy the full SHA 1b7be6cView commit details
Commits on Dec 3, 2023
-
Configuration menu - View commit details
-
Copy full SHA for 14f6713 - Browse repository at this point
Copy the full SHA 14f6713View commit details
Commits on Feb 9, 2024
-
Configuration menu - View commit details
-
Copy full SHA for 508dcde - Browse repository at this point
Copy the full SHA 508dcdeView commit details
Commits on Feb 16, 2024
-
Configuration menu - View commit details
-
Copy full SHA for 74248fb - Browse repository at this point
Copy the full SHA 74248fbView commit details -
Configuration menu - View commit details
-
Copy full SHA for 12e187e - Browse repository at this point
Copy the full SHA 12e187eView commit details -
Configuration menu - View commit details
-
Copy full SHA for cfdfeaf - Browse repository at this point
Copy the full SHA cfdfeafView commit details -
Configuration menu - View commit details
-
Copy full SHA for 0803048 - Browse repository at this point
Copy the full SHA 0803048View commit details -
Configuration menu - View commit details
-
Copy full SHA for f8bb97f - Browse repository at this point
Copy the full SHA f8bb97fView commit details -
Configuration menu - View commit details
-
Copy full SHA for 12cda04 - Browse repository at this point
Copy the full SHA 12cda04View commit details -
Configuration menu - View commit details
-
Copy full SHA for 3861773 - Browse repository at this point
Copy the full SHA 3861773View commit details -
Configuration menu - View commit details
-
Copy full SHA for adf5773 - Browse repository at this point
Copy the full SHA adf5773View commit details -
Set publishWebProjects: false.
`Hello-NativeAOTFromJNI.csproj` isn't an ASP.NET project, so it isn't a web project, and shouldn't be treated as such. We want to invoke the "real" `dotnet publish` command. Also use `projects: path/to/Hello-NativeAOTFromJNI.csproj`, just in case.
Configuration menu - View commit details
-
Copy full SHA for 65f7d90 - Browse repository at this point
Copy the full SHA 65f7d90View commit details -
Currently fails with: /Users/runner/work/1/s/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets(101,5): error MSB6003: The specified task executable "sh" could not be run. System.IO.DirectoryNotFoundException: The working directory "bin/Release/osx-x64/publish/" does not exist. [/Users/runner/work/1/s/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj] Maybe if we set workingDirectory to `samples/Hello-NativeAOTFromJNI` it will work?
Configuration menu - View commit details
-
Copy full SHA for 429bb4d - Browse repository at this point
Copy the full SHA 429bb4dView commit details -
Setting workingDirectory didn't fix things.
Printf debug this; what is `$(PublishDir)` when running `RunJavaSample`? What files exist?
Configuration menu - View commit details
-
Copy full SHA for b4cddb7 - Browse repository at this point
Copy the full SHA b4cddb7View commit details -
Configuration menu - View commit details
-
Copy full SHA for 42c7251 - Browse repository at this point
Copy the full SHA 42c7251View commit details -
This is quite confusing; as per CI logs, during `dotnet publish`: Hello-NativeAOTFromJNI -> /Users/runner/work/1/s/samples/Hello-NativeAOTFromJNI/bin/Release/osx-x64/publish/ which implies to me that `/Users/runner/work/1/s/samples/Hello-NativeAOTFromJNI/bin/Release/osx-x64/publish` *exists*. However, when we get to `dotnet build -t:RunJavaSample`: ##[error]samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets(106,5): Error MSB6003: The specified task executable "sh" could not be run. System.IO.DirectoryNotFoundException: The working directory "/Users/runner/work/1/s/samples/Hello-NativeAOTFromJNI/bin/Release/osx-x64/publish/" does not exist. Which looks the same to me! Dump out dir contents.
Configuration menu - View commit details
-
Copy full SHA for f656870 - Browse repository at this point
Copy the full SHA f656870View commit details -
Through the glory of printing the contents of the directory after `dotnet publish` and as part of `dotnet build -t:RunJavaSample`, we see that the `$(PublishDir)` `bin/Release/osx-x64/publish` exists after `dotnet publish`, but is *gone* when `dotnet build` runs (?!). In its place is a `publish.zip` file, which doesn't do us any good! We thus infer and assume that the DotNetCoreCLI@2 task is creating this `publish.zip` file and removing the directory, which prevents the execution step from actually executing. Replace DotNetCoreCLI@2 with a powershell script which directly invokes `dotnet publish` & co. Hopefully this will avoid the problem.
Configuration menu - View commit details
-
Copy full SHA for 1b8b1af - Browse repository at this point
Copy the full SHA 1b8b1afView commit details -
Configuration menu - View commit details
-
Copy full SHA for 59314fc - Browse repository at this point
Copy the full SHA 59314fcView commit details -
Fix some
dotnet publish
linker warnings.Warnings fixed: `Type.MakeGenericType()` needs to ensure constructors are preserved: src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs(378): Trim analysis warning IL2068: Java.Interop.JniRuntime.JniValueManager.<GetInvokerType>g__MakeGenericType|31_1(Type,Type[]): 'Java.Interop.JniRuntime.JniValueManager.<GetInvokerType>g__MakeGenericType|31_1(Type,Type[])' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors' requirements. The parameter 'type' of method 'Java.Interop.JniRuntime.JniValueManager.<GetInvokerType>g__MakeGenericType|31_1(Type,Type[])' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. `Expression.New()` requires the constructor be kept, so "fake it" by wrapping `Type.GetType()` w/ `[DynamicallyAccessedMembers]`: src/Java.Interop/Java.Interop/JniValueMarshaler.cs(175): Trim analysis warning IL2072: Java.Interop.JniValueMarshaler.CreateSelf(JniValueMarshalerContext,ParameterExpression): 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Linq.Expressions.Expression.New(Type)'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. `[DynamicallyAccessedMembers]` should be on properties, not getters: src/Java.Interop/Java.Interop/JniValueMarshalerAttribute.cs(33): Trim analysis warning IL2078: Java.Interop.JniValueMarshalerAttribute.MarshalerType.get: 'Java.Interop.JniValueMarshalerAttribute.MarshalerType.get' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor', 'DynamicallyAccessedMemberTypes.Interfaces' requirements. The field 'Java.Interop.JniValueMarshalerAttribute.<MarshalerType>k__BackingField' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. Silence use of `Assembly.Location`, when it's optional: src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs(106): warning IL3000: Java.Interop.JreRuntime.CreateJreVM(JreRuntimeOptions): 'System.Reflection.Assembly.Location.get' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'. src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs(323): warning IL3000: Java.Interop.JreNativeMethods..cctor(): 'System.Reflection.Assembly.Location.get' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.
Configuration menu - View commit details
-
Copy full SHA for 2a012c7 - Browse repository at this point
Copy the full SHA 2a012c7View commit details -
Configuration menu - View commit details
-
Copy full SHA for f79d3e1 - Browse repository at this point
Copy the full SHA f79d3e1View commit details -
$(Standalone) by default, and prefer
native-library
loader in JreRu……ntime. These changes mean we don't need `java-interop.dll` on Windows, which vastly simplifies things.
Configuration menu - View commit details
-
Copy full SHA for 213a57b - Browse repository at this point
Copy the full SHA 213a57bView commit details -
Configuration menu - View commit details
-
Copy full SHA for cf240f9 - Browse repository at this point
Copy the full SHA cf240f9View commit details