Skip to content

[NativeAOT] Fix application linking with API level > 21#10812

Merged
grendello merged 4 commits intomainfrom
dev/grendel/naot-link-api-level
Feb 18, 2026
Merged

[NativeAOT] Fix application linking with API level > 21#10812
grendello merged 4 commits intomainfrom
dev/grendel/naot-link-api-level

Conversation

@grendello
Copy link
Contributor

@grendello grendello commented Feb 13, 2026

Context: bef768d
Context: dotnet/runtime#124461

Follow up to bef768d which puts the non-mono builds API level in
several more locations throughout the source. This is necessary for
NativeAOT builds to correctly link as they must use the same API
level .NET for Android was built with. Failure to do so may result
in missing native symbols when linking.

NativeAOT builds now use full path to the linker (in our case clang++)
and pass the --target=${ARCH}-linux-android${API} argument to it, just
like the toolchain wrapper scripts in the NDK do. Without the parameter,
the lowest supported API level will be used (currently 21).

Copilot AI review requested due to automatic review settings February 13, 2026 12:14
@grendello grendello mentioned this pull request Feb 13, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the .NET for Android NativeAOT build/link pipeline so that non-Mono (NativeAOT/CoreCLR) builds consistently use the same Android API level that the runtime pack was built with, avoiding missing native symbols at link time (especially when targeting API > 21).

Changes:

  • Add “non-mono” NDK API level placeholders and propagate them into generated MSBuild props/projitems.
  • Update NativeAOT linking to use the NDK’s clang++ via full path and pass an explicit --target=${ARCH}-linux-android${API} linker argument.
  • Split minimum-supported API metadata for arm64/x86_64 based on runtime flavor.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.props.in Adds non-mono API level properties and runtime-conditional minimum API items (currently with issues).
src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets Wires new placeholder replacements into Common.props generation.
src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets Uses NDK clang++ full path and adds --target=... to linker args.
build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs Adds new placeholder values for non-mono API levels when generating Ndk.projitems.
build-tools/scripts/Ndk.projitems.in Introduces properties/metadata for non-mono API levels for arm64/x64.

Copy link
Member

@jonathanpeppers jonathanpeppers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some errors building NativeAOT projects like:

gcc : error : unrecognized command-line option '--target=x86_64-linux-android21' [C:\a\_work\1\a\TestRelease\02-13_14.27.07\temp\BuildApplicationAndCleanTrueapkNativeAOT\UnnamedProject.csproj]
         gcc : error : unrecognized command-line option '--target=x86_64-linux-android24' [C:\a\_work\1\a\TestRelease\02-13_14.27.07\temp\BuildApplicationAndCleanTrueapkNativeAOT\UnnamedProject.csproj]
         C:\Users\cloudtest\.nuget\packages\microsoft.dotnet.ilcompiler\11.0.0-preview.1.26076.102\build\Microsoft.NETCore.Native.targets(391,5): error MSB3073: The command ""gcc" "obj\Release\android-x64\native\UnnamedProject.o" -o "bin\Release\android-x64\native\UnnamedProject.so" -Wl,--version-script="obj\Release\android-x64\native\UnnamedProject.exports" -Wl,--export-dynamic -gz=zlib -fuse-ld=lld C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libSystem.Native.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libSystem.Globalization.Native.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libSystem.IO.Compression.Native.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libSystem.Security.Cryptography.Native.Android.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libbootstrapperdll.o C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libRuntime.WorkstationGC.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libeventpipe-disabled.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libRuntime.VxsortDisabled.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libstandalonegc-disabled.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libaotminipal.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libbrotlienc.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libbrotlidec.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libbrotlicommon.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libzstd.a --target=x86_64-linux-android21 -g -Wl,--build-id=sha1 -Wl,--as-needed -Wl,-e,0x0 -pthread -ldl -lz -llog -lm -shared -Wl,-z,relro -Wl,-z,now -Wl,--eh-frame-hdr -Wl,-z,max-page-size=16384 --target=x86_64-linux-android24 "-Wl,-soname,libUnnamedProject.so" -Wl,--error-unresolved-symbols -Wl,--no-undefined "C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Runtime.NativeAOT.36.android-x64\36.1.99-ci.dev-grendel-naot-link-api-level.147\runtimes\android-x64\native\libnaot-android.release-static-release.a" "C:\Android\android-sdk\ndk\29.0.14206865\toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_static.a" "C:\Android\android-sdk\ndk\29.0.14206865\toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++abi.a" obj\Release\android-x64\android\jni_init_funcs.x86_64.o obj\Release\android-x64\android\environment.x86_64.o -Wl,--discard-all -Wl,--gc-sections" exited with code 1. [C:\a\_work\1\a\TestRelease\02-13_14.27.07\temp\BuildApplicationAndCleanTrueapkNativeAOT\UnnamedProject.csproj]

