WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

What files can be deleted when publishing an unpackaged app?

Open BenJKuhn opened this issue 3 years ago • 4 comments

I'm opening this since I suspect we need more detailed documentation on this topic.

Discussed in https://github.com/microsoft/WindowsAppSDK/discussions/2001

Originally posted by AzAgarampur January 21, 2022 After building my unpackaged app in Release, there are some files in the release directory that seem to be used only when creating MSIX packages, not unpackaged apps. I already deleted the .pdb and linker files because they are unnecessary, but what about the .winmd files and .pri files?

For a test, create an unpackaged app using the directions on microsoft docs. Build in release, then remove the pdb and extra linker files. Then, delete everything except the .XBF files. Run the program, and notice how it runs the same compared to if the files were present.

Is this safe to do, and in what situations will we need those other files?

On the other hand, is there a way for .XBFs to be merged into our app the same way they are merged if you are publishing a C++/WinRT or C# UWP app?

BenJKuhn avatar Jan 24 '22 20:01 BenJKuhn

There are a few ways in which the WinMD files might be used at runtime. We've always required them to be present in UWPs in part to support tooling in the store submission pipeline, and in part for use at runtime.

Here are a few ways the metadata might be used at runtime:

  1. Metadata based marshalling. WinRT APIs are built on COM concepts, and App SDK Apps, like UWP Apps, use COM apartments pretty extensively. To pass an object between apartments, the object needs to be apartment-agile or be marshalable. For all system objects, we pre-compile the marshallers and build them into the OS. This provides slightly better performance, esp. on first use. However, there are quite a few build steps involved in creating the DLLs and registering them. To simplify this for app developers, we created metadata-based marshalling. The COM marshaller knows how to search the metadata for an interface, generate the NDR marshalling strings based on metadata, and create proxies from that. In practice, this is pretty narrowly used, mostly for delegates created on the UI thread to satisfy async completion of operations like IO and networking. Since the system types are already registered, applications only encounter this if they introduce their own async APIs or events. The Windows App SDK does have instances of this, so there are cases where this might arise depending on how the projection implements delegates under the covers (C# WinRT or C++ WinRT, for example).

  2. API existence checks. If you're trying to write "light-up" code that dynamically asks if a feature is present, the light-up functionality answer the question by examining the metadata. This is most often used with OS behavior, but will become a growing consideration with Windows App SDK as more code is built on top of it over time.

  3. Runtime projections. This is largely not a consideration at this moment, since the projections that support Windows App SDK right now are all computed at compile-time. For the sake of example though, the original WWA support for JavaScript apps using the Microsoft Chakra engine used runtime parsing of metadata to project the Windows Runtime style APIs into the JavaScript environment. NodeRT (not affiliated with Microsoft) and PyWinRt both use static projections, though there has been calls for a dynamic PyWinRT projection at times because it would reduce the code size quite a bit. Metadata is more compact than any of the generated projections that we've ever produced, though projections for C++ & Rust benefit from being able to scope the generated code to only the set of types statically referenced by the client code.

That's a pretty long answer. In short, you might get away with removing it. It's used very narrowly in practice. But there's some runtime variability in behavior, esp. with async completion and how delegates are called back, that could lead to things working sometimes or most of the time. Async completion can be called back synchronously if the delegate is assigned after the async operation completes. This means that you might not see marshalling on a fast dev machine, but on a more constrained piece of hardware those same operations may actually complete asynchronously and require marshalling of the delegate.

Unless you're extremely concerned about size, it's better to have the metadata present. It's usually not large, and having it present removes the chance of hitting difficult-to-reproduce failures. Unfortunately, there's no deterministic way to test whether you actually need it.

BenJKuhn avatar Feb 10 '22 07:02 BenJKuhn

Apparently when you use Visual Studio's "publish" tool to publish a WinUI 3 app (unpackaged, C#), the "publish" tool knows what to keep and what to get rid of. Example:

image

This results in the following output: image

However, if I clear the "produce single file" option, this is the output: image

So this results in a few things:

  • XBF and other resources are being merged into the .PRI files
  • Somehow the "publish" command knows that the winmd is unnecessary (or it is in the PRI, but I don't think that can happen), or it is just forgetting the winmd altogether. (read PS note at the bottom)
  • C++ apps build in Release do not have any XBF files merged into a PRI file, or anything else merged as well (basically the original question I asked here)

If the proper behavior can be published, or maybe a "publish" feature for C++ apps can be created, this would help alleviate most of the problems.

PS: I think the winmds are created for C++ apps because of the compiler's "generate windows runtime metadata setting". If you look at C# apps, there are no winmds created at all. Unless they might be created only when needed.

AzAgarampur avatar Mar 26 '22 17:03 AzAgarampur

Did some research, it seems like for C++ projects, the generated .pri file already has the XBF inside of it (checked with makepri dump command), and the XBF files are just copied and seem to have no use. There was also an issue here that was asking if XBFs for C++ projects were intentionally left out of the pri, I just cant seem to remember where the issue was.

AzAgarampur avatar Mar 26 '22 18:03 AzAgarampur

Apparently when you use Visual Studio's "publish" tool to publish a WinUI 3 app (unpackaged, C#), the "publish" tool knows what to keep and what to get rid of. Example:

image

This results in the following output: image

However, if I clear the "produce single file" option, this is the output: image

So this results in a few things:

  • XBF and other resources are being merged into the .PRI files
  • Somehow the "publish" command knows that the winmd is unnecessary (or it is in the PRI, but I don't think that can happen), or it is just forgetting the winmd altogether. (read PS note at the bottom)
  • C++ apps build in Release do not have any XBF files merged into a PRI file, or anything else merged as well (basically the original question I asked here)

If the proper behavior can be published, or maybe a "publish" feature for C++ apps can be created, this would help alleviate most of the problems.

PS: I think the winmds are created for C++ apps because of the compiler's "generate windows runtime metadata setting". If you look at C# apps, there are no winmds created at all. Unless they might be created only when needed.

Using your same template project and performing publishing - regardless a specific target/configuration - i noticed that if you set in the main .csproj file the <EnableMsixTooling>false</EnableMsixTooling> you won't have any .pri file in the published output dir ( and your app won't run obviously ), while in the build output dir nothing will change. Setting to "true" the above prop, you will get the resources.pri file in published output dir. I don't know if it's by design, but it does not seems well documented this behavior.

David-Buyer avatar Aug 23 '22 16:08 David-Buyer