Skip to content

[build] fix make prepare on clean agents: empty $(PkgMono_Unix)#12231

Open
jonathanpeppers wants to merge 1 commit into
mainfrom
jonathanpeppers-fix-mono-unix-path-property
Open

[build] fix make prepare on clean agents: empty $(PkgMono_Unix)#12231
jonathanpeppers wants to merge 1 commit into
mainfrom
jonathanpeppers-fix-mono-unix-path-property

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Summary

The Xamarin.Android Nightly build fails in make jenkins -> make prepare:

/Users/builder/.dotnet/sdk/10.0.302/Microsoft.Common.CurrentVersion.targets(5397,5):
  error MSB3030: Could not copy the file "/runtimes/linux-x64/native/libMono.Unix.so"
  because it was not found.
  [.../build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks.csproj]

The leading bare / shows $(PkgMono_Unix) evaluated to an empty string. The package content is present; the path property was simply never set.

Root cause

$(PkgMono_Unix) comes from GeneratePathProperty="true" on the Mono.Unix PackageReference in MSBuildReferences.projitems. NuGet writes it into obj\*.nuget.g.props, which only a fresh project evaluation picks up. build-tools/scripts/Prepare.proj invoked BootstrapTasks with:

<MSBuild Projects="...BootstrapTasks.csproj" Targets="Restore;Build" />

The MSBuild task evaluates a project once and runs both targets against that single project instance, so unlike the -restore switch it never re-evaluates between Restore and Build. With no pre-existing obj/, the static None item in MonoUnixNative.targets therefore resolved to a root-relative path.

Before 94e4833 the prepare target ran dotnet build Xamarin.Android.BootstrapTasks.sln, whose implicit restore does re-evaluate — which is why this only regressed now, and only on clean agents. A warm obj/ on a dev machine hides it.

Fix

Build these projects out of process with dotnet build, matching the approach in #12199. The change to Prepare.proj here is identical to that PR's, so the two will not conflict. dotnet build restores in a separate evaluation and also writes a .binlog per project, so the next make prepare failure is diagnosable from CI artifacts.

PrepareOpenJDK in DotNet.targets gets the same treatment, since it had the identical latent bug.

Also adds _ValidateMonoUnixPackagePath to MonoUnixNative.targets so an unset $(PkgMono_Unix) reports what is actually wrong rather than an MSB3030 on a nonsense path. It runs BeforeTargets="PrepareForBuild" so it fires before _CopyOutOfDateSourceItemsToOutputDirectory can attempt the copy.

Testing

Verified locally with a clean bin/ and obj/:

  • The old Targets="Restore;Build" pattern reproduces the failure — D:\runtimes\... on Windows, the same empty-prefix bug as CI's /runtimes/....
  • With the guard in place, that same pattern now reports only:
    error : `$(PkgMono_Unix)` is not set. Build this project with `dotnet build` so
    NuGet-generated props are evaluated after restore.
    
  • dotnet build of BootstrapTasks succeeds with 0 warnings and 0 errors, and copies the real libMono.Unix.so (120768 bytes, matching the file in the Mono.Unix package) plus libMono.Unix.dylib.

The `Xamarin.Android Nightly` build fails in `make jenkins` -> `make prepare`:

    /Users/builder/.dotnet/sdk/10.0.302/Microsoft.Common.CurrentVersion.targets(5397,5):
      error MSB3030: Could not copy the file "/runtimes/linux-x64/native/libMono.Unix.so"
      because it was not found.
      [.../build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks.csproj]

The leading bare `/` shows `$(PkgMono_Unix)` evaluated to an empty string. The
package content is present; the path property was simply never set.

`$(PkgMono_Unix)` comes from `GeneratePathProperty="true"` on the `Mono.Unix`
`PackageReference` in `MSBuildReferences.projitems`. NuGet writes it into
`obj\*.nuget.g.props`, which only a *fresh project evaluation* picks up.
`build-tools/scripts/Prepare.proj` invoked BootstrapTasks with:

    <MSBuild Projects="...BootstrapTasks.csproj" Targets="Restore;Build" />

The `MSBuild` task evaluates a project once and runs both targets against that
single project instance, so unlike the `-restore` switch it never re-evaluates
between `Restore` and `Build`. With no pre-existing `obj/`, the static `None`
item in `MonoUnixNative.targets` therefore resolved to a root-relative path.

Before 94e4833 the `prepare` target ran
`dotnet build Xamarin.Android.BootstrapTasks.sln`, whose implicit restore does
re-evaluate, which is why this only regressed now and only on clean agents --
a warm `obj/` on a dev machine hides it.

