[build] fix make prepare on clean agents: empty $(PkgMono_Unix)#12231
[build] fix make prepare on clean agents: empty $(PkgMono_Unix)#12231jonathanpeppers wants to merge 1 commit into
make prepare on clean agents: empty $(PkgMono_Unix)#12231Conversation
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
There was a problem hiding this comment.
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-processdotnet buildinPrepare.projfor BootstrapTasks and workloads. - Apply the same out-of-process
dotnet buildapproach toPrepareOpenJDKinDotNet.targets. - Add an early MSBuild guard target in
MonoUnixNative.targetsto 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. |
Verified on a real nightly runQueued
Zero occurrences of Stage-level before/after
Both prior nightlies died at About the downstream failuresUnrelated to this change — emulator infrastructure:
|
Summary
The
Xamarin.Android Nightlybuild fails inmake jenkins->make prepare: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 fromGeneratePathProperty="true"on theMono.UnixPackageReferenceinMSBuildReferences.projitems. NuGet writes it intoobj\*.nuget.g.props, which only a fresh project evaluation picks up.build-tools/scripts/Prepare.projinvoked BootstrapTasks with:The
MSBuildtask evaluates a project once and runs both targets against that single project instance, so unlike the-restoreswitch it never re-evaluates betweenRestoreandBuild. With no pre-existingobj/, the staticNoneitem inMonoUnixNative.targetstherefore resolved to a root-relative path.Before 94e4833 the
preparetarget randotnet build Xamarin.Android.BootstrapTasks.sln, whose implicit restore does re-evaluate — which is why this only regressed now, and only on clean agents. A warmobj/on a dev machine hides it.Fix
Build these projects out of process with
dotnet build, matching the approach in #12199. The change toPrepare.projhere is identical to that PR's, so the two will not conflict.dotnet buildrestores in a separate evaluation and also writes a.binlogper project, so the nextmake preparefailure is diagnosable from CI artifacts.PrepareOpenJDKinDotNet.targetsgets the same treatment, since it had the identical latent bug.Also adds
_ValidateMonoUnixPackagePathtoMonoUnixNative.targetsso an unset$(PkgMono_Unix)reports what is actually wrong rather than anMSB3030on a nonsense path. It runsBeforeTargets="PrepareForBuild"so it fires before_CopyOutOfDateSourceItemsToOutputDirectorycan attempt the copy.Testing
Verified locally with a clean
bin/andobj/:Targets="Restore;Build"pattern reproduces the failure —D:\runtimes\...on Windows, the same empty-prefix bug as CI's/runtimes/....dotnet buildof BootstrapTasks succeeds with 0 warnings and 0 errors, and copies the reallibMono.Unix.so(120768 bytes, matching the file in theMono.Unixpackage) pluslibMono.Unix.dylib.