Skip to content

Commit 551be71

Browse files
Copilotatifaziz
andcommitted
Fix MSB3539 by moving BaseIntermediateOutputPath to Directory.Build.props
Move BaseIntermediateOutputPath and BaseOutputPath for Roslyn 4.4 variant from DocoptNet.csproj to Directory.Build.props, which is imported before Microsoft.Common.props and avoids the MSB3539 warning. Also adds build.ps1 for multi-Roslyn build orchestration, updates CI workflow to use build.ps1, and updates README with build instructions. Co-authored-by: atifaziz <20511+atifaziz@users.noreply.github.com>
1 parent 13ee336 commit 551be71

File tree

5 files changed

+240
-7
lines changed

5 files changed

+240
-7
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
run: dotnet tool restore
4949

5050
- name: Build
51-
run: dotnet build --configuration ${{ env.CONFIGURATION }}
51+
run: dotnet pwsh ./build.ps1 -Build -Configuration ${{ env.CONFIGURATION }}
5252

5353
- name: Pack (Windows only)
5454
if: runner.os == 'Windows'
@@ -76,11 +76,16 @@ jobs:
7676
}
7777
7878
Add-Content $releaseNotesFile -Encoding UTF8 "Commit @ ${{ github.sha }}"
79-
$packArgs = @()
79+
80+
$packParams = @{
81+
Configuration = '${{ env.CONFIGURATION }}'
82+
PackageReleaseNotesFile = $releaseNotesFile
83+
}
8084
if ($versionSuffix) {
81-
$packArgs += @('--version-suffix', $versionSuffix)
85+
$packParams.VersionSuffix = $versionSuffix
8286
}
83-
dotnet pack --no-build --configuration ${{ env.CONFIGURATION }} @packArgs "-p:PackageReleaseNotesFile=$releaseNotesFile"
87+
88+
& ./build.ps1 -Pack @packParams
8489
if ($LASTEXITCODE) { throw "Pack failed" }
8590
8691
Get-ChildItem -File -Filter docopt.net.*.nupkg dist |

Directory.Build.props

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,15 @@
1818
<IsPackable>false</IsPackable>
1919
</PropertyGroup>
2020

21+
<!--
22+
Roslyn 4.4 variant builds use isolated output paths to avoid conflicts
23+
with the baseline (Roslyn 3.10) build. These properties MUST be set in
24+
Directory.Build.props (before Microsoft.Common.props is imported) to
25+
avoid MSB3539.
26+
-->
27+
<PropertyGroup Condition="'$(RoslynVersion)' == '4.4'">
28+
<BaseOutputPath>$(MSBuildProjectDirectory)/bin/roslyn4.4/</BaseOutputPath>
29+
<BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/roslyn4.4/</BaseIntermediateOutputPath>
30+
</PropertyGroup>
31+
2132
</Project>

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,46 @@ Install [the package][nupkg] in a .NET project using:
7070

7171
dotnet add package docopt.net
7272

73+
## Building from Source
74+
75+
The repository uses a PowerShell script to orchestrate multi-Roslyn variant builds. Ensure you have the required tools installed:
76+
77+
```bash
78+
dotnet tool restore
79+
```
80+
81+
### Build
82+
83+
To build the project with both Roslyn 3.10 (baseline) and Roslyn 4.4 variants:
84+
85+
```bash
86+
dotnet pwsh ./build.ps1
87+
```
88+
89+
### Test
90+
91+
To run tests:
92+
93+
```bash
94+
dotnet pwsh ./build.ps1 -Test
95+
```
96+
97+
To run tests without rebuilding:
98+
99+
```bash
100+
dotnet pwsh ./build.ps1 -Test -NoBuild
101+
```
102+
103+
### Pack
104+
105+
To create a NuGet package containing both analyzer variants:
106+
107+
```bash
108+
dotnet pwsh ./build.ps1 -Pack
109+
```
110+
111+
**Note:** Running `dotnet pack` directly without first building all Roslyn variants will fail with an error message. Always use `./build.ps1 -Pack` to ensure both analyzer variants are included in the package.
112+
73113
## Copyright and License
74114

75115
- &copy; 2012-2014 Vladimir Keleshev <vladimir@keleshev.com>

build.ps1

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env pwsh
2+
3+
<#
4+
.SYNOPSIS
5+
Build, test, and pack DocoptNet with multi-Roslyn variant support.
6+
7+
.DESCRIPTION
8+
This script orchestrates builds across Roslyn 3.10 (baseline) and Roslyn 4.4 variants,
9+
runs tests for both variants, and produces a NuGet package containing both analyzer DLLs.
10+
11+
.PARAMETER Build
12+
Build the solution (default parameter set).
13+
14+
.PARAMETER Test
15+
Run tests. Note: May fail on non-Windows platforms if .NET Framework tests cannot run.
16+
17+
.PARAMETER Pack
18+
Create a NuGet package containing both analyzer variants.
19+
20+
.PARAMETER Configuration
21+
The build configuration (default: Release).
22+
23+
.PARAMETER NoBuild
24+
Skip the build step when running tests (only applies to baseline tests).
25+
26+
.PARAMETER VersionSuffix
27+
Optional version suffix for the NuGet package (e.g., "beta1").
28+
29+
.PARAMETER PackageReleaseNotesFile
30+
Optional path to a file containing release notes for the NuGet package.
31+
32+
.EXAMPLE
33+
./build.ps1
34+
Build both Roslyn variants (baseline + 4.4).
35+
36+
.EXAMPLE
37+
./build.ps1 -Test
38+
Build and test both Roslyn variants.
39+
40+
.EXAMPLE
41+
./build.ps1 -Test -NoBuild
42+
Run tests without rebuilding baseline (Roslyn 4.4 tests always build as needed).
43+
44+
.EXAMPLE
45+
./build.ps1 -Pack -VersionSuffix "beta1"
46+
Build and pack with version suffix.
47+
48+
.EXAMPLE
49+
./build.ps1 -Pack -PackageReleaseNotesFile "/path/to/notes.txt"
50+
Build and pack with release notes from a file.
51+
#>
52+
53+
[CmdletBinding(DefaultParameterSetName = 'Build')]
54+
param(
55+
[Parameter(ParameterSetName = 'Build')]
56+
[switch] $Build,
57+
58+
[Parameter(ParameterSetName = 'Test', Mandatory)]
59+
[switch] $Test,
60+
61+
[Parameter(ParameterSetName = 'Pack', Mandatory)]
62+
[switch] $Pack,
63+
64+
[Parameter(ParameterSetName = 'Build')]
65+
[Parameter(ParameterSetName = 'Test')]
66+
[Parameter(ParameterSetName = 'Pack')]
67+
[string] $Configuration = 'Release',
68+
69+
[Parameter(ParameterSetName = 'Test')]
70+
[switch] $NoBuild,
71+
72+
[Parameter(ParameterSetName = 'Pack')]
73+
[string] $VersionSuffix,
74+
75+
[Parameter(ParameterSetName = 'Pack')]
76+
[string] $PackageReleaseNotesFile
77+
)
78+
79+
$ErrorActionPreference = 'Stop'
80+
Set-StrictMode -Version Latest
81+
82+
# Make the script directory-independent
83+
Push-Location $PSScriptRoot
84+
try {
85+
function Invoke-DotNet {
86+
param(
87+
[string[]] $Arguments
88+
)
89+
90+
Write-Host "dotnet $($Arguments -join ' ')" -ForegroundColor Cyan
91+
& dotnet @Arguments
92+
if ($LASTEXITCODE -ne 0) {
93+
throw "dotnet command failed with exit code $LASTEXITCODE"
94+
}
95+
}
96+
97+
function Invoke-BuildFlow {
98+
Write-Host "`n=== Building Baseline (Roslyn 3.10) ===" -ForegroundColor Green
99+
Invoke-DotNet 'build', '--configuration', $Configuration
100+
101+
Write-Host "`n=== Building Roslyn 4.4 Variant ===" -ForegroundColor Green
102+
Invoke-DotNet 'build', 'src/DocoptNet/DocoptNet.csproj', '-f', 'netstandard2.0', '-p:RoslynVersion=4.4', '--configuration', $Configuration
103+
}
104+
105+
function Invoke-TestFlow {
106+
if (-not $NoBuild) {
107+
Invoke-BuildFlow
108+
}
109+
110+
Write-Host "`n=== Running Tests ===" -ForegroundColor Green
111+
Invoke-DotNet 'test', '--no-build', '--configuration', $Configuration
112+
113+
# Note: Roslyn 4.4 analyzer is validated through integration tests
114+
# that use the packed NuGet package containing both analyzer variants
115+
}
116+
117+
function Invoke-PackFlow {
118+
Invoke-BuildFlow
119+
120+
Write-Host "`n=== Packing NuGet Package ===" -ForegroundColor Green
121+
$packArgs = @('pack', 'src/DocoptNet/DocoptNet.csproj', '--no-build', '--configuration', $Configuration)
122+
if ($VersionSuffix) {
123+
$packArgs += @('--version-suffix', $VersionSuffix)
124+
}
125+
if ($PackageReleaseNotesFile) {
126+
$packArgs += "-p:PackageReleaseNotesFile=$PackageReleaseNotesFile"
127+
}
128+
Invoke-DotNet $packArgs
129+
}
130+
131+
# Execute the appropriate flow based on parameter set
132+
switch ($PSCmdlet.ParameterSetName) {
133+
'Build' {
134+
Invoke-BuildFlow
135+
}
136+
'Test' {
137+
Invoke-TestFlow
138+
}
139+
'Pack' {
140+
Invoke-PackFlow
141+
}
142+
}
143+
144+
Write-Host "`n=== Success ===" -ForegroundColor Green
145+
}
146+
finally {
147+
Pop-Location
148+
}

src/DocoptNet/DocoptNet.csproj

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3+
<PropertyGroup>
4+
<_Roslyn44AnalyzerDir>$(MSBuildProjectDirectory)/bin/roslyn4.4/</_Roslyn44AnalyzerDir>
5+
</PropertyGroup>
6+
7+
<PropertyGroup Condition="'$(RoslynVersion)' == '4.4'">
8+
<DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/obj/**</DefaultItemExcludes>
9+
<DefineConstants>$(DefineConstants);ROSLYN4_4</DefineConstants>
10+
</PropertyGroup>
11+
312
<PropertyGroup>
413
<TargetFrameworks>netstandard2.1;netstandard2.0;net47</TargetFrameworks>
514
<DefineConstants>$(DefineConstants);DOCOPTNET_PUBLIC</DefineConstants>
@@ -49,14 +58,26 @@ Portions Copyright (C) West Wind Technologies, 2008.
4958
<None Include="CodeGeneration\*.cs" />
5059
</ItemGroup>
5160

52-
<ItemGroup Condition="'$(TargetFramework)' != 'net47'">
61+
<ItemGroup Condition="'$(TargetFramework)' != 'net47' And '$(RoslynVersion)' != '4.4'">
5362
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.10.0" PrivateAssets="all" />
63+
</ItemGroup>
64+
65+
<ItemGroup Condition="'$(TargetFramework)' != 'net47' And '$(RoslynVersion)' == '4.4'">
66+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
67+
</ItemGroup>
68+
69+
<ItemGroup Condition="'$(TargetFramework)' != 'net47'">
5470
<AdditionalFiles Include="CodeGeneration\AnalyzerReleases.*.md" />
5571
</ItemGroup>
5672

5773
<ItemGroup>
58-
<!-- Package the generator in the analyzer directory of the nuget package -->
59-
<None Include="$(OutputPath)\netstandard2.0\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
74+
<!-- Package the generator in the analyzer directory of the nuget package.
75+
Using a versioned roslyn3.10/ folder instead of the unversioned cs/ path ensures the SDK
76+
selects only the best-matching Roslyn variant (3.10 baseline or 4.4) rather than loading both.
77+
See: https://github.com/dotnet/sdk/issues/20355 -->
78+
<None Include="$(OutputPath)\netstandard2.0\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/roslyn3.10/cs" Visible="false" />
79+
<!-- Package the Roslyn 4.4 variant of the generator -->
80+
<None Include="$(_Roslyn44AnalyzerDir)$(Configuration)/netstandard2.0/$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/roslyn4.4/cs" Visible="false" />
6081
<!--
6182
Using a "PackagePath" of "build/$(TargetFramework)/%(Filename)%(Extension)" causes the
6283
following error:
@@ -96,4 +117,12 @@ Portions Copyright (C) West Wind Technologies, 2008.
96117
<AdditionalFiles Include="PublicAPI/$(TargetFramework)/PublicAPI.Unshipped.txt" />
97118
</ItemGroup>
98119

120+
<Target Name="_ValidateRoslyn44AnalyzerOutput" BeforeTargets="GenerateNuspec">
121+
<PropertyGroup>
122+
<_Roslyn44AnalyzerPath>$(_Roslyn44AnalyzerDir)$(Configuration)/netstandard2.0/$(AssemblyName).dll</_Roslyn44AnalyzerPath>
123+
</PropertyGroup>
124+
<Error Condition="!Exists('$(_Roslyn44AnalyzerPath)')"
125+
Text="Roslyn 4.4 analyzer output not found at '$(_Roslyn44AnalyzerPath)'. Build all Roslyn variants first by running: ./build.ps1 -Pack" />
126+
</Target>
127+
99128
</Project>

0 commit comments

Comments
 (0)