@grendello
Copy link
Contributor Author

There are some errors building NativeAOT projects like:

gcc : error : unrecognized command-line option '--target=x86_64-linux-android21' [C:\a\_work\1\a\TestRelease\02-13_14.27.07\temp\BuildApplicationAndCleanTrueapkNativeAOT\UnnamedProject.csproj]
         gcc : error : unrecognized command-line option '--target=x86_64-linux-android24' [C:\a\_work\1\a\TestRelease\02-13_14.27.07\temp\BuildApplicationAndCleanTrueapkNativeAOT\UnnamedProject.csproj]
         C:\Users\cloudtest\.nuget\packages\microsoft.dotnet.ilcompiler\11.0.0-preview.1.26076.102\build\Microsoft.NETCore.Native.targets(391,5): error MSB3073: The command ""gcc" "obj\Release\android-x64\native\UnnamedProject.o" -o "bin\Release\android-x64\native\UnnamedProject.so" -Wl,--version-script="obj\Release\android-x64\native\UnnamedProject.exports" -Wl,--export-dynamic -gz=zlib -fuse-ld=lld C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libSystem.Native.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libSystem.Globalization.Native.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libSystem.IO.Compression.Native.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libSystem.Security.Cryptography.Native.Android.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libbootstrapperdll.o C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libRuntime.WorkstationGC.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libeventpipe-disabled.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libRuntime.VxsortDisabled.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libstandalonegc-disabled.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libaotminipal.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libbrotlienc.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libbrotlidec.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libbrotlicommon.a C:\Users\cloudtest\.nuget\packages\microsoft.netcore.app.runtime.nativeaot.android-x64\11.0.0-preview.1.26076.102/runtimes/android-x64/\native\libzstd.a --target=x86_64-linux-android21 -g -Wl,--build-id=sha1 -Wl,--as-needed -Wl,-e,0x0 -pthread -ldl -lz -llog -lm -shared -Wl,-z,relro -Wl,-z,now -Wl,--eh-frame-hdr -Wl,-z,max-page-size=16384 --target=x86_64-linux-android24 "-Wl,-soname,libUnnamedProject.so" -Wl,--error-unresolved-symbols -Wl,--no-undefined "C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Runtime.NativeAOT.36.android-x64\36.1.99-ci.dev-grendel-naot-link-api-level.147\runtimes\android-x64\native\libnaot-android.release-static-release.a" "C:\Android\android-sdk\ndk\29.0.14206865\toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_static.a" "C:\Android\android-sdk\ndk\29.0.14206865\toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++abi.a" obj\Release\android-x64\android\jni_init_funcs.x86_64.o obj\Release\android-x64\android\environment.x86_64.o -Wl,--discard-all -Wl,--gc-sections" exited with code 1. [C:\a\_work\1\a\TestRelease\02-13_14.27.07\temp\BuildApplicationAndCleanTrueapkNativeAOT\UnnamedProject.csproj]

This is odd, it works fine locally. I'll investigate.

@grendello grendello force-pushed the dev/grendel/naot-link-api-level branch from 72b35dc to 3381021 Compare February 16, 2026 10:28
@grendello
Copy link
Contributor Author

So the reason for NAOT tests failing on Windows was that the <Exec> task is confused by the mixture of Unix and Windows path separator chars in $(_NdkBinDir):

SetupOSSpecificProps:
         where /Q "C:\Android\android-sdk\ndk\29.0.14206865\toolchains/llvm/prebuilt/windows-x86_64/bin/clang++"
     1>EXEC : error : Invalid pattern is specified in "path:pattern". [C:\a\_work\1\a\TestRelease\02-13_14.27.07\temp\BindingCustomJavaApplicationClassNativeAOT\App\UnnamedProject.csproj]
         The command "where /Q "C:\Android\android-sdk\ndk\29.0.14206865\toolchains/llvm/prebuilt/windows-x86_64/bin/clang++"" exited with code 2.
         where /Q "gcc"
         "gcc" -fuse-ld=lld -Wl,--version

@grendello grendello merged commit a4e565c into main Feb 18, 2026
6 checks passed
@grendello grendello deleted the dev/grendel/naot-link-api-level branch February 18, 2026 08:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments