Skip to content

Commit 836da28

Browse files
Refactor Native /Assembly resolution (#8606)
* Refactor native resolution * Fcs -- compile * typo * buildy * Linux * Update src/fsharp/CompileOps.fs Co-Authored-By: Phillip Carter <pcarter@fastmail.com> * feedback * temp * c# * fix delete and fsharpcore reference. * improve surface area Co-authored-by: Phillip Carter <pcarter@fastmail.com>
1 parent d9b92bb commit 836da28

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1347
-421
lines changed

fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -522,11 +522,23 @@
522522
<Compile Include="$(FSharpSourcesRoot)/fsharp/DotNetFrameworkDependencies.fs">
523523
<Link>Driver\DotNetFrameworkDependencies.fs</Link>
524524
</Compile>
525-
<Compile Include="$(FSharpSourcesRoot)/fsharp/Interactive.DependencyManager/DependencyManager.fsi">
526-
<Link>Driver/DependencyManager.fsi</Link>
525+
<Compile Include="$(FSharpSourcesRoot)/fsharp/Interactive.DependencyManager/AssemblyResolveHandler.fsi">
526+
<Link>Driver\AssemblyResolveHandler.fsi</Link>
527527
</Compile>
528-
<Compile Include="$(FSharpSourcesRoot)/fsharp/Interactive.DependencyManager/DependencyManager.fs">
529-
<Link>Driver/DependencyManager.fs</Link>
528+
<Compile Include="$(FSharpSourcesRoot)/fsharp/Interactive.DependencyManager/AssemblyResolveHandler.fs">
529+
<Link>Driver\AssemblyResolveHandler.fs</Link>
530+
</Compile>
531+
<Compile Include="$(FSharpSourcesRoot)/fsharp/Interactive.DependencyManager/NativeDllResolveHandler.fsi">
532+
<Link>Driver\NativeDllResolveHandler.fsi</Link>
533+
</Compile>
534+
<Compile Include="$(FSharpSourcesRoot)/fsharp/Interactive.DependencyManager/NativeDllResolveHandler.fs">
535+
<Link>Driver\NativeDllResolveHandler.fs</Link>
536+
</Compile>
537+
<Compile Include="$(FSharpSourcesRoot)/fsharp/Interactive.DependencyManager/DependencyProvider.fsi">
538+
<Link>Driver/DependencyProvider.fsi</Link>
539+
</Compile>
540+
<Compile Include="$(FSharpSourcesRoot)/fsharp/Interactive.DependencyManager/DependencyProvider.fs">
541+
<Link>Driver/DependencyProvider.fs</Link>
530542
</Compile>
531543
<Compile Include="$(FSharpSourcesRoot)/fsharp/CompileOps.fsi">
532544
<Link>Driver/CompileOps.fsi</Link>

src/fsharp/CompileOps.fs

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,7 +2199,7 @@ type TcConfigBuilder =
21992199
mutable productNameForBannerText: string
22002200
/// show the MS (c) notice, e.g. with help or fsi?
22012201
mutable showBanner: bool
2202-
2202+
22032203
/// show times between passes?
22042204
mutable showTimes: bool
22052205
mutable showLoadedAssemblies: bool
@@ -2229,7 +2229,7 @@ type TcConfigBuilder =
22292229
mutable emitDebugInfoInQuotations: bool
22302230

22312231
mutable exename: string option
2232-
2232+
22332233
// If true - the compiler will copy FSharp.Core.dll along the produced binaries
22342234
mutable copyFSharpCore: CopyFSharpCoreFlag
22352235

@@ -2390,9 +2390,24 @@ type TcConfigBuilder =
23902390
noConditionalErasure = false
23912391
pathMap = PathMap.empty
23922392
langVersion = LanguageVersion("default")
2393-
dependencyProvider = new DependencyProvider()
2393+
dependencyProvider = Unchecked.defaultof<DependencyProvider>
23942394
}
23952395

2396+
// Directories to start probing in
2397+
// Algorithm:
2398+
// Search for native libraries using:
2399+
// 1. Include directories
2400+
// 2. compilerToolPath directories
2401+
// 3. reference dll's
2402+
// 4. The implicit include directory
2403+
member private tcConfigB.nativeProbingRoots () =
2404+
seq {
2405+
yield! tcConfigB.includes
2406+
yield! tcConfigB.compilerToolPaths
2407+
yield! (tcConfigB.referencedDLLs |> Seq.map(fun ref -> Path.GetDirectoryName(ref.Text)))
2408+
yield tcConfigB.implicitIncludeDir
2409+
} |> Seq.distinct
2410+
23962411
static member CreateNew(legacyReferenceResolver, defaultFSharpBinariesDir, reduceMemoryUsage, implicitIncludeDir,
23972412
isInteractive, isInvalidationSupported, defaultCopyFSharpCore, tryGetMetadataSnapshot) =
23982413

@@ -2401,17 +2416,20 @@ type TcConfigBuilder =
24012416
if (String.IsNullOrEmpty defaultFSharpBinariesDir) then
24022417
failwith "Expected a valid defaultFSharpBinariesDir"
24032418

2404-
{ TcConfigBuilder.Initial with
2405-
implicitIncludeDir = implicitIncludeDir
2406-
defaultFSharpBinariesDir = defaultFSharpBinariesDir
2407-
reduceMemoryUsage = reduceMemoryUsage
2408-
legacyReferenceResolver = legacyReferenceResolver
2409-
isInteractive = isInteractive
2410-
isInvalidationSupported = isInvalidationSupported
2411-
copyFSharpCore = defaultCopyFSharpCore
2412-
tryGetMetadataSnapshot = tryGetMetadataSnapshot
2413-
useFsiAuxLib = isInteractive
2414-
}
2419+
let tcConfigBuilder =
2420+
{ TcConfigBuilder.Initial with
2421+
implicitIncludeDir = implicitIncludeDir
2422+
defaultFSharpBinariesDir = defaultFSharpBinariesDir
2423+
reduceMemoryUsage = reduceMemoryUsage
2424+
legacyReferenceResolver = legacyReferenceResolver
2425+
isInteractive = isInteractive
2426+
isInvalidationSupported = isInvalidationSupported
2427+
copyFSharpCore = defaultCopyFSharpCore
2428+
tryGetMetadataSnapshot = tryGetMetadataSnapshot
2429+
useFsiAuxLib = isInteractive
2430+
}
2431+
tcConfigBuilder.dependencyProvider <- new DependencyProvider(NativeResolutionProbe(tcConfigBuilder.nativeProbingRoots))
2432+
tcConfigBuilder
24152433

24162434
member tcConfigB.ResolveSourceFile(m, nm, pathLoadedFrom) =
24172435
use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parameter
@@ -4964,10 +4982,13 @@ let ProcessMetaCommandsFromInput
49644982
if not canHaveScriptMetaCommands then
49654983
errorR(HashReferenceNotAllowedInNonScript m)
49664984

4967-
let reportError errorType error =
4968-
match errorType with
4969-
| ErrorReportType.Warning -> warning(Error(error,m))
4970-
| ErrorReportType.Error -> errorR(Error(error, m))
4985+
let reportError =
4986+
let report errorType err msg =
4987+
let error = err, msg
4988+
match errorType with
4989+
| ErrorReportType.Warning -> warning(Error(error, m))
4990+
| ErrorReportType.Error -> errorR(Error(error, m))
4991+
ResolvingErrorReport (report)
49714992

49724993
match args with
49734994
| [path] ->
@@ -5257,10 +5278,13 @@ module ScriptPreprocessClosure =
52575278
match packageManagerLines with
52585279
| [] -> ()
52595280
| (_, _, m)::_ ->
5260-
let reportError errorType error =
5261-
match errorType with
5262-
| ErrorReportType.Warning -> warning(Error(error,m))
5263-
| ErrorReportType.Error -> errorR(Error(error, m))
5281+
let reportError =
5282+
let report errorType err msg =
5283+
let error = err, msg
5284+
match errorType with
5285+
| ErrorReportType.Warning -> warning(Error(error, m))
5286+
| ErrorReportType.Error -> errorR(Error(error, m))
5287+
ResolvingErrorReport (report)
52645288

52655289
match origTcConfig.packageManagerLines |> Map.tryFind packageManagerKey with
52665290
| Some oldDependencyManagerLines when oldDependencyManagerLines = packageManagerLines -> ()
@@ -5273,22 +5297,23 @@ module ScriptPreprocessClosure =
52735297
| dependencyManager ->
52745298
let inline snd3 (_, b, _) = b
52755299
let packageManagerTextLines = packageManagerLines |> List.map snd3
5276-
match tcConfig.dependencyProvider.Resolve(dependencyManager, tcConfig.implicitIncludeDir, mainFile, scriptName, ".fsx", packageManagerTextLines, reportError, executionTfm) with
5277-
| true, _references, generatedScripts, additionalIncludeFolders ->
5300+
let result = tcConfig.dependencyProvider.Resolve(dependencyManager, ".fsx", packageManagerTextLines, reportError, executionTfm, tcConfig.implicitIncludeDir, mainFile, scriptName)
5301+
match result.Success with
5302+
| true ->
52785303
// Resolution produced no errors
5279-
if not (Seq.isEmpty additionalIncludeFolders) then
5304+
if not (Seq.isEmpty result.Roots) then
52805305
let tcConfigB = tcConfig.CloneOfOriginalBuilder
5281-
for folder in additionalIncludeFolders do
5306+
for folder in result.Roots do
52825307
tcConfigB.AddIncludePath(m, folder, "")
52835308
tcConfigB.packageManagerLines <- tcConfigB.packageManagerLines |> Map.map(fun _ l -> l |> List.map(fun (_, p, m) -> true, p, m))
52845309
tcConfig <- TcConfig.Create(tcConfigB, validate=false)
5285-
for script in generatedScripts do
5310+
for script in result.SourceFiles do
52865311
let scriptText = File.ReadAllText script
52875312
loadScripts.Add script |> ignore
52885313
let iSourceText = SourceText.ofString scriptText
52895314
yield! loop (ClosureSource(script, m, iSourceText, true))
52905315

5291-
| false, _, _, _ ->
5316+
| false ->
52925317
// Resolution produced errors update packagerManagerLines entries to note these failure
52935318
// failed resolutions will no longer be considered
52945319
let tcConfigB = tcConfig.CloneOfOriginalBuilder
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
# FSharp.Build resource strings
2+
cantReferenceSystemPackage,"PackageManager can not reference the System Package '%s'"
3+
requiresAValue,"%s requires a value"
4+
unableToApplyImplicitArgument,"Unable to apply implicit argument number %d"
25
notUsed,"Not used."

src/fsharp/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ $(PACKAGEREFERENCES)
187187
<ItemGroup>
188188
<ResolvedReferenceLines Remove='*' />
189189
<ResolvedReferenceLines
190-
Condition="'$(SCRIPTEXTENSION)'=='.fsx' and '%(InteractiveResolvedFile.NugetPackageId)'!='FSharp.Core'"
190+
Condition="'$(SCRIPTEXTENSION)'=='.csx' or '%(InteractiveResolvedFile.NugetPackageId)'!='FSharp.Core'"
191191
Include='%(InteractiveResolvedFile.NugetPackageId),%(InteractiveResolvedFile.NugetPackageVersion),%(InteractiveResolvedFile.PackageRoot),%(InteractiveResolvedFile.FullPath),%(InteractiveResolvedFile.IsNotImplementationReference),%(InteractiveResolvedFile.InitializeSourcePath),%(NativeIncludeRoots.Path)'
192192
KeepDuplicates="false" />
193193
</ItemGroup>

src/fsharp/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -152,16 +152,16 @@ module internal Utilities =
152152
else
153153
None
154154

155-
let drainStreamToFile (stream: StreamReader) filename =
156-
use file = File.OpenWrite(filename)
157-
use writer = new StreamWriter(file)
155+
let drainStreamToMemory (stream: StreamReader) =
156+
let mutable list = ResizeArray()
158157
let rec copyLines () =
159158
match stream.ReadLine() with
160159
| null -> ()
161160
| line ->
162-
writer.WriteLine(line)
161+
list.Add line
163162
copyLines ()
164163
copyLines ()
164+
list.ToArray()
165165

166166
let executeBuild pathToExe arguments workingDir =
167167
match pathToExe with
@@ -179,24 +179,24 @@ module internal Utilities =
179179
p.StartInfo <- psi
180180
p.Start() |> ignore
181181

182-
let standardOutput = Path.Combine(workingDir, "StandardOutput.txt")
183-
let standardError = Path.Combine(workingDir, "StandardError.txt")
184-
drainStreamToFile p.StandardOutput (Path.Combine(workingDir, standardOutput))
185-
drainStreamToFile p.StandardError (Path.Combine(workingDir, standardError))
182+
let stdOut = drainStreamToMemory p.StandardOutput
183+
let stdErr = drainStreamToMemory p.StandardError
184+
185+
#if Debug
186+
File.WriteAllLines(Path.Combine(workingDir, "StandardOutput.txt"), stdOut)
187+
File.WriteAllLines(Path.Combine(workingDir, "StandardError.txt"), stdErr)
188+
#endif
186189

187190
p.WaitForExit()
191+
188192
if p.ExitCode <> 0 then
189193
//Write StandardError.txt to err stream
190-
let text = File.ReadAllText(standardOutput)
191-
Console.Out.Write(text)
192-
193-
//Write StandardOutput.txt to out stream
194-
let text = File.ReadAllText(standardError)
195-
Console.Out.Write(text)
194+
for line in stdOut do Console.Out.WriteLine(line)
195+
for line in stdErr do Console.Error.WriteLine(line)
196196

197-
p.ExitCode = 0
197+
p.ExitCode = 0, stdOut, stdErr
198198

199-
| None -> false
199+
| None -> false, Array.empty, Array.empty
200200

201201
let buildProject projectPath binLogPath =
202202
let binLoggingArguments =
@@ -213,7 +213,7 @@ module internal Utilities =
213213

214214
let workingDir = Path.GetDirectoryName projectPath
215215

216-
let succeeded =
216+
let succeeded, stdOut, stdErr =
217217
if not (isRunningOnCoreClr) then
218218
// The Desktop build uses "msbuild" to build
219219
executeBuild msbuildExePath (arguments "") workingDir
@@ -223,4 +223,4 @@ module internal Utilities =
223223

224224
let outputFile = projectPath + ".resolvedReferences.paths"
225225
let resultOutFile = if succeeded && File.Exists(outputFile) then Some outputFile else None
226-
succeeded, resultOutFile
226+
succeeded, stdOut, stdErr, resultOutFile

src/fsharp/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.fs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ open System.IO
1010
open FSharp.DependencyManager.Nuget
1111
open FSharp.DependencyManager.Nuget.Utilities
1212
open FSharp.DependencyManager.Nuget.ProjectFile
13-
13+
open FSDependencyManager
1414

1515
module FSharpDependencyManager =
1616

@@ -43,7 +43,7 @@ module FSharpDependencyManager =
4343
let parsePackageReferenceOption (line: string) =
4444
let validatePackageName package packageName =
4545
if String.Compare(packageName, package, StringComparison.OrdinalIgnoreCase) = 0 then
46-
raise (ArgumentException(sprintf "PackageManager can not reference the System Package '%s'" packageName)) // @@@@@@@@@@@@@@@@@@@@@@@ Globalize me please
46+
raise (ArgumentException(SR.cantReferenceSystemPackage(packageName)))
4747
let rec parsePackageReferenceOption' (options: (string option * string option) list) (implicitArgumentCount: int) (packageReference: PackageReference option) =
4848
let current =
4949
match packageReference with
@@ -61,11 +61,11 @@ module FSharpDependencyManager =
6161
let setVersion v = Some { current with Version = v }
6262
match opt with
6363
| Some "include", Some v -> addInclude v |> parsePackageReferenceOption' rest implicitArgumentCount
64-
| Some "include", None -> raise (ArgumentException(sprintf "%s requires a value" "Include")) // @@@@@@@@@@@@@@@@@@@@@@@ Globalize me please
64+
| Some "include", None -> raise (ArgumentException(SR.requiresAValue("Include")))
6565
| Some "version", Some v -> setVersion v |> parsePackageReferenceOption' rest implicitArgumentCount
66-
| Some "version", None -> raise (ArgumentException(sprintf "%s requires a value" "Version")) // @@@@@@@@@@@@@@@@@@@@@@@ Globalize me please
66+
| Some "version", None -> setVersion "*" |> parsePackageReferenceOption' rest implicitArgumentCount
6767
| Some "restoresources", Some v -> Some { current with RestoreSources = concat current.RestoreSources v } |> parsePackageReferenceOption' rest implicitArgumentCount
68-
| Some "restoresources", None -> raise (ArgumentException(sprintf "%s requires a value" "RestoreSources")) // @@@@@@@@@@@@@@@@@@@@@@@ Globalize me please
68+
| Some "restoresources", None -> raise (ArgumentException(SR.requiresAValue("RestoreSources")))
6969
| Some "script", Some v -> Some { current with Script = v } |> parsePackageReferenceOption' rest implicitArgumentCount
7070
| Some "bl", value ->
7171
match value with
@@ -88,7 +88,7 @@ module FSharpDependencyManager =
8888
match implicitArgumentCount with
8989
| 0 -> addInclude v
9090
| 1 -> setVersion v
91-
| _ -> raise (ArgumentException(sprintf "Unable to apply implicit argument number %d" (implicitArgumentCount + 1))) // @@@@@@@@@@@@@@@@@@@@@@@ Globalize me please
91+
| _ -> raise (ArgumentException(SR.unableToApplyImplicitArgument(implicitArgumentCount + 1)))
9292
|> parsePackageReferenceOption' rest (implicitArgumentCount + 1)
9393
| _ -> parsePackageReferenceOption' rest implicitArgumentCount packageReference
9494
let options = getOptions line
@@ -98,12 +98,34 @@ module FSharpDependencyManager =
9898
|> List.distinct
9999
|> (fun l -> l, binLogPath)
100100

101+
102+
/// The results of ResolveDependencies
103+
type ResolveDependenciesResult (success: bool, stdOut: string array, stdError: string array, resolutions: string seq, sourceFiles: string seq, roots: string seq) =
104+
105+
/// Succeded?
106+
member __.Success = success
107+
108+
/// The resolution output log
109+
member __.StdOut = stdOut
110+
111+
/// The resolution error log (* process stderror *)
112+
member __.StdError = stdError
113+
114+
/// The resolution paths
115+
member __.Resolutions = resolutions
116+
117+
/// The source code file paths
118+
member __.SourceFiles = sourceFiles
119+
120+
/// The roots to package directories
121+
member __.Roots = roots
122+
101123
type [<DependencyManagerAttribute>] FSharpDependencyManager (outputDir:string option) =
102124

103125
let key = "nuget"
104126
let name = "MsBuild Nuget DependencyManager"
105127
let scriptsPath =
106-
let path = Path.Combine(Path.GetTempPath(), key, Process.GetCurrentProcess().Id.ToString())
128+
let path = Path.Combine(Path.GetTempPath(), key, Process.GetCurrentProcess().Id.ToString() + "--"+ Guid.NewGuid().ToString())
107129
match outputDir with
108130
| None -> path
109131
| Some v -> Path.Combine(path, v)
@@ -112,8 +134,12 @@ type [<DependencyManagerAttribute>] FSharpDependencyManager (outputDir:string op
112134

113135
let deleteScripts () =
114136
try
137+
#if !Debug
115138
if Directory.Exists(scriptsPath) then
116-
() //Directory.Delete(scriptsPath, true)
139+
Directory.Delete(scriptsPath, true)
140+
#else
141+
()
142+
#endif
117143
with | _ -> ()
118144

119145
let deleteAtExit =
@@ -136,7 +162,7 @@ type [<DependencyManagerAttribute>] FSharpDependencyManager (outputDir:string op
136162

137163
member __.Key = key
138164

139-
member __.ResolveDependencies(scriptExt:string, packageManagerTextLines:string seq, tfm: string) : bool * string seq * string seq * string seq =
165+
member __.ResolveDependencies(scriptExt:string, packageManagerTextLines:string seq, tfm: string) : obj =
140166

141167
let scriptExt, poundRprefix =
142168
match scriptExt with
@@ -170,7 +196,7 @@ type [<DependencyManagerAttribute>] FSharpDependencyManager (outputDir:string op
170196

171197
writeFile projectPath generateProjBody
172198

173-
let result, resolutionsFile = buildProject projectPath binLogPath
199+
let result, stdOut, stdErr, resolutionsFile = buildProject projectPath binLogPath
174200
match resolutionsFile with
175201
| Some file ->
176202
let resolutions = getResolutionsFromFile file
@@ -183,10 +209,10 @@ type [<DependencyManagerAttribute>] FSharpDependencyManager (outputDir:string op
183209
List.concat [ [scriptPath]; loads] |> List.toSeq
184210
let includes = (findIncludesFromResolutions resolutions) |> Array.toSeq
185211

186-
result, references, scripts, includes
212+
ResolveDependenciesResult(result, stdOut, stdErr, references, scripts, includes)
187213

188214
| None ->
189215
let empty = Seq.empty<string>
190-
result, empty, empty, empty
216+
ResolveDependenciesResult(result, stdOut, stdErr, empty, empty, empty)
191217

192-
generateAndBuildProjectArtifacts
218+
generateAndBuildProjectArtifacts :> obj

0 commit comments

Comments
 (0)