diff --git a/src/Paket.Core/PaketConfigFiles/ProjectFile.fs b/src/Paket.Core/PaketConfigFiles/ProjectFile.fs
index c7fac7430c..eeff28f21f 100644
--- a/src/Paket.Core/PaketConfigFiles/ProjectFile.fs
+++ b/src/Paket.Core/PaketConfigFiles/ProjectFile.fs
@@ -1069,6 +1069,20 @@ module ProjectFile =
|> Array.map (fun x -> x.Trim())
|> Array.toList
+ // Same as getTargetFramework/getTargetFrameworksParsed above but evaluates conditional
+ // PropertyGroups (e.g. `Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"`)
+ // using the given Configuration/Platform, instead of an empty property map.
+ let getTargetFrameworkWithDefaults defaultProperties (project:ProjectFile) =
+ getPropertyWithDefaults "TargetFramework" defaultProperties project
+
+ let getTargetFrameworksParsedWithDefaults defaultProperties (project:ProjectFile) =
+ getPropertyWithDefaults "TargetFrameworks" defaultProperties project
+ |> Option.map (fun x -> x.Split([|';'|],StringSplitOptions.RemoveEmptyEntries))
+ |> Option.toArray
+ |> Array.concat
+ |> Array.map (fun x -> x.Trim())
+ |> Array.toList
+
let getToolsVersion (project:ProjectFile) =
let adjustIfWeHaveSDK v =
try
@@ -1622,22 +1636,28 @@ module ProjectFile =
sprintf "%s.%s" assemblyName ending
let getOutputDirectory buildConfiguration buildPlatform (targetProfile : TargetProfile option) (project:ProjectFile) =
+ // Some projects put TargetFramework(s) inside a conditional PropertyGroup keyed on
+ // Configuration/Platform (e.g. `Condition="'$(Configuration)'=='Release'"`), so we must
+ // evaluate the property map with the requested Configuration/Platform, not an empty one,
+ // or the frameworks won't be found at all (see issue #3799).
+ let defaultProperties =
+ Map.ofList [("Configuration", buildConfiguration); ("Platform", buildPlatform)]
let targetFramework =
match targetProfile with
| Some targetProfile ->
let targetProfile = targetProfile.ToString()
- match getTargetFramework project with
+ match getTargetFrameworkWithDefaults defaultProperties project with
| Some x -> if x = targetProfile then x else ""
| None ->
- let parsedTargetFrameworks = getTargetFrameworksParsed project
+ let parsedTargetFrameworks = getTargetFrameworksParsedWithDefaults defaultProperties project
match List.tryFind ((=) targetProfile) parsedTargetFrameworks with
| Some x -> x
| None -> ""
| None ->
- match getTargetFramework project with
+ match getTargetFrameworkWithDefaults defaultProperties project with
| Some x -> x
| None ->
- match getTargetFrameworksParsed project with
+ match getTargetFrameworksParsedWithDefaults defaultProperties project with
| fwk :: _ -> fwk
| [] -> ""
diff --git a/tests/Paket.Tests/Paket.Tests.fsproj b/tests/Paket.Tests/Paket.Tests.fsproj
index 0ff0e05548..2beb860531 100644
--- a/tests/Paket.Tests/Paket.Tests.fsproj
+++ b/tests/Paket.Tests/Paket.Tests.fsproj
@@ -130,6 +130,8 @@
+
+
diff --git a/tests/Paket.Tests/ProjectFile/OutputSpecs.fs b/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
index 88b95a32ed..7ab8f22034 100644
--- a/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
+++ b/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
@@ -103,6 +103,48 @@ let ``should detect output path for netsdk with outputPath and appendTargetFrame
let expected = (System.IO.Path.Combine(@"bin", configuration,"netstandard1.4_bin") |> normalizePath)
outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())
+[]
+let ``should detect output path for netsdk with conditional target frameworks csproj file``
+ ([] configuration) =
+ ensureDir ()
+ let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest").Value
+ // Should not throw "Unable to find output path node" (see issue #3799)
+ let outPath = projectFile.GetOutputDirectory configuration "" None
+ outPath |> shouldNotEqual ""
+
+[]
+let ``should detect output path for netsdk with only conditional target frameworks (no unconditional fallback) csproj file``
+ ([] configuration) =
+ ensureDir ()
+ // Reproduces the exact shape from issue #3799: no unconditional TargetFramework/TargetFrameworks
+ // element exists at all, only Configuration-conditioned PropertyGroups.
+ let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
+ let outPath = projectFile.GetOutputDirectory configuration "" None
+ outPath |> shouldNotEqual ""
+
+[]
+let ``should pick the conditional target frameworks matching the requested configuration for netsdk csproj file``
+ ([] configuration) =
+ ensureDir ()
+ let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
+ let outPath = projectFile.GetOutputDirectory configuration "" None
+ // Debug config only lists netstandard2.0;net45, Release additionally lists net47;
+ // the first framework in each list is netstandard2.0, and it should be selected as the default.
+ let expected = (System.IO.Path.Combine(@"bin", configuration, "netstandard2.0") |> normalizePath)
+ outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())
+
+[]
+let ``should detect output path for a specific target profile in a conditional target frameworks csproj file``
+ ([] configuration) =
+ ensureDir ()
+ let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
+ let targetProfile =
+ FrameworkDetection.internalExtract "net45"
+ |> Option.map TargetProfile.SinglePlatform
+ let outPath = projectFile.GetOutputDirectory configuration "" targetProfile
+ let expected = (System.IO.Path.Combine(@"bin", configuration, "net45") |> normalizePath)
+ outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())
+
[]
let ``should detect framework profile for ProjectWithConditions file`` () =
ensureDir ()
diff --git a/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest b/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest
new file mode 100644
index 0000000000..23350487da
--- /dev/null
+++ b/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest
@@ -0,0 +1,15 @@
+
+
+
+ TestPaket
+ netstandard2.0
+
+
+
+ netstandard2.0;net45
+
+
+
+ netstandard2.0;net45;net47
+
+
diff --git a/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest b/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest
new file mode 100644
index 0000000000..7b87c3d03c
--- /dev/null
+++ b/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest
@@ -0,0 +1,10 @@
+
+
+
+ netstandard2.0;net45
+
+
+
+ netstandard2.0;net45;net47
+
+