-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Isolate MSBuildTaskHost from the rest of MSBuild Codebase #13232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Copies all shared files and files linked from other projects directly into MSBuildTaskHost. In addition, all <Compile> items in MSBuildTaskHost.csproj have been updated to point to the new files.
Split the PropertyGroup for $(DefineConstants) into two: one for net3* and one for net4*
This polyfill is unused in MSBuildTaskHost.
Since MSBuildTaskHost only targets .NET 3.5, it does not require conditional compilation for FEATURE_LEGACY_GETCURRENTDIRECTORY. It *always* includes the code path that provides an optimized GetCurrentDirectory on .NET Framework targets earlier than 4.6.2.
Since MSBuildTaskHost only targets .NET 3.5, it does not require conditional compilation for FEATURE_LEGACY_GETFULLPATH. It *always* includes the code path that provides an optimized GetFullPath on .NET Framework targets earlier than 4.6.2.
Since MSBuildTaskHost only targets .NET 3.5, System.Reflection.Assembly.Location is always available.
The FEATURE_CULTUREINFO_GETCULTURES code path is unused by MSBuildTaskHost.
The FEATURE_APM code path is always used by MSBuildTaskHost. .NET Framework 3.5 does support System.Threading.Tasks, so MSBuildTaskHost uses the older "asynchronous programming model (APM)".
…Host Many of the FEATURE_* conditional compilation constants defined for .NET 3.5 builds never appear in code compiled within MSBuildTaskHost. This change removes all of those for .NET 3.5 builds.
The FEATURE_PIPE_SECURITY and FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR code paths is always used by MSBuildTaskHost.
The FEATURE_SECURITY_PERMISSIONS code paths are always available in MSBuildTaskHost.
The FEATURE_SECURITY_PRINCIPAL_WINDOWS code paths are always available in MSBuildTaskHost.
The FEATURE_THREAD_ABORT code paths are always available in MSBuildTaskHost.
The FEATURE_VISUALSTUDIOSETUP code paths are never available in MSBuildTaskHost. This constant is always removed from .NET 3.5 builds.
The FeatureAppDomain, FeatureSystemConfiguration, and FeatureXamlTypes properties are not used in .NET 3.5 builds. NOTE: It seems that FeatureAppDomain is the only one of these properties that are used anywhere. However, it is used in a target in Microsoft.Build, which is not built for .NET 3.5.
The FEATURE_REPORTFILEACCESSES code paths are not available in MSBuildTaskHost. This constant was never included in .NET 3.5 builds.
BuildEnvironmentHelper includes a check for AppContext.BaseDirectory that is always returns null on .NET 3.5 and the MSBuildTaskHost. This change removes that check and related code.
VisualStudioLocationHelper.GetInstances() always returns an empty list on .NET 3.5. So, BuildEnvironmentHelper.TryFromSetupApi (the only caller) can be removed from MSBuildTaskHost along with all of VisualStuiodLocationHelper.
RUNTIME_TYPE_NETCORE code paths aren't ever compiled in .NET 3.5 builds.
CopyOnWriteDictionary, ReadOnlyEmptyCollection, and ReadOnlyEmptyDictionary are never used in MSBuildTaskHost and can be safely removed.
Since MSBuildTaskHost only builds for .NET 3.5, there are many code blocks specific to other .NET versions that can be removed. NOTE: Disabled code blocks were intentionally NOT removed from polyfill types.
BUILDINGAPPXTASKS is not relevant when building MSBuildTaskHost, so code compiled with BUILDINGAPPXTASKS can be removed.
MSBuildTaskHost is always compiled with CLR2COMPATIBILITY, so code blocks that aren't compiled with that conditional compilation constant can be removed.
MSBuildTaskHost is always compiled with TASKHOST. So, code blocks disabled when compiled with TASKHOST can be removed.
MSBuildTaskHost is never compiled with FEATURE_ASSEMBLYLOADCONTEXT.
MSBuildTaskHost is never compiled with FEATURE_PIPEOPTIONS_CURRENTUSERONLY. So, code blocks disabled with FEATURE_PIPEOPTIONS_CURRENTUSERONLY can be removed.
MSBuildTaskHost is always compiled with FEATURE_NET35_TASKHOST.
MSBuildTaskHost is always compiled with NO_FRAMEWORK_IVT. So, code blocks disabled under NO_FRAMEWORK_IVT can be removed.
- File-scoped namespace - Expression-bodied members - Enable nullability
- File-scoped namespace - Expression-bodied members - Enable nullability
- File-scoped namespace - Expression-bodied members - Enable nullability
- File-scoped namespace - Expression-bodied members - Enable nullability
- File-scoped namespace - Enable nullability
- File-scoped namespace - Expression-bodied members - Enable nullability - Remove unneeded members
- File-scoped namespace - Expression-bodied members - Enable nullability - Rename to CollectionExtensions
- File-scoped namespace - Expression-bodied members - Enable nullability
- File-scoped namespace - Expression-bodied members - Enable nullability
- File-scoped namespace - Expression-bodied members - Enable nullability
- File-scoped namespace
- File-scoped namespace - Remove uncalled members
- File-scoped namespace - Expression-bodied members - Enable nullability - Remove unneeded members
- File-scoped namespace - Expression-bodied members - Enable nullability - Use pattern matching
- File-scoped namespace - Expression-bodied members - Enable nullability - Remove FixFilePath. This doesn't really do anything in the MSBuildTaskHost, since it always runs on Windows.
- File-scoped namespace - Expression-bodied members - Enable nullability - Rename file to FileUtilities.ItemSpecModifiers.cs - Refactor and break down GetItemSpecModifier for clarity - Use Dictionary<string, ItemSpecModifierKind> rather than HashSet<string> to avoid repeated string comparisons. - Use same approach for ModifiedTime as CreatedTime and AccessedTime, resulting in uncalled methods to remove in FileUtilities.
- File-scoped namespace - Enable nullability
- File-scoped namespace - Expression-bodied members - Enable nullability - Remove unnecessary Trace overloads and use interpolated strings at callsites. - Always perform process sessionId calculation and cache the result, since includeSessionId is always true. - Use Dictionary<,> rather than IDictionary<,>
- File-scoped namespace
- File-scoped namespace - Expression-bodied members - Enable nullability - Add note about STA vs. MTA.
- File-scoped namespace - Expression-bodied members - Enable nullability
- File-scoped namespace - Expression-bodied members
- File-scoped namespace - Seal classes
- File-scoped namespace - Expression-bodied members - Enable nullability - Remove unused parameters - Seal types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR isolates MSBuildTaskHost.exe (the .NET Framework 3.5 task host) into a self-contained codebase so it no longer shares/blocks modernization work in the main MSBuild codebase, while keeping the node/taskhost communication protocol compatible and adding coverage for building a legacy .NET 3.5 project.
Changes:
- Adds a standalone
src/MSBuildTaskHost/codebase (utilities, backend packet protocol, exception transfer, resources). - Refactors task host launch/handshake plumbing to make the tools directory/salt computation deterministic.
- Adds a Windows/.NET Framework + .NET 3.5 installed test that builds a .NET 3.5 WinForms project, gated by a new
WindowsNet35OnlyFactAttribute.
Reviewed changes
Copilot reviewed 92 out of 97 changed files in this pull request and generated 62 comments.
Show a summary per file
| File | Description |
|---|---|
| src/UnitTests.Shared/WindowsNet35OnlyFactAttribute.cs | New test attribute to gate tests on Windows + .NET Framework + .NET 3.5 installed. |
| src/Shared/UnitTests/ImmutableDictionary_Tests.cs | Removes old immutable dictionary tests that depended on the previous taskhost aliasing approach. |
| src/Shared/LogMessagePacketBase.cs | Documents enum value sync requirement with MSBuildTaskHost. |
| src/Shared/INodePacket.cs | Documents packet type sync requirement with MSBuildTaskHost. |
| src/MSBuildTaskHost/Utilities/StringBuilderCache.cs | Adds thread-static StringBuilder cache for allocations reduction in taskhost. |
| src/MSBuildTaskHost/Utilities/ExceptionHandling.cs | Adds taskhost exception classification + dump-to-file support. |
| src/MSBuildTaskHost/Utilities/ErrorUtilities.cs | Adds taskhost-local validation/throw helpers. |
| src/MSBuildTaskHost/Utilities/EnvironmentUtilities.cs | Adds taskhost process/environment helpers (pid/path/session). |
| src/MSBuildTaskHost/Traits.cs | Adds taskhost traits/escape hatches for debug/reuse/long-path toggles. |
| src/MSBuildTaskHost/TaskLoader.cs | Implements task loading and AppDomain isolation logic inside taskhost. |
| src/MSBuildTaskHost/Resources/xlf/SR.zh-Hant.xlf | Taskhost localized resources (zh-Hant). |
| src/MSBuildTaskHost/Resources/xlf/SR.zh-Hans.xlf | Taskhost localized resources (zh-Hans). |
| src/MSBuildTaskHost/Resources/xlf/SR.tr.xlf | Taskhost localized resources (tr). |
| src/MSBuildTaskHost/Resources/xlf/SR.ru.xlf | Taskhost localized resources (ru). |
| src/MSBuildTaskHost/Resources/xlf/SR.pt-BR.xlf | Taskhost localized resources (pt-BR). |
| src/MSBuildTaskHost/Resources/xlf/SR.pl.xlf | Taskhost localized resources (pl). |
| src/MSBuildTaskHost/Resources/xlf/SR.ko.xlf | Taskhost localized resources (ko). |
| src/MSBuildTaskHost/Resources/xlf/SR.ja.xlf | Taskhost localized resources (ja). |
| src/MSBuildTaskHost/Resources/xlf/SR.it.xlf | Taskhost localized resources (it). |
| src/MSBuildTaskHost/Resources/xlf/SR.fr.xlf | Taskhost localized resources (fr). |
| src/MSBuildTaskHost/Resources/xlf/SR.es.xlf | Taskhost localized resources (es). |
| src/MSBuildTaskHost/Resources/xlf/SR.de.xlf | Taskhost localized resources (de). |
| src/MSBuildTaskHost/Resources/xlf/SR.cs.xlf | Taskhost localized resources (cs). |
| src/MSBuildTaskHost/Resources/SR.resx | Taskhost base resource strings. |
| src/MSBuildTaskHost/Properties/AssemblyInfo.cs | Adds IVT for unit tests (moved from removed AssemblyInfo). |
| src/MSBuildTaskHost/Polyfills/NullableAttributes.cs | Adds nullable/analysis attribute polyfills for net35 compilation. |
| src/MSBuildTaskHost/Polyfills/IsExternalInit.cs | Adds init-setter polyfill/type-forwarding support. |
| src/MSBuildTaskHost/Polyfills/CallerArgumentExpressionAttribute.cs | Adds CallerArgumentExpression polyfill/type-forwarding support. |
| src/MSBuildTaskHost/OutOfProcTaskHostTaskResult.cs | Adds task execution result model (success/failure/crash + outputs). |
| src/MSBuildTaskHost/OutOfProcTaskHost.cs | Taskhost main entry point + node lifecycle loop. |
| src/MSBuildTaskHost/OutOfProcTaskAppDomainWrapper.cs | Implements task execution (instantiate, set params, execute, collect outputs) within taskhost. |
| src/MSBuildTaskHost/LoadedType.cs | Adds loaded type metadata container for task instantiation / AppDomain load. |
| src/MSBuildTaskHost/Immutable/ImmutableDictionary.cs | Removes old internal immutable dictionary shim from taskhost. |
| src/MSBuildTaskHost/FileSystem/MSBuildTaskHostFileSystem.cs | Removes legacy taskhost filesystem abstraction. |
| src/MSBuildTaskHost/Exceptions/InternalErrorException.cs | Adds taskhost-local internal error exception type. |
| src/MSBuildTaskHost/Exceptions/GeneralBuildTransferredException.cs | Adds fallback for unknown remote exceptions. |
| src/MSBuildTaskHost/Exceptions/BuildExceptionSerializationHelper.cs | Adds helper for exception serialization keying + factory selection. |
| src/MSBuildTaskHost/Exceptions/BuildExceptionRemoteState.cs | Adds container for remote exception state fields. |
| src/MSBuildTaskHost/Exceptions/BuildExceptionBase.cs | Adds base exception type supporting custom translation over node protocol. |
| src/MSBuildTaskHost/Collections/CollectionExtensions.cs | Adds small dictionary helper extension used by taskhost. |
| src/MSBuildTaskHost/BackEnd/TranslatorHelpers.cs | Adds translation helpers for value-factory based (de)serialization patterns. |
| src/MSBuildTaskHost/BackEnd/TaskParameterTypeVerifier.cs | Adds task parameter type validation helpers. |
| src/MSBuildTaskHost/BackEnd/TaskHostTaskComplete.cs | Adds completion packet type for taskhost→parent communication. |
| src/MSBuildTaskHost/BackEnd/TaskHostTaskCancelled.cs | Adds cancellation packet type for parent→taskhost communication. |
| src/MSBuildTaskHost/BackEnd/NodeShutdown.cs | Adds node shutdown packet type and reason mapping. |
| src/MSBuildTaskHost/BackEnd/NodePacketFactory.cs | Adds packet factory/router used by the taskhost endpoint. |
| src/MSBuildTaskHost/BackEnd/NodeEngineShutdownReason.cs | Adds taskhost’s shutdown reason enum. |
| src/MSBuildTaskHost/BackEnd/NodeBuildComplete.cs | Adds build complete packet. |
| src/MSBuildTaskHost/BackEnd/InterningBinaryReader.cs | Adds string-interning BinaryReader for protocol performance. |
| src/MSBuildTaskHost/BackEnd/ITranslator.cs | Adds taskhost protocol translator interface. |
| src/MSBuildTaskHost/BackEnd/ITranslatable.cs | Adds translatable marker interface for packets. |
| src/MSBuildTaskHost/BackEnd/INodePacketHandler.cs | Adds packet handler interface for routing. |
| src/MSBuildTaskHost/BackEnd/INodePacketFactory.cs | Adds packet factory interface for packet reconstruction/routing. |
| src/MSBuildTaskHost/BackEnd/INodePacket.cs | Adds taskhost packet type enum + protocol version helpers. |
| src/MSBuildTaskHost/BackEnd/INodeEndpoint.cs | Adds taskhost endpoint interface abstraction. |
| src/MSBuildTaskHost/BackEnd/BufferedReadStream.cs | Adds buffered stream wrapper for pipe reads. |
| src/MSBuildTaskHost/BackEnd/BinaryWriterExtensions.cs | Adds optional value serialization helpers. |
| src/MSBuildTaskHost/BackEnd/BinaryReaderFactory.cs | Adds factory for reusable BinaryReader/buffers. |
| src/MSBuildTaskHost/BackEnd/BinaryReaderExtensions.cs | Adds optional value deserialization helpers. |
| src/MSBuildTaskHost/AssemblyResources.cs | Removes old shared resource accessor (taskhost now owns SR). |
| src/MSBuildTaskHost/AssemblyInfo.cs | Removes old assembly-level file (IVT moved to Properties/AssemblyInfo.cs). |
| src/Directory.BeforeCommon.targets | Adjusts feature-constant definitions (no longer applied to net3* targets). |
| src/Build/Microsoft.Build.csproj | Includes new TaskHostLaunchArgs source in build project. |
| src/Build/BackEnd/Components/Communications/TaskHostLaunchArgs.cs | New helper for composing taskhost exe/args/handshake across runtime contexts. |
| src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcTaskHost.cs | Refactors taskhost process creation to use TaskHostLaunchArgs. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/TestNet35WinForms.csproj | Adds legacy .NET 3.5 WinForms test project asset. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Properties/Settings.settings | WinForms test asset file. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Properties/Settings.Designer.cs | Generated settings designer for WinForms test asset. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Properties/Resources.resx | Resources for WinForms test asset. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Properties/Resources.Designer.cs | Generated resources designer for WinForms test asset. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Properties/AssemblyInfo.cs | Assembly metadata for WinForms test asset. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Program.cs | WinForms test asset entry point. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Form1.resx | WinForms form resources (includes localized metadata). |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Form1.cs | WinForms form code-behind. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/Form1.Designer.cs | WinForms designer-generated form code. |
| src/Build.UnitTests/TestAssets/Net35WinFormsApp/App.config | WinForms test asset runtime config (CLR 2). |
| src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj | Excludes the WinForms asset from compilation and removes obsolete immutable dictionary tests. |
| src/Build.UnitTests/MSBuildTaskHostTests.cs | Adds new integration test to build the .NET 3.5 WinForms asset. |
Files not reviewed (3)
- src/Build.UnitTests/TestAssets/Net35WinFormsApp/Form1.Designer.cs: Language not supported
- src/Build.UnitTests/TestAssets/Net35WinFormsApp/Properties/Resources.Designer.cs: Language not supported
- src/Build.UnitTests/TestAssets/Net35WinFormsApp/Properties/Settings.Designer.cs: Language not supported
src/Build/BackEnd/Components/Communications/TaskHostLaunchArgs.cs
Outdated
Show resolved
Hide resolved
src/MSBuildTaskHost/Exceptions/BuildExceptionSerializationHelper.cs
Outdated
Show resolved
Hide resolved
- Fix TaskHostLaunchArgs to exclude empty quotes at front of command-line args. - Fix XML doc comment - Don't assert for non-localized string in test. - Remove company and copyright text from Net35WinFormsApp test assets. - Fix logic error in BuildExceptionSerializationHelper.DeserializeException. - Make a few fields read-only.
Summary
MSBuildTaskHost.exeprovides legacy support for running .NET Framework 3.5 tasks. It is itself a .NET Framework 3.5 application and loads theMicrosoft.Build.*3.5.0.0 assemblies from the GAC when .NET 3.5 is installed. Today, common targets force three .NET 3.5 tasks to run in MSBuildTaskHost:RegisterAssembly,UnregisterAssembly, and especially,GenerateResource. For .NET 3.5 builds, it is essentially that the 3.5 version ofGenerateResourceruns, since theBinaryFormatteroutput format changed between CLR 2.0 and CLR 4.0.For more than 15 years, MSBuildTaskHost has been compiled from the same shared source files as the rest of MSBuild. This made sense in the .NET Framework 4.0 era, when the delta between 3.5 and 4.0 was small. But as MSBuild has evolved, this arrangement has become increasingly restrictive. Any shared code that uses modern .NET features (
Span<T>,Task<T>, immutable collections, etc.) becomes problematic because MSBuildTaskHost cannot consume them. Shared code changes also risk breaking MSBuildTaskHost and, by extension, the ability to build legacy .NET 3.5 projects.This PR isolates MSBuildTaskHost into its own self‑contained codebase, decoupled from the rest of MSBuild.
Approach
The isolation work follows these steps:
NET,RUNTIME_TYPE_NETCORE, orFEATURE_*flags irrelevant to .NET 3.5 (e.g.,FEATURE_VISUALSTUDIOSETUP).CLR2COMPATIBILITYorFEATURE_ASSEMBLY_LOCATION.Microsoft.Build.Framework3.5.0.0 (e.g.,IBuildEngine3,ITaskItem2,RunInSTAAttribute).Additional Changes Outside MSBuildTaskHost
Refactor handshake components to make the tools directory path deterministic by using the
MSBuildTaskHost.exedirectory when computing handshake salt. (22fb64e)Add a test that verifies building a .NET 3.5 WinForms application on Windows/.NET Framework when .NET 3.5 is installed. (9941c15)
Next Steps
Remove dead code paths from all shared MSBuild files now that .NET 3.5 compatibility is no longer required. (In progress)
Audit conditional compilation constants across MSBuild. (In progress)
Move remaining shared code into a dedicated shared binary (
Microsoft.Build.Framework). (Requires reworking how string resources are consumed across MSBuild binaries.)Future Work
Refactor task host communication to introduce a “protocol adapter” layer. Now that MSBuildTaskHost is effectively frozen in time, this adapter would shield it from future protocol changes while allowing MSBuild to evolve independently.