Analyzers for publish only functionality
See original GitHub issueProblem statement
For example for application trimming the goal is to make the experience predictable, as such the plan is to employ multiple tools to provide feedback to the user about the application’s compatibility with trimming. The same applies to single-file publishing, AOT publishing and potentially more.
These tools will run in different stages of the SDK pipeline. Roslyn analyzers will be added to provide immediate feedback about the source code during code editing and in inner build loops. There’s already the ILLink tool which performs trimming but also analyses the app as a whole and provides feedback about the entire app. In the future there might be a “global analysis” tool somewhere in between these two.
All these tools need to be enabled only when it makes sense. If the user has no plans to ever trim the application, it would be a bad experience to show warnings about trimming.
Similarly for single-file there’s an existing Roslyn analyzer and we plan to add single-file analysis into ILLink tool.
Currently the SDK defines properties which turn on the respective feature during publish. For example PublishTrimmed=true
turns on trimming of the application, PublishSingleFile=true
turns on publishing as single-file and so on. These properties only take effect during dotnet publish
.
Ability to declare intent
To be able to keep all of the various parts of SDK in sync and provide consistent experience there needs to be a mechanism through which user declares an intent to use a publishing feature. For example a way to declare the intent to trim the application. Such mechanism must be in place across the entire SDK pipeline and not just during the publish phase.
The proposal is to repurpose the existing properties which turn on various publishing modes like PublishTrimmed
or PublishSingleFile
. Currently these properties only take effect during publish. The new behavior would be that these properties declare the intent to use their respective feature in the app.
Note: We’ve already started on this with the Roslyn single-file analyzer which is enabled only when PublishSingleFile=true
. For it to work well, the property needs to be set in project file so that it’s effective in builds, IDE and publish all the same. This proposal is to turn this into a general approach and design the end-to-end experience around it.
This would mean:
- Unlike today, it would be much more common to specify these properties in the applications project file itself.
- The values defined in the project file would become defaults for publishing, but they could be overwritten by specifying new values for a specific publish run. This is how it already works today, it’s just not very common to specify these properties in the project file.
- SDK would still need to guarantee that the properties do not directly affect results of actions like build or run. For example setting
PublishSingleFile=true
does not make the SDK to produce a single-file executable indotnet build
. This also is already the case today. - It is expected that some behavior will change even for build and run. For example
PublishTrimmed=true
would disable startup hooks in the application by default, for all configurations, includingdotnet build
. This is to make the experience consistent and in line with the goal that for example the action of trimming the application doesn’t change its behavior. (As oppose to making the application compatible with trimming may change its behavior. Such a change can mean a direct code change or configuration change, like in this example disabling a feature switch.).
See dotnet/sdk#14475 for a proposal on changing default feature switch values when trimming is enabled. - Various analysis tools would rely on these properties to enable/disable specific analysis for a given feature (trimming, single file, …).
- Current VS UI has these properties in the publishing workflow only, they would need to be promoted to project-wide workflow, but also stay in the publishing workflow as overrides.
- There’s a downside in which the properties are called “Publish…” but now they would have noticeable effect outside of publish phase.
An example of declaring the intent to trim the app:
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
Alternative solutions
- Introduce a new property which would only declare the intent to eventually use trimming (or single-file, …), but leave the existing property to define the actual action of performing the trimming (or bundling to single-file, …). Such property would be harder to discover and less likely for users to use correctly.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:4
- Comments:10 (9 by maintainers)
Top GitHub Comments
Huh, I actually thought it was the reverse. Good to know you can write MSBuild for years and still fundamentally misunderstand the evaluation model.
Just FYI: I updated the issue description to include the fact that project settings for these properties should be conditional, to allow command-line overrides.
I do agree that we’re walking a bit of a fine line between keeping the “with or without trimming works the same” and “good defaults” solutions.
Maybe I’ll describe what I think is a good place to be in with a “sample”:
The above will run the app 5 times. I would like to get to a place where all 5 times the app behaves as close to “the same” as possible. But at the same time, we can have good defaults for trimming, single-file, self-contained and so on, meaning ideally no warnings from linker, small app size, …
Trimming is the most problematic right now (AOT will be even worse in the future), because some features of .NET are inherently incompatible with it (startup-hooks is a good example).
So to this end I think we can describe it as:
There are other aspects to this, not just trimming:
net5.0-windows
as theTargetFramework
in which case the app is allowed to call windows specific APIs (and will get a new assembly which exposes these APIs). Similarly fornet5.0-android
ornet5.0-ios
and so on.We should have (and in some cases already have) analyzers which validate that the app uses only the allowed APIs. For example the platform specific APIs go deeper into actual version of the OS it runs on and which APIs the OS exposes. The analyzer then validates that the code correctly “lights up” based on actual OS/version values at runtime.
Note that the TFMs are declared in the project file, and then at publish time I can ask to build the app for a specific RID and it has to be compatible with the pre-declared TFMs. The analyzers try to make sure that the app will behave consistently across all of these TFMs (in this case it doesn’t mean “the same”, it means it will not try to call API which doesn’t exist).
If I “constrain” myself to just TFM=
net5.0
, then the app can’t use any platform specific APIs. I declare this restriction in the project file and then all of “build” and “publish” respect that restriction.Trimming can be treated very similarly. In order to make the app compatible with trimming, I need to restrict it to only the set of behaviors (APIs, …) which are compatible with trimming. The proposal is to do that in the project file by setting
PublishTrimmed=true
. After that any “build” or “publish” should respect that and behave consistently (in case of trimming the consistent ~= the same). Feature switches are a good example how to achieve this - they try to make sure the behavior is the same trimming or not. Linker and all of its smarts is another way achieve it - linker tries hard to not change the behavior of the app. If it can’t do that, it issues a warning (just like the platform specific API analyzer above warns if API which will not be available is called).Sorry for the long description - we need to work on this some more to distill this down to a short message, but I think the general idea/intent is as I describe above.
Maybe the
Publish*
name is unfortunate, since the meaning is somewhat different in the new world - and maybe we should go through the pain to rename it, to better fit the new usage patterns. Or introduce a new property and accept the issues with discoverability.