dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.71k stars 1.06k forks source link

SDK targets for post-build transformations #2583

Open sbomer opened 6 years ago

sbomer commented 6 years ago

Numerous tools exist today which perform some transformation on IL or other files that are deployed with a published app. Examples include:

These tools all need to run at similar places during the build, and many of the tools can usefully be used independently. It is desirable for developers to have the final say over which tools run during a build, allowing them to weigh tradeoffs and make the right decision for their apps. I'll be focusing on the linker, but it's worth keeping these other tools in mind.

Some of these tools only provide commandline executables, leaving the developer to write MSBuild logic or scripts to run the tool during a build. Others attempt to provide full integration with the SDK, providing tasks and targets that can be turned on or off with a simple boolean property.

This proposal is for the SDK to provide a supported, documented way for such tools to make themselves a part of the build, reducing the amount of duplicated effort it takes for tool authors to ship tools that are properly integrated with the rest of the build logic.

This may involve coordination with MSBuild, since some of the relevant targets belong to MSBuild itself. See this issue on MSBuild transformations for details.

Problems with the existing approach

Some of the existing tools (ILLink, CoreRT, Crossgen) ship with their own targets that hook into the SDK to run at the right place. They use BeforeTargets to run just before ComputeFilesToPublish, where they rewrite ResolvedAssembliesToPublish, IntermediateAssembly, and other items to point to the transformed assemblies:

https://github.com/mono/linker/blob/7c11deffc05005b6b60eeccb80a7cf133e24c007/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets#L91-L117

The existing targets are factored in a way that makes transparently rewriting these inputs difficult. These are some of the issues that come up:

Downstream targets implicitly rely on invariants broken by the linker

Upstream targets capture pre-transform values of these ItemGroups

Dependencies between the publish set and other targets are not expressed

Duplicated work to understand inputs to ComputeFilesToPublish

SDK changes break tools that rely on this approach in subtle ways

Duplicate work to handle common build concerns

Cooperative phase ordering

Proposal

We should work together to come up with a contract that defines a single place where the linker and similar rewriting tools can hook in, without having to work around unrelated logic elsewhere in the SDK and MSBuild. As a start, here are the current behaviors I'm aware of, and some requirements for the contract to be useful to each tool. Note that there are many similarities between these tools.

ILLink

Current behavior

Native dependency trimming (part of ILLink.Tasks)

Current behavior

Crossgen

Current behavior

ILC

I'm less aware of the details of this tool, but here's my understanding:

Current behavior

Other tools to consider

It may be helpful to keep in mind Fody, ILMerge, ILRepack, single exe, installer technology, and any tools that filter the publish set, like the runtime store, because they could all benefit from a documented set of behavior around publish, enabling them to work well with the .NET SDK out of the box.

@nguerrera @zamont @swaroop-sridhar @morganbr @jeffschwMSFT

morganbr commented 6 years ago

Thanks for putting this together, @sbomer. Having a supported way to find and change all of the files that would be included in publishing (including all managed assemblies and even miscellaneous files in the app) would make constructing these tools much more straightforward. Phase ordering will also help a lot -- I could easily imagine users wanting to run ILLink, followed by CrossGen, Single exe tooling, or ILC, followed by installer packaging and that ordering is very important. Of course, they might only want to run one or two of those steps as well.

I'd also emphasize the importance of being able to run tools in the build phase instead of publish -- some of these tools, such as ILLink can significantly change application behavior, so developers should be able to debug their app in the same way it will ship.

nguerrera commented 6 years ago

Cc @peterhuene

@sbomer This is a great write up and exactly what I was hoping to see next after our chat. Thanks!

nguerrera commented 6 years ago

Cc @tmat

nguerrera commented 6 years ago

I'd also emphasize the importance of being able to run tools in the build phase instead of publish

Good point. We are also working to effectivity make publish an optional step for common cases in 3.0. Build output will include nuget deoendencies and be xcopyable to other machines.

I'm hoping we can avhieve this while reducing code duplication between build and publish (for example, today they have separate paths for deps.json generation). Ideally this could help mean that such a tools like this can write code once that can easily be configured to run on build or only on publish.