Build these projects out of process with `dotnet build` instead, matching the
approach in #12199 (the change to `Prepare.proj` here is identical, so the two
will not conflict). `dotnet build` restores in a separate evaluation and also
writes a `.binlog` per project, so the next `make prepare` failure is
diagnosable from CI artifacts. `PrepareOpenJDK` in `DotNet.targets` gets the
same treatment, since it had the identical latent bug.

Also add `_ValidateMonoUnixPackagePath` to `MonoUnixNative.targets` so an unset
`$(PkgMono_Unix)` reports what is actually wrong rather than an `MSB3030` on a
nonsense path. It runs `BeforeTargets="PrepareForBuild"` so it fires before
`_CopyOutOfDateSourceItemsToOutputDirectory` can attempt the copy.

Verified locally with a clean `bin/` and `obj/`:

- the old `Targets="Restore;Build"` pattern reproduces the failure
  (`D:\runtimes\...` on Windows, the same empty-prefix bug as CI's `/runtimes/...`)
- with the guard in place that same pattern now reports only:
  ``error : `$(PkgMono_Unix)` is not set. Build this project with `dotnet build` so NuGet-generated props are evaluated after restore.``
- `dotnet build` of BootstrapTasks succeeds with 0 warnings and 0 errors, and
  copies the real `libMono.Unix.so` (120768 bytes, matching the file in the
  `Mono.Unix` package) plus `libMono.Unix.dylib`

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 99a8e361-6a58-4f81-95ae-6634ebfa7ba4
Copilot AI review requested due to automatic review settings July 24, 2026 18:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes a clean-agent make prepare failure where NuGet GeneratePathProperty values (notably $(PkgMono_Unix)) were unset during build because restore/build were executed in a single MSBuild project evaluation.

Changes:

  • Replace in-proc <MSBuild Targets="Restore;Build"> invocations with out-of-process dotnet build in Prepare.proj for BootstrapTasks and workloads.
  • Apply the same out-of-process dotnet build approach to PrepareOpenJDK in DotNet.targets.
  • Add an early MSBuild guard target in MonoUnixNative.targets to fail with a clear error when $(PkgMono_Unix) is not set.

Reviewed changes

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

File Description
build-tools/scripts/Prepare.proj Switches BootstrapTasks/workloads builds to dotnet build so NuGet path props are available on clean agents.
build-tools/scripts/MonoUnixNative.targets Adds an explicit validation target to error clearly when $(PkgMono_Unix) is missing.
build-tools/scripts/DotNet.targets Updates OpenJDK preparation to use dotnet build for the same restore/evaluation correctness.

@jonathanpeppers
jonathanpeppers enabled auto-merge (squash) July 24, 2026 21:18
@jonathanpeppers

Copy link
Copy Markdown
Member Author

Verified on a real nightly run

Queued Xamarin.Android Nightly (definition 14072) against this branch: build 14762051 at 7e64dfe8.

make jenkins and macOS > Create Installers both succeeded. From the CI log:

Prepare:
  ".../bin/Release/dotnet/dotnet" build ".../Xamarin.Android.Tools.BootstrapTasks.csproj" \
    -p:Configuration=Release -bl:.../msbuild-20260724T112106-bootstrap-tasks.binlog
    Restored .../Xamarin.Android.Tools.BootstrapTasks.csproj (in 940 ms).
    Xamarin.Android.Tools.BootstrapTasks -> .../bin/BuildRelease/net10.0/Xamarin.Android.Tools.BootstrapTasks.dll
  Build succeeded.
      0 Warning(s)
      0 Error(s)
  BinaryLogger wrote to: .../msbuild-20260724T112106-bootstrap-tasks.binlog

Zero occurrences of MSB3030 in the log, and libMono.Unix.so now copies from the real package path (/Users/builder/.nuget/packages/mono.unix/7.1.0-final.1.21458.1/runtimes/...) instead of the root-relative /runtimes/.... The per-project binlogs land as expected.

Stage-level before/after

Stage main 14755074 14759563 this PR 14762051
Build failed failed succeeded
Test APKs skipped skipped failed
Test Localization skipped skipped failed
Test TimeZoneInfo skipped skipped failed

Both prior nightlies died at make jenkins, so every downstream stage was skipped. This is the first run where Build goes green and the pipeline actually reaches the test stages.

About the downstream failures

Unrelated to this change — emulator infrastructure:

error : Unexpected output of 'pm list features' command: 'cmd: Can't find service: package'
error XABAS0000: com.android.tools.build.bundletool...

bundletool is querying an emulator whose package service isn't up yet. It retried 3x and failed. These stages have been skipped for at least the last four nightlies, so there is no green baseline to compare against — they were simply never reachable before. Out of scope here.

@jonathanpeppers jonathanpeppers added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants