From b10af0de7cf3af4c139e3d58367e483af7aaaee8 Mon Sep 17 00:00:00 2001 From: ncave <777696+ncave@users.noreply.github.com> Date: Thu, 16 Jan 2020 14:05:10 -0800 Subject: [PATCH] Export metadata --- fcs/Directory.Build.props | 2 +- .../FSharp.Compiler.Service.fsproj | 1 + fcs/build.fsx | 19 ++++ fcs/fcs-export/Program.fs | 88 +++++++++++++++++++ fcs/fcs-export/fcs-export.fsproj | 20 +++++ fcs/global.json | 2 +- global.json | 2 +- src/absil/ilwrite.fs | 6 ++ src/buildtools/buildtools.targets | 4 +- src/fsharp/CompileOps.fs | 32 +++++++ 10 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 fcs/fcs-export/Program.fs create mode 100644 fcs/fcs-export/fcs-export.fsproj diff --git a/fcs/Directory.Build.props b/fcs/Directory.Build.props index 2841a5fb34f7..758d5f179bfe 100644 --- a/fcs/Directory.Build.props +++ b/fcs/Directory.Build.props @@ -31,7 +31,7 @@ $(FSharpSourcesRoot)\..\packages\FSharp.Compiler.Tools.4.1.27\tools fsi.exe - 4.6.2 + 4.7.0 net461 diff --git a/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj b/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj index f99d7aac7af6..a4f53925b5e5 100644 --- a/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj +++ b/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj @@ -5,6 +5,7 @@ $(FcsTargetNetFxFramework);netstandard2.0 true + $(DefineConstants);EXPORT_METADATA $(DefineConstants);COMPILER_SERVICE_AS_DLL $(DefineConstants);COMPILER $(DefineConstants);ENABLE_MONO_SUPPORT diff --git a/fcs/build.fsx b/fcs/build.fsx index 00dc80cf6f34..cc1e573daa98 100644 --- a/fcs/build.fsx +++ b/fcs/build.fsx @@ -62,6 +62,10 @@ Target.create "BuildVersion" (fun _ -> Shell.Exec("appveyor", sprintf "UpdateBuild -Version \"%s\"" buildVersion) |> ignore ) +Target.create "BuildTools" (fun _ -> + runDotnet __SOURCE_DIRECTORY__ "build" "../src/buildtools/buildtools.proj -v n -c Proto" +) + Target.create "Build" (fun _ -> runDotnet __SOURCE_DIRECTORY__ "build" "../src/buildtools/buildtools.proj -v n -c Proto" let fslexPath = __SOURCE_DIRECTORY__ + "/../artifacts/bin/fslex/Proto/netcoreapp3.0/fslex.dll" @@ -104,6 +108,17 @@ Target.create "PublishNuGet" (fun _ -> WorkingDir = releaseDir }) ) +// -------------------------------------------------------------------------------------- +// Export Metadata binaries + +Target.create "Export.Metadata" (fun _ -> + let projPath = + match Environment.environVarOrNone "FCS_EXPORT_PROJECT" with + | Some x -> x + | None -> __SOURCE_DIRECTORY__ + "/fcs-export" + runDotnet projPath "run" "-c Release" +) + // -------------------------------------------------------------------------------------- // Run all targets by default. Invoke 'build ' to override @@ -147,4 +162,8 @@ open Fake.Core.TargetOperators "GenerateDocs" ==> "Release" +"Clean" + ==> "BuildTools" + ==> "Export.Metadata" + Target.runOrDefaultWithArguments "Build" diff --git a/fcs/fcs-export/Program.fs b/fcs/fcs-export/Program.fs new file mode 100644 index 000000000000..6cfee63a8afc --- /dev/null +++ b/fcs/fcs-export/Program.fs @@ -0,0 +1,88 @@ +open System.IO +open System.Collections.Generic +open FSharp.Compiler +open FSharp.Compiler.SourceCodeServices + +let readRefs (folder : string) (projectFile: string) = + let runProcess (workingDir: string) (exePath: string) (args: string) = + let psi = System.Diagnostics.ProcessStartInfo() + psi.FileName <- exePath + psi.WorkingDirectory <- workingDir + psi.RedirectStandardOutput <- false + psi.RedirectStandardError <- false + psi.Arguments <- args + psi.CreateNoWindow <- true + psi.UseShellExecute <- false + + use p = new System.Diagnostics.Process() + p.StartInfo <- psi + p.Start() |> ignore + p.WaitForExit() + + let exitCode = p.ExitCode + exitCode, () + + let runCmd exePath args = runProcess folder exePath (args |> String.concat " ") + let msbuildExec = Dotnet.ProjInfo.Inspect.dotnetMsbuild runCmd + let result = Dotnet.ProjInfo.Inspect.getProjectInfo ignore msbuildExec Dotnet.ProjInfo.Inspect.getFscArgs [] projectFile + match result with + | Ok(Dotnet.ProjInfo.Inspect.GetResult.FscArgs x) -> + x + |> List.filter (fun s -> s.StartsWith("-r:")) + |> List.map (fun s -> s.Replace("-r:", "")) + | _ -> [] + +let mkStandardProjectReferences () = + let file = "fcs-export.fsproj" + let projDir = __SOURCE_DIRECTORY__ + readRefs projDir file + +let mkProjectCommandLineArgsForScript (dllName, fileNames) = + [| yield "--simpleresolution" + yield "--noframework" + yield "--debug:full" + yield "--define:DEBUG" + yield "--optimize-" + yield "--out:" + dllName + yield "--doc:test.xml" + yield "--warn:3" + yield "--fullpaths" + yield "--flaterrors" + yield "--target:library" + for x in fileNames do + yield x + let references = mkStandardProjectReferences () + for r in references do + yield "-r:" + r + |] + +let checker = FSharpChecker.Create() + +let parseAndCheckScript (file, input) = + let dllName = Path.ChangeExtension(file, ".dll") + let projName = Path.ChangeExtension(file, ".fsproj") + let args = mkProjectCommandLineArgsForScript (dllName, [file]) + // printfn "file: %s" file + // args |> Array.iter (printfn "args: %s") + let projectOptions = checker.GetProjectOptionsFromCommandLineArgs (projName, args) + let parseRes, typedRes = checker.ParseAndCheckFileInProject(file, 0, input, projectOptions) |> Async.RunSynchronously + + if parseRes.Errors.Length > 0 then + printfn "---> Parse Input = %A" input + printfn "---> Parse Error = %A" parseRes.Errors + + match typedRes with + | FSharpCheckFileAnswer.Succeeded(res) -> parseRes, res + | res -> failwithf "Parsing did not finish... (%A)" res + +[] +let main argv = + ignore argv + printfn "Exporting metadata..." + let file = "/temp/test.fsx" + let input = "let a = 42" + let sourceText = FSharp.Compiler.Text.SourceText.ofString input + // parse script just to export metadata + let parseRes, typedRes = parseAndCheckScript(file, sourceText) + printfn "Exporting is done." + 0 diff --git a/fcs/fcs-export/fcs-export.fsproj b/fcs/fcs-export/fcs-export.fsproj new file mode 100644 index 000000000000..77b037325fb9 --- /dev/null +++ b/fcs/fcs-export/fcs-export.fsproj @@ -0,0 +1,20 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + + + diff --git a/fcs/global.json b/fcs/global.json index 2223a05e3123..f1c2b2b96c81 100644 --- a/fcs/global.json +++ b/fcs/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "3.0.100" + "version": "3.1.101" } } \ No newline at end of file diff --git a/global.json b/global.json index f12de7638777..7bb51b488527 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "tools": { - "dotnet": "3.1.100", + "dotnet": "3.1.101", "vs": { "version": "16.3", "components": [ diff --git a/src/absil/ilwrite.fs b/src/absil/ilwrite.fs index 1464e2992391..4063227c662a 100644 --- a/src/absil/ilwrite.fs +++ b/src/absil/ilwrite.fs @@ -2501,6 +2501,9 @@ let GenMethodDefAsRow cenv env midx (md: ILMethodDef) = if cenv.entrypoint <> None then failwith "duplicate entrypoint" else cenv.entrypoint <- Some (true, midx) let codeAddr = +#if EXPORT_METADATA + 0x0000 +#else (match md.Body.Contents with | MethodBody.IL ilmbody -> let addr = cenv.nextCodeAddr @@ -2546,6 +2549,7 @@ let GenMethodDefAsRow cenv env midx (md: ILMethodDef) = | MethodBody.Native -> failwith "cannot write body of native method - Abstract IL cannot roundtrip mixed native/managed binaries" | _ -> 0x0000) +#endif UnsharedRow [| ULong codeAddr @@ -3522,6 +3526,7 @@ let writeBinaryAndReportMappings (outfile, match signer, modul.Manifest with | Some _, _ -> signer | _, None -> signer +#if !EXPORT_METADATA | None, Some {PublicKey=Some pubkey} -> (dprintn "Note: The output assembly will be delay-signed using the original public" dprintn "Note: key. In order to load it you will need to either sign it with" @@ -3531,6 +3536,7 @@ let writeBinaryAndReportMappings (outfile, dprintn "Note: private key when converting the assembly, assuming you have access to" dprintn "Note: it." Some (ILStrongNameSigner.OpenPublicKey pubkey)) +#endif | _ -> signer let modul = diff --git a/src/buildtools/buildtools.targets b/src/buildtools/buildtools.targets index 185fd4d05992..baddd10b5844 100644 --- a/src/buildtools/buildtools.targets +++ b/src/buildtools/buildtools.targets @@ -20,7 +20,7 @@ BeforeTargets="CoreCompile"> - $(ArtifactsDir)\Bootstrap\fslex\fslex.dll + $(ArtifactsDir)\bin\fslex\Proto\netcoreapp3.0\fslex.dll @@ -43,7 +43,7 @@ BeforeTargets="CoreCompile"> - $(ArtifactsDir)\Bootstrap\fsyacc\fsyacc.dll + $(ArtifactsDir)\bin\fsyacc\Proto\netcoreapp3.0\fsyacc.dll diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index 22171840542d..f91ecce6435a 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -4771,6 +4771,38 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse FSharp.Compiler.AbstractIL.Internal.AsciiConstants.parseILGlobals <- tcGlobals.ilg #endif frameworkTcImports.SetTcGlobals tcGlobals + +#if EXPORT_METADATA + let metadataPath = __SOURCE_DIRECTORY__ + "/../../temp/metadata2/" + let writeMetadata (dllInfo: ImportedBinary) = + let outfile = Path.GetFullPath(metadataPath + Path.GetFileName(dllInfo.FileName)) + let ilModule = dllInfo.RawMetadata.TryGetILModuleDef().Value + try + let args: ILBinaryWriter.options = { + ilg = ilGlobals + pdbfile = None + emitTailcalls = false + deterministic = false + showTimes = false + portablePDB = false + embeddedPDB = false + embedAllSource = false + embedSourceList = [] + sourceLink = "" + checksumAlgorithm = tcConfig.checksumAlgorithm + signer = None + dumpDebugInfo = false + pathMap = tcConfig.pathMap } + ILBinaryWriter.WriteILBinary (outfile, args, ilModule, id) + with Failure msg -> + printfn "Export error: %s" msg + + let! dllinfos, _ccuinfos = frameworkTcImports.RegisterAndImportReferencedAssemblies (ctok, tcResolutions.GetAssemblyResolutions()) + dllinfos |> List.iter writeMetadata + let! dllinfos, _ccuinfos = frameworkTcImports.RegisterAndImportReferencedAssemblies (ctok, tcAltResolutions.GetAssemblyResolutions()) + dllinfos |> List.iter writeMetadata +#endif + return tcGlobals, frameworkTcImports }