Skip to content

[Breaking change]: Single-file applications no longer always look for native libraries in executable directory #46356

Open
@elinor-fung

Description

@elinor-fung

Description

Previously, in single-file .NET applications, the directory of the single-file executable was added to the NATIVE_DLL_SEARCH_DIRECTORIES property during startup. This means that the application directory was always probed when loading unmanaged libraries. On non-Windows with NativeAOT, the rpath was set to the application directory by default, such that it also always looked for native libraries in the application directory.

The application directory is no longer added to NATIVE_DLL_SEARCH_DIRECTORIES in single-file and the rpath i setting has been removed in NativeAOT. In both cases, DllImportSearchPath.AssemblyDirectory (included in the default behaviour for p/invokes) means the application directory - specifying that flag or leaving the default will look in the application directory. Specifying flags without that value will no longer look in the application directory.

Issue: dotnet/runtime#114717
PR: dotnet/runtime#115236

Version

.NET 10 Preview 6

Previous behavior

Single-file applications always looked in the application directory when loading native libraries. NativeAOT applications on non-Windows always looked in the application directory when loading native libraries.

This meant that the following p/invoke would actually look in the application directory for lib and load it from there if it exists:

[DllImport("lib")
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
static extern void Method()

New behavior

Single-file applications only look in the application directory if the search paths for a native library load indicate including the assembly directory.

// Look in System32 on Windows, OS search on non-Windows
[DllImport("lib")
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
static extern void Method()

// Look next to the single-file app because assembly directory means application directory for single-file
[DllImport("lib")
[DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
static extern void Method()

// Look next to the single-file app (because we search assembly directory by default), then default OS search
[DllImport("lib")
static extern void Method()

Type of breaking change

  • Binary incompatible: Existing binaries might encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
  • Source incompatible: When recompiled using the new SDK or component or to target the new runtime, existing source code might require source changes to compile successfully.
  • Behavioral change: Existing binaries might behave differently at run time.

Reason for change

The existing behaviour - always looking in the application directory even if search paths exclude it - has caused confusion in the past. It is also inconsistent with how the search flags are handled in regular (non-single-file, non-NativeAOT) .NET applications.

Recommended action

If the application/assembly directory is desired for a p/invoke or native library load and was not previously specified, specify DllImportSearchPath.AssemblyDirectory.

If the RPATH setting is desired in NativeAOT, explicitly add the corresponding linker args to your project: https://learn.microsoft.com/dotnet/core/deploying/native-aot/interop#linking

Feature area

Interop

Affected APIs

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Status

🔖 Ready

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions