[msbuild] Restore library resources on incremental builds Fixes #5755#26004
Conversation
Image assets (and other compiled resources) coming from referenced libraries were lost on incremental builds. When a library is referenced, its embedded resources are extracted by the `_UnpackLibraryResources` target into typed item groups (`ImageAsset`, `AtlasTexture`, `InterfaceDefinition`, `Collada`, `CoreMLModel`, `SceneKitAsset`). That target is incremental (keyed on the referenced assemblies), so on a rebuild where the library is unchanged it's skipped and those item groups end up empty. For most resource types this is harmless because the resulting files are copied individually and persist in the app bundle. But image assets from all projects are compiled together into a single `Assets.car` by `actool`. When an app-owned asset changes, `actool` re-runs and regenerates `Assets.car` from the (now empty of library assets) `ImageAsset` group, dropping every image asset that came from a referenced library. Fix this the same way the partial app manifests are already handled: route the unpacked typed resources to private item groups, cache them to disk, and restore them into the real item groups from a new always-run `_LoadUnpackedLibraryResources` target, so they're present even when `_UnpackLibraryResources` is skipped. Also add a regression test that builds an app referencing a library with image assets, touches an app-owned asset to force `actool` to re-run, and verifies the library's asset is still present in `Assets.car`. Fixes #5755 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
Fixes an MSBuild incremental-build issue where typed resources (notably ImageAsset inputs to actool) unpacked from referenced libraries could disappear from the item graph when _UnpackLibraryResources is skipped, causing Assets.car to be regenerated without library assets (#5755).
Changes:
- Cache typed resources produced by
_UnpackLibraryResourcesto disk and restore them via a new always-run_LoadUnpackedLibraryResourcestarget before asset compilation. - Add a regression test that builds an app referencing a library with
.xcassets, forcesactoolto re-run by touching an app asset, and asserts the library image asset remains inAssets.car. - Add app-owned
.xcassetsto the test app project to ensureactoolruns for the app itself.
Reviewed changes
Copilot reviewed 5 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/dotnet/UnitTests/AssetsTest.cs | Adds a regression test that verifies referenced-library image assets survive incremental rebuilds that re-run actool. |
| tests/dotnet/AppWithLibraryWithResourcesReference/shared.csproj | Includes an app-owned ImageAsset item so actool runs and can reproduce the incremental-loss scenario. |
| tests/dotnet/AppWithLibraryWithResourcesReference/AppImages.xcassets/Contents.json | Adds the root asset catalog metadata for the test app’s image assets. |
| tests/dotnet/AppWithLibraryWithResourcesReference/AppImages.xcassets/AppImage.imageset/Contents.json | Adds the imageset metadata for the app-owned AppImage asset used in the regression test. |
| msbuild/Xamarin.Shared/Xamarin.Shared.targets | Routes unpacked typed resources to private item groups, writes them to cache files, and restores them via _LoadUnpackedLibraryResources during incremental builds. |
Address PR review feedback: _LoadUnpackedLibraryResources restored cached typed resources whenever the cache files existed, even for a library that was removed since the last full unpack. When several libraries are referenced and only one is removed, _UnpackLibraryResources is skipped (the remaining references are unchanged), so the combined cache would keep re-adding the removed library's resources - and its image assets would get compiled into Assets.car again. Read each cache into a private _CachedUnpacked* group and only restore items whose 'BundledInAssembly' is still among the current @(_UnpackLibraryResourceItems), mirroring the existing per-library _BundleResourceWithLogicalName restore behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7e4e7bdd-8fa5-46c8-8649-9e84e6129329
This comment has been minimized.
This comment has been minimized.
✅ API diff for current PR / commitNET (empty diffs)✅ API diff vs stableNET (empty diffs)ℹ️ Generator diffGenerator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes) Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
🚀 [CI Build #811c9e2] Test results 🚀Test results✅ All tests passed on VSTS: test results. 🎉 All 199 tests passed 🎉 Tests counts✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download macOS tests✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download Linux Build VerificationPipeline on Agent |
Image assets (and other compiled resources) coming from referenced
libraries were lost on incremental builds.
When a library is referenced, its embedded resources are extracted by the
_UnpackLibraryResourcestarget into typed item groups (ImageAsset,AtlasTexture,InterfaceDefinition,Collada,CoreMLModel,SceneKitAsset). That target is incremental (keyed on the referencedassemblies), so on a rebuild where the library is unchanged it's skipped
and those item groups end up empty.
For most resource types this is harmless because the resulting files are
copied individually and persist in the app bundle. But image assets from
all projects are compiled together into a single
Assets.carbyactool.When an app-owned asset changes,
actoolre-runs and regeneratesAssets.carfrom the (now empty of library assets)ImageAssetgroup,dropping every image asset that came from a referenced library.
Fix this the same way the partial app manifests are already handled: route
the unpacked typed resources to private item groups, cache them to disk,
and restore them into the real item groups from a new always-run
_LoadUnpackedLibraryResourcestarget, so they're present even when_UnpackLibraryResourcesis skipped.Also add a regression test that builds an app referencing a library with
image assets, touches an app-owned asset to force
actoolto re-run, andverifies the library's asset is still present in
Assets.car.Fixes #5755
🤖 Pull request created by Copilot