diff --git a/src/fsharp/ReferenceResolver.fs b/src/fsharp/ReferenceResolver.fs index e5ec487352..0eef26292d 100644 --- a/src/fsharp/ReferenceResolver.fs +++ b/src/fsharp/ReferenceResolver.fs @@ -65,10 +65,13 @@ type Resolver = logerror:(string->string->unit) -> ResolvedFile[] -let ScriptingNaiveResolver = +let SimulatedMSBuildResolver = { new Resolver with member __.HighestInstalledNetFrameworkVersion() = "v4.5" member __.DotNetFrameworkReferenceAssembliesRootDirectory = +#if RESHAPED_MSBUILD + "" +#else if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then let PF = match Environment.GetEnvironmentVariable("ProgramFiles(x86)") with @@ -77,10 +80,12 @@ let ScriptingNaiveResolver = PF + @"\Reference Assemblies\Microsoft\Framework\.NETFramework" else "" +#endif member __.Resolve(resolutionEnvironment, references, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, outputDirectory, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) = +#if !RESHAPED_MSBUILD let registrySearchPaths() = [ let registryKey = @"Software\Microsoft\.NetFramework"; use key = Registry.LocalMachine.OpenSubKey(registryKey) @@ -107,79 +112,126 @@ let ScriptingNaiveResolver = match subSubSubKey.GetValue(null) with | :? string as s -> yield s | _ -> () ] +#endif - + let results = ResizeArray() let searchPaths = [ yield! targetFrameworkDirectories yield! explicitIncludeDirs yield fsharpCoreDir yield implicitIncludeDir +#if !RESHAPED_MSBUILD if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then - yield! registrySearchPaths() ] + yield! registrySearchPaths() +#endif + ] - [| for (baggage,r) in references do + for (r, baggage) in references do + //printfn "resolving %s" r let mutable found = false let success path = if not found then + //printfn "resolved %s --> %s" r path found <- true - [ { itemSpec = path; prepareToolTip = snd; baggage=baggage } ] - else [] - if Path.IsPathRooted(r) then - if FileSystem.SafeExists(r) then - yield! success r - else - let isFileName = - r.EndsWith("dll",StringComparison.InvariantCultureIgnoreCase) || - r.EndsWith("exe",StringComparison.InvariantCultureIgnoreCase) - - let qual = if isFileName then r else try AssemblyName(r).Name + ".dll" with _ -> r + ".dll" - - for searchPath in searchPaths do - if not found then - let trialPath = Path.Combine(searchPath,qual) - if FileSystem.SafeExists(trialPath) then - yield! success trialPath - if not found then - let ass = try Some (System.Reflection.Assembly.ReflectionOnlyLoad(r)) with _ -> None - match ass with - | None -> () - | Some ass -> yield! success ass.Location |] } + results.Add { itemSpec = path; prepareToolTip = snd; baggage=baggage } -#if INTERACTIVE -ScriptingNaiveResolver.DotNetFrameworkReferenceAssembliesRootDirectory -ScriptingNaiveResolver.HighestInstalledNetFrameworkVersion() + try + if not found && Path.IsPathRooted(r) then + if FileSystem.SafeExists(r) then + success r + with e -> logWarning "SR001" (e.ToString()) -let fscoreDir = - if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then // file references only valid on Windows - let PF = - match Environment.GetEnvironmentVariable("ProgramFiles(x86)") with - | null -> Environment.GetEnvironmentVariable("ProgramFiles") // if PFx86 is null, then we are 32-bit and just get PF - | s -> s - PF + @"\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.4.0.0" - else - System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory() +#if !RESHAPED_MSBUILD + // For this one we need to get the version search exactly right, without doing a load + try + if not found && r.StartsWith("FSharp.Core, Version=") && Environment.OSVersion.Platform = PlatformID.Win32NT then + let n = AssemblyName(r) + let fscoreDir0 = + let PF = + match Environment.GetEnvironmentVariable("ProgramFiles(x86)") with + | null -> Environment.GetEnvironmentVariable("ProgramFiles") + | s -> s + PF + @"\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\" + n.Version.ToString() + let trialPath = Path.Combine(fscoreDir0,n.Name + ".dll") + if FileSystem.SafeExists(trialPath) then + success trialPath + with e -> logWarning "SR001" (e.ToString()) +#endif -let resolve s = - ScriptingNaiveResolver.Resolve(ResolutionEnvironment.CompileTimeLike,[| for a in s -> ("", a) |],"v4.5.1", [ScriptingNaiveResolver.DotNetFrameworkReferenceAssembliesRootDirectory + @"\v4.5.1" ],"", "", fscoreDir,[],__SOURCE_DIRECTORY__,ignore, (fun _ _ -> ()), (fun _ _-> ())) + let isFileName = + r.EndsWith("dll",StringComparison.OrdinalIgnoreCase) || + r.EndsWith("exe",StringComparison.OrdinalIgnoreCase) -resolve ["System"; "mscorlib"; "mscorlib.dll"; "FSharp.Core"; "FSharp.Core.dll"; "Microsoft.SqlServer.Dmf.dll"; "Microsoft.SqlServer.Dmf" ] + let qual = if isFileName then r else try AssemblyName(r).Name + ".dll" with _ -> r + ".dll" -resolve [ "FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" ] + for searchPath in searchPaths do + try + if not found then + let trialPath = Path.Combine(searchPath,qual) + if FileSystem.SafeExists(trialPath) then + success trialPath + with e -> logWarning "SR001" (e.ToString()) + +#if !RESHAPED_MSBUILD + try + // Seach the GAC on Windows + if not found && not isFileName && Environment.OSVersion.Platform = PlatformID.Win32NT then + let n = AssemblyName(r) + let netfx = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory() + let gac = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(netfx.TrimEnd('\\'))),"assembly") + match n.Version, n.GetPublicKeyToken() with + | null, _ | _,null -> + let options = + [ for gacdir in Directory.EnumerateDirectories(gac) do + let assdir = Path.Combine(gacdir,n.Name) + if Directory.Exists(assdir) then + for tdir in Directory.EnumerateDirectories(assdir) do + let trialPath = Path.Combine(tdir,qual) + if FileSystem.SafeExists(trialPath) then + yield trialPath ] + //printfn "sorting GAC paths: %A" options + options + |> List.sort // puts latest version last + |> List.tryLast + |> function None -> () | Some p -> success p + + | v,tok -> + for gacdir in Directory.EnumerateDirectories(gac) do + //printfn "searching GAC directory: %s" gacdir + let assdir = Path.Combine(gacdir,n.Name) + if Directory.Exists(assdir) then + //printfn "searching GAC directory: %s" assdir + + let tokText = String.concat "" [| for b in tok -> sprintf "%02x" b |] + let verdir = Path.Combine(assdir,"v4.0_"+v.ToString()+"__"+tokText) + //printfn "searching GAC directory: %s" verdir + + if Directory.Exists(verdir) then + let trialPath = Path.Combine(verdir,qual) + //printfn "searching GAC: %s" trialPath + if FileSystem.SafeExists(trialPath) then + success trialPath + with e -> logWarning "SR001" (e.ToString()) #endif + results.ToArray() } + let GetDefaultResolver(msbuildEnabled: bool, msbuildVersion: string option) = - //let msbuildEnabled = msbuildEnabled && false +#if RESHAPED_MSBUILD + ignore msbuildVersion + ignore msbuildEnabled +#else + let msbuildEnabled = msbuildEnabled && false + let msbuildVersion = defaultArg msbuildVersion "12" let tryMSBuild v = - if msbuildEnabled then - // Detect if MSBuild v12 is on the machine, if so use the resolver from there - let mb = try System.Reflection.Assembly.Load(sprintf "Microsoft.Build.Framework, Version=%s.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" v) |> Option.ofObj with _ -> None - let ass = mb |> Option.bind (fun _ -> try System.Reflection.Assembly.Load(sprintf "FSharp.Compiler.Service.MSBuild.v%s" v) |> Option.ofObj with _ -> None) + // Detect if MSBuild is on the machine, if so use the resolver from there + let mb = try Assembly.Load(sprintf "Microsoft.Build.Framework, Version=%s.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" v) |> Option.ofObj with _ -> None + let ass = mb |> Option.bind (fun _ -> try Assembly.Load(sprintf "FSharp.Compiler.Service.MSBuild.v%s" v) |> Option.ofObj with _ -> None) let ty = ass |> Option.bind (fun ass -> ass.GetType("Microsoft.FSharp.Compiler.MSBuildReferenceResolver") |> Option.ofObj) - let obj = ty |> Option.bind (fun ty -> ty.InvokeMember("get_Resolver",System.Reflection.BindingFlags.Static ||| System.Reflection.BindingFlags.Public ||| System.Reflection.BindingFlags.InvokeMethod ||| System.Reflection.BindingFlags.NonPublic, null, null, [| |]) |> Option.ofObj) + let obj = ty |> Option.bind (fun ty -> ty.InvokeMember("get_Resolver",BindingFlags.Static ||| BindingFlags.Public ||| BindingFlags.InvokeMethod ||| BindingFlags.NonPublic, null, null, [| |]) |> Option.ofObj) let resolver = obj |> Option.bind (fun obj -> match obj with :? Resolver as r -> Some r | _ -> None) resolver - else None - match tryMSBuild (defaultArg msbuildVersion "12") with + match (if msbuildEnabled then tryMSBuild msbuildVersion else None) with | Some r -> r | None -> //match tryMSBuild "15" with @@ -188,7 +240,53 @@ let GetDefaultResolver(msbuildEnabled: bool, msbuildVersion: string option) = //match tryMSBuild "14" with //| Some r -> r //| None -> - match tryMSBuild "12" with + match (if msbuildEnabled && msbuildVersion <> "12" then tryMSBuild "12" else None) with | Some r -> r | None -> - ScriptingNaiveResolver +#endif + SimulatedMSBuildResolver + + +#if INTERACTIVE +// Some manual testing +SimulatedMSBuildResolver.DotNetFrameworkReferenceAssembliesRootDirectory +SimulatedMSBuildResolver.HighestInstalledNetFrameworkVersion() + +let fscoreDir = + if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then // file references only valid on Windows + let PF = + match Environment.GetEnvironmentVariable("ProgramFiles(x86)") with + | null -> Environment.GetEnvironmentVariable("ProgramFiles") // if PFx86 is null, then we are 32-bit and just get PF + | s -> s + PF + @"\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.4.0.0" + else + System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory() + +let resolve s = + SimulatedMSBuildResolver.Resolve(ResolutionEnvironment.CompileTimeLike,[| for a in s -> (a, "") |],"v4.5.1", [SimulatedMSBuildResolver.DotNetFrameworkReferenceAssembliesRootDirectory + @"\v4.5.1" ],"", "", fscoreDir,[],__SOURCE_DIRECTORY__,ignore, (fun _ _ -> ()), (fun _ _-> ())) + +// Resolve partial name to something on search path +resolve ["FSharp.Core" ] + +// Resolve DLL name to something on search path +resolve ["FSharp.Core.dll" ] + +// Resolve from reference assemblies +resolve ["System"; "mscorlib"; "mscorlib.dll" ] + +// Resolve from Registry AssemblyFolders +resolve ["Microsoft.SqlServer.Dmf.dll"; "Microsoft.SqlServer.Dmf" ] + +// Resolve exact version of FSharp.Core +resolve [ "FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" ] + +// Resolve from GAC: +resolve [ "EventViewer, Version=6.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" ] + +// Resolve from GAC: +resolve [ "EventViewer" ] + +resolve [ "Microsoft.SharePoint.Client, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" ] +resolve [ "Microsoft.SharePoint.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" ] +#endif + diff --git a/tests/service/FSharp.Compiler.Service.Tests.fsproj b/tests/service/FSharp.Compiler.Service.Tests.fsproj index 0d2ad6bb97..178fab3b46 100644 --- a/tests/service/FSharp.Compiler.Service.Tests.fsproj +++ b/tests/service/FSharp.Compiler.Service.Tests.fsproj @@ -99,11 +99,6 @@ {887630a3-4b1d-40ea-b8b3-2d842e9c40db} True - - TestTP - {ff76bd3c-5e0a-4752-b6c3-044f6e15719b} - True - diff --git a/tests/service/ProjectAnalysisTests.fs b/tests/service/ProjectAnalysisTests.fs index 095abdbaac..2f2dd0a4f9 100644 --- a/tests/service/ProjectAnalysisTests.fs +++ b/tests/service/ProjectAnalysisTests.fs @@ -4510,15 +4510,6 @@ module Project35b = let options = checker.GetProjectOptionsFromScript(fileName1, fileSource1) |> Async.RunSynchronously #endif -[] -let ``Test project35b Dependency files for ParseFileInProject`` () = - // This is testing legacy functionality - let parseFileResults = checker.ParseFileInProject(Project35b.fileName1, Project35b.fileSource1, Project35b.options) |> Async.RunSynchronously - for d in parseFileResults.DependencyFiles do - printfn "ParseFileInProject dependency: %s" d - parseFileResults.DependencyFiles |> List.exists (fun s -> s.Contains "notexist.dll") |> shouldEqual true - parseFileResults.DependencyFiles |> List.exists (fun s -> s.Contains Project35b.fileName1) |> shouldEqual true - [] let ``Test project35b Dependency files for ParseAndCheckFileInProject`` () = let checkFileResults =