@@ -1986,243 +1986,4 @@ let mainCompile (argv,bannerAlreadyPrinted,exiter:Exiter,createErrorLogger) =
19861986|> main3
19871987|> main4
19881988
1989- /// Collect the output from the stdout and stderr streams, character by character,
1990- /// recording the console color used along the way.
1991- type OutputCollector () =
1992- let output = ResizeArray()
1993- let outWriter isOut =
1994- { new TextWriter() with
1995- member x.Write ( c : char ) =
1996- lock output( fun () ->
1997- #if SILVERLIGHT
1998- output.Add( isOut, None, c))
1999- #else
2000- output.Add( isOut, ( try Some System.Console.ForegroundColorwith _ -> None) , c))
2001- #endif
2002- member x.Encoding = Encoding.UTF8}
2003- #if FX_ ATLEAST_ SILVERLIGHT_ 50
2004- #else
2005- do ignore outWriter
2006- do System.Console.SetOut( outWritertrue )
2007- do System.Console.SetError( outWriterfalse )
2008- #endif
2009- member x.GetTextAndClear () = lock output( fun () -> let res = output.ToArray() in output.Clear(); res)
2010-
2011- #if SILVERLIGHT
2012- #else
2013- /// Implement the optional resident compilation service
2014- module FSharpResidentCompiler =
2015-
2016- open System
2017- open System.Diagnostics
2018- open System.Runtime .Remoting .Channels
2019- open System.Runtime .Remoting
2020- open System.Runtime .Remoting .Lifetime
2021-
2022- /// The compilation server, which runs in the server process. Accessed by clients using .NET remoting.
2023- type FSharpCompilationServer ( exiter : Exiter ) =
2024- inherit MarshalByRefObject()
2025-
2026- static let onWindows =
2027- match System.Environment.OSVersion.Platformwith
2028- | PlatformID.Win32NT| PlatformID.Win32S| PlatformID.Win32Windows| PlatformID.WinCE-> true
2029- | _ -> false
2030-
2031- // The channel/socket name is qualified by the user name (and domain on windows)
2032- static let domainName = if onWindowsthen Environment.GetEnvironmentVariable" USERDOMAIN" else " "
2033- static let userName = Environment.GetEnvironmentVariable( if onWindowsthen " USERNAME" else " USER" )
2034- // Use different base channel names on mono and CLR as a CLR remoting process can't talk
2035- // to a mono server
2036- static let baseChannelName = if runningOnMonothen " FSCChannelMono" else " FSCChannel"
2037- static let channelName = baseChannelName+ " _" + domainName+ " _" + userName
2038- static let serverName = if runningOnMonothen " FSCServerMono" else " FSCSever"
2039- static let mutable serverExists = true
2040-
2041- let outputCollector = new OutputCollector()
2042-
2043- // This background agent ensures all compilation requests sent to the server are serialized
2044- let agent = MailboxProcessor<_>. Start( fun inbox ->
2045- async {
2046- while true do
2047- let! ( pwd , argv , reply : AsyncReplyChannel < _ >) = inbox.Receive()
2048- if ! progressthen printfn" server agent: got compilation request, argv =%A " argv
2049- let exitCode =
2050- try
2051- Environment.CurrentDirectory<- pwd
2052- let createErrorLogger = ( fun tcConfigB -> ErrorLoggerThatQuitsAfterMaxErrors( tcConfigB, exiter))
2053- mainCompile( argv, true , exiter, createErrorLogger);
2054- if ! progressthen printfn" server: finished compilation request, argv =%A " argv
2055- 0
2056- with e->
2057- if ! progressthen printfn" server: finished compilation request with errors, argv =%A " argv
2058- errorRecoveryNoRange e
2059- 1
2060- let output = outputCollector.GetTextAndClear()
2061- reply.Reply( output, exitCode)
2062- GC.Collect( 3 )
2063- // Exit the server if there are no outstanding requests and the
2064- // current memory usage after collection is over 200MB
2065- if inbox.CurrentQueueLength= 0 && GC.GetTotalMemory( true ) > 200 L* 1024 L* 1024 Lthen
2066- Environment.Exit0
2067- })
2068-
2069- member x.Run () =
2070- while serverExistsdo
2071- if ! progressthen printfn" server: startup thread sleeping..."
2072- System.Threading.Thread.Sleep1000
2073-
2074- abstract Ping : unit -> string
2075- abstract Compile : string * string [] -> ( bool * System.ConsoleColor option * char ) [] * int
2076- default x.Ping () = " ping"
2077- default x.Compile ( pwd , argv ) =
2078- if ! progressthen printfn" server: got compilation request, (pwd, argv) =%A " ( pwd, argv)
2079- agent.PostAndReply( fun reply -> ( pwd, argv, reply))
2080-
2081- override x.Finalize () =
2082- serverExists<- false
2083-
2084- // This is called on the server object by .NET remoting to initialize the lifetime characteristics
2085- // of the server object.
2086- override x.InitializeLifetimeService () =
2087- let lease = ( base .InitializeLifetimeService() :?> ILease)
2088- if ( lease.CurrentState= LeaseState.Initial) then
2089- lease.InitialLeaseTime<- TimeSpan.FromDays( 1.0 );
2090- lease.SponsorshipTimeout<- TimeSpan.FromMinutes( 2.0 );
2091- lease.RenewOnCallTime<- TimeSpan.FromDays( 1.0 );
2092- box lease
2093-
2094- static member RunServer ( exiter : Exiter ) =
2095- progress:= condition" FSHARP_SERVER_PROGRESS"
2096- if ! progressthen printfn" server: initializing server object"
2097- let server = new FSharpCompilationServer( exiter)
2098- let chan = new Ipc.IpcChannel( channelName)
2099- ChannelServices.RegisterChannel( chan, false );
2100- RemotingServices.Marshal( server, serverName) |> ignore
2101-
2102- // On Unix, the file permissions of the implicit socket need to be set correctly to make this
2103- // private to the user.
2104- if runningOnMonothen
2105- try
2106- let monoPosix = System.Reflection.Assembly.Load( " Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" )
2107- let monoUnixFileInfo = monoPosix.GetType( " Mono.Unix.UnixFileSystemInfo" )
2108- let socketName = Path.Combine( FileSystem.GetTempPathShim(), channelName)
2109- let fileEntry = monoUnixFileInfo.InvokeMember( " GetFileSystemEntry" , ( BindingFlags.InvokeMethod||| BindingFlags.Static||| BindingFlags.Public), null , null , [| box socketName|], System.Globalization.CultureInfo.InvariantCulture)
2110- // Add 0x00000180 (UserReadWriteExecute) to the access permissions on Unix
2111- monoUnixFileInfo.InvokeMember( " set_FileAccessPermissions" , ( BindingFlags.InvokeMethod||| BindingFlags.Instance||| BindingFlags.Public), null , fileEntry, [| box0x00000180 |], System.Globalization.CultureInfo.InvariantCulture) |> ignore
2112- #if DEBUG
2113- printfn" server: good, set permissions on socket name '%s '" socketName
2114- let fileEntry = monoUnixFileInfo.InvokeMember( " GetFileSystemEntry" , ( BindingFlags.InvokeMethod||| BindingFlags.Static||| BindingFlags.Public), null , null , [| box socketName|], System.Globalization.CultureInfo.InvariantCulture)
2115- let currPermissions = monoUnixFileInfo.InvokeMember( " get_FileAccessPermissions" , ( BindingFlags.InvokeMethod||| BindingFlags.Instance||| BindingFlags.Public), null , fileEntry, [| |], System.Globalization.CultureInfo.InvariantCulture) |> unbox< int>
2116- if ! progressthen printfn" server: currPermissions = '%o ' (octal)" currPermissions
2117- #endif
2118- with e->
2119- #if DEBUG
2120- printfn" server: failed to set permissions on socket, perhaps on windows? Is is not needed there."
2121- #endif
2122- ()
2123- // Fail silently
2124- server.Run()
2125-
2126- static member private ConnectToServer () =
2127- Activator.GetObject( typeof< FSharpCompilationServer>, " ipc://" + channelName+ " /" + serverName)
2128- :?> FSharpCompilationServer
2129-
2130- static member TryCompileUsingServer ( fscServerExe , argv ) =
2131- let pwd = System.Environment.CurrentDirectory
2132- let clientOpt =
2133- // Detect the absence of the channel via the exception. Probably not the best way.
2134- // Different exceptions get thrown here on Mono and Windows.
2135- let client = FSharpCompilationServer.ConnectToServer()
2136- try
2137- if ! progressthen printfn" client: attempting to connect to existing service (1)"
2138- client.Ping() |> ignore
2139- if ! progressthen printfn" client: connected to existing service"
2140- Some client
2141- with _ ->
2142- let procInfo =
2143- if runningOnMonothen
2144- let shellName , useShellExecute =
2145- match System.Environment.GetEnvironmentVariable( " FSC_MONO" ) with
2146- | null ->
2147- if onWindowsthen
2148- Path.Combine( Path.GetDirectoryName( typeof< Object>. Assembly.Location), @" ..\..\..\bin\mono.exe" ), false
2149- else
2150- " mono" , true
2151- | path-> path, false
2152-
2153- // e.g. "C:\Program Files\Mono-2.6.1\lib\mono20\mscorlib.dll" --> "C:\Program Files\Mono-2.6.1\bin\mono.exe"
2154- ProcessStartInfo( FileName= shellName,
2155- Arguments= fscServerExe+ " /server" ,
2156- CreateNoWindow= true ,
2157- UseShellExecute= useShellExecute)
2158- else
2159- ProcessStartInfo( FileName= fscServerExe,
2160- Arguments= " /server" ,
2161- CreateNoWindow= true ,
2162- UseShellExecute= false )
2163-
2164- let cmdProcess = new Process( StartInfo= procInfo)
2165-
2166- //let exitE = cmdProcess.Exited |> Observable.map (fun x -> x)
2167-
2168- cmdProcess.Start() |> ignore
2169- //exitE.Add(fun _ -> if !progress then eprintfn "client: the server has exited")
2170- cmdProcess.EnableRaisingEvents<- true ;
2171-
2172- // Create the client proxy and attempt to connect to the server
2173- let rec tryAcccesServer nRemaining =
2174- if nRemaining= 0 then
2175- // Failed to connect to server, give up
2176- None
2177- else
2178- try
2179- if ! progressthen printfn" client: attempting to connect to existing service (2)"
2180- client.Ping() |> ignore
2181- if ! progressthen printfn" client: connected to existing service"
2182- Some client
2183- // Detect the absence of the channel via the exception. Probably not the best way.
2184- // Different exceptions get thrown here on Mono and Windows.
2185- with _ (* System.Runtime.Remoting.RemotingException*) ->
2186- // Sleep a bit
2187- System.Threading.Thread.Sleep50
2188- tryAcccesServer( nRemaining- 1 )
2189-
2190- tryAcccesServer20
2191-
2192- match clientOptwith
2193- | Some client->
2194- if ! progressthen printfn" client: calling client.Compile(%A )" argv
2195- // Install the global error logger and never remove it. This logger does have all command-line flags considered.
2196- try
2197- let ( output , exitCode ) =
2198- try client.Compile( pwd, argv)
2199- with e->
2200- printfn" server error:%s " ( e.ToString())
2201- raise( Error( FSComp.SR.fscRemotingError(), rangeStartup))
2202-
2203- if ! progressthen printfn" client: returned from client.Compile(%A ), res =%d " argv exitCode
2204- use holder=
2205- try let originalConsoleColor = Console.ForegroundColor
2206- { new System.IDisposablewith member x.Dispose () = Console.ForegroundColor<- originalConsoleColor}
2207- with _ -> null
2208- let mutable prevConsoleColor = try Console.ForegroundColorwith _ -> ConsoleColor.Black
2209- for ( isOut, consoleColorOpt, c: char) in outputdo
2210- try match consoleColorOptwith
2211- | Some consoleColor->
2212- if prevConsoleColor<> consoleColorthen
2213- Console.ForegroundColor<- consoleColor;
2214- | None-> ()
2215- with _ -> ()
2216- c|> ( if isOutthen System.Console.Out.Writeelse System.Console.Error.Write)
2217- Some exitCode
2218- with err->
2219- let sb = System.Text.StringBuilder()
2220- OutputErrorOrWarning( pwd, true , false , ErrorStyle.DefaultErrors, true ) sb( PhasedError.Create( err, BuildPhase.Compile))
2221- eprintfn" %s " ( sb.ToString())
2222- // We continue on and compile in-process - the server appears to have died half way through.
2223- None
2224- | None->
2225- None
2226-
2227- #endif // SILVERLIGHT
2228- #endif // NO_COMPILER_BACKEND
1989+ #endif //NO_COMPILER_BACKEND