Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Compiler/Driver/CompilerImports.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,7 @@ and [<Sealed>] TcImports
CheckDisposed()

let tcConfig = tcConfigP.Get ctok

let runMethod =
match tcConfig.parallelReferenceResolution with
| ParallelReferenceResolution.On -> NodeCode.Parallel
Expand Down
61 changes: 52 additions & 9 deletions src/Compiler/Driver/FxResolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -382,16 +382,16 @@ type internal FxResolver

let tryGetNetCoreRefsPackDirectoryRoot () = tryNetCoreRefsPackDirectoryRoot.Force()

let getTfmNumber (v: string) =
let arr = v.Split([| '.' |], 3)
arr[0] + "." + arr[1]

// Tries to figure out the tfm for the compiler instance.
// On coreclr it uses the deps.json file
//
// On-demand because (a) some FxResolver are ephemeral (b) we want to avoid recomputation
let tryGetRunningTfm =
let tryGetRunningTfm () =
let runningTfmOpt =
let getTfmNumber (v: string) =
let arr = v.Split([| '.' |], 3)
arr[0] + "." + arr[1]

// Compute TFM from System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription
// System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription;;
// val it: string = ".NET 6.0.7"
Expand Down Expand Up @@ -548,6 +548,24 @@ type internal FxResolver
assemblyReferences |> List.iter traverseDependencies
assemblies

let tryGetTfmFromSdkDir (sdkDir: string) =
let dotnetConfigFile = Path.Combine(sdkDir, "dotnet.runtimeconfig.json")

try
use stream = FileSystem.OpenFileForReadShim(dotnetConfigFile)
let dotnetConfig = stream.ReadAllText()
let pattern = "\"tfm\": \""

let startPos =
dotnetConfig.IndexOf(pattern, StringComparison.OrdinalIgnoreCase)
+ pattern.Length

let endPos = dotnetConfig.IndexOf("\"", startPos)
let tfm = dotnetConfig[startPos .. endPos - 1]
tfm
with _ ->
tryGetRunningTfm ()

// This list is the default set of references for "non-project" files.
//
// These DLLs are
Expand Down Expand Up @@ -806,12 +824,37 @@ type internal FxResolver
RequireFxResolverLock(fxtok, "assuming all member require lock")
tryGetSdkDir () |> replayWarnings)

/// Gets the selected target framework moniker, e.g netcore3.0, net472, and the running rid of the current machine
/// Gets
/// 1. The Target Framework Moniker (TFM) used for scripting (e.g netcore3.0, net472)
/// 2. The running RID of the current machine (e.g. win-x64)
///
/// When analyzing scripts for editing, this is **not** necessarily the running TFM. Rather, it is the TFM to use for analysing
/// a script.
///
/// Summary:
/// - When running scripts (isInteractive = true) this is identical to the running TFM.
///
/// - When analyzing .NET Core scripts (isInteractive = false, tryGetSdkDir is Some),
/// the scripting TFM is determined from dotnet.runtimeconfig.json in the SDK directory
///
/// - Otherwise, the running TFM is used. That is, if editing with .NET Framework/Core-based tooling a script is assumed
/// to be .NET Framework/Core respectively.
///
/// The RID returned is always the RID of the running machine.
member _.GetTfmAndRid() =
fxlock.AcquireLock(fun fxtok ->
RequireFxResolverLock(fxtok, "assuming all member require lock")

let runningTfm = tryGetRunningTfm
// Interactive processes read their own configuration to find the running tfm
let targetTfm =
if isInteractive then
tryGetRunningTfm ()
else
let sdkDir = tryGetSdkDir () |> replayWarnings

match sdkDir with
| Some dir -> tryGetTfmFromSdkDir dir
| None -> tryGetRunningTfm ()

// Coreclr has mechanism for getting rid
// System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier
Expand Down Expand Up @@ -862,7 +905,7 @@ type internal FxResolver
| Architecture.Arm64 -> baseRid + "-arm64"
| _ -> baseRid + "-arm"

runningTfm, runningRid)
targetTfm, runningRid)

static member ClearStaticCaches() =
desiredDotNetSdkVersionForDirectoryCache.Clear()
Expand All @@ -885,7 +928,7 @@ type internal FxResolver
let defaultReferences =
if assumeDotNetFramework then
getDotNetFrameworkDefaultReferences useFsiAuxLib, assumeDotNetFramework
else if useSdkRefs then
elif useSdkRefs then
// Go fetch references
let sdkDir = tryGetSdkRefsPackDirectory () |> replayWarnings

Expand Down
29 changes: 28 additions & 1 deletion tests/service/ScriptOptionsTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ let pi = Math.PI
"""

[<TestCase(true, false, [| "--targetprofile:mscorlib" |])>]
[<TestCase(false, false, [| "--targetprofile:netcore" |])>]
[<TestCase(false, true, [| "--targetprofile:netcore" |])>]
[<Test>]
let ``can generate options for different frameworks regardless of execution environment``(assumeNetFx, useSdk, flags) =
let path = Path.GetTempPath()
let file = tryCreateTemporaryFileName ()
let file = tryCreateTemporaryFileName () + ".fsx"
let tempFile = Path.Combine(path, file)
let _, errors =
checker.GetProjectOptionsFromScript(tempFile, SourceText.ofString scriptSource, assumeDotNetFramework = assumeNetFx, useSdkRefs = useSdk, otherFlags = flags)
Expand All @@ -37,6 +38,32 @@ let ``can generate options for different frameworks regardless of execution envi
| [] -> ()
| errors -> failwithf "Error while parsing script with assumeDotNetFramework:%b, useSdkRefs:%b, and otherFlags:%A:\n%A" assumeNetFx useSdk flags errors

#if NETFRAMEWORK
// See https://github.com/dotnet/fsharp/pull/13994#issuecomment-1259663865
//
// .NET Core-based tooling can't resolve nuget packages to .NET Framework references
[<TestCase(true, false, [| "--targetprofile:mscorlib" |])>]
#endif
[<TestCase(false, true, [| "--targetprofile:netcore" |])>]
[<Test>]
let ``can resolve nuget packages to right target framework for different frameworks regardless of execution environment``(assumeNetFx, useSdk, flags) =
let path = Path.GetTempPath()
let file = tryCreateTemporaryFileName () + ".fsx"
let tempFile = Path.Combine(path, file)
let scriptSource = """
#r "nuget: FSharp.Data, 3.3.3"
open System
let pi = Math.PI
"""
let options, errors =
checker.GetProjectOptionsFromScript(tempFile, SourceText.ofString scriptSource, assumeDotNetFramework = assumeNetFx, useSdkRefs = useSdk, otherFlags = flags)
|> Async.RunImmediate
match errors with
| [] -> ()
| errors -> failwithf "Error while parsing script with assumeDotNetFramework:%b, useSdkRefs:%b, and otherFlags:%A:\n%A" assumeNetFx useSdk flags errors
let expectedReferenceText = (if assumeNetFx then "net45" else "netstandard2.0")
let found = options.OtherOptions |> Array.exists (fun s -> s.Contains(expectedReferenceText) && s.Contains("FSharp.Data.dll"))
Assert.IsTrue(found)

// This test atempts to use a bad SDK number 666.666.666
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ type private FSharpProjectOptionsReactor (checker: FSharpChecker) =
let! scriptProjectOptions, _ =
checker.GetProjectOptionsFromScript(document.FilePath,
sourceText.ToFSharpSourceText(),
SessionsProperties.fsiPreview,
previewEnabled=SessionsProperties.fsiPreview,
assumeDotNetFramework=not SessionsProperties.fsiUseNetCore,
userOpName=userOpName)

Expand Down
10 changes: 5 additions & 5 deletions vsintegration/src/FSharp.VS.FSI/fsiLanguageService.fs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ type FsiPropertyPage() =
[<ResourceDescription(SRProperties.FSharpInteractiveShadowCopyDescr)>]
member this.FsiShadowCopy with get() = SessionsProperties.fsiShadowCopy and set (x:bool) = SessionsProperties.fsiShadowCopy <- x

[<ResourceCategory(SRProperties.FSharpInteractiveMisc)>]
[<ResourceDisplayName(SRProperties.FSharpInteractiveUseNetCore)>]
[<ResourceDescription(SRProperties.FSharpInteractiveUseNetCoreDescr)>]
member this.FsiUseNetCore with get() = SessionsProperties.fsiUseNetCore and set (x:bool) = SessionsProperties.fsiUseNetCore <- x

[<ResourceCategory(SRProperties.FSharpInteractiveDebugging)>]
[<ResourceDisplayName(SRProperties.FSharpInteractiveDebugMode)>]
[<ResourceDescription(SRProperties.FSharpInteractiveDebugModeDescr)>]
Expand All @@ -56,11 +61,6 @@ type FsiPropertyPage() =
[<ResourceDescription(SRProperties.FSharpInteractivePreviewModeDescr)>]
member this.FsiPreview with get() = SessionsProperties.fsiPreview and set (x:bool) = SessionsProperties.fsiPreview <- x

[<ResourceCategory(SRProperties.FSharpInteractivePreview)>]
[<ResourceDisplayName(SRProperties.FSharpInteractiveUseNetCore)>]
[<ResourceDescription(SRProperties.FSharpInteractiveUseNetCoreDescr)>]
member this.FsiUseNetCore with get() = SessionsProperties.fsiUseNetCore and set (x:bool) = SessionsProperties.fsiUseNetCore <- x

// CompletionSet
type internal FsiCompletionSet(imageList,source:Source) =
inherit CompletionSet(imageList, source)
Expand Down