@@ -7,14 +7,15 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies
77 open System
88 open System.Collections .Generic
99 open System.Diagnostics
10+ open System.Globalization
1011 open System.IO
1112 open System.Reflection
1213
1314 type private TypeInThisAssembly = class end
1415
1516 let getFSharpCoreLibraryName = " FSharp.Core"
1617 let getFsiLibraryName = " FSharp.Compiler.Interactive.Settings"
17- let frameworkDir = Path.GetDirectoryName( typeof< Object >. Assembly.Location)
18+ let implementationAssemblyDir = Path.GetDirectoryName( typeof< obj >. Assembly.Location)
1819 let getDefaultFSharpCoreReference = typeof< Microsoft.FSharp.Core.Unit>. Assembly.Location
1920 let getFSharpCompilerLocation = Path.GetDirectoryName( typeof< TypeInThisAssembly>. Assembly.Location)
2021
@@ -34,120 +35,85 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies
3435 None
3536 with _ -> None
3637
37- // Compare nuget version strings
38+
39+ // Algorithm:
40+ // use implementation location of obj type, on shared frameworks it will always be in:
3841 //
39- // Format:
40- // =======
41- // $(Major).$(Minor).$(Build) [-SomeSuffix]
42- // Major, Minor, Build collates normally
43- // Strings without -SomeSuffix collate higher than SomeSuffix,
44- // SomeSuffix collates using normal alphanumeric rules
42+ // dotnet\shared\Microsoft.NETCore.App\sdk-version\System.Private.CoreLib.dll
4543 //
46- let deconstructVersion ( version : string ) =
47- let version , suffix =
48- let pos = version.IndexOf( " -" )
49- if pos >= 0 then
50- version.Substring( 0 , pos), version.Substring( pos + 1 )
51- else version, " "
52-
53- let elements = version.Split( '.' )
54- if elements.Length < 3 then
55- struct ( 0 , 0 , 0 , suffix)
56- else
57- struct ( Int32.Parse( elements.[ 0 ]), Int32.Parse( elements.[ 1 ]), Int32.Parse( elements.[ 2 ]), suffix)
58-
59- let versionCompare c1 c2 =
60- if c1 = c2 then 0
61- else
62- try
63- let struct ( major1 , minor1 , build1 , suffix1 ) = deconstructVersion c1
64- let struct ( major2 , minor2 , build2 , suffix2 ) = deconstructVersion c2
65- let v = major1 - major2
66- if v <> 0 then v
67- else
68- let v = minor1 - minor2
69- if v <> 0 then v
70- else
71- let v = build1 - build2
72- if v <> 0 then v
73- else
74- match String.IsNullOrEmpty( suffix1), String.IsNullOrEmpty( suffix2) with
75- | true , true -> 0
76- | true , false -> 1
77- | false , true -> - 1
78- | false , false -> String.Compare( suffix1, suffix2, StringComparison.InvariantCultureIgnoreCase)
79- with _ -> 0
80-
81- let executionTfm =
82- let file =
83- try
84- let depsJsonPath = Path.ChangeExtension( Assembly.GetEntryAssembly() .Location, " deps.json" )
85- if File.Exists( depsJsonPath) then
86- File.ReadAllText( depsJsonPath)
87- else
88- " "
89- with _ -> " "
90-
91- let tfmPrefix = " .NETCoreApp,Version=v"
92- let pattern = " \" name\" : \" " + tfmPrefix
93- let startPos =
94- let startPos = file.IndexOf( pattern, StringComparison.OrdinalIgnoreCase)
95- if startPos >= 0 then startPos + ( pattern.Length) else startPos
96-
97- let length =
98- if startPos >= 0 then
99- let ep = file.IndexOf( " \" " , startPos)
100- if ep >= 0 then ep - startPos else ep
101- else - 1
102- match startPos, length with
103- | - 1 , _
104- | _, - 1 -> None
105- | pos, length -> Some ( " netcoreapp" + file.Substring( pos, length))
106-
107-
108- let getFrameworkRefsPackDirectoryPath =
109- match executionTfm with
110- | Some _ ->
111- let appRefDir = Path.Combine( getFSharpCompilerLocation, " ../../../packs/Microsoft.NETCore.App.Ref" )
112- if Directory.Exists( appRefDir) then
113- Some appRefDir
44+ // if that changes we will need to find another way to do this. Hopefully the sdk will eventually provide an API
45+ // use the well know location for obj to traverse the file system towards the
46+ //
47+ // packs\Microsoft.NETCore.App.Ref\sdk-version\netcoreappn.n
48+ // we will rely on the sdk-version match on the two paths to ensure that we get the product that ships with the
49+ // version of the runtime we are executing on
50+ // Use the reference assemblies for the highest netcoreapp tfm that we find in that location.
51+ let version , frameworkRefsPackDirectoryRoot =
52+ try
53+ let version = DirectoryInfo( implementationAssemblyDir) .Name
54+ let microsoftNETCoreAppRef = Path.Combine( implementationAssemblyDir, " ../../../packs/Microsoft.NETCore.App.Ref" )
55+ if Directory.Exists( microsoftNETCoreAppRef) then
56+ Some version, Some microsoftNETCoreAppRef
11457 else
115- None
116- | _ -> None
58+ Some version , None
59+ with | _ -> None , None
11760
11861 let isInReferenceAssemblyPackDirectory filename =
119- match getFrameworkRefsPackDirectoryPath with
120- | Some appRefDir ->
62+ match frameworkRefsPackDirectoryRoot with
63+ | Some root ->
12164 let path = Path.GetDirectoryName( filename)
122- path.StartsWith( appRefDir , StringComparison.OrdinalIgnoreCase)
65+ path.StartsWith( root , StringComparison.OrdinalIgnoreCase)
12366 | _ -> false
12467
125- let getFrameworkRefsPackDirectory =
126- match executionTfm, getFrameworkRefsPackDirectoryPath with
127- | Some tfm, Some appRefDir ->
68+ let frameworkRefsPackDirectory =
69+ let tfmPrefix = " netcoreapp"
70+ let tfmCompare c1 c2 =
71+ let deconstructTfmApp ( netcoreApp : DirectoryInfo ) =
72+ let name = netcoreApp.Name
73+ try
74+ if name.StartsWith( tfmPrefix, StringComparison.InvariantCultureIgnoreCase) then
75+ Some ( Double.Parse( name.Substring( tfmPrefix.Length), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture))
76+ else
77+ None
78+ with _ -> None
79+
80+ if c1 = c2 then 0
81+ else
82+ match ( deconstructTfmApp c1), ( deconstructTfmApp c2) with
83+ | Some c1, Some c2 -> int( c1 - c2)
84+ | None, Some _ -> - 1
85+ | Some _, None -> 1
86+ | _ -> 0
87+
88+ match version, frameworkRefsPackDirectoryRoot with
89+ | Some version, Some root ->
12890 try
129- let refDirs = Directory.GetDirectories( appRefDir)
130- let versionPath = refDirs |> Array.sortWith ( versionCompare) |> Array.last
131- Some( Path.Combine( versionPath, " ref" , tfm))
91+ let ref = Path.Combine( root, version, " ref" )
92+ let highestTfm = DirectoryInfo( ref) .GetDirectories()
93+ |> Array.sortWith tfmCompare
94+ |> Array.tryLast
95+
96+ match highestTfm with
97+ | Some tfm -> Some ( Path.Combine( ref, tfm.Name))
98+ | None -> None
13299 with | _ -> None
133100 | _ -> None
134101
135-
136-
137102 let getDependenciesOf assemblyReferences =
138103 let assemblies = new Dictionary< string, string>()
139104
140105 // Identify path to a dll in the framework directory from a simple name
141106 let frameworkPathFromSimpleName simpleName =
142- let pathDll = Path.Combine( frameworkDir, simpleName + " .dll" )
143- if not ( File.Exists( pathDll)) then
144- let pathExe = Path.Combine( frameworkDir, simpleName + " .exe" )
145- if not ( File.Exists( pathExe)) then
146- pathDll
147- else
148- pathExe
149- else
150- pathDll
107+ let root = Path.Combine( implementationAssemblyDir, simpleName)
108+ let pathOpt =
109+ [| " " ; " .dll" ; " .exe" |]
110+ |> Seq.tryPick( fun ext ->
111+ let path = root + ext
112+ if File.Exists( path) then Some path
113+ else None)
114+ match pathOpt with
115+ | Some path -> path
116+ | None -> root
151117
152118 // Collect all assembly dependencies into assemblies dictionary
153119 let rec traverseDependencies reference =
@@ -228,14 +194,14 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies
228194 let getImplementationReferences () =
229195 // Coreclr supports netstandard assemblies only for now
230196 ( getDependenciesOf [
231- yield Path.Combine( frameworkDir , " netstandard.dll" )
197+ yield Path.Combine( implementationAssemblyDir , " netstandard.dll" )
232198 yield getDefaultFSharpCoreReference
233199 if useFsiAuxLib then yield getFsiLibraryName
234200 ]) .Values |> Seq.toList
235201
236202 if useSdkRefs then
237203 // Go fetch references
238- match getFrameworkRefsPackDirectory with
204+ match frameworkRefsPackDirectory with
239205 | Some path ->
240206 try [ yield ! Directory.GetFiles( path, " *.dll" )
241207 yield getDefaultFSharpCoreReference
0 commit comments