NativeAOT: LinkNative target fails with MSB4086 when NativeLib=Static and LinkerFlavor=lld

Open Beginner friendly
#126,978 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
68/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
android, csharp
Domain
build-system

Research direction

Inspect Microsoft.NETCore.Native.targets around the LinkNative conditions and Microsoft.NETCore.Native.Unix.targets around _LinkerVersion detection. Reproduce a Static build with LinkerFlavor=lld, then verify both numeric comparisons are guarded consistently and the build no longer reports MSB4086.

Written by the indexing model from the issue text.

Description

area-NativeAOT-coreclr

This content was created with assistance from AI.

Description

When NativeLib=Static is set (to have ILC produce a .a archive instead of a shared library), the LinkNative target in Microsoft.NETCore.Native.targets fails with:

Microsoft.NETCore.Native.targets(351,96): error MSB4086: A numeric comparison was attempted on "$(_LinkerVersion)" that evaluates to "" instead of a number, in condition '$(LinkerFlavor)' == 'lld' and '$(_LinkerVersion)' > '12'"

Root Cause

In Microsoft.NETCore.Native.Unix.targets, the _LinkerVersion detection is correctly skipped when NativeLib=Static:

<!-- Line ~332: version detection is skipped for static builds -->
<Exec Command="&quot;$(CppLinker)&quot; -fuse-ld=lld -Wl,--version"
      Condition="'$(LinkerFlavor)' == 'lld' and '$(NativeLib)' != 'Static'" ...>

However, in Microsoft.NETCore.Native.targets, the CustomLinkerArg item group inside LinkNative evaluates _LinkerVersion without the same NativeLib guard:

<!-- Line ~351: no NativeLib guard on this condition -->
<CustomLinkerArg Include="-Wl,-T,&quot;$(NativeIntermediateOutputPath)sections.ld&quot;"
                 Condition="'$(LinkerFlavor)' == 'lld' and '$(_LinkerVersion)' > '12'" />

The same issue exists on line ~368:

<WriteLinesToFile ... Condition="... '$(LinkerFlavor)' == 'lld' and '$(_LinkerVersion)' > '12'" />

Since _LinkerVersion is empty (detection was skipped), the numeric comparison '' > '12' causes MSBuild error MSB4086.

When This Triggers

This triggers when:

  1. NativeLib=Static (so version detection is skipped), AND
  2. LinkerFlavor=lld (set automatically for android, linux-bionic, and freebsd targets)

This combination occurs when Android or other platforms set NativeLib=Static to take ownership of the final native link step (producing their own shared library from the ILC .o output), following the same pattern used by xamarin-macios.

Suggested Fix

Add '$(NativeLib)' != 'Static' to the conditions on lines ~351 and ~368, consistent with the guard on the version detection itself:

<CustomLinkerArg Include="-Wl,-T,&quot;$(NativeIntermediateOutputPath)sections.ld&quot;"
                 Condition="'$(LinkerFlavor)' == 'lld' and '$(NativeLib)' != 'Static' and '$(_LinkerVersion)' > '12'" />

Alternatively, the version detection could default _LinkerVersion to 0 when skipped, so the comparison always succeeds safely.

Workaround

Clear LinkerFlavor before LinkNative runs:

<PropertyGroup>
  <LinkerFlavor />
</PropertyGroup>

This must be done inside a target (not a static PropertyGroup) because the ILC Unix targets set LinkerFlavor in a static PropertyGroup that evaluates after the consumer's import.

Dominant language
C#
Stars
18.3k
Forks
5.6k
Avg merge
2d 19h
Merged PRs (30d)
589

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from dotnet/runtime

All issues in dotnet/runtime

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.