Skip to content

Commit

Permalink
Update to latest version of output path design proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
dsplaisted committed Mar 23, 2023
1 parent e772177 commit 498f932
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 93 deletions.
40 changes: 23 additions & 17 deletions src/Tasks/Microsoft.NET.Build.Tasks/sdk/Sdk.props
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Copyright (c) .NET Foundation. All rights reserved.



<!-- We need to put the UseStandardOutputPaths logic after the import of Directory.Build.props, but before the MSBuild Project Extensions .props import.
<!-- We need to put the UseArtifactsOutput logic after the import of Directory.Build.props, but before the MSBuild Project Extensions .props import.
However, both of these things happen in Microsoft.Common.props with no opportunity to insert logic in between them.
So what we do here is duplicate the Directory.Build.props import logic from Microsoft.Common.props, and then set ImportDirectoryBuildProps to
Expand All @@ -57,26 +57,32 @@ Copyright (c) .NET Foundation. All rights reserved.
<ImportDirectoryBuildProps>false</ImportDirectoryBuildProps>
</PropertyGroup>

<!-- Setting RootOutputPath automatically opts in to standard output paths -->
<PropertyGroup Condition="'$(RootOutputPath)' != ''">
<UseStandardOutputPaths Condition="'$(UseStandardOutputPaths)' == ''">true</UseStandardOutputPaths>
<BaseStandardOutputPath>$(RootOutputPath)</BaseStandardOutputPath>
<!-- Setting ArtifactsPath automatically opts in to the artifacts output format -->
<PropertyGroup Condition="'$(ArtifactsPath)' != ''">
<UseArtifactsOutput Condition="'$(UseArtifactsOutput)' == ''">true</UseArtifactsOutput>
</PropertyGroup>

<!-- Set up base standard output folders if UseStandardOutputPaths is set -->
<PropertyGroup Condition="'$(UseStandardOutputPaths)' == 'true'">
<UseStandardIntermediateOutput Condition="'$(UseStandardIntermediateOutput)' == ''">true</UseStandardIntermediateOutput>

<BaseStandardOutputPath Condition="'$(BaseStandardOutputPath)' == ''">bin\</BaseStandardOutputPath>
<BaseStandardOutputPath>$([MSBuild]::EnsureTrailingSlash($(BaseStandardOutputPath)))</BaseStandardOutputPath>
<!-- Set up base output folders if UseArtifactsOutput is set -->
<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true' And '$(ArtifactsPath)' == '' And '$(_DirectoryBuildPropsBasePath)' != ''">
<!-- Default ArtifactsPath to be in the directory where Directory.Build.props is found
Note that we do not append a backslash to the ArtifactsPath as we do with most paths, because it may be a global property passed in on the command-line which we can't easily change -->
<ArtifactsPath>$(_DirectoryBuildPropsBasePath)\.artifacts</ArtifactsPath>
<IncludeProjectNameInArtifactsPaths Condition="'$(IncludeProjectNameInArtifactsPaths)' == ''">true</IncludeProjectNameInArtifactsPaths>
</PropertyGroup>

<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">$(BaseStandardOutputPath)build\</BaseOutputPath>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">$(BaseStandardOutputPath)obj\</BaseIntermediateOutputPath>
<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true' And '$(ArtifactsPath)' == ''">
<!-- If there was no Directory.Build.props file, then put the artifacts path in the project folder -->
<ArtifactsPath>$(MSBuildProjectDirectory)\.artifacts</ArtifactsPath>
</PropertyGroup>

<!-- If RootOutputPath is set, then projects share the BaseStandardOutputPath, and the project name should be appended to the output and
intermediate output paths -->
<BaseOutputPath Condition="'$(RootOutputPath)' != ''">$(BaseOutputPath)$(MSBuildProjectName)\</BaseOutputPath>
<BaseIntermediateOutputPath Condition="'$(RootOutputPath)' != ''">$(BaseIntermediateOutputPath)$(MSBuildProjectName)\</BaseIntermediateOutputPath>
<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true'">
<UseArtifactsIntermediateOutput Condition="'$(UseArtifactsIntermediateOutput)' == ''">true</UseArtifactsIntermediateOutput>
<ArtifactsProjectName Condition="'$(ArtifactsProjectName)' == ''">$(MSBuildProjectName)</ArtifactsProjectName>
</PropertyGroup>

<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true' And '$(BaseIntermediateOutputPath)' == '' And '$(UseArtifactsIntermediateOutput)' == 'true'">
<BaseIntermediateOutputPath Condition="'$(IncludeProjectNameInArtifactsPaths)' == 'true'">$(ArtifactsPath)\obj\$(ArtifactsProjectName)\</BaseIntermediateOutputPath>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">$(ArtifactsPath)\obj\</BaseIntermediateOutputPath>
</PropertyGroup>

<PropertyGroup Condition="'$(MSBuildProjectFullPath)' == '$(ProjectToOverrideProjectExtensionsPath)'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,46 +25,95 @@ Copyright (c) .NET Foundation. All rights reserved.
<AppendTargetFrameworkToOutputPath Condition="'$(AppendTargetFrameworkToOutputPath)' == ''">true</AppendTargetFrameworkToOutputPath>
</PropertyGroup>

<!-- NOTE: If we want to default UseStandardOutputPaths to true when targeting a given version of .NET or higher, this is where we would do it.
<!-- NOTE: If we want to default UseArtifactsOutput to true when targeting a given version of .NET or higher, this is where we would do it.
It would look something like this:
<PropertyGroup Condition="'$(UseStandardOutputPaths)' == '' and
<PropertyGroup Condition="'$(UseArtifactsOutput)' == '' and
'$(TargetFrameworks)' == '' and
'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
$([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 8.0))">
<UseStandardOutputPaths>true</UseStandardOutputPaths>
<UseArtifactsOutput>true</UseArtifactsOutput>
</PropertyGroup>
-->

<!-- Handle RootOutputPath and if it wasn't set in Sdk.props -->
<PropertyGroup Condition="'$(RootOutputPath)' != ''">
<UseStandardOutputPaths Condition="'$(UseStandardOutputPaths)' == ''">true</UseStandardOutputPaths>
<BaseStandardOutputPath Condition="'$(BaseStandardOutputPath)' == ''">$(RootOutputPath)</BaseStandardOutputPath>
<!-- Handle ArtifactsPath if it wasn't set in Sdk.props -->
<PropertyGroup Condition="'$(ArtifactsPath)' != ''">
<UseArtifactsOutput Condition="'$(UseArtifactsOutput)' == ''">true</UseArtifactsOutput>
</PropertyGroup>

<!-- Set BaseOutputPath for standard output format if it wasn't set in Sdk.props -->
<PropertyGroup Condition="'$(UseStandardOutputPaths)' == 'true' And '$(BaseOutputPath)' == ''">
<BaseStandardOutputPath Condition="'$(BaseStandardOutputPath)' == ''">bin\</BaseStandardOutputPath>
<BaseStandardOutputPath>$([MSBuild]::EnsureTrailingSlash($(BaseStandardOutputPath)))</BaseStandardOutputPath>
<!-- Repeat ArtifactsPath logic from Sdk.props here, in case UseArtifactsOutput was set in the project file -->
<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true' And '$(ArtifactsPath)' == '' And '$(_DirectoryBuildPropsBasePath)' != ''">
<!-- Default ArtifactsPath to be in the directory where Directory.Build.props is found
Note that we do not append a backslash to the ArtifactsPath as we do with most paths, because it may be a global property passed in on the command-line which we can't easily change -->
<ArtifactsPath>$(_DirectoryBuildPropsBasePath)\.artifacts</ArtifactsPath>
<IncludeProjectNameInArtifactsPaths Condition="'$(IncludeProjectNameInArtifactsPaths)' == ''">true</IncludeProjectNameInArtifactsPaths>
</PropertyGroup>

<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true' And '$(ArtifactsPath)' == ''">
<!-- If there was no Directory.Build.props file, then put the artifacts path in the project folder -->
<ArtifactsPath>$(MSBuildProjectDirectory)\.artifacts</ArtifactsPath>
</PropertyGroup>

<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true'">
<ArtifactsProjectName Condition="'$(ArtifactsProjectName)' == ''">$(MSBuildProjectName)</ArtifactsProjectName>

<ArtifactsBinOutputName Condition="'$(ArtifactsBinOutputName)' == ''">bin</ArtifactsBinOutputName>
<ArtifactsPublishOutputName Condition="'$(ArtifactsPublishOutputName)' == ''">publish</ArtifactsPublishOutputName>
<ArtifactsPackageOutputName Condition="'$(ArtifactsPackageOutputName)' == ''">package</ArtifactsPackageOutputName>

<!-- ArtifactsPivots instead? -->
<ArtifactsPivots>$(Configuration.ToLowerInvariant())</ArtifactsPivots>

<!-- Include the TargetFramework in the pivots if the project is multi-targeted (ie TargetFrameworks) is defined -->
<ArtifactsPivots Condition="'$(TargetFrameworks)' != ''"
>$(ArtifactsPivots)_$(TargetFramework.ToLowerInvariant())</ArtifactsPivots>

<!-- This targets file is evaluated before RuntimeIdentifierInference.targets, so this will only include the
RuntimeIdentifier in the path if it was explicitly specified, not if it was inferred. This is the
behavior we want.
<BaseOutputPath>$(BaseStandardOutputPath)build\</BaseOutputPath>
The BlazorWebAssembly .props file sets the RuntimeIdentifier to blazor-wasm, so treat that as a special case.
-->
<ArtifactsPivots Condition="'$(RuntimeIdentifier)' != '' And !('$(RuntimeIdentifier)' == 'browser-wasm' And '$(AppendRuntimeIdentifierToOutputPath)' == 'false')"
>$(ArtifactsPivots)_$(RuntimeIdentifier.ToLowerInvariant())</ArtifactsPivots>

</PropertyGroup>

<!-- If RootOutputPath is set, then projects share the BaseStandardOutputPath, and the project name should be appended to the output path -->
<BaseOutputPath Condition="'$(RootOutputPath)' != ''">$(BaseOutputPath)$(MSBuildProjectName)\</BaseOutputPath>
<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true' And '$(IncludeProjectNameInArtifactsPaths)' == 'true'">
<!-- Set artifacts paths when project name should be included in the path -->
<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">$(ArtifactsPath)\$(ArtifactsBinOutputName)\$(ArtifactsProjectName)\</BaseOutputPath>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == '' And '$(UseArtifactsIntermediateOutput)' == 'true'">$(ArtifactsPath)\obj\$(ArtifactsProjectName)\</BaseIntermediateOutputPath>
<PublishDir Condition="'$(PublishDir)' == ''">$(ArtifactsPath)\$(ArtifactsPublishOutputName)\$(ArtifactsProjectName)\$(ArtifactsPivots)\</PublishDir>
</PropertyGroup>

<PropertyGroup Condition="'$(UseStandardOutputPaths)' != 'true'">
<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true' And '$(IncludeProjectNameInArtifactsPaths)' != 'true'">
<!-- Set artifacts paths when project name should not be included in the path -->
<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">$(ArtifactsPath)\$(ArtifactsBinOutputName)\</BaseOutputPath>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == '' And '$(UseArtifactsIntermediateOutput)' == 'true'">$(ArtifactsPath)\obj\</BaseIntermediateOutputPath>
<PublishDir Condition="'$(PublishDir)' == ''">$(ArtifactsPath)\$(ArtifactsPublishOutputName)\$(ArtifactsPivots)\</PublishDir>
</PropertyGroup>

<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true'">
<OutputPath Condition="'$(OutputPath)' == ''">$(BaseOutputPath)$(ArtifactsPivots)\</OutputPath>
<IntermediateOutputPath Condition=" $(IntermediateOutputPath) == '' And '$(UseArtifactsIntermediateOutput)' == 'true'">$(BaseIntermediateOutputPath)$(ArtifactsPivots)\</IntermediateOutputPath>

<!-- The package output path does not include the project name, and only includes the Configuration as a pivot -->
<PackageOutputPath Condition="'$(PackageOutputPath)' == ''">$(ArtifactsPath)\$(ArtifactsPackageOutputName)\$(Configuration.ToLowerInvariant())\</PackageOutputPath>

</PropertyGroup>

<PropertyGroup Condition="'$(UseArtifactsOutput)' != 'true'">
<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">bin\</BaseOutputPath>
<BaseOutputPath Condition="!HasTrailingSlash('$(BaseOutputPath)')">$(BaseOutputPath)\</BaseOutputPath>
<OutputPath Condition="'$(OutputPath)' == '' and '$(PlatformName)' == 'AnyCPU'">$(BaseOutputPath)$(Configuration)\</OutputPath>
<OutputPath Condition="'$(OutputPath)' == '' and '$(PlatformName)' != 'AnyCPU'">$(BaseOutputPath)$(PlatformName)\$(Configuration)\</OutputPath>
<OutputPath Condition="!HasTrailingSlash('$(OutputPath)')">$(OutputPath)\</OutputPath>
</PropertyGroup>

<!-- If "UseStandardOutputPaths" wasn't set when the MSBuild project extensions .props files were imported, then use "obj" for the intermediate output path
instead of $(BaseStandardOutputPath)\obj. To have the intermediate output path in the standard output folder, "UseStandardOutputPaths" should be set in Directory.Build.props-->
<PropertyGroup Condition="'$(UseStandardIntermediateOutput)' != 'true'">
<!-- If "UseArtifactsOutput" wasn't set when the MSBuild project extensions .props files were imported, then use "obj" in the project folder for the intermediate output path
instead a folder under ArtifactsPath. To have the intermediate output path in the artifacts folder, "UseArtifactsOutput" should be set in Directory.Build.props-->
<PropertyGroup Condition="'$(UseArtifactsIntermediateOutput)' != 'true'">
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">obj\</BaseIntermediateOutputPath>
<BaseIntermediateOutputPath Condition="!HasTrailingSlash('$(BaseIntermediateOutputPath)')">$(BaseIntermediateOutputPath)\</BaseIntermediateOutputPath>
<IntermediateOutputPath Condition=" $(IntermediateOutputPath) == '' and '$(PlatformName)' == 'AnyCPU' ">$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
Expand All @@ -74,67 +123,32 @@ Copyright (c) .NET Foundation. All rights reserved.

<!-- Set the package output path (for nuget pack target) now, before the TargetFramework is appended -->
<PropertyGroup Condition="'$(PackageOutputPath)' == ''">
<PackageOutputPath Condition="'$(UseStandardOutputPaths)' != 'true'">$(OutputPath)</PackageOutputPath>
<PackageOutputPath Condition="'$(UseStandardOutputPaths)' == 'true'">$(BaseStandardOutputPath)\package\$(Configuration.ToLowerInvariant())\</PackageOutputPath>
<PackageOutputPath Condition="'$(UseArtifactsOutput)' != 'true'">$(OutputPath)</PackageOutputPath>
</PropertyGroup>

<!-- Exclude files from OutputPath and IntermediateOutputPath from default item globs. Use the value
of these properties before the TargetFramework is appended, so that if these values are specified
in the project file, the specified value will be used for the exclude. -->
<PropertyGroup Condition="'$(UseStandardOutputPaths)' != 'true'">
<PropertyGroup Condition="'$(UseArtifactsOutput)' != 'true'">
<DefaultItemExcludes>$(DefaultItemExcludes);$(OutputPath)/**</DefaultItemExcludes>
<DefaultItemExcludes>$(DefaultItemExcludes);$(IntermediateOutputPath)/**</DefaultItemExcludes>
</PropertyGroup>

<PropertyGroup Condition="'$(UseStandardOutputPaths)' == 'true'">
<DefaultItemExcludes>$(DefaultItemExcludes);$(BaseStandardOutputPath)/**</DefaultItemExcludes>
<PropertyGroup Condition="'$(UseArtifactsOutput)' == 'true'">
<DefaultItemExcludes>$(DefaultItemExcludes);$(ArtifactsPath)/**</DefaultItemExcludes>
</PropertyGroup>

<!--
Append $(TargetFramework) directory to output and intermediate paths to prevent bin clashes between
targets.
-->
<PropertyGroup Condition="'$(UseStandardOutputPaths)' != 'true' and
<PropertyGroup Condition="'$(UseArtifactsOutput)' != 'true' and
'$(AppendTargetFrameworkToOutputPath)' == 'true' and '$(TargetFramework)' != '' and '$(_UnsupportedTargetFrameworkError)' != 'true'">
<OutputPath>$(OutputPath)$(TargetFramework.ToLowerInvariant())\</OutputPath>
</PropertyGroup>

<PropertyGroup Condition="'$(UseStandardIntermediateOutput)' != 'true' and
<PropertyGroup Condition="'$(UseArtifactsOutput)' != 'true' and
'$(AppendTargetFrameworkToOutputPath)' == 'true' and '$(TargetFramework)' != '' and '$(_UnsupportedTargetFrameworkError)' != 'true'">
<IntermediateOutputPath>$(IntermediateOutputPath)$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
</PropertyGroup>

<PropertyGroup Condition="'$(UseStandardOutputPaths)' == 'true'">
<_ArtifactPivots>$(Configuration.ToLowerInvariant())</_ArtifactPivots>

<!-- Per the design, we should include the TargetFramework in the pivots if TargetFrameworks is defined, or if TargetFramework is a global property.
However, basing this on whether TargetFramework is a global property currently breaks "dotnet pack": https://github.com/NuGet/Home/issues/12323
Because of this, for now we will only include the TargetFramework in the pivots if TargetFrameworks is defined, and won't look at whether
TargetFramework is a global property or not. -->
<_ArtifactPivots Condition="'$(TargetFrameworks)' != ''"
>$(_ArtifactPivots)_$(TargetFramework.ToLowerInvariant())</_ArtifactPivots>

<!-- This targets file is evaluated before RuntimeIdentifierInference.targets, so this will only include the
RuntimeIdentifier in the path if it was explicitly specified, not if it was inferred. This is the
behavior we want.
The BlazorWebAssembly .props file sets the RuntimeIdentifier to blazor-wasm, so treat that as a special case.
-->

<_ArtifactPivots Condition="'$(RuntimeIdentifier)' != '' And !('$(RuntimeIdentifier)' == 'browser-wasm' And '$(AppendRuntimeIdentifierToOutputPath)' == 'false')"
>$(_ArtifactPivots)_$(RuntimeIdentifier.ToLowerInvariant())</_ArtifactPivots>

<OutputPath Condition="'$(OutputPath)' == ''">$(BaseOutputPath)$(_ArtifactPivots)\</OutputPath>

<!-- Publish path -->
<PublishDirName Condition="'$(PublishDirName)' == ''">publish</PublishDirName>

<PublishDir Condition="'$(PublishDir)' == '' And '$(RootOutputPath)' == ''">$(BaseStandardOutputPath)$(PublishDirName)\$(_ArtifactPivots)\</PublishDir>
<PublishDir Condition="'$(PublishDir)' == '' And '$(RootOutputPath)' != ''">$(BaseStandardOutputPath)$(PublishDirName)\$(MSBuildProjectName)\$(_ArtifactPivots)\</PublishDir>

</PropertyGroup>

<PropertyGroup Condition="'$(UseStandardOutputPaths)' == 'true' and '$(UseStandardIntermediateOutput)' == 'true'">
<IntermediateOutputPath Condition=" $(IntermediateOutputPath) == '' ">$(BaseIntermediateOutputPath)$(_ArtifactPivots)\</IntermediateOutputPath>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ Copyright (c) .NET Foundation. All rights reserved.
append a RID the user never mentioned in the path and do so even in the AnyCPU case.
-->
<PropertyGroup Condition="'$(AppendRuntimeIdentifierToOutputPath)' == 'true' and '$(RuntimeIdentifier)' != '' and '$(_UsingDefaultRuntimeIdentifier)' != 'true'">
<IntermediateOutputPath Condition="'$(UseStandardIntermediateOutput)' != 'true'">$(IntermediateOutputPath)$(RuntimeIdentifier)\</IntermediateOutputPath>
<OutputPath Condition="'$(UseStandardOutputPaths)' != 'true'">$(OutputPath)$(RuntimeIdentifier)\</OutputPath>
<IntermediateOutputPath Condition="'$(UseArtifactsIntermediateOutput)' != 'true'">$(IntermediateOutputPath)$(RuntimeIdentifier)\</IntermediateOutputPath>
<OutputPath Condition="'$(UseArtifactsOutput)' != 'true'">$(OutputPath)$(RuntimeIdentifier)\</OutputPath>
</PropertyGroup>

<UsingTask TaskName="Microsoft.NET.Build.Tasks.GetDefaultPlatformTargetForNetFramework"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ Copyright (c) .NET Foundation. All rights reserved.
</PropertyGroup>

<!-- Set PublishDir here, before Microsoft.Common.targets, to avoid a competing default there.
If using standard output path format, PublishDir is already set in Microsoft.NET.DefaultOutputPaths.targets -->
<PropertyGroup Condition="'$(UseStandardOutputPaths)' != 'true'">
If using artifacts output path format, PublishDir is already set in Microsoft.NET.DefaultOutputPaths.targets -->
<PropertyGroup Condition="'$(UseArtifactsOutput)' != 'true'">
<PublishDirName Condition="'$(PublishDirName)' == ''">publish</PublishDirName>
<!-- ensure the PublishDir is RID specific-->
<PublishDir Condition="'$(PublishDir)' == '' and
Expand Down
Loading

0 comments on commit 498f932

Please sign in to comment.