Skip to content

Fix native lib resolution for cross-arch publish (#205)#206

Open
JamestsaiTW wants to merge 3 commits into
CoreyKaylor:mainfrom
JamestsaiTW:upstream-cross-arch-publish
Open

Fix native lib resolution for cross-arch publish (#205)#206
JamestsaiTW wants to merge 3 commits into
CoreyKaylor:mainfrom
JamestsaiTW:upstream-cross-arch-publish

Conversation

@JamestsaiTW

Copy link
Copy Markdown

Problem

LightningDB.targets's LightningDBIncludeNativeDll target selects the native lmdb/liblmdb binary based on the build machine's OS/architecture (RuntimeInformation.OSArchitecture / MSBuild.IsOsPlatform), instead of the target RuntimeIdentifier. This breaks dotnet publish -r <rid> when publishing for a different architecture/OS than the host (issue #205).

Fix

The .NET SDK already resolves native binaries correctly per the target RID via the standard NuGet runtimes/{rid}/native package layout + .deps.json runtimeTargets, including in transitive PackageReference scenarios (App -> ProjectReference -> Library -> PackageReference(LightningDB)), where the custom target's host-arch copy could otherwise win the SDK's asset conflict resolution and copy the wrong binary.

To fix this while preserving compatibility for legacy packages.config / non-SDK-style consumers (the original reason this target was added, per be15808, for net45 support), the LightningDBIncludeNativeDll target now only runs when:

  • $(LightningDBEnableNativeCopyTarget) is explicitly set to true (opt-in, used by this repo's own ProjectReference consumers: LightningDB.Tests, SecondProcess, LightningDB.Benchmarks), or
  • The consuming project is NOT using PackageReference (i.e. $(RestoreProjectStyle) != 'PackageReference' and no @(PackageReference) items) — preserving the original copy-to-output behavior for packages.config consumers.

Modern PackageReference consumers now rely entirely on the SDK's built-in RID-based native asset resolution, which correctly handles the target RID (not the build machine's) in all publish scenarios, including transitive references.

Verification

  • Local repro (App -> Library(ProjectReference) -> PackageReference(LightningDB)), published with -r win-x86, -r win-arm64, -r linux-arm64, -r osx-x64 on a win-x64 host — SHA256 hash comparison confirmed each publish output contained the correct RID-specific native binary (not the host's).
  • RID-less local build/run scenario verified native lib loads successfully.
  • dotnet pack verified the packed nupkg still contains build/LightningDB.targets and all native runtime assets unchanged.
  • Simulated legacy/packages.config consumer (-p:RestoreProjectStyle=PackagesConfig) confirmed the copy-to-output behavior still triggers correctly.
  • dotnet test on LightningDB.Tests (net8.0): 137/138 passing (1 pre-existing unrelated failure that also reproduces on main).
  • Full repo solution build confirmed LightningDB.Tests/SecondProcess/LightningDB.Benchmarks (which opt in via LightningDBEnableNativeCopyTarget=true) still get native DLLs copied for local execution.
  • Additionally validated via an automated CI workflow on my fork (not included in this PR) that packed, published, and SHA256-verified the native asset for 7 RIDs (win-x86/x64/arm64, linux-x64/arm64, osx-x64/arm64) in the transitive PackageReference scenario — all passed.
  • Existing .NET Tests CI workflow (ubuntu-latest/windows-latest/macOS-latest) passes on this branch.

Fixes #205

JamestsaiTW and others added 3 commits July 12, 2026 18:51
)

Stop packing LightningDB.targets as a build asset. The custom target runs in projects that directly reference the package, where a consuming application's RuntimeIdentifier may not be available, and can copy a host-architecture binary into cross-RID publish output.

Keep the standard runtimes/<rid>/native assets in the package so the .NET SDK selects the correct binary for the final application's target RID, including transitive PackageReference scenarios.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep LightningDB.targets in the package for packages.config consumers, but skip its host-architecture copy logic when PackageReference is in use so the SDK can resolve runtimes/<rid>/native assets for the final target RID.

Repository projects explicitly opt in because they consume LightningDB through ProjectReference rather than the packed runtime assets.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 12, 2026 10:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adjusts how native LMDB binaries are copied/resolved so dotnet publish -r <rid> uses the correct target-RID native asset instead of accidentally copying a host-architecture binary via a custom MSBuild target.

Changes:

  • Gate LightningDBIncludeNativeDll so it only runs for legacy non-PackageReference consumers, or when explicitly opted in.
  • Add LightningDBEnableNativeCopyTarget=true to internal ProjectReference consumers so local execution still gets native binaries copied.
  • Update LightningDB.targets with guidance about relying on SDK RID-based native asset resolution for PackageReference consumers.

Reviewed changes

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

File Description
src/SecondProcess/SecondProcess.csproj Opts into legacy native copy target for ProjectReference-based local execution.
src/LightningDB/LightningDB.targets Gates the legacy copy target to avoid overriding SDK RID-based native asset resolution for PackageReference consumers.
src/LightningDB.Tests/LightningDB.Tests.csproj Opts into legacy native copy target for tests when using ProjectReference.
src/LightningDB.Benchmarks/LightningDB.Benchmarks.csproj Opts into legacy native copy target for benchmarks when using ProjectReference.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

<LightningDBTargetRuntimeRelativePath Condition=" '$(LightningDBTargetRuntimeRelativePath)' == '' ">\..\</LightningDBTargetRuntimeRelativePath>
</PropertyGroup>
<Target Name="LightningDBIncludeNativeDll" AfterTargets="BeforeResolveReferences">
<!-- For PackageReference consumers, the SDK resolves runtimes/{rid}/native assets for the app's RID; set LightningDBEnableNativeCopyTarget=true to force the legacy copy behavior (e.g. packages.config or ProjectReference builds). -->
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<LangVersion>13</LangVersion>
<LightningDBEnableNativeCopyTarget>true</LightningDBEnableNativeCopyTarget>
<PackageId>LightningDB.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<IsTestProject>true</IsTestProject>
<LightningDBEnableNativeCopyTarget>true</LightningDBEnableNativeCopyTarget>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>13</LangVersion>
<LightningDBEnableNativeCopyTarget>true</LightningDBEnableNativeCopyTarget>
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.

build/LightningDB.targets copies native lib based on build-machine architecture, not the target RuntimeIdentifier (breaks cross-arch dotnet publish)

2 participants