diff --git a/.gitignore b/.gitignore index ae99f5bc14..60e72aaf27 100644 --- a/.gitignore +++ b/.gitignore @@ -221,3 +221,8 @@ tests/fsharpqa/testenv/bin/System.ValueTuple.dll lib/netcore/fsc/bin/ !lib/bootstrap/signed/**/* +*/.fake +/fcs/packages/ +*/paket-files/ +/fcs/TestResult.xml +/tests/fcs/ diff --git a/.travis.yml b/.travis.yml index a1302c7d3b..759da5ce62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: csharp +sudo: required os: - linux @@ -10,9 +11,6 @@ mono: - 4.8.0 - 4.4.2 - -sudo: false - install: script: @@ -23,7 +21,6 @@ script: # This fails because NUnit gives an exception (!!!!) # - ./fcs/build.sh Test.NetFx # -# System.IO.FileNotFoundException: Could not load file or assembly 'nunit.engine.api, Version=3.0.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb' or one of its dependencies. # # This fails because Nuget packaging doesn't like backslashes in the package file, but Windows does # - ./fcs/build.sh NuGet diff --git a/fcs/.paket/Paket.Restore.targets b/fcs/.paket/Paket.Restore.targets index 920482ad21..b534b82274 100644 --- a/fcs/.paket/Paket.Restore.targets +++ b/fcs/.paket/Paket.Restore.targets @@ -30,7 +30,7 @@ true - + @@ -84,11 +84,11 @@ - + - + diff --git a/fcs/.paket/paket.bootstrapper.exe b/fcs/.paket/paket.bootstrapper.exe deleted file mode 100644 index 64fdf248bf..0000000000 Binary files a/fcs/.paket/paket.bootstrapper.exe and /dev/null differ diff --git a/fcs/.paket/paket.exe b/fcs/.paket/paket.exe new file mode 100644 index 0000000000..ef3ea32af2 Binary files /dev/null and b/fcs/.paket/paket.exe differ diff --git a/fcs/.paket/paket.targets b/fcs/.paket/paket.targets deleted file mode 100644 index 22c9f0a87a..0000000000 --- a/fcs/.paket/paket.targets +++ /dev/null @@ -1,38 +0,0 @@ - - - - - true - - true - $(MSBuildThisFileDirectory) - $(MSBuildThisFileDirectory)..\ - - - - $(PaketToolsPath)paket.exe - $(PaketToolsPath)paket.bootstrapper.exe - "$(PaketExePath)" - mono --runtime=v4.0.30319 $(PaketExePath) - "$(PaketBootStrapperExePath)" - mono --runtime=v4.0.30319 $(PaketBootStrapperExePath) - - $(MSBuildProjectDirectory)\paket.references - $(MSBuildProjectFullPath).paket.references - $(PaketCommand) restore --references-files "$(PaketReferences)" - $(PaketBootStrapperCommand) - - RestorePackages; $(BuildDependsOn); - - - - - - - - - - - - - diff --git a/fcs/FSharp.Compiler.Service.MSBuild.v12/FSharp.Compiler.Service.MSBuild.v12.fsproj b/fcs/FSharp.Compiler.Service.MSBuild.v12/FSharp.Compiler.Service.MSBuild.v12.fsproj index e929138c56..f66cda2f77 100644 --- a/fcs/FSharp.Compiler.Service.MSBuild.v12/FSharp.Compiler.Service.MSBuild.v12.fsproj +++ b/fcs/FSharp.Compiler.Service.MSBuild.v12/FSharp.Compiler.Service.MSBuild.v12.fsproj @@ -89,4 +89,4 @@ - \ No newline at end of file + diff --git a/fcs/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs b/fcs/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs index 45fab18685..7a36085de0 100644 --- a/fcs/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs +++ b/fcs/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs @@ -8,18 +8,17 @@ open System.Diagnostics open System.Text open System.IO open System +open System.Xml -type ProjectCracker = - static member GetProjectOptionsFromProjectFileLogged(projectFileName : string, ?properties : (string * string) list, ?loadedTimeStamp, ?enableLogging) = - let loadedTimeStamp = defaultArg loadedTimeStamp DateTime.MaxValue // Not 'now', we don't want to force reloading - let properties = defaultArg properties [] - let enableLogging = defaultArg enableLogging true +module Utils = + + let Convert loadedTimeStamp (originalOpts: ProjectCrackerTool.ProjectOptions) = let logMap = ref Map.empty - let rec convert (opts: ProjectCrackerTool.ProjectOptions) : FSharpProjectOptions = + let rec convertProject (opts: ProjectCrackerTool.ProjectOptions) = if not (isNull opts.Error) then failwith opts.Error - let referencedProjects = Array.map (fun (a, b) -> a, convert b) opts.ReferencedProjectOptions + let referencedProjects() = Array.map (fun (a, b) -> a,convertProject b) opts.ReferencedProjectOptions let sourceFiles, otherOptions = opts.Options @@ -41,7 +40,7 @@ type ProjectCracker = { ProjectFileName = opts.ProjectFile SourceFiles = sourceFiles OtherOptions = otherOptions - ReferencedProjects = referencedProjects + ReferencedProjects = referencedProjects() IsIncompleteTypeCheckEnvironment = false UseScriptResolutionRules = false LoadTime = loadedTimeStamp @@ -50,6 +49,16 @@ type ProjectCracker = ExtraProjectInfo = None Stamp = None } + convertProject originalOpts, !logMap + +type ProjectCracker = + + static member GetProjectOptionsFromProjectFileLogged(projectFileName : string, ?properties : (string * string) list, ?loadedTimeStamp, ?enableLogging) = + let loadedTimeStamp = defaultArg loadedTimeStamp DateTime.MaxValue // Not 'now', we don't want to force reloading + let properties = defaultArg properties [] + let enableLogging = defaultArg enableLogging true + + #if NETSTANDARD1_6 let arguments = [| yield projectFileName @@ -70,20 +79,47 @@ type ProjectCracker = let codebase = Path.GetDirectoryName(Uri(typeof.Assembly.CodeBase).LocalPath) let crackerFilename = Path.Combine(codebase,"FSharp.Compiler.Service.ProjectCrackerTool.exe") - if not (File.Exists crackerFilename) then failwithf "ProjectCracker exe not found at: %s it must be next to the ProjectCracker dll." crackerFilename + if not (File.Exists crackerFilename) then + failwithf "ProjectCracker exe not found at: %s it must be next to the ProjectCracker dll." crackerFilename + let p = new System.Diagnostics.Process() + p.StartInfo.FileName <- crackerFilename p.StartInfo.Arguments <- arguments.ToString() p.StartInfo.UseShellExecute <- false p.StartInfo.CreateNoWindow <- true p.StartInfo.RedirectStandardOutput <- true + p.StartInfo.RedirectStandardError <- true + + let sbOut = StringBuilder() + let sbErr = StringBuilder() + + p.ErrorDataReceived.AddHandler(fun _ a -> sbErr.AppendLine a.Data |> ignore) + p.OutputDataReceived.AddHandler(fun _ a -> sbOut.AppendLine a.Data |> ignore) + ignore <| p.Start() - let ser = new DataContractJsonSerializer(typeof) - let opts = ser.ReadObject(p.StandardOutput.BaseStream) :?> ProjectCrackerTool.ProjectOptions + p.EnableRaisingEvents <- true + p.BeginOutputReadLine() + p.BeginErrorReadLine() + + p.WaitForExit() + + let crackerOut = sbOut.ToString() + let crackerErr = sbErr.ToString() + + let opts = + try + let ser = new DataContractJsonSerializer(typeof) + let stringBytes = Encoding.Unicode.GetBytes crackerOut + use ms = new MemoryStream(stringBytes) + ser.ReadObject(ms) :?> ProjectCrackerTool.ProjectOptions + with + exn -> + raise (Exception(sprintf "error parsing ProjectCrackerTool output, stdoutput was:\n%s\n\nstderr was:\n%s" crackerOut crackerErr, exn)) #endif - convert opts, !logMap + Utils.Convert loadedTimeStamp opts static member GetProjectOptionsFromProjectFile(projectFileName : string, ?properties : (string * string) list, ?loadedTimeStamp) = fst (ProjectCracker.GetProjectOptionsFromProjectFileLogged( diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCrackerTool.fsproj b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCrackerTool.fsproj index 07bae7e576..66d196a1d5 100644 --- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCrackerTool.fsproj +++ b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCrackerTool.fsproj @@ -46,24 +46,9 @@ + - - $(FSharpSourcesRoot)/../fcs/dependencies/MSBuild.v14.0/Microsoft.Build.Framework.dll - false - - - $(FSharpSourcesRoot)/../fcs/dependencies/MSBuild.v14.0/Microsoft.Build.Engine.dll - false - - - $(FSharpSourcesRoot)/../fcs/dependencies/MSBuild.v14.0/Microsoft.Build.dll - false - - - $(FSharpSourcesRoot)/../fcs/dependencies/MSBuild.v12.0/Microsoft.Build.Utilities.v12.0.dll - false - @@ -71,13 +56,75 @@ - $(FSharpSourcesRoot)\..\packages\Microsoft.Portable.FSharp.Core.4.1.20\lib\profiles\net40\FSharp.Core.dll false - + + + + + ..\packages\Microsoft.Build\lib\net45\Microsoft.Build.dll + True + True + + + + + + + + + ..\packages\Microsoft.Build.Engine\lib\net45\Microsoft.Build.Engine.dll + True + True + + + + + + + + + ..\packages\Microsoft.Build.Framework\lib\net45\Microsoft.Build.Framework.dll + True + True + + + + + + + + + ..\packages\Microsoft.Build.Utilities.Core\lib\net45\Microsoft.Build.Utilities.Core.dll + True + True + + + + + + + + + True + + + + + + + + + ..\packages\System.Threading.Tasks.Dataflow\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll + True + True + + + + \ No newline at end of file diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/Program.fs b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/Program.fs index ed8a8b1599..7ce360c312 100644 --- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/Program.fs +++ b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/Program.fs @@ -1,21 +1,46 @@ namespace Microsoft.FSharp.Compiler.SourceCodeServices.ProjectCrackerTool open System -open System.IO +open System.Reflection open System.Runtime.Serialization.Json module Program = - [] - let main argv = - let text = Array.exists (fun (s: string) -> s = "--text") argv - let argv = Array.filter (fun (s: string) -> s <> "--text") argv +#if !DOTNETCORE + let addMSBuildv14BackupResolution () = + let onResolveEvent = new ResolveEventHandler(fun sender evArgs -> + let requestedAssembly = AssemblyName(evArgs.Name) + if requestedAssembly.Name.StartsWith("Microsoft.Build") && + not (requestedAssembly.Name.EndsWith(".resources")) && + not (requestedAssembly.Version.ToString().Contains("12.0.0.0")) + then + // If the version of MSBuild that we're using wasn't present on the machine, then + // just revert back to 12.0.0.0 since that's normally installed as part of the .NET + // Framework. + requestedAssembly.Version <- Version("12.0.0.0") + Assembly.Load requestedAssembly + else + null) + AppDomain.CurrentDomain.add_AssemblyResolve(onResolveEvent) +#endif + let crackAndSendOutput asText argv = let ret, opts = ProjectCrackerTool.crackOpen argv - if text then + if asText then printfn "%A" opts else let ser = new DataContractJsonSerializer(typeof) ser.WriteObject(Console.OpenStandardOutput(), opts) ret + + + [][] + let main argv = + let asText = Array.exists (fun (s: string) -> s = "--text") argv + let argv = Array.filter (fun (s: string) -> s <> "--text") argv + +#if !DOTNETCORE + addMSBuildv14BackupResolution () +#endif + crackAndSendOutput asText argv diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerTool.fs b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerTool.fs index 9be9c37537..a20c7a33c0 100644 --- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerTool.fs +++ b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerTool.fs @@ -2,12 +2,13 @@ open System open System.IO -open System.Reflection open System.Text open Microsoft.Build.Framework open Microsoft.Build.Utilities module internal ProjectCrackerTool = + open System.Collections.Generic + open Microsoft.Build.Evaluation let runningOnMono = #if DOTNETCORE @@ -36,17 +37,159 @@ module internal ProjectCrackerTool = member th.Compile(_:obj, _:obj, _:obj) = 0 interface ITaskHost + let vs = + let programFiles = + let getEnv v = + let result = System.Environment.GetEnvironmentVariable(v) + match result with + | null -> None + | _ -> Some result + + match List.tryPick getEnv [ "ProgramFiles(x86)"; "ProgramFiles" ] with + | Some r -> r + | None -> "C:\\Program Files (x86)" + + let vsVersions = ["14.0"; "12.0"] + let msbuildBin v = IO.Path.Combine(programFiles, "MSBuild", v, "Bin", "MSBuild.exe") + List.tryFind (fun v -> IO.File.Exists(msbuildBin v)) vsVersions + + let mkAbsolute dir v = + if Path.IsPathRooted v then v + else Path.Combine(dir, v) + + let mkAbsoluteOpt dir v = Option.map (mkAbsolute dir) v + + let CrackProjectUsingNewBuildAPI fsprojFile properties logOpt = + let fsprojFullPath = try Path.GetFullPath(fsprojFile) with _ -> fsprojFile + let fsprojAbsDirectory = Path.GetDirectoryName fsprojFullPath + + use _pwd = + let dir = Directory.GetCurrentDirectory() + Directory.SetCurrentDirectory(fsprojAbsDirectory) + { new System.IDisposable with + member x.Dispose() = Directory.SetCurrentDirectory(dir) } + use engine = new Microsoft.Build.Evaluation.ProjectCollection() + let host = new HostCompile() + + engine.HostServices.RegisterHostObject(fsprojFullPath, "CoreCompile", "Fsc", host) + + let projectInstanceFromFullPath (fsprojFullPath: string) = + use file = new FileStream(fsprojFullPath, FileMode.Open, FileAccess.Read, FileShare.Read) + use stream = new StreamReader(file) + use xmlReader = System.Xml.XmlReader.Create(stream) + + let project = + try + engine.LoadProject(xmlReader, FullPath=fsprojFullPath) + with + | exn -> + let tools = engine.Toolsets |> Seq.map (fun x -> x.ToolsPath) |> Seq.toList + raise (new Exception(sprintf "Could not load project %s in ProjectCollection. Available tools: %A. Message: %s" fsprojFullPath tools exn.Message)) + + project.SetGlobalProperty("BuildingInsideVisualStudio", "true") |> ignore + if not (List.exists (fun (p,_) -> p = "VisualStudioVersion") properties) then + match vs with + | Some version -> project.SetGlobalProperty("VisualStudioVersion", version) |> ignore + | None -> () + project.SetGlobalProperty("ShouldUnsetParentConfigurationAndPlatform", "false") |> ignore + for (prop, value) in properties do + project.SetGlobalProperty(prop, value) |> ignore + + project.CreateProjectInstance() + + let project = projectInstanceFromFullPath fsprojFullPath + let directory = project.Directory + + let getprop (p: Microsoft.Build.Execution.ProjectInstance) s = + let v = p.GetPropertyValue s + if String.IsNullOrWhiteSpace v then None + else Some v + + let outFileOpt = getprop project "TargetPath" + + let log = match logOpt with + | None -> [] + | Some l -> [l :> ILogger] + + project.Build([| "Build" |], log) |> ignore + + let getItems s = [ for f in project.GetItems(s) -> mkAbsolute directory f.EvaluatedInclude ] + + let projectReferences = + [ for cp in project.GetItems("ProjectReference") do + yield cp.GetMetadataValue("FullPath") + ] + + let references = + [ for i in project.GetItems("ReferencePath") do + yield i.EvaluatedInclude + for i in project.GetItems("ChildProjectReferences") do + yield i.EvaluatedInclude ] + + outFileOpt, directory, getItems, references, projectReferences, getprop project, project.FullPath + +#if !DOTNETCORE + let CrackProjectUsingOldBuildAPI (fsprojFile:string) properties logOpt = + let engine = new Microsoft.Build.BuildEngine.Engine() + Option.iter (fun l -> engine.RegisterLogger(l)) logOpt + + let bpg = Microsoft.Build.BuildEngine.BuildPropertyGroup() + + bpg.SetProperty("BuildingInsideVisualStudio", "true") + for (prop, value) in properties do + bpg.SetProperty(prop, value) + + engine.GlobalProperties <- bpg + + let projectFromFile (fsprojFile:string) = + // We seem to need to pass 12.0/4.0 in here for some unknown reason + let project = new Microsoft.Build.BuildEngine.Project(engine, engine.DefaultToolsVersion) + do project.Load(fsprojFile) + project + + let project = projectFromFile fsprojFile + project.Build([| "ResolveReferences" |]) |> ignore + let directory = Path.GetDirectoryName project.FullFileName + + let getProp (p: Microsoft.Build.BuildEngine.Project) s = + let v = p.GetEvaluatedProperty s + if String.IsNullOrWhiteSpace v then None + else Some v + + let outFileOpt = + match mkAbsoluteOpt directory (getProp project "OutDir") with + | None -> None + | Some d -> mkAbsoluteOpt d (getProp project "TargetFileName") + + let getItems s = + let fs = project.GetEvaluatedItemsByName(s) + [ for f in fs -> mkAbsolute directory f.FinalItemSpec ] + + let projectReferences = + [ for i in project.GetEvaluatedItemsByName("ProjectReference") do + yield mkAbsolute directory i.FinalItemSpec + ] + + let references = + [ for i in project.GetEvaluatedItemsByName("ReferencePath") do + yield i.FinalItemSpec + for i in project.GetEvaluatedItemsByName("ChildProjectReferences") do + yield i.FinalItemSpec ] + // Duplicate slashes sometimes appear in the output here, which prevents + // them from matching keys used in FSharpProjectOptions.ReferencedProjects + |> List.map (fun (s: string) -> s.Replace("//","/")) + + outFileOpt, directory, getItems, references, projectReferences, getProp project, project.FullFileName + +#endif + //---------------------------------------------------------------------------- // FSharpProjectFileInfo // [] type FSharpProjectFileInfo (fsprojFileName:string, ?properties, ?enableLogging) = - let properties = defaultArg properties [] let enableLogging = defaultArg enableLogging false - let mkAbsolute dir v = - if Path.IsPathRooted v then v - else Path.Combine(dir, v) let logOpt = if enableLogging then @@ -55,152 +198,17 @@ module internal ProjectCrackerTool = Some log else None - -#if !DOTNETCORE - let mkAbsoluteOpt dir v = Option.map (mkAbsolute dir) v - - let CrackProjectUsingOldBuildAPI(fsprojFile:string) = - let engine = new Microsoft.Build.BuildEngine.Engine() - Option.iter (fun l -> engine.RegisterLogger(l)) logOpt - - let bpg = Microsoft.Build.BuildEngine.BuildPropertyGroup() - - bpg.SetProperty("BuildingInsideVisualStudio", "true") - for (prop, value) in properties do - bpg.SetProperty(prop, value) - - engine.GlobalProperties <- bpg - - let projectFromFile (fsprojFile:string) = - // We seem to need to pass 12.0/4.0 in here for some unknown reason - let project = new Microsoft.Build.BuildEngine.Project(engine, engine.DefaultToolsVersion) - do project.Load(fsprojFile) - project - - let project = projectFromFile fsprojFile - project.Build([| "ResolveReferences" |]) |> ignore - let directory = Path.GetDirectoryName project.FullFileName - - let getProp (p: Microsoft.Build.BuildEngine.Project) s = - let v = p.GetEvaluatedProperty s - if String.IsNullOrWhiteSpace v then None - else Some v - - let outFileOpt = - match mkAbsoluteOpt directory (getProp project "OutDir") with - | None -> None - | Some d -> mkAbsoluteOpt d (getProp project "TargetFileName") - - let getItems s = - let fs = project.GetEvaluatedItemsByName(s) - [ for f in fs -> mkAbsolute directory f.FinalItemSpec ] - - let projectReferences = - [ for i in project.GetEvaluatedItemsByName("ProjectReference") do - yield mkAbsolute directory i.FinalItemSpec - ] - - let references = - [ for i in project.GetEvaluatedItemsByName("ReferencePath") do - yield i.FinalItemSpec - for i in project.GetEvaluatedItemsByName("ChildProjectReferences") do - yield i.FinalItemSpec ] - // Duplicate slashes sometimes appear in the output here, which prevents - // them from matching keys used in FSharpProjectOptions.ReferencedProjects - |> List.map (fun (s: string) -> s.Replace("//","/")) - - outFileOpt, directory, getItems, references, projectReferences, getProp project, project.FullFileName -#endif - - let vs = - let programFiles = - let getEnv v = - let result = System.Environment.GetEnvironmentVariable(v) - match result with - | null -> None - | _ -> Some result - - match List.tryPick getEnv [ "ProgramFiles(x86)"; "ProgramFiles" ] with - | Some r -> r - | None -> "C:\\Program Files (x86)" - - let vsVersions = ["14.0"; "12.0"] - let msbuildBin v = IO.Path.Combine(programFiles, "MSBuild", v, "Bin", "MSBuild.exe") - List.tryFind (fun v -> IO.File.Exists(msbuildBin v)) vsVersions - - let CrackProjectUsingNewBuildAPI(fsprojFile) = - let fsprojFullPath = try Path.GetFullPath(fsprojFile) with _ -> fsprojFile - let fsprojAbsDirectory = Path.GetDirectoryName fsprojFullPath - - use _pwd = - let dir = Directory.GetCurrentDirectory() - Directory.SetCurrentDirectory(fsprojAbsDirectory) - { new System.IDisposable with - member x.Dispose() = Directory.SetCurrentDirectory(dir) } - use engine = new Microsoft.Build.Evaluation.ProjectCollection() - let host = new HostCompile() - engine.HostServices.RegisterHostObject(fsprojFullPath, "CoreCompile", "Fsc", host) - - - let projectInstanceFromFullPath (fsprojFullPath: string) = - use file = new FileStream(fsprojFullPath, FileMode.Open, FileAccess.Read, FileShare.Read) - use stream = new StreamReader(file) - use xmlReader = System.Xml.XmlReader.Create(stream) - - let project = engine.LoadProject(xmlReader, FullPath=fsprojFullPath) - - project.SetGlobalProperty("BuildingInsideVisualStudio", "true") |> ignore - if not (List.exists (fun (p,_) -> p = "VisualStudioVersion") properties) then - match vs with - | Some version -> project.SetGlobalProperty("VisualStudioVersion", version) |> ignore - | None -> () - project.SetGlobalProperty("ShouldUnsetParentConfigurationAndPlatform", "false") |> ignore - for (prop, value) in properties do - project.SetGlobalProperty(prop, value) |> ignore - - project.CreateProjectInstance() - - let project = projectInstanceFromFullPath fsprojFullPath - let directory = project.Directory - - let getprop (p: Microsoft.Build.Execution.ProjectInstance) s = - let v = p.GetPropertyValue s - if String.IsNullOrWhiteSpace v then None - else Some v - - let outFileOpt = getprop project "TargetPath" - - let log = match logOpt with - | None -> [] - | Some l -> [l :> ILogger] - - project.Build([| "Build" |], log) |> ignore - - let getItems s = [ for f in project.GetItems(s) -> mkAbsolute directory f.EvaluatedInclude ] - - let projectReferences = - [ for cp in project.GetItems("ProjectReference") do - yield cp.GetMetadataValue("FullPath") - ] - - let references = - [ for i in project.GetItems("ReferencePath") do - yield i.EvaluatedInclude - for i in project.GetItems("ChildProjectReferences") do - yield i.EvaluatedInclude ] - - outFileOpt, directory, getItems, references, projectReferences, getprop project, project.FullPath - + let outFileOpt, directory, getItems, references, projectReferences, getProp, fsprojFullPath = try #if DOTNETCORE - CrackProjectUsingNewBuildAPI(fsprojFileName) + CrackProjectUsingNewBuildAPI fsprojFileName properties logOpt with #else if runningOnMono then - CrackProjectUsingOldBuildAPI(fsprojFileName) + CrackProjectUsingOldBuildAPI fsprojFileName properties logOpt else - CrackProjectUsingNewBuildAPI(fsprojFileName) + CrackProjectUsingNewBuildAPI fsprojFileName properties logOpt with | :? Microsoft.Build.BuildEngine.InvalidProjectFileException as e -> raise (Microsoft.Build.Exceptions.InvalidProjectFileException( @@ -384,66 +392,57 @@ module internal ProjectCrackerTool = static member Parse(fsprojFileName:string, ?properties, ?enableLogging) = new FSharpProjectFileInfo(fsprojFileName, ?properties=properties, ?enableLogging=enableLogging) let getOptions file enableLogging properties = + let cache = new Dictionary<_,_>() let rec getOptions file : Option * ProjectOptions = - let parsedProject = FSharpProjectFileInfo.Parse(file, properties=properties, enableLogging=enableLogging) - let referencedProjectOptions = - [| for file in parsedProject.ProjectReferences do - if Path.GetExtension(file) = ".fsproj" then - match getOptions file with - | Some outFile, opts -> yield outFile, opts - | None, _ -> () |] - - // Workaround for Mono 4.2, which doesn't populate the subproject - // details anymore outside of a solution context. See https://github.com/mono/mono/commit/76c6a08e730393927b6851709cdae1d397cbcc3a#diff-59afd196a55d61d5d1eaaef7bd49d1e5 - // and some explanation from the author at https://github.com/fsharp/FSharp.Compiler.Service/pull/455#issuecomment-154103963 - // - // In particular we want the output path, which we can get from - // fully parsing that project itself. We also have to specially parse - // C# referenced projects, as we don't look at them otherwise. - let referencedProjectOutputs = - if runningOnMono then - [ yield! Array.map (fun (s,_) -> "-r:" + s) referencedProjectOptions - for file in parsedProject.ProjectReferences do - let ext = Path.GetExtension(file) - if ext = ".csproj" || ext = ".vbproj" then - let parsedProject = FSharpProjectFileInfo.Parse(file, properties=properties, enableLogging=false) - match parsedProject.OutputFile with - | None -> () - | Some f -> yield "-r:" + f ] - else - [] - - // On some versions of Mono the referenced projects are already - // correctly included, so we make sure not to introduce duplicates - |> List.filter (fun r -> not (Set.contains r (set parsedProject.Options))) - - let options = { ProjectFile = file - Options = Array.ofSeq (parsedProject.Options @ referencedProjectOutputs) - ReferencedProjectOptions = referencedProjectOptions - LogOutput = parsedProject.LogOutput - Error = null } - - parsedProject.OutputFile, options + match cache.TryGetValue file with + | true, option -> option + | _ -> + let parsedProject = FSharpProjectFileInfo.Parse(file, properties=properties, enableLogging=enableLogging) + + let referencedProjectOptions = + [| for file in parsedProject.ProjectReferences do + if Path.GetExtension(file) = ".fsproj" then + match getOptions file with + | Some outFile, opts -> yield outFile, opts + | None, _ -> () |] + + // Workaround for Mono 4.2, which doesn't populate the subproject + // details anymore outside of a solution context. See https://github.com/mono/mono/commit/76c6a08e730393927b6851709cdae1d397cbcc3a#diff-59afd196a55d61d5d1eaaef7bd49d1e5 + // and some explanation from the author at https://github.com/fsharp/FSharp.Compiler.Service/pull/455#issuecomment-154103963 + // + // In particular we want the output path, which we can get from + // fully parsing that project itself. We also have to specially parse + // C# referenced projects, as we don't look at them otherwise. + let referencedProjectOutputs = + if runningOnMono then + [ yield! Array.map (fun (s,_) -> "-r:" + s) referencedProjectOptions + for file in parsedProject.ProjectReferences do + let ext = Path.GetExtension(file) + if ext = ".csproj" || ext = ".vbproj" then + let parsedProject = FSharpProjectFileInfo.Parse(file, properties=properties, enableLogging=false) + match parsedProject.OutputFile with + | None -> () + | Some f -> yield "-r:" + f ] + else + [] + + // On some versions of Mono the referenced projects are already + // correctly included, so we make sure not to introduce duplicates + |> List.filter (fun r -> not (Set.contains r (set parsedProject.Options))) + + let options = { ProjectFile = file + Options = Array.ofSeq (parsedProject.Options @ referencedProjectOutputs) + ReferencedProjectOptions = referencedProjectOptions + LogOutput = parsedProject.LogOutput + Error = null } + + let result = parsedProject.OutputFile, options + cache.Add(file,result) + result snd (getOptions file) -#if !DOTNETCORE - let addMSBuildv14BackupResolution () = - let onResolveEvent = new ResolveEventHandler(fun sender evArgs -> - let requestedAssembly = AssemblyName(evArgs.Name) - if requestedAssembly.Name.StartsWith("Microsoft.Build") && - not (requestedAssembly.Name.EndsWith(".resources")) && - not (requestedAssembly.Version.ToString().Contains("12.0.0.0")) then - // If the version of MSBuild that we're using wasn't present on the machine, then - // just revert back to 12.0.0.0 since that's normally installed as part of the .NET - // Framework. - requestedAssembly.Version <- Version("12.0.0.0") - Assembly.Load (requestedAssembly) - else - null) - AppDomain.CurrentDomain.add_AssemblyResolve(onResolveEvent) -#endif - + let rec pairs l = match l with | [] | [_] -> [] @@ -456,9 +455,6 @@ module internal ProjectCrackerTool = | true, true -> true | _ -> false try -#if !DOTNETCORE - addMSBuildv14BackupResolution () -#endif let props = pairs (List.ofArray argv.[2..]) let opts = getOptions argv.[0] enableLogging props 0, opts @@ -466,8 +462,8 @@ module internal ProjectCrackerTool = 2, { ProjectFile = projectFile; Options = [||]; ReferencedProjectOptions = [||]; - LogOutput = e.ToString() - Error = e.Message } + LogOutput = e.ToString() + " StackTrace: " + e.StackTrace + Error = e.Message + " StackTrace: " + e.StackTrace } else 1, { ProjectFile = ""; Options = [||]; diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/paket.references b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/paket.references new file mode 100644 index 0000000000..3ad1f9662c --- /dev/null +++ b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/paket.references @@ -0,0 +1,4 @@ +Microsoft.Build.Utilities.Core +Microsoft.Build.Engine +Microsoft.Build +System.Threading.Tasks.Dataflow \ No newline at end of file diff --git a/fcs/FSharp.Compiler.Service.Tests.netcore/FSharp.Compiler.Service.Tests.netcore.fsproj b/fcs/FSharp.Compiler.Service.Tests.netcore/FSharp.Compiler.Service.Tests.netcore.fsproj index 058a83e551..05af96b7e4 100644 --- a/fcs/FSharp.Compiler.Service.Tests.netcore/FSharp.Compiler.Service.Tests.netcore.fsproj +++ b/fcs/FSharp.Compiler.Service.Tests.netcore/FSharp.Compiler.Service.Tests.netcore.fsproj @@ -1,3 +1,4 @@ + netcoreapp1.0 @@ -56,4 +57,5 @@ + \ No newline at end of file diff --git a/fcs/FSharp.Compiler.Service.Tests/App.config b/fcs/FSharp.Compiler.Service.Tests/App.config index 93936674d8..1e7989fe8c 100644 --- a/fcs/FSharp.Compiler.Service.Tests/App.config +++ b/fcs/FSharp.Compiler.Service.Tests/App.config @@ -13,4 +13,7 @@ + + + diff --git a/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj b/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj index 98e86a0644..d53494b86f 100644 --- a/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj +++ b/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj @@ -80,8 +80,8 @@ PreserveNewest + - @@ -97,7 +97,6 @@ - $(FSharpSourcesRoot)\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll @@ -112,7 +111,6 @@ $(FSharpSourcesRoot)\..\packages\FSharp.Compiler.Tools.4.1.27\tools\FSharp.Core.dll true - CSharp_Analysis {887630A3-4B1D-40EA-B8B3-2D842E9C40DB} @@ -130,4 +128,66 @@ + + + + + ..\packages\Microsoft.Build\lib\net45\Microsoft.Build.dll + True + True + + + + + + + + + ..\packages\Microsoft.Build.Engine\lib\net45\Microsoft.Build.Engine.dll + True + True + + + + + + + + + ..\packages\Microsoft.Build.Framework\lib\net45\Microsoft.Build.Framework.dll + True + True + + + + + + + + + ..\packages\Microsoft.Build.Utilities.Core\lib\net45\Microsoft.Build.Utilities.Core.dll + True + True + + + + + + + + + True + + + + + + + + + True + + + + \ No newline at end of file diff --git a/fcs/FSharp.Compiler.Service.Tests/paket.references b/fcs/FSharp.Compiler.Service.Tests/paket.references new file mode 100644 index 0000000000..c64e284f16 --- /dev/null +++ b/fcs/FSharp.Compiler.Service.Tests/paket.references @@ -0,0 +1,3 @@ +Microsoft.Build.Utilities.Core +Microsoft.Build.Engine +Microsoft.Build \ No newline at end of file diff --git a/fcs/FSharp.Compiler.Service.netstandard/FSharp.Compiler.Service.netstandard.fsproj b/fcs/FSharp.Compiler.Service.netstandard/FSharp.Compiler.Service.netstandard.fsproj index eb20755c31..eef6171a57 100644 --- a/fcs/FSharp.Compiler.Service.netstandard/FSharp.Compiler.Service.netstandard.fsproj +++ b/fcs/FSharp.Compiler.Service.netstandard/FSharp.Compiler.Service.netstandard.fsproj @@ -1,3 +1,4 @@ + $(MSBuildProjectDirectory)\..\..\src @@ -646,5 +647,7 @@ - + + + \ No newline at end of file diff --git a/fcs/dependencies/README.md b/fcs/FSharp.Compiler.Service.netstandard/paket.references similarity index 100% rename from fcs/dependencies/README.md rename to fcs/FSharp.Compiler.Service.netstandard/paket.references diff --git a/fcs/FSharp.Compiler.Service/paket.references b/fcs/FSharp.Compiler.Service/paket.references new file mode 100644 index 0000000000..e69de29bb2 diff --git a/fcs/build.cmd b/fcs/build.cmd index 5597c915e8..c18c0a1f22 100644 --- a/fcs/build.cmd +++ b/fcs/build.cmd @@ -1,8 +1,8 @@ @echo off -.nuget\NuGet.exe restore -PackagesDirectory packages + setlocal cd fcs -.paket\paket.bootstrapper.exe + if errorlevel 1 ( endlocal exit /b %errorlevel% diff --git a/fcs/build.fsx b/fcs/build.fsx index cf5e7620b3..d708948692 100644 --- a/fcs/build.fsx +++ b/fcs/build.fsx @@ -13,8 +13,21 @@ open Fake.ReleaseNotesHelper #if MONO // prevent incorrect output encoding (e.g. https://github.com/fsharp/FAKE/issues/1196) System.Console.OutputEncoding <- System.Text.Encoding.UTF8 + +CleanDir (__SOURCE_DIRECTORY__ + "/../tests/TestResults") +File.WriteAllText(__SOURCE_DIRECTORY__ + "/../tests/TestResults/notestsyet.txt","No tests yet") #endif +let dotnetExePath = DotNetCli.InstallDotNetSDK "2.0.0" +let runDotnet workingDir args = + let result = + ExecProcess (fun info -> + info.FileName <- dotnetExePath + info.WorkingDirectory <- workingDir + info.Arguments <- args) TimeSpan.MaxValue + + if result <> 0 then failwithf "dotnet %s failed" args + // -------------------------------------------------------------------------------------- // Utilities // -------------------------------------------------------------------------------------- @@ -69,6 +82,22 @@ let buildVersion = else if isAppVeyorBuild then sprintf "%s-b%s" assemblyVersion AppVeyorEnvironment.BuildNumber else assemblyVersion +Target "Clean" (fun _ -> + CleanDir releaseDir +) + +Target "Restore" (fun _ -> + for p in (!! "./../**/packages.config") do + let result = + ExecProcess (fun info -> + info.FileName <- FullName @"./../.nuget/NuGet.exe" + info.WorkingDirectory <- FullName @"./.." + info.Arguments <- sprintf "restore %s -PackagesDirectory \"%s\" -ConfigFile \"%s\"" (FullName p) (FullName "./../packages") (FullName "./../.nuget/NuGet.Config")) TimeSpan.MaxValue + if result <> 0 then failwithf "nuget restore %s failed" p + + runDotnet __SOURCE_DIRECTORY__ "restore tools.fsproj" +) + Target "BuildVersion" (fun _ -> Shell.Exec("appveyor", sprintf "UpdateBuild -Version \"%s\"" buildVersion) |> ignore ) @@ -88,11 +117,24 @@ Target "Build.NetFx" (fun _ -> // Run the unit tests using test runner Target "Test.NetFx" (fun _ -> - !! (releaseDir + "/fcs/net45/FSharp.Compiler.Service.Tests.dll") + let testDir = __SOURCE_DIRECTORY__ + "/../tests/fcs" + CleanDir testDir + + let outDir = releaseDir + "/fcs" + + !! (outDir + "/**/*.*") + |> CopyFiles testDir + + let toolPath = __SOURCE_DIRECTORY__ + "/../packages/NUnit.Console.3.0.0/tools" + !! (toolPath + "/*.*") + |> CopyFiles testDir + + !! (testDir + "/**/FSharp.Compiler.Service.Tests.dll") |> Fake.Testing.NUnit3.NUnit3 (fun p -> { p with - ToolPath = @"..\packages\NUnit.Console.3.0.0\tools\nunit3-console.exe" + ToolPath = testDir + "/nunit3-console.exe" ShadowCopy = false + WorkingDir = FullName testDir TimeOut = TimeSpan.FromMinutes 20. }) ) @@ -109,26 +151,14 @@ Target "NuGet.NetFx" (fun _ -> // -------------------------------------------------------------------------------------- // .NET Core and .NET Core SDK -let isDotnetSDKInstalled = - match Fake.EnvironmentHelper.environVarOrNone "FCS_DNC" with - | Some flag -> - match bool.TryParse flag with - | true, result -> result - | _ -> false - | None -> - try - Shell.Exec("dotnet", "--info") = 0 - with - _ -> false - Target "Build.NetStd" (fun _ -> - runCmdIn __SOURCE_DIRECTORY__ "dotnet" "pack %s -v n -c Release" "FSharp.Compiler.Service.netstandard.sln" + runDotnet __SOURCE_DIRECTORY__ (sprintf "pack %s -v n -c Release" "FSharp.Compiler.Service.netstandard.sln") ) Target "Test.NetStd" (fun _ -> - runCmdIn __SOURCE_DIRECTORY__ "dotnet" "run -p FSharp.Compiler.Service.Tests.netcore/FSharp.Compiler.Service.Tests.netcore.fsproj -c Release -- --result:TestResults.NetStd.xml;format=nunit3" + runDotnet __SOURCE_DIRECTORY__ (sprintf "run -p FSharp.Compiler.Service.Tests.netcore/FSharp.Compiler.Service.Tests.netcore.fsproj -c Release -- --result:TestResults.NetStd.xml;format=nunit3") ) @@ -136,8 +166,7 @@ Target "Test.NetStd" (fun _ -> Target "Nuget.AddNetStd" (fun _ -> let nupkg = sprintf "%s/FSharp.Compiler.Service.%s.nupkg" releaseDir release.AssemblyVersion let netcoreNupkg = sprintf "FSharp.Compiler.Service.netstandard/bin/Release/FSharp.Compiler.Service.%s.nupkg" release.AssemblyVersion - runCmdIn __SOURCE_DIRECTORY__ "dotnet" "restore tools.fsproj" - runCmdIn __SOURCE_DIRECTORY__ "dotnet" "mergenupkg --source %s --other %s --framework netstandard1.6" nupkg netcoreNupkg + runDotnet __SOURCE_DIRECTORY__ (sprintf "mergenupkg --source %s --other %s --framework netstandard1.6" nupkg netcoreNupkg) ) @@ -169,7 +198,6 @@ Target "PublishNuGet" (fun _ -> // -------------------------------------------------------------------------------------- // Run all targets by default. Invoke 'build ' to override -Target "Clean" DoNothing Target "Release" DoNothing Target "NuGet" DoNothing Target "Build" DoNothing @@ -178,10 +206,12 @@ Target "TestAndNuGet" DoNothing "Clean" =?> ("BuildVersion", isAppVeyorBuild) + ==> "Restore" ==> "Build.NetStd" "Clean" =?> ("BuildVersion", isAppVeyorBuild) + ==> "Restore" ==> "Build.NetFx" "Build.NetFx" @@ -191,15 +221,15 @@ Target "TestAndNuGet" DoNothing ==> "Test.NetStd" "Build.NetFx" - =?> ("Build.NetStd", isDotnetSDKInstalled) + ==> "Build.NetStd" ==> "Build" "Build.NetStd" - =?> ("Nuget.AddNetStd", isDotnetSDKInstalled) + ==> "Nuget.AddNetStd" "Build.NetFx" ==> "NuGet.NetFx" - =?> ("Nuget.AddNetStd", isDotnetSDKInstalled) + ==> "Nuget.AddNetStd" ==> "NuGet" "Test.NetFx" @@ -207,9 +237,7 @@ Target "TestAndNuGet" DoNothing "NuGet" ==> "TestAndNuGet" - -//"Test.NetStd" -// ==> "TestAndNuGet" + "Build" ==> "NuGet" diff --git a/fcs/build.sh b/fcs/build.sh index 3e7e80e7d8..53e6962df7 100755 --- a/fcs/build.sh +++ b/fcs/build.sh @@ -4,8 +4,6 @@ then # use .Net cmd fcs/build.cmd $@ else - mono .nuget/NuGet.exe restore -PackagesDirectory packages - cd fcs # use mono @@ -13,14 +11,6 @@ else mozroots --import --sync --quiet fi - dotnet restore tools.fsproj - - mono .paket/paket.bootstrapper.exe - exit_code=$? - if [ $exit_code -ne 0 ]; then - exit $exit_code - fi - mono .paket/paket.exe restore exit_code=$? if [ $exit_code -ne 0 ]; then @@ -28,4 +18,4 @@ else fi mono packages/FAKE/tools/FAKE.exe $@ --fsiargs -d:MONO build.fsx -fi \ No newline at end of file +fi diff --git a/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.Engine.dll b/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.Engine.dll deleted file mode 100644 index 0661150997..0000000000 Binary files a/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.Engine.dll and /dev/null differ diff --git a/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.Framework.dll b/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.Framework.dll deleted file mode 100644 index 74d6e05b85..0000000000 Binary files a/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.Framework.dll and /dev/null differ diff --git a/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.dll b/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.dll deleted file mode 100644 index c702184ec0..0000000000 Binary files a/fcs/dependencies/MSBuild.v14.0/Microsoft.Build.dll and /dev/null differ diff --git a/fcs/paket.dependencies b/fcs/paket.dependencies index bfd298568f..2b2685c670 100644 --- a/fcs/paket.dependencies +++ b/fcs/paket.dependencies @@ -1,7 +1,16 @@ -framework: net45 +framework: net45, net46 source https://www.nuget.org/api/v2/ nuget FAKE nuget FSharp.Formatting +nuget Microsoft.Build.Utilities.Core 14.3.0 +nuget Microsoft.Build.Framework 14.3.0 +nuget Microsoft.Build.Engine 14.3.0 +nuget Microsoft.Build 14.3.0 +nuget System.Threading.Tasks.Dataflow 4.5.24.0 +nuget FSharp.Core + +clitool dotnet-mergenupkg +clitool dotnet-fssrgen \ No newline at end of file diff --git a/fcs/paket.lock b/fcs/paket.lock index 2e454bee77..5a5e2b6582 100644 --- a/fcs/paket.lock +++ b/fcs/paket.lock @@ -1,10 +1,27 @@ -RESTRICTION: == net45 +RESTRICTION: || (== net45) (== net46) NUGET remote: https://www.nuget.org/api/v2 + dotnet-fssrgen (3.4) - clitool: true + dotnet-mergenupkg (2.1) - clitool: true FAKE (4.63.2) FSharp.Compiler.Service (2.0.0.6) + FSharp.Core (4.2.3) FSharp.Formatting (2.14.4) FSharp.Compiler.Service (2.0.0.6) FSharpVSPowerTools.Core (>= 2.3 < 2.4) FSharpVSPowerTools.Core (2.3) FSharp.Compiler.Service (>= 2.0.0.3) + Microsoft.Build (14.3) + Microsoft.Build.Framework (14.3) + Microsoft.Build.Engine (14.3) + Microsoft.Build.Framework (14.3) + Microsoft.Build.Framework (14.3) + System.Collections (>= 4.0.11) - restriction: || (&& (== net45) (>= netstandard1.3)) (== net46) + System.Runtime (>= 4.1) - restriction: || (&& (== net45) (>= netstandard1.3)) (== net46) + System.Runtime.InteropServices (>= 4.1) - restriction: || (&& (== net45) (>= netstandard1.3)) (== net46) + Microsoft.Build.Utilities.Core (14.3) + Microsoft.Build.Framework (14.3) + System.Collections (4.3) - restriction: || (&& (== net45) (>= netstandard1.3)) (== net46) + System.Runtime (4.3) - restriction: || (&& (== net45) (>= netstandard1.3)) (== net46) + System.Runtime.InteropServices (4.3) - restriction: || (&& (== net45) (>= netstandard1.3)) (== net46) + System.Threading.Tasks.Dataflow (4.5.24) diff --git a/fcs/paket.references b/fcs/paket.references new file mode 100644 index 0000000000..88dc1b868a --- /dev/null +++ b/fcs/paket.references @@ -0,0 +1,3 @@ +dotnet-mergenupkg +dotnet-fssrgen +FSharp.Core \ No newline at end of file diff --git a/fcs/tools.fsproj b/fcs/tools.fsproj index 45aa251d76..e1d507598e 100644 --- a/fcs/tools.fsproj +++ b/fcs/tools.fsproj @@ -1,10 +1,7 @@ + - Exe - net45 + netstandard2.0 - - - - + \ No newline at end of file