From 5875dae880109c05366eb43d3a90f87cec477fd4 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 21 Oct 2022 16:24:06 -0400 Subject: [PATCH 1/4] Add proposal to simplify output paths --- accepted/2022/simplify-output-paths.md | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 accepted/2022/simplify-output-paths.md diff --git a/accepted/2022/simplify-output-paths.md b/accepted/2022/simplify-output-paths.md new file mode 100644 index 000000000..1c2a9cec0 --- /dev/null +++ b/accepted/2022/simplify-output-paths.md @@ -0,0 +1,53 @@ +# Simplify .NET Output Paths + +We'd like to simplify the output paths for .NET 8. + +Currently, the default output path for a .NET project includes folders for the `TargetFramework` and the `RuntimeIdentifier` (if it is set). Additionally, the publish output goes in a `publish` subfolder of the output folder. The resulting paths are as follows: + +- `bin\\` - Build output with no `RuntimeIdentifier` +- `bin\\\` - Build output with `RuntimeIdentifier` +- `bin\\\publish` - Publish output with no `RuntimeIdentifier` +- `bin\\\\publish` - Publish output with `RuntimeIdentifier` + +This makes it harder to find the output of a project, and sometimes nests one type of output in another output folder. + +## Proposed behavior + +Projects targeting .NET 8 and higher will by default not include the `TargetFramework` in the output path unless the project is multi-targeted. Similarly, the `RuntimeIdentifier` will not by default be part of the output path. Finally, the publish output path will be `bin\publish` by default instead of a `publish` subfolder inside of the output path. + +These would be the default output paths for .NET 8 projects: + +- `bin\` - Build output path for single targeted project +- `bin\\` - Build output for multi-targeted project +- `bin\publish` - Publish output for single targeted project +- `bin\publish\` - Publish output for multi-targeted project + +## Implementation + +There are currently properties that control whether the TargetFramework and RuntimeIdentifier should be included in the output path: `AppendTargetFrameworkToOutputPath` and `AppendRuntimeIdentifierToOutputPath`. Both of these currently default to true. We will change the default values as follows: + +- `AppendTargetFrameworkToOutputPath` will default to true if the `TargetFrameworks` property is set (as multi-targeted projects still need different output paths for each TargetFramework), or the project is targeting .NET 7 or lower. Otherwise it will default to false. +- `AppendRuntimeIdentifierToOutputPath` will default to true only when targeting .NET 7 or lower. + - To be discussed: Should we also default it to true if `RuntimeIdentifiers` is set? + +For publish, we would change the publish output path only when targeting .NET 8 or higher and when the Configuration is set to Release (which we [plan to make the default](https://github.com/dotnet/sdk/issues/10357#issuecomment-1208564539) for .NET 8). In that case we would set the publish output path to `$(BaseOutputPath)\publish` (by default `bin\publish`), and append the `TargetFramework` and `RuntimeIdentifier` to the path based on `AppendTargetFrameworkToOutputPath` and `AppendRuntimeIdentifierToOutputPath`. + +## Considerations + +### Breaking changes + +These changes could break things such as scripts that copy the output of the build or custom MSBuild logic that hard-codes these paths. Tieing these changes to the project TargetFramework ensures that these breaks will be encountered when the project is modified to target a new TargetFramework, not when updating to a new version of the .NET SDK. + +### Why have different output paths at all? + +It is worth considering why we have different output paths at all. The advantage of having different output paths for some pivot (such as configuration, target framework, or RuntimeIdentifier) is that you can keep outputs for the different values of the pivot side-by-side, and that if you are switching back and forth between building them, the builds for a given pivot value can be incremental. + +Therefore, the assumption with these changes is that it is not common to switch back and forth between different target frameworks or different runtime identifiers. Projects where it is common to switch back and forth could still set `AppendTargetFrameworkToOutputPath` or `AppendRuntimeIdentifierToOutputPath` to true. + +### Incremental publish + +Originally, the .NET SDK did not support incremental publish. This meant that if you published for one RuntimeIdentifier, and then published for another RuntimeIdentifier using the same publish path, the files from the first RuntimeIdentifier that should not have been included in the second publish would still be left in the folder. Probably because of this, the RuntimeIdentifier is [always added to the publish output path](https://github.com/dotnet/sdk/blob/efef23ab729388ffb081731e5b1adbabc6e6b327/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.BeforeCommon.targets#L122-L126) regardless of the value for `AppendRuntimeIdentifierToOutputPath`. However, we now [support incremental publish](https://github.com/dotnet/sdk/pull/3957), so this isn't a concern anymore. + +### Capitalization + +Should the default publish output path be `bin\publish` or `bin\Publish`? Uppercase matches the Configuration values of `Debug` and `Release`, which the publish folder will be a sibling of. However, the current publish folder capitalization is lowercase. From 927595c466b1a3e2584425c6aa457487044c326c Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 26 Oct 2022 15:25:20 -0400 Subject: [PATCH 2/4] Add background for publish relation to Configuration --- accepted/2022/simplify-output-paths.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/accepted/2022/simplify-output-paths.md b/accepted/2022/simplify-output-paths.md index 1c2a9cec0..4f919cddc 100644 --- a/accepted/2022/simplify-output-paths.md +++ b/accepted/2022/simplify-output-paths.md @@ -22,6 +22,8 @@ These would be the default output paths for .NET 8 projects: - `bin\publish` - Publish output for single targeted project - `bin\publish\` - Publish output for multi-targeted project +Note that the publish output paths would only apply when publishing the Release Configuration, which we plan to make the default configuration for `dotnet publish` in .NET 8. + ## Implementation There are currently properties that control whether the TargetFramework and RuntimeIdentifier should be included in the output path: `AppendTargetFrameworkToOutputPath` and `AppendRuntimeIdentifierToOutputPath`. Both of these currently default to true. We will change the default values as follows: @@ -30,7 +32,7 @@ There are currently properties that control whether the TargetFramework and Runt - `AppendRuntimeIdentifierToOutputPath` will default to true only when targeting .NET 7 or lower. - To be discussed: Should we also default it to true if `RuntimeIdentifiers` is set? -For publish, we would change the publish output path only when targeting .NET 8 or higher and when the Configuration is set to Release (which we [plan to make the default](https://github.com/dotnet/sdk/issues/10357#issuecomment-1208564539) for .NET 8). In that case we would set the publish output path to `$(BaseOutputPath)\publish` (by default `bin\publish`), and append the `TargetFramework` and `RuntimeIdentifier` to the path based on `AppendTargetFrameworkToOutputPath` and `AppendRuntimeIdentifierToOutputPath`. +For publish, we would change the publish output path only when targeting .NET 8 or higher and when the Configuration is set to Release (which we [plan to make the default](https://github.com/dotnet/sdk/issues/27066) for .NET 8). In that case we would set the publish output path to `$(BaseOutputPath)\publish` (by default `bin\publish`), and append the `TargetFramework` and `RuntimeIdentifier` to the path based on `AppendTargetFrameworkToOutputPath` and `AppendRuntimeIdentifierToOutputPath`. ## Considerations @@ -44,6 +46,25 @@ It is worth considering why we have different output paths at all. The advantag Therefore, the assumption with these changes is that it is not common to switch back and forth between different target frameworks or different runtime identifiers. Projects where it is common to switch back and forth could still set `AppendTargetFrameworkToOutputPath` or `AppendRuntimeIdentifierToOutputPath` to true. +### Publish versus Configuration + +Putting the publish output in the `bin\publish` folder may appear to conflate publish with a Configuration. This, however, is intentional. We'd like to make publish behave more like a configuration. + +Some factors influencing this: + +- It is rarely correct to publish with the Debug configuration, as publish is used to create artifacts that are deployed. +- Currently, there are operations that are only supported during publish, such as `PublishSingleFile`, `PublishTrimmed`, and `PublishAot`. It would be more flexible to allow these to be specified for Build also. +- There's not a good way to set MSBuild properties differently for the Publish operation. This makes it hard to implement properties such as PublishSingleFile and PublishRuntimeIdentifier, and means that those properties will work with `dotnet publish` but not `dotnet build /t:Publish`. Developers may also want to condition properties on whether the Publish operation is being run. On the other hand, conditioning properties based on Configuration is trivial. + +We've been thinking about Publish versus Build for a while. Here's some of that background: + +- https://github.com/dotnet/sdk/issues/26446 +- https://github.com/dotnet/sdk/issues/26247 +- https://github.com/dotnet/core/issues/7566 +- https://github.com/dotnet/docs/issues/30023 +- https://gist.github.com/dsplaisted/f032de83be1dda7e14ca77f350100065 +- https://github.com/dotnet/sdk/issues/15726 + ### Incremental publish Originally, the .NET SDK did not support incremental publish. This meant that if you published for one RuntimeIdentifier, and then published for another RuntimeIdentifier using the same publish path, the files from the first RuntimeIdentifier that should not have been included in the second publish would still be left in the folder. Probably because of this, the RuntimeIdentifier is [always added to the publish output path](https://github.com/dotnet/sdk/blob/efef23ab729388ffb081731e5b1adbabc6e6b327/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.BeforeCommon.targets#L122-L126) regardless of the value for `AppendRuntimeIdentifierToOutputPath`. However, we now [support incremental publish](https://github.com/dotnet/sdk/pull/3957), so this isn't a concern anymore. From 929ecbdad8e6c38bcfe6b6e26bfc2b64f2166dd0 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 26 Oct 2022 19:45:14 -0400 Subject: [PATCH 3/4] Add note about iOS projects and including RID in output path --- accepted/2022/simplify-output-paths.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/accepted/2022/simplify-output-paths.md b/accepted/2022/simplify-output-paths.md index 4f919cddc..6a72e0f0b 100644 --- a/accepted/2022/simplify-output-paths.md +++ b/accepted/2022/simplify-output-paths.md @@ -46,6 +46,8 @@ It is worth considering why we have different output paths at all. The advantag Therefore, the assumption with these changes is that it is not common to switch back and forth between different target frameworks or different runtime identifiers. Projects where it is common to switch back and forth could still set `AppendTargetFrameworkToOutputPath` or `AppendRuntimeIdentifierToOutputPath` to true. +Some project types may set `AppendRuntimeIdentifierToOutputPath` to true by default. This will be the case for iOS projects, where different RuntimeIdentifiers are used for targeting a simulator versus a device, and it is common to switch back and forth. + ### Publish versus Configuration Putting the publish output in the `bin\publish` folder may appear to conflate publish with a Configuration. This, however, is intentional. We'd like to make publish behave more like a configuration. From f32ac128df6fe89b60c7efc833c8ba82719a9e26 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 11 Nov 2022 16:37:26 -0500 Subject: [PATCH 4/4] Update proposal to always include RuntimeIdentifier in publish output path --- accepted/2022/simplify-output-paths.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/accepted/2022/simplify-output-paths.md b/accepted/2022/simplify-output-paths.md index 6a72e0f0b..53a6ba99d 100644 --- a/accepted/2022/simplify-output-paths.md +++ b/accepted/2022/simplify-output-paths.md @@ -13,14 +13,14 @@ This makes it harder to find the output of a project, and sometimes nests one ty ## Proposed behavior -Projects targeting .NET 8 and higher will by default not include the `TargetFramework` in the output path unless the project is multi-targeted. Similarly, the `RuntimeIdentifier` will not by default be part of the output path. Finally, the publish output path will be `bin\publish` by default instead of a `publish` subfolder inside of the output path. +Projects targeting .NET 8 and higher will by default not include the `TargetFramework` in the output path unless the project is multi-targeted. Similarly, the `RuntimeIdentifier` will not by default be part of the build output path. Finally, the publish output path will be `bin\publish` by default instead of a `publish` subfolder inside of the output path. These would be the default output paths for .NET 8 projects: - `bin\` - Build output path for single targeted project - `bin\\` - Build output for multi-targeted project -- `bin\publish` - Publish output for single targeted project -- `bin\publish\` - Publish output for multi-targeted project +- `bin\publish\` - Publish output for single targeted project +- `bin\publish\\` - Publish output for multi-targeted project Note that the publish output paths would only apply when publishing the Release Configuration, which we plan to make the default configuration for `dotnet publish` in .NET 8. @@ -32,7 +32,7 @@ There are currently properties that control whether the TargetFramework and Runt - `AppendRuntimeIdentifierToOutputPath` will default to true only when targeting .NET 7 or lower. - To be discussed: Should we also default it to true if `RuntimeIdentifiers` is set? -For publish, we would change the publish output path only when targeting .NET 8 or higher and when the Configuration is set to Release (which we [plan to make the default](https://github.com/dotnet/sdk/issues/27066) for .NET 8). In that case we would set the publish output path to `$(BaseOutputPath)\publish` (by default `bin\publish`), and append the `TargetFramework` and `RuntimeIdentifier` to the path based on `AppendTargetFrameworkToOutputPath` and `AppendRuntimeIdentifierToOutputPath`. +For publish, we would change the publish output path only when targeting .NET 8 or higher and when the Configuration is set to Release (which we [plan to make the default](https://github.com/dotnet/sdk/issues/27066) for .NET 8). In that case we would set the publish output path to `$(BaseOutputPath)\publish` (by default `bin\publish`), and append the `TargetFramework` to the path based on `AppendTargetFrameworkToOutputPath` property. The `RuntimeIdentifier` will always be appended to the publish output path, as is the case today. ## Considerations @@ -48,6 +48,8 @@ Therefore, the assumption with these changes is that it is not common to switch Some project types may set `AppendRuntimeIdentifierToOutputPath` to true by default. This will be the case for iOS projects, where different RuntimeIdentifiers are used for targeting a simulator versus a device, and it is common to switch back and forth. +For publish, we believe it is more common to switch between different RuntimeIdentifiers, so we will continue to include the `RuntimeIdentifier` in the publish output path. + ### Publish versus Configuration Putting the publish output in the `bin\publish` folder may appear to conflate publish with a Configuration. This, however, is intentional. We'd like to make publish behave more like a configuration. @@ -73,4 +75,4 @@ Originally, the .NET SDK did not support incremental publish. This meant that i ### Capitalization -Should the default publish output path be `bin\publish` or `bin\Publish`? Uppercase matches the Configuration values of `Debug` and `Release`, which the publish folder will be a sibling of. However, the current publish folder capitalization is lowercase. +The default publish output path could either be `bin\publish` or `bin\Publish`. Uppercase matches the Configuration values of `Debug` and `Release`, which the publish folder will be a sibling of. However, the current publish folder capitalization is lowercase. The current plan is to go with the lowercase `bin\publish`.