Skip to content

Shipping Reactor.pri under lib/ triggers the Windows App SDK PRI-expansion step, which fails on long paths #1271

Description

Summary

Because Microsoft.UI.Reactor (and .Advanced / .Devtools) ship a .pri file under lib/, every app that references the package pulls those files into a reference-related path. That makes the shared Windows App SDK target Microsoft.Windows.SDK.BuildTools.MSIX.MrtCore.PriExpansion.targets run WinAppSdkExpandPriContent → makepri.exe Dump once per .pri, writing into $(IntermediateOutputPath). Those output paths fail once they pass 260 characters, so a Reactor app fails to build at a path depth where the equivalent XAML app builds fine. XAML apps never run this step at all, because WinUI's .pri files live under runtimes-framework/<rid>/native/.

The underlying long-path defect is in the SDK task and I've filed it separately as microsoft/WindowsAppSDK#6795. This issue is a question for you, not a claim that Reactor is doing something wrong: is there a packaging layout that keeps the sidecar delivery you need while not placing the physical .pri in a reference path?

I want to be explicit that I am not proposing "just move the .pri". Your buildTransitive/Microsoft.UI.Reactor.targets (L111-130) documents exactly why these files ship where they do:

ReactorApplication.InitializeComponent loads XAML resources from these sidecar assets. ProjectReference consumers get them from the library output automatically, but PackageReference publish only copies assemblies unless the package target explicitly marks these files for output/publish.

and I confirmed Reactor.pri is not a stub — makepri dump shows it carrying ReactorApplication.xbf as EmbeddedData at ms-resource://Reactor/Files/Reactor/Hosting/ReactorApplication.xbf. Relocating the file naively would trade a build failure for a launch failure.

The narrower question

The <None> items that deliver the sidecars are keyed on a path:

<None Include="$(MSBuildThisFileDirectory)..\lib\**\Reactor.pri"
      Link="Reactor.pri" TargetPath="Reactor.pri"
      CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest"
      Visible="false" />

The file must still be copied to output — that's load-bearing. But does the physical file have to sit in lib/, where _ReferenceRelatedPaths / ReferenceCopyLocalPaths pick it up and feed it to makepri.exe? Could it ship from a non-reference location (build/, content/, …) with these Include paths updated to match, preserving sidecar delivery while removing the expansion trigger?

WinUI's runtimes-framework/<rid>/native/ placement is a precedent, not a template — WinUI is a framework package resolved at runtime, Reactor is a plain library whose sidecars must land next to the consuming app. You'll know constraints here that I don't, which is why this is phrased as a question.

Secondary, cheaper question

ReactorApplication.xbf ships both loose (via the <None> item above) and embedded inside Reactor.pri. Does the .pri need to carry it embedded as well?

Caveat on how far my evidence goes: suppressing the expansion step still leaves all three sidecars (Reactor.pri, ReactorApplication.xbf, ReactorApplication.xaml) in the output, because the <None> items deliver them by a different mechanism — and the app builds, launches and runs. That shows the extraction the expansion performs is redundant for this app. It does not establish which copy InitializeComponent actually reads, and I only tested the default reactor template app. An app relying on an asset present only inside the .pri would be a different case.

Evidence

Four cells, fresh apps via winapp new --template-version installed, identical except for the stated variable. Cell C suppresses only the expansion step by emptying _PriFilesToExpandFromReference immediately before the task runs — no package modified.

Cell Template Path Expansion Built PRI### Longest path produced Runs
A reactor deep stock ❌ failed 6 291 —
B reactor short stock ✅ 0 140 ✅
C reactor deep suppressed ✅ 0 295 —
D winui-mvvm deep stock ✅ 0 295 ✅
E reactor short suppressed ✅ 0 — ✅

Cells C and D build at 295 characters, longer than the 291 at which cell A failed — so this is the step, not build depth generally. Cell E launches and runs (PID returned, Responding = True, real window title), identical to the unsuppressed control.

Cell A's errors:

WINAPPSDKEXPANDPRICONTENT : error : PRI175: 0x80070003 - MakePri failed with error: The system cannot find the path specified.
WINAPPSDKEXPANDPRICONTENT : error : PRI222: 0x80070003 - Unspecified error occurred.
…MrtCore.PriExpansion.targets(53,5): error APPX0002: Task 'WinAppSdkExpandPriContent' failed.
  Could not find file '…\obj\x64\Debug\net10.0-windows10.0.26100.0\win-x64\Microsoft.UI.Reactor.Devtools.pri.xml'.

The three invocations the step generates, from a -v:normal build log:

makepri.exe Dump -IndexFile …\microsoft.ui.reactor\0.1.0-preview.14\lib\net10.0-windows10.0.22621\Reactor.pri                       -OutputFile obj\…\win-x64\Reactor.pri.xml
makepri.exe Dump -IndexFile …\microsoft.ui.reactor.advanced\0.1.0-preview.14\lib\net10.0-windows10.0.22621\Reactor.Advanced.pri     -OutputFile obj\…\win-x64\Reactor.Advanced.pri.xml
makepri.exe Dump -IndexFile …\microsoft.ui.reactor.devtools\0.1.0-preview.14\lib\net10.0-windows10.0.22621\Microsoft.UI.Reactor.Devtools.pri -OutputFile obj\…\win-x64\Microsoft.UI.Reactor.Devtools.pri.xml

With a 173-character project directory those resolve to 239, 248 and 261 characters. Only the third crosses 260 — it has the longest file name, so in practice the Devtools package is what tips a borderline path over. The equivalent winui-mvvm project produces zero of these (AddPriPayloadFilesToCopyToOutputDirectoryItems appears 0 times in its -v:normal -t:Rebuild log, vs. 1 time for the Reactor project).

For completeness: both templates invoke makepri once for their own resources.pri (makepri New). That one is not the problem — only the three extra Dump calls are.

Versions

  • Microsoft.UI.Reactor / .Advanced / .Devtools 0.1.0-preview.14 (pinned by the reactor template in Microsoft.WindowsAppSDK.WinUI.CSharp.Templates 0.0.7-alpha-2026-0911-2329-pr0)
  • Microsoft.Windows.SDK.BuildTools.MSIX 1.7.251221100, Microsoft.Windows.SDK.BuildTools 10.0.28000.2705, Microsoft.WindowsAppSDK 2.5.1
  • TFM net10.0-windows10.0.26100.0, Platform=x64, Configuration=Debug
  • LongPathsEnabled = 1 on the test machine (it makes no difference — makepri.exe isn't long-path aware unless handed a \\?\ path)

The same lib/ placement and the same <None> items are present in 0.1.0-preview.15.13 and 0.1.0-preview.16, so this is current rather than a preview.14 artifact.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions