diff --git a/.gitignore b/.gitignore index f75c0e414f..7f3870c3d0 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,4 @@ msbuild.binlog /fcs/FSharp.Compiler.Service.netstandard/*.fs /fcs/FSharp.Compiler.Service.netstandard/*.fsi /.ionide/ +**/.DS_Store diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index ae80119d95..e9e5ce6501 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -2806,7 +2806,7 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = if Directory.Exists runtimeRootWPF then yield runtimeRootWPF // PresentationCore.dll is in C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF - match getFrameworkRefsPackDirectory with + match frameworkRefsPackDirectory with | Some path when Directory.Exists(path) -> yield path | _ -> () diff --git a/src/fsharp/DotNetFrameworkDependencies.fs b/src/fsharp/DotNetFrameworkDependencies.fs index 3c0c6d0048..0c969bad54 100644 --- a/src/fsharp/DotNetFrameworkDependencies.fs +++ b/src/fsharp/DotNetFrameworkDependencies.fs @@ -7,6 +7,7 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies open System open System.Collections.Generic open System.Diagnostics + open System.Globalization open System.IO open System.Reflection @@ -14,7 +15,7 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies let getFSharpCoreLibraryName = "FSharp.Core" let getFsiLibraryName = "FSharp.Compiler.Interactive.Settings" - let frameworkDir = Path.GetDirectoryName(typeof.Assembly.Location) + let implementationAssemblyDir = Path.GetDirectoryName(typeof.Assembly.Location) let getDefaultFSharpCoreReference = typeof.Assembly.Location let getFSharpCompilerLocation = Path.GetDirectoryName(typeof.Assembly.Location) let isRunningOnCoreClr = (typeof.Assembly).FullName.StartsWith("System.Private.CoreLib", StringComparison.InvariantCultureIgnoreCase) @@ -35,49 +36,28 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies None with _ -> None - // Compare nuget version strings - // - // Format: - // ======= - // $(Major).$(Minor).$(Build) [-SomeSuffix] - // Major, Minor, Build collates normally - // Strings without -SomeSuffix collate higher than SomeSuffix, - // SomeSuffix collates using normal alphanumeric rules - // - let deconstructVersion (version:string) = - let version, suffix = - let pos = version.IndexOf("-") - if pos >= 0 then - version.Substring(0, pos), version.Substring(pos + 1) - else version, "" - let elements = version.Split('.') - if elements.Length < 3 then - struct (0, 0, 0, suffix) - else - struct (Int32.Parse(elements.[0]), Int32.Parse(elements.[1]), Int32.Parse(elements.[2]), suffix) - - let versionCompare c1 c2 = - if c1 = c2 then 0 - else - try - let struct (major1, minor1, build1, suffix1 ) = deconstructVersion c1 - let struct (major2, minor2, build2, suffix2 ) = deconstructVersion c2 - let v = major1 - major2 - if v <> 0 then v - else - let v = minor1 - minor2 - if v <> 0 then v - else - let v = build1 - build2 - if v <> 0 then v - else - match String.IsNullOrEmpty(suffix1), String.IsNullOrEmpty(suffix2) with - | true, true -> 0 - | true, false -> 1 - | false, true -> -1 - | false, false -> String.Compare(suffix1, suffix2, StringComparison.InvariantCultureIgnoreCase) - with _ -> 0 + // Algorithm: + // use implementation location of obj type, on shared frameworks it will always be in: + // + // dotnet\shared\Microsoft.NETCore.App\sdk-version\System.Private.CoreLib.dll + // + // if that changes we will need to find another way to do this. Hopefully the sdk will eventually provide an API + // use the well know location for obj to traverse the file system towards the + // + // packs\Microsoft.NETCore.App.Ref\sdk-version\netcoreappn.n + // we will rely on the sdk-version match on the two paths to ensure that we get the product that ships with the + // version of the runtime we are executing on + // Use the reference assemblies for the highest netcoreapp tfm that we find in that location. + let version, frameworkRefsPackDirectoryRoot = + try + let version = DirectoryInfo(implementationAssemblyDir).Name + let microsoftNETCoreAppRef = Path.Combine(implementationAssemblyDir, "../../../packs/Microsoft.NETCore.App.Ref") + if Directory.Exists(microsoftNETCoreAppRef) then + Some version, Some microsoftNETCoreAppRef + else + Some version, None + with | _ -> None, None // Tries to figure out the tfm for the compiler instance. // On coreclr it uses the deps.json file @@ -163,31 +143,44 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies match netcoreTfm with | Some tfm -> tfm | _ -> getWindowsDesktopTfm () - - let getFrameworkRefsPackDirectoryPath = - match netcoreTfm with - | Some _ -> - let appRefDir = Path.Combine(getFSharpCompilerLocation, "../../../packs/Microsoft.NETCore.App.Ref") - if Directory.Exists(appRefDir) then - Some appRefDir - else - None - | _ -> None - let isInReferenceAssemblyPackDirectory filename = - match getFrameworkRefsPackDirectoryPath with - | Some appRefDir -> + match frameworkRefsPackDirectoryRoot with + | Some root -> let path = Path.GetDirectoryName(filename) - path.StartsWith(appRefDir, StringComparison.OrdinalIgnoreCase) + path.StartsWith(root, StringComparison.OrdinalIgnoreCase) | _ -> false - let getFrameworkRefsPackDirectory = - match netcoreTfm, getFrameworkRefsPackDirectoryPath with - | Some tfm, Some appRefDir -> + let frameworkRefsPackDirectory = + let tfmPrefix = "netcoreapp" + let tfmCompare c1 c2 = + let deconstructTfmApp (netcoreApp: DirectoryInfo) = + let name = netcoreApp.Name + try + if name.StartsWith(tfmPrefix, StringComparison.InvariantCultureIgnoreCase) then + Some (Double.Parse(name.Substring(tfmPrefix.Length), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture)) + else + None + with _ -> None + + if c1 = c2 then 0 + else + match (deconstructTfmApp c1), (deconstructTfmApp c2) with + | Some c1, Some c2 -> int(c1 - c2) + | None, Some _ -> -1 + | Some _, None -> 1 + | _ -> 0 + + match version, frameworkRefsPackDirectoryRoot with + | Some version, Some root -> try - let refDirs = Directory.GetDirectories(appRefDir) - let versionPath = refDirs |> Array.sortWith (versionCompare) |> Array.last - Some(Path.Combine(versionPath, "ref", tfm)) + let ref = Path.Combine(root, version, "ref") + let highestTfm = DirectoryInfo(ref).GetDirectories() + |> Array.sortWith tfmCompare + |> Array.tryLast + + match highestTfm with + | Some tfm -> Some (Path.Combine(ref, tfm.Name)) + | None -> None with | _ -> None | _ -> None @@ -196,15 +189,16 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies // Identify path to a dll in the framework directory from a simple name let frameworkPathFromSimpleName simpleName = - let pathDll = Path.Combine(frameworkDir, simpleName + ".dll") - if not (File.Exists(pathDll)) then - let pathExe = Path.Combine(frameworkDir, simpleName + ".exe") - if not (File.Exists(pathExe)) then - pathDll - else - pathExe - else - pathDll + let root = Path.Combine(implementationAssemblyDir, simpleName) + let pathOpt = + [| ""; ".dll"; ".exe" |] + |> Seq.tryPick(fun ext -> + let path = root + ext + if File.Exists(path) then Some path + else None) + match pathOpt with + | Some path -> path + | None -> root // Collect all assembly dependencies into assemblies dictionary let rec traverseDependencies reference = @@ -285,14 +279,14 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies let getImplementationReferences () = // Coreclr supports netstandard assemblies only for now (getDependenciesOf [ - yield Path.Combine(frameworkDir, "netstandard.dll") + yield Path.Combine(implementationAssemblyDir, "netstandard.dll") yield getDefaultFSharpCoreReference if useFsiAuxLib then yield getFsiLibraryName ]).Values |> Seq.toList if useSdkRefs then // Go fetch references - match getFrameworkRefsPackDirectory with + match frameworkRefsPackDirectory with | Some path -> try [ yield! Directory.GetFiles(path, "*.dll") yield getDefaultFSharpCoreReference diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index b387b6b7f1..818e9d3ec2 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -66,7 +66,7 @@ type LanguageVersion (specifiedVersion) = match specifiedVersion with | "?" -> 0m | "preview" -> previewVersion - | "default" -> latestVersion + | "default" -> defaultVersion | "latest" -> latestVersion | "latestmajor" -> latestMajorVersion | _ -> diff --git a/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj b/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj index be4e9125a2..790fdc6431 100644 --- a/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj +++ b/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj @@ -18,7 +18,6 @@ - diff --git a/tests/FSharp.Compiler.UnitTests/VersionCompare.fs b/tests/FSharp.Compiler.UnitTests/VersionCompare.fs deleted file mode 100644 index f5d5f709b5..0000000000 --- a/tests/FSharp.Compiler.UnitTests/VersionCompare.fs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace FSharp.Compiler.UnitTests - -open System -open System.Globalization -open System.Text -open NUnit.Framework -open FSharp.Compiler - -[] -module VersionCompare = - open FSharp.Compiler.DotNetFrameworkDependencies - - [] // 1.0.0 < 1.0.1 - [] // 1.0.0 = 1.0.0 - [] // 1.0.1 > 1.0.1 - [] // 0.0.9 < 1.0.0-Suffix1 - [] // 1.0.0 > 1.0.0-Suffix1 - [] // 1.0.0-Suffix1 < 1.0.0 - [] // 1.0.0-Suffix1 < 1.0.0-Suffix2 - [] // 1.0.0-Suffix2 > 1.0.0-Suffix1 - [] // 1.0.0-Suffix1 > 1.0.0-Suffix2 - [] // 1.0.1 > 1.0.0-Suffix1 - [] // 1.0.0-Suffix1 < 1.0.1 - let VersionCompareTest (str1: string, str2: string) : int = - versionCompare str1 str2 - - - [] - [] - let VersionCompareSortArrayHighestPreview _: string = - let versions = [| - "1.0.0-preview4-20000-01" - "3.0.0-preview4-27610-06" - "1.0.0-preview4-20000-02" - "3.0.0-preview4-27610-05" - "3.0.0-preview4-27609-10" - |] - versions |> Array.sortWith (versionCompare) |> Array.last - - [] - [] - let VersionCompareSortArrayHighestRelease _: string = - let versions = [| - "1.0.0-preview4-20000-01" - "3.0.0" - "3.0.0-preview4-27610-06" - "1.0.0-preview4-20000-02" - "3.0.0-preview4-27610-05" - "3.0.0-preview4-27609-10" - |] - versions |> Array.sortWith (versionCompare) |> Array.last - - [] - [] - let VersionCompareSortArrayEvenHighestRelease _: string = - let versions = [| - "3.0.1" - "1.0.0-preview4-20000-01" - "3.0.0" - "3.0.0-preview4-27610-06" - "1.0.0-preview4-20000-02" - "3.0.0-preview4-27610-05" - "3.0.0-preview4-27609-10" - |] - versions |> Array.sortWith (versionCompare) |> Array.last