diff --git a/FSharp.Compiler.Service.sln b/FSharp.Compiler.Service.sln
index d00e651dc0..03de2676e4 100644
--- a/FSharp.Compiler.Service.sln
+++ b/FSharp.Compiler.Service.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
+VisualStudioVersion = 12.0.30501.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{B6B68AE6-E7A4-4D43-9B34-FFA74BFE192B}"
ProjectSection(SolutionItems) = preProject
@@ -57,6 +57,10 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Fsc", "samples\FscExe\Fsc.f
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharp_Analysis", "tests\service\data\CSharp_Analysis\CSharp_Analysis.csproj", "{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service.ProjectCracker.Exe", "src\fsharp\FSharp.Compiler.Service.ProjectCracker.Exe\FSharp.Compiler.Service.ProjectCracker.Exe.fsproj", "{B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service.ProjectCracker", "src\fsharp\FSharp.Compiler.Service.ProjectCracker\FSharp.Compiler.Service.ProjectCracker.fsproj", "{893C3CD9-5AF8-4027-A667-21E62FC2C703}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -190,6 +194,36 @@ Global
{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Release|x86.ActiveCfg = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Proto|Any CPU.ActiveCfg = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Proto|Any CPU.Build.0 = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Proto|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Proto|Mixed Platforms.Build.0 = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Proto|x86.ActiveCfg = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Release|x86.ActiveCfg = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Proto|Any CPU.ActiveCfg = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Proto|Any CPU.Build.0 = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Proto|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Proto|Mixed Platforms.Build.0 = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Proto|x86.ActiveCfg = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Release|Any CPU.Build.0 = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/build.fsx b/build.fsx
index 473f895196..b1e59a3d0a 100644
--- a/build.fsx
+++ b/build.fsx
@@ -141,6 +141,12 @@ Target "NuGet" (fun _ ->
Version = release.NugetVersion
OutputPath = buildDir
ReleaseNotes = toLines release.Notes })
+ Paket.Pack (fun p ->
+ { p with
+ TemplateFile = "nuget/projectcracker.template"
+ Version = release.NugetVersion
+ OutputPath = buildDir
+ ReleaseNotes = toLines release.Notes })
)
diff --git a/nuget/projectcracker.template b/nuget/projectcracker.template
new file mode 100644
index 0000000000..4a15816b51
--- /dev/null
+++ b/nuget/projectcracker.template
@@ -0,0 +1,21 @@
+type file
+id FSharp.Compiler.Service.ProjectCracker
+description
+ Adds cracking capabilities.
+authors
+ Microsoft Corporation, Robin Neatherway
+summary
+ Cracking projects
+licenseurl https://github.com/fsharp/FSharp.Compiler.Service/blob/master/LICENSE
+projecturl https://github.com/fsharp/FSharp.Compiler.Service
+iconurl https://raw.github.com/fsharp/FSharp.Compiler.Service/master/misc/logo.png
+tags
+ F#, fsharp, msbuild, editor
+files
+ ../bin/v4.5/FSharp.Compiler.Service.ProjectCracker.Exe.exe ==> lib/net45
+ ../bin/v4.5/FSharp.Compiler.Service.ProjectCracker.Exe.?db ==> lib/net45
+ ../bin/v4.5/FSharp.Compiler.Service.ProjectCracker.Exe.exe.?db ==> lib/net45
+ ../bin/v4.5/FSharp.Compiler.Service.ProjectCracker.dll ==> lib/net45
+ ../bin/v4.5/FSharp.Compiler.Service.ProjectCracker.XML ==> lib/net45
+ ../bin/v4.5/FSharp.Compiler.Service.ProjectCracker.?db ==> lib/net45
+ ../bin/v4.5/FSharp.Compiler.Service.ProjectCracker.dll.?db ==> lib/net45
\ No newline at end of file
diff --git a/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/App.config b/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/App.config
new file mode 100644
index 0000000000..3c6dcfe227
--- /dev/null
+++ b/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/App.config
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/FSharp.Compiler.Service.ProjectCracker.Exe.fsproj b/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/FSharp.Compiler.Service.ProjectCracker.Exe.fsproj
new file mode 100644
index 0000000000..bfc08be931
--- /dev/null
+++ b/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/FSharp.Compiler.Service.ProjectCracker.Exe.fsproj
@@ -0,0 +1,96 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 2.0
+ b1bdd96d-47e1-4e65-8107-fbae23a06db4
+ Exe
+ FSharp.Compiler.Service.ProjectCracker.Exe
+ FSharp.Compiler.Service.ProjectCracker.Exe
+ v4.5
+ 4.3.0.0
+ ..\..\..\
+ FSharp.Compiler.Service.ProjectCracker.Exe
+ $(OtherFlags) --staticlink:FSharp.Core
+ $(NoWarn);40
+ true
+ FSharp.Compiler.Service.ProjectCracker.Exe
+ ..\..\..\bin\$(TargetFrameworkVersion)
+ ..\..\..\bin\$(TargetFrameworkVersion)\FSharp.Compiler.Service.ProjectCracker.Exe.XML
+
+
+ true
+ full
+ false
+ false
+ DEBUG;TRACE
+ 3
+ AnyCPU
+ true
+
+
+ pdbonly
+ true
+ true
+ TRACE
+ 3
+ AnyCPU
+ true
+
+
+ 11
+
+
+
+
+ $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
+
+
+
+
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+
+
+ False
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/Program.fs b/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/Program.fs
new file mode 100644
index 0000000000..7659db1804
--- /dev/null
+++ b/src/fsharp/FSharp.Compiler.Service.ProjectCracker.Exe/Program.fs
@@ -0,0 +1,451 @@
+namespace FSharp.Compiler.Service.ProjectCracker.Exe
+
+open Microsoft.Build.Framework
+open Microsoft.Build.Utilities
+open System.Text
+open System.IO
+open System
+open System.Reflection
+open System.Runtime.Serialization.Formatters.Binary
+
+type ProjectOptions =
+ {
+ ProjectFile: string
+ Options: string[]
+ ReferencedProjectOptions: (string * ProjectOptions)[]
+ LogOutput: string
+ }
+
+module Program =
+ let runningOnMono =
+ try match System.Type.GetType("Mono.Runtime") with null -> false | _ -> true
+ with e -> false
+
+ type internal BasicStringLogger() =
+ inherit Logger()
+
+ let sb = new StringBuilder()
+
+ let log (e: BuildEventArgs) =
+ sb.Append(e.Message) |> ignore
+ sb.AppendLine() |> ignore
+
+ override x.Initialize(eventSource:IEventSource) =
+ sb.Clear() |> ignore
+ eventSource.AnyEventRaised.Add(log)
+
+ member x.Log = sb.ToString()
+
+ type internal HostCompile() =
+ member th.Compile(_, _, _) = 0
+ interface ITaskHost
+
+ //----------------------------------------------------------------------------
+ // 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 mkAbsoluteOpt dir v = Option.map (mkAbsolute dir) v
+
+ let logOpt =
+ if enableLogging then
+ let log = new BasicStringLogger()
+ do log.Verbosity <- Microsoft.Build.Framework.LoggerVerbosity.Diagnostic
+ Some log
+ else
+ None
+
+ // Use the old API on Mono, with ToolsVersion = 12.0
+ 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
+
+ let CrackProjectUsingNewBuildAPI(fsprojFile) =
+ let fsprojFullPath = try Path.GetFullPath(fsprojFile) with _ -> fsprojFile
+ let fsprojAbsDirectory = Path.GetDirectoryName fsprojFullPath
+
+ use _pwd =
+ let dir = Environment.CurrentDirectory
+ Environment.CurrentDirectory <- fsprojAbsDirectory
+ { new System.IDisposable with member x.Dispose() = Environment.CurrentDirectory <- dir }
+ use engine = new Microsoft.Build.Evaluation.ProjectCollection()
+ let host = new HostCompile()
+ engine.HostServices.RegisterHostObject(fsprojFullPath, "CoreCompile", "Fsc", host)
+
+ let projectInstanceFromFullPath (fsprojFullPath: string) =
+ use stream = new IO.StreamReader(fsprojFullPath)
+ use xmlReader = System.Xml.XmlReader.Create(stream)
+
+ let project = engine.LoadProject(xmlReader, FullPath=fsprojFullPath)
+
+ project.SetGlobalProperty("BuildingInsideVisualStudio", "true") |> ignore
+ project.SetGlobalProperty("VisualStudioVersion", "12.0") |> ignore
+ for (prop, value) in properties do
+ project.SetProperty(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 runningOnMono then
+ CrackProjectUsingOldBuildAPI(fsprojFileName)
+ else
+ CrackProjectUsingNewBuildAPI(fsprojFileName)
+ with
+ | :? Microsoft.Build.BuildEngine.InvalidProjectFileException as e ->
+ raise (Microsoft.Build.Exceptions.InvalidProjectFileException(
+ e.ProjectFile,
+ e.LineNumber,
+ e.ColumnNumber,
+ e.EndLineNumber,
+ e.EndColumnNumber,
+ e.Message,
+ e.ErrorSubcategory,
+ e.ErrorCode,
+ e.HelpKeyword))
+ | :? ArgumentException as e -> raise (IO.FileNotFoundException(e.Message))
+
+
+ let logOutput = match logOpt with None -> "" | Some l -> l.Log
+ let pages = getItems "Page"
+ let embeddedResources = getItems "EmbeddedResource"
+ let files = getItems "Compile"
+ let resources = getItems "Resource"
+ let noaction = getItems "None"
+ let content = getItems "Content"
+
+ let split (s : string option) (cs : char []) =
+ match s with
+ | None -> [||]
+ | Some s ->
+ if String.IsNullOrWhiteSpace s then [||]
+ else s.Split(cs, StringSplitOptions.RemoveEmptyEntries)
+
+ let getbool (s : string option) =
+ match s with
+ | None -> false
+ | Some s ->
+ match (Boolean.TryParse s) with
+ | (true, result) -> result
+ | (false, _) -> false
+
+ let fxVer = getProp "TargetFrameworkVersion"
+ let optimize = getProp "Optimize" |> getbool
+ let assemblyNameOpt = getProp "AssemblyName"
+ let tailcalls = getProp "Tailcalls" |> getbool
+ let outputPathOpt = getProp "OutputPath"
+ let docFileOpt = getProp "DocumentationFile"
+ let outputTypeOpt = getProp "OutputType"
+ let debugTypeOpt = getProp "DebugType"
+ let baseAddressOpt = getProp "BaseAddress"
+ let sigFileOpt = getProp "GenerateSignatureFile"
+ let keyFileOpt = getProp "KeyFile"
+ let pdbFileOpt = getProp "PdbFile"
+ let platformOpt = getProp "Platform"
+ let targetTypeOpt = getProp "TargetType"
+ let versionFileOpt = getProp "VersionFile"
+ let targetProfileOpt = getProp "TargetProfile"
+ let warnLevelOpt = getProp "Warn"
+ let subsystemVersionOpt = getProp "SubsystemVersion"
+ let win32ResOpt = getProp "Win32ResourceFile"
+ let heOpt = getProp "HighEntropyVA" |> getbool
+ let win32ManifestOpt = getProp "Win32ManifestFile"
+ let debugSymbols = getProp "DebugSymbols" |> getbool
+ let prefer32bit = getProp "Prefer32Bit" |> getbool
+ let warnAsError = getProp "TreatWarningsAsErrors" |> getbool
+ let defines = split (getProp "DefineConstants") [| ';'; ','; ' ' |]
+ let nowarn = split (getProp "NoWarn") [| ';'; ','; ' ' |]
+ let warningsAsError = split (getProp "WarningsAsErrors") [| ';'; ','; ' ' |]
+ let libPaths = split (getProp "ReferencePath") [| ';'; ',' |]
+ let otherFlags = split (getProp "OtherFlags") [| ' ' |]
+ let isLib = (outputTypeOpt = Some "Library")
+
+ let docFileOpt =
+ match docFileOpt with
+ | None -> None
+ | Some docFile -> Some(mkAbsolute directory docFile)
+
+
+ let options =
+ [ yield "--simpleresolution"
+ yield "--noframework"
+ match outFileOpt with
+ | None -> ()
+ | Some outFile -> yield "--out:" + outFile
+ match docFileOpt with
+ | None -> ()
+ | Some docFile -> yield "--doc:" + docFile
+ match baseAddressOpt with
+ | None -> ()
+ | Some baseAddress -> yield "--baseaddress:" + baseAddress
+ match keyFileOpt with
+ | None -> ()
+ | Some keyFile -> yield "--keyfile:" + keyFile
+ match sigFileOpt with
+ | None -> ()
+ | Some sigFile -> yield "--sig:" + sigFile
+ match pdbFileOpt with
+ | None -> ()
+ | Some pdbFile -> yield "--pdb:" + pdbFile
+ match versionFileOpt with
+ | None -> ()
+ | Some versionFile -> yield "--versionfile:" + versionFile
+ match warnLevelOpt with
+ | None -> ()
+ | Some warnLevel -> yield "--warn:" + warnLevel
+ match subsystemVersionOpt with
+ | None -> ()
+ | Some s -> yield "--subsystemversion:" + s
+ if heOpt then yield "--highentropyva+"
+ match win32ResOpt with
+ | None -> ()
+ | Some win32Res -> yield "--win32res:" + win32Res
+ match win32ManifestOpt with
+ | None -> ()
+ | Some win32Manifest -> yield "--win32manifest:" + win32Manifest
+ match targetProfileOpt with
+ | None -> ()
+ | Some targetProfile -> yield "--targetprofile:" + targetProfile
+ yield "--fullpaths"
+ yield "--flaterrors"
+ if warnAsError then yield "--warnaserror"
+ yield
+ if isLib then "--target:library"
+ else "--target:exe"
+ for symbol in defines do
+ if not (String.IsNullOrWhiteSpace symbol) then yield "--define:" + symbol
+ for nw in nowarn do
+ if not (String.IsNullOrWhiteSpace nw) then yield "--nowarn:" + nw
+ for nw in warningsAsError do
+ if not (String.IsNullOrWhiteSpace nw) then yield "--warnaserror:" + nw
+ yield if debugSymbols then "--debug+"
+ else "--debug-"
+ yield if optimize then "--optimize+"
+ else "--optimize-"
+ yield if tailcalls then "--tailcalls+"
+ else "--tailcalls-"
+ match debugTypeOpt with
+ | None -> ()
+ | Some debugType ->
+ match debugType.ToUpperInvariant() with
+ | "NONE" -> ()
+ | "PDBONLY" -> yield "--debug:pdbonly"
+ | "FULL" -> yield "--debug:full"
+ | _ -> ()
+ match platformOpt |> Option.map (fun o -> o.ToUpperInvariant()), prefer32bit,
+ targetTypeOpt |> Option.map (fun o -> o.ToUpperInvariant()) with
+ | Some "ANYCPU", true, Some "EXE" | Some "ANYCPU", true, Some "WINEXE" -> yield "--platform:anycpu32bitpreferred"
+ | Some "ANYCPU", _, _ -> yield "--platform:anycpu"
+ | Some "X86", _, _ -> yield "--platform:x86"
+ | Some "X64", _, _ -> yield "--platform:x64"
+ | Some "ITANIUM", _, _ -> yield "--platform:Itanium"
+ | _ -> ()
+ match targetTypeOpt |> Option.map (fun o -> o.ToUpperInvariant()) with
+ | Some "LIBRARY" -> yield "--target:library"
+ | Some "EXE" -> yield "--target:exe"
+ | Some "WINEXE" -> yield "--target:winexe"
+ | Some "MODULE" -> yield "--target:module"
+ | _ -> ()
+ yield! otherFlags
+ for f in resources do
+ yield "--resource:" + f
+ for i in libPaths do
+ yield "--lib:" + mkAbsolute directory i
+ for r in references do
+ yield "-r:" + r
+ yield! files ]
+
+ member x.Options = options
+ member x.FrameworkVersion = fxVer
+ member x.ProjectReferences = projectReferences
+ member x.References = references
+ member x.CompileFiles = files
+ member x.ResourceFiles = resources
+ member x.EmbeddedResourceFiles = embeddedResources
+ member x.ContentFiles = content
+ member x.OtherFiles = noaction
+ member x.PageFiles = pages
+ member x.OutputFile = outFileOpt
+ member x.Directory = directory
+ member x.AssemblyName = assemblyNameOpt
+ member x.OutputPath = outputPathOpt
+ member x.FullPath = fsprojFullPath
+ member x.LogOutput = logOutput
+ static member Parse(fsprojFileName:string, ?properties, ?enableLogging) = new FSharpProjectFileInfo(fsprojFileName, ?properties=properties, ?enableLogging=enableLogging)
+
+ let getOptions file enableLogging properties =
+ 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
+ [||]
+
+ let options = { ProjectFile = file
+ Options = Array.append (Array.ofList (parsedProject.Options))
+ referencedProjectOutputs
+ ReferencedProjectOptions = referencedProjectOptions
+ LogOutput = parsedProject.LogOutput }
+
+ parsedProject.OutputFile, options
+
+ snd (getOptions file)
+
+ 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")) then
+ requestedAssembly.Version <- Version("14.0.0.0")
+ Assembly.Load (requestedAssembly)
+ else
+ null)
+ AppDomain.CurrentDomain.add_AssemblyResolve(onResolveEvent)
+
+ let rec pairs l =
+ match l with
+ | [] | [_] -> []
+ | x::y::rest -> (x,y) :: pairs rest
+
+ []
+ let main argv =
+ let text = Array.exists (fun (s: string) -> s = "--text") argv
+ let argv = Array.filter (fun (s: string) -> s <> "--text") argv
+
+ let ret, opts =
+ if argv.Length >= 2 then
+ let projectFile = argv.[0]
+ let enableLogging = match Boolean.TryParse(argv.[1]) with
+ | true, true -> true
+ | _ -> false
+ try
+ addMSBuildv14BackupResolution ()
+ let props = pairs (List.ofArray argv.[2..])
+ let opts = getOptions argv.[0] enableLogging props
+ 0, opts
+ with e ->
+ 2, { ProjectFile = projectFile;
+ Options = [||];
+ ReferencedProjectOptions = [||];
+ LogOutput = e.ToString() }
+ else
+ 1, { ProjectFile = "";
+ Options = [||];
+ ReferencedProjectOptions = [||];
+ LogOutput = "At least two arguments required." }
+
+ if text then
+ printfn "%A" opts
+ else
+ let fmt = new BinaryFormatter()
+ use out = new StreamWriter(System.Console.OpenStandardOutput())
+ fmt.Serialize(out.BaseStream, opts)
+ ret
diff --git a/src/fsharp/FSharp.Compiler.Service.ProjectCracker/FSharp.Compiler.Service.ProjectCracker.fsproj b/src/fsharp/FSharp.Compiler.Service.ProjectCracker/FSharp.Compiler.Service.ProjectCracker.fsproj
new file mode 100644
index 0000000000..2b1f1e14aa
--- /dev/null
+++ b/src/fsharp/FSharp.Compiler.Service.ProjectCracker/FSharp.Compiler.Service.ProjectCracker.fsproj
@@ -0,0 +1,85 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 2.0
+ 893c3cd9-5af8-4027-a667-21e62fc2c703
+ Library
+ FSharp.Compiler.Service.ProjectCracker
+ FSharp.Compiler.Service.ProjectCracker
+ v4.5
+ ..\..\..\
+ 4.3.0.0
+ FSharp.Compiler.Service.ProjectCracker
+ ..\..\..\bin\$(TargetFrameworkVersion)
+ ..\..\..\bin\$(TargetFrameworkVersion)\FSharp.Compiler.Service.ProjectCracker.XML
+
+
+ true
+ full
+ false
+ false
+ DEBUG;TRACE
+ 3
+ AnyCPU
+ true
+
+
+ pdbonly
+ true
+ true
+ TRACE
+ 3
+ AnyCPU
+ true
+
+
+
+
+ False
+
+
+
+
+
+
+
+
+
+
+ FSharp.Compiler.Service.ProjectCracker.Exe
+ {b1bdd96d-47e1-4e65-8107-fbae23a06db4}
+ True
+
+
+ FSharp.Compiler.Service
+ {2e4d67b4-522d-4cf7-97e4-ba940f0b18f3}
+ True
+
+
+
+ 11
+
+
+
+
+ $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
+
+
+
+
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/fsharp/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs b/src/fsharp/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs
new file mode 100644
index 0000000000..c0fdafb216
--- /dev/null
+++ b/src/fsharp/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs
@@ -0,0 +1,53 @@
+namespace FSharp.Compiler.Service
+
+open System.Diagnostics
+open System.Text
+open System.IO
+open System
+open System.Runtime
+
+open Microsoft.FSharp.Compiler.SourceCodeServices
+
+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 false
+ let logMap = ref Map.empty
+
+ let rec convert (opts: FSharp.Compiler.Service.ProjectCracker.Exe.ProjectOptions) : FSharpProjectOptions =
+ let referencedProjects = Array.map (fun (a, b) -> a, convert b) opts.ReferencedProjectOptions
+ logMap := Map.add opts.ProjectFile opts.LogOutput !logMap
+ { ProjectFileName = opts.ProjectFile
+ ProjectFileNames = [| |]
+ OtherOptions = opts.Options
+ ReferencedProjects = referencedProjects
+ IsIncompleteTypeCheckEnvironment = false
+ UseScriptResolutionRules = false
+ LoadTime = loadedTimeStamp
+ UnresolvedReferences = None }
+
+ let arguments = new StringBuilder()
+ arguments.Append(projectFileName) |> ignore
+ arguments.Append(' ').Append(enableLogging.ToString()) |> ignore
+ for k, v in properties do
+ arguments.Append(' ').Append(k).Append(' ').Append(v) |> ignore
+
+ let p = new System.Diagnostics.Process()
+ p.StartInfo.FileName <- Path.Combine(Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly().Location),
+ "FSharp.Compiler.Service.ProjectCracker.Exe.exe")
+ p.StartInfo.Arguments <- arguments.ToString()
+ p.StartInfo.UseShellExecute <- false
+ p.StartInfo.CreateNoWindow <- true
+ p.StartInfo.RedirectStandardOutput <- true
+ ignore <| p.Start()
+
+ let fmt = new Serialization.Formatters.Binary.BinaryFormatter()
+ let opts = fmt.Deserialize(p.StandardOutput.BaseStream) :?> FSharp.Compiler.Service.ProjectCracker.Exe.ProjectOptions
+ p.WaitForExit()
+
+ convert opts, !logMap
+
+ static member GetProjectOptionsFromProjectFile(projectFileName : string, ?properties : (string * string) list, ?loadedTimeStamp) =
+ fst (ProjectCracker.GetProjectOptionsFromProjectFileLogged(projectFileName, ?properties=properties, ?loadedTimeStamp=loadedTimeStamp))
diff --git a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
index 726aff06b8..6b492fbcf1 100644
--- a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
+++ b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
@@ -1,4 +1,4 @@
-
+