Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4c10b32

Browse files
committed
Enable shadowcopying when FSI references an assembly.
Add a commandline switch --shadowCopyReferences[+/-] to control it.Modify reference message in fsi, when underlying assembly has changed.Tests for locking/not locking behavior on fsi.exe (changeset 1263181)
1 parent7223dde commit4c10b32

File tree

11 files changed

+177
-44
lines changed

11 files changed

+177
-44
lines changed

‎src/fsharp/build.fs‎

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,6 +1997,9 @@ type TcConfigBuilder =
19971997

19981998
/// if true - every expression in quotations will be augmented with full debug info (filename, location in file)
19991999
mutable emitDebugInfoInQuotations:bool
2000+
2001+
/// When false FSI will lock referenced assemblies requiring process restart, false = disable Shadow Copy false (*default*)
2002+
mutable shadowCopyReferences:bool
20002003
}
20012004

20022005

@@ -2138,6 +2141,7 @@ type TcConfigBuilder =
21382141
sqmNumOfSourceFiles=0
21392142
sqmSessionStartedTime= System.DateTime.Now.Ticks
21402143
emitDebugInfoInQuotations=false
2144+
shadowCopyReferences=false
21412145
}
21422146

21432147
membertcConfigB.ResolveSourceFile(m,nm,pathLoadedFrom)=
@@ -2265,7 +2269,7 @@ type TcConfigBuilder =
22652269
ri,fileNameOfPath ri,ILResourceAccess.Public
22662270

22672271

2268-
letOpenILBinary(filename,optimizeForMemory,openBinariesInMemory,ilGlobalsOpt,pdbPathOption,primaryAssemblyName,noDebugData)=
2272+
letOpenILBinary(filename,optimizeForMemory,openBinariesInMemory,ilGlobalsOpt,pdbPathOption,primaryAssemblyName,noDebugData,shadowCopyReferences)=
22692273
letilGlobals=
22702274
// ILScopeRef.Local can be used only for primary assembly (mscorlib or System.Runtime) itself
22712275
// Remaining assemblies should be opened using existing ilGlobals (so they can properly locate fundamental types)
@@ -2283,7 +2287,17 @@ let OpenILBinary(filename,optimizeForMemory,openBinariesInMemory,ilGlobalsOpt, p
22832287
// Visual Studio uses OpenILModuleReaderAfterReadingAllBytes for all DLLs to avoid having to dispose of any readers explicitly
22842288
if openBinariesInMemory// && not syslib
22852289
then ILBinaryReader.OpenILModuleReaderAfterReadingAllBytes filename opts
2286-
else ILBinaryReader.OpenILModuleReader filename opts
2290+
else
2291+
letlocation=
2292+
// In order to use memory mapped files on the shadow copied version of the Assembly, we `preload the assembly
2293+
// We swallow all exceptions so that we do not change the exception contract of this API
2294+
if shadowCopyReferencesthen
2295+
try
2296+
System.Reflection.Assembly.ReflectionOnlyLoadFrom(filename).Location
2297+
with e-> filename
2298+
else
2299+
filename
2300+
ILBinaryReader.OpenILModuleReader location opts
22872301

22882302
#if DEBUG
22892303
[<System.Diagnostics.DebuggerDisplayAttribute("AssemblyResolution({resolvedPath})")>]
@@ -2391,7 +2405,7 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) =
23912405
letfilename= ComputeMakePathAbsolute data.implicitIncludeDir primaryAssemblyFilename
23922406
try
23932407

2394-
letilReader= OpenILBinary(filename,data.optimizeForMemory,data.openBinariesInMemory,None,None, data.primaryAssembly.Name, data.noDebugData)
2408+
letilReader= OpenILBinary(filename,data.optimizeForMemory,data.openBinariesInMemory,None,None, data.primaryAssembly.Name, data.noDebugData, data.shadowCopyReferences)
23952409
try
23962410
letilModule= ilReader.ILModuleDef
23972411

@@ -2451,7 +2465,7 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) =
24512465
| Some(fslibFilename)->
24522466
letfilename= ComputeMakePathAbsolute data.implicitIncludeDir fslibFilename
24532467
try
2454-
letilReader= OpenILBinary(filename,data.optimizeForMemory,data.openBinariesInMemory,None,None, data.primaryAssembly.Name, data.noDebugData)
2468+
letilReader= OpenILBinary(filename,data.optimizeForMemory,data.openBinariesInMemory,None,None, data.primaryAssembly.Name, data.noDebugData, data.shadowCopyReferences)
24552469
try
24562470
checkFSharpBinaryCompatWithMscorlib filename ilReader.ILAssemblyRefs ilReader.ILModuleDef.ManifestOfAssembly.Version rangeStartup;
24572471
letfslibRoot= Path.GetDirectoryName(FileSystem.GetFullPathShim(filename))
@@ -2586,6 +2600,7 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) =
25862600
memberx.sqmSessionGuid= data.sqmSessionGuid
25872601
memberx.sqmNumOfSourceFiles= data.sqmNumOfSourceFiles
25882602
memberx.sqmSessionStartedTime= data.sqmSessionStartedTime
2603+
memberx.shadowCopyReferences= data.shadowCopyReferences
25892604

25902605
static memberCreate(builder,validate)=
25912606
use unwindBuildPhase= PushThreadBuildPhaseUntilUnwind(BuildPhase.Parameter)
@@ -3667,7 +3682,7 @@ type TcImports(tcConfigP:TcConfigProvider, initialResolutions:TcAssemblyResoluti
36673682
else
36683683
None
36693684

3670-
letilILBinaryReader= OpenILBinary(filename,tcConfig.optimizeForMemory,tcConfig.openBinariesInMemory,ilGlobalsOpt,pdbPathOption, tcConfig.primaryAssembly.Name, tcConfig.noDebugData)
3685+
letilILBinaryReader= OpenILBinary(filename,tcConfig.optimizeForMemory,tcConfig.openBinariesInMemory,ilGlobalsOpt,pdbPathOption, tcConfig.primaryAssembly.Name, tcConfig.noDebugData, tcConfig.shadowCopyReferences)
36713686

36723687
tcImports.AttachDisposeAction(fun _-> ILBinaryReader.CloseILModuleReader ilILBinaryReader);
36733688
ilILBinaryReader.ILModuleDef, ilILBinaryReader.ILAssemblyRefs

‎src/fsharp/build.fsi‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ type TcConfigBuilder =
333333
mutable sqmSessionGuid:System.Guid option
334334
mutable sqmNumOfSourceFiles:int
335335
sqmSessionStartedTime:int64
336-
mutable emitDebugInfoInQuotations:bool}
336+
mutable emitDebugInfoInQuotations:bool
337+
mutable shadowCopyReferences:bool}
338+
337339

338340
static memberCreateNew:
339341
defaultFSharpBinariesDir:string*
@@ -491,7 +493,8 @@ type TcConfig =
491493
member sqmSessionGuid: System.Guid option
492494
member sqmNumOfSourceFiles: int
493495
member sqmSessionStartedTime: int64
494-
496+
member shadowCopyReferences: bool
497+
495498
static member Create: TcConfigBuilder* validate: bool-> TcConfig
496499

497500

‎src/fsharp/fsi/FSIstrings.txt‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ fsiAbortingMainThread,"- Aborting main thread..."
4242
fsiCouldNotInstallCtrlCHandler,"Failed to install ctrl-c handler - Ctrl-C handling will not be available. Error was:\n\t%s"
4343
fsiDidAHashr,"--> Referenced '%s'"
4444
fsiDidAHashrWithLockWarning,"--> Referenced '%s' (file may be locked by F# Interactive process)"
45+
fsiDidAHashrWithStaleWarning,"--> Referenced '%s' (an assembly with a different timestamp has already been referenced from this location, reset fsi to load the updated assembly)"
4546
fsiDidAHashI,"--> Added '%s' to library include path"
4647
fsiTurnedTimingOn,"--> Timing now on"
4748
fsiTurnedTimingOff,"--> Timing now off"
4849
fsiUnexpectedThreadAbortException,"- Unexpected ThreadAbortException (Ctrl-C) during event handling: Trying to restart..."
4950
fsiFailedToResolveAssembly,"Failed to resolve assembly '%s'"
5051
fsiBindingSessionTo,"Binding session to '%s'..."
51-
fsiProductName,"Microsoft (R) F# Interactive version %s"
52+
fsiProductName,"Microsoft (R) F# Interactive version %s"
53+
shadowCopyReferences,"Prevents references from being locked by the F# Interactive process"

‎src/fsharp/fsi/fsi.fs‎

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ open Internal.Utilities
1313
moduleTc= Microsoft.FSharp.Compiler.TypeChecker
1414

1515
openSystem
16+
openSystem.Collections.Generic
1617
openSystem.Diagnostics
1718
openSystem.Globalization
1819
openSystem.Runtime.InteropServices
@@ -83,6 +84,7 @@ module Utilities =
8384

8485
letignoreAllErrors f=try f()with_->()
8586

87+
letreferencedAssemblies= Dictionary<string, DateTime>()
8688

8789
//----------------------------------------------------------------------------
8890
// Timing support
@@ -501,16 +503,13 @@ type FsiCommandLineOptions(argv: string[], tcConfigB, fsiConsoleOutput: FsiConso
501503
CompilerOption("full-help", tagNone, OptionHelp(fun blocks-> displayHelpFsi tcConfigB blocks), None, None);// "Short form of --help");
502504
]);
503505
PublicOptions(FSComp.SR.optsHelpBannerAdvanced(),
504-
[CompilerOption("exec","", OptionUnit(fun()-> interact<-false), None,
505-
Some(FSIstrings.SR.fsiExec()));
506-
CompilerOption("gui", tagNone, OptionSwitch(fun flag-> gui<-(flag= On)),None,
507-
Some(FSIstrings.SR.fsiGui()));
508-
CompilerOption("quiet","", OptionUnit(fun()-> tcConfigB.noFeedback<-true), None,
509-
Some(FSIstrings.SR.fsiQuiet()));
506+
[CompilerOption("exec","", OptionUnit(fun()-> interact<-false), None, Some(FSIstrings.SR.fsiExec()));
507+
CompilerOption("gui", tagNone, OptionSwitch(fun flag-> gui<-(flag= On)),None,Some(FSIstrings.SR.fsiGui()));
508+
CompilerOption("quiet","", OptionUnit(fun()-> tcConfigB.noFeedback<-true), None,Some(FSIstrings.SR.fsiQuiet()));
510509
(* Renamed --readline and --no-readline to --tabcompletion:+|-*)
511-
CompilerOption("readline",tagNone, OptionSwitch(function flag-> enableConsoleKeyProcessing<-(flag= On)),None,
512-
Some(FSIstrings.SR.fsiReadline()));
513-
CompilerOption("quotations-debug", tagNone, OptionSwitch(funswitch-> tcConfigB.emitDebugInfoInQuotations<-switch= On), None, Some(FSIstrings.SR.fsiEmitDebugInfoInQuotations()))
510+
CompilerOption("readline",tagNone, OptionSwitch(fun flag-> enableConsoleKeyProcessing<-(flag= On)),None, Some(FSIstrings.SR.fsiReadline()));
511+
CompilerOption("quotations-debug",tagNone, OptionSwitch(fun switch-> tcConfigB.emitDebugInfoInQuotations<- switch= On),None,Some(FSIstrings.SR.fsiEmitDebugInfoInQuotations()));
512+
CompilerOption("shadowcopyreferences", tagNone, OptionSwitch(funflag-> tcConfigB.shadowCopyReferences<-flag= On),None, Some(FSIstrings.SR.shadowCopyReferences()));
514513
]);
515514
]
516515

@@ -1583,9 +1582,21 @@ type FsiInteractionProcessor(tcConfigB,
15831582
| IHash(ParsedHashDirective(("reference"|"r"),[path],m),_)->
15841583
letresolutions,istate= fsiDynamicCompiler.EvalRequireReference istate m path
15851584
resolutions|> List.iter(fun ar->
1586-
letformat=if fsiOptions.IsInteractiveServerthen FSIstrings.SR.fsiDidAHashrWithLockWarning(ar.resolvedPath)else FSIstrings.SR.fsiDidAHashr(ar.resolvedPath)
1587-
fsiConsoleOutput.uprintnfnn"%s" format
1588-
)
1585+
letformat=
1586+
if tcConfig.shadowCopyReferencesthen
1587+
letresolvedPath= ar.resolvedPath.ToUpperInvariant()
1588+
letfileTime= File.GetLastWriteTimeUtc(resolvedPath)
1589+
match referencedAssemblies.TryGetValue(resolvedPath)with
1590+
|false,_->
1591+
referencedAssemblies.Add(resolvedPath, fileTime)
1592+
FSIstrings.SR.fsiDidAHashr(ar.resolvedPath)
1593+
|true, timewhen time<> fileTime->
1594+
FSIstrings.SR.fsiDidAHashrWithStaleWarning(ar.resolvedPath)
1595+
|_->
1596+
FSIstrings.SR.fsiDidAHashr(ar.resolvedPath)
1597+
else
1598+
FSIstrings.SR.fsiDidAHashrWithLockWarning(ar.resolvedPath)
1599+
fsiConsoleOutput.uprintnfnn"%s" format)
15891600
istate,Completed
15901601

15911602
| IHash(ParsedHashDirective("I",[path],m),_)->
@@ -2050,7 +2061,6 @@ let DriveFsiEventLoop (fsiConsoleOutput: FsiConsoleOutput) =
20502061

20512062
runLoop();
20522063

2053-
20542064
/// The primary type, representing a full F# Interactive session, reading from the given
20552065
/// text input, writing to the given text output and error writers.
20562066
typeinternalFsiEvaluationSession(argv:string[],inReader:TextReader,outWriter:TextWriter,errorWriter: TextWriter)=
@@ -2076,7 +2086,8 @@ type internal FsiEvaluationSession (argv:string[], inReader:TextReader, outWrite
20762086
doif runningOnMonothen enableConsoleColoring<-false
20772087

20782088
do SetUninitializedErrorLoggerFallback AssertFalseErrorLogger
2079-
2089+
2090+
20802091
//----------------------------------------------------------------------------
20812092
// tcConfig - build the initial config
20822093
//----------------------------------------------------------------------------
@@ -2102,7 +2113,7 @@ type internal FsiEvaluationSession (argv:string[], inReader:TextReader, outWrite
21022113

21032114
letfsiStdinSyphon=new FsiStdinSyphon(errorWriter)
21042115
letfsiConsoleOutput= FsiConsoleOutput(tcConfigB, outWriter, errorWriter)
2105-
2116+
21062117
leterrorLogger= ErrorLoggerThatStopsOnFirstError(tcConfigB, fsiStdinSyphon, fsiConsoleOutput)
21072118

21082119
do InstallErrorLoggingOnThisThread errorLogger// FSI error logging on main thread.
@@ -2334,30 +2345,34 @@ let MainMain argv =
23342345
ignore argv
23352346
letargv= System.Environment.GetCommandLineArgs()
23362347

2337-
// When VFSI is running, set the input/output encoding to UTF8.
2338-
// Otherwise, unicode gets lost during redirection.
2339-
// It is required only under Net4.5 or above (with unicode console feature).
2340-
if FSharpEnvironment.IsRunningOnNetFx45OrAbove&&
2341-
argv|> Array.exists(fun x-> x.Contains"fsi-server")then
2342-
Console.InputEncoding<- System.Text.Encoding.UTF8
2343-
Console.OutputEncoding<- System.Text.Encoding.UTF8
2348+
letevaluateSession()=
2349+
// When VFSI is running, set the input/output encoding to UTF8.
2350+
// Otherwise, unicode gets lost during redirection.
2351+
// It is required only under Net4.5 or above (with unicode console feature).
2352+
if FSharpEnvironment.IsRunningOnNetFx45OrAbove&&
2353+
argv|> Array.exists(fun x-> x.Contains"fsi-server")then
2354+
Console.InputEncoding<- System.Text.Encoding.UTF8
2355+
Console.OutputEncoding<- System.Text.Encoding.UTF8
23442356

23452357
#if DEBUG
2346-
if argv|> Array.exists(fun x-> x="/pause"|| x="--pause")then
2347-
Console.WriteLine("Press any key to continue...")
2348-
Console.ReadKey()|> ignore
2349-
2350-
try
2351-
letfsi= FsiEvaluationSession(argv, Console.In, Console.Out, Console.Error)
2352-
fsi.Run()
2353-
with e-> printf"Exception by fsi.exe:\n%+A\n" e
2358+
if argv|> Array.exists(fun x-> x="/pause"|| x="--pause")then
2359+
Console.WriteLine("Press any key to continue...")
2360+
Console.ReadKey()|> ignore
2361+
2362+
try
2363+
letfsi= FsiEvaluationSession(argv, Console.In, Console.Out, Console.Error)
2364+
fsi.Run()
2365+
with e-> printf"Exception by fsi.exe:\n%+A\n" e
23542366
#else
2355-
letfsi= FsiEvaluationSession(argv, Console.In, Console.Out, Console.Error)
2356-
fsi.Run()
2367+
letfsi= FsiEvaluationSession(argv, Console.In, Console.Out, Console.Error)
2368+
fsi.Run()
23572369
#endif
23582370

2371+
if argv|> Array.exists(fun x-> x="/shadowcopyreferences"|| x="--shadowcopyreferences"|| x="/shadowcopyreferences+"|| x="--shadowcopyreferences+")then
2372+
letsetupInformation= AppDomain.CurrentDomain.SetupInformation
2373+
setupInformation.ShadowCopyFiles<-"true"
2374+
lethelper= AppDomain.CreateDomain("FSI_Domain",null, setupInformation)
2375+
helper.DoCallBack(fun()-> evaluateSession())
2376+
else
2377+
evaluateSession()
23592378
0
2360-
2361-
2362-
2363-
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespaceLibrary1
2+
3+
typeClass1()=
4+
memberthis.X="C#"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
@if"%_echo%"==""echooff
2+
3+
setlocal
4+
rem there is no build.bat for this testcase, so don't check for build.ok
5+
6+
call%~d0%~p0..\..\..\config.bat
7+
8+
ifexist test1.ok (del /f /q test1.ok)
9+
"%FSI%"%fsi_flags%< test1.fsx
10+
ifNOTEXIST test1.okgoto SetError
11+
12+
ifexist test1.ok (del /f /q test1.ok)
13+
"%FSI%"%fsi_flags% --shadowcopyreferences-< test1.fsx
14+
ifNOTEXIST test1.okgoto SetError
15+
16+
ifexist test2.ok (del /f /q test2.ok)
17+
"%FSI%"%fsi_flags% --shadowcopyreferences< test2.fsx
18+
ifNOTEXIST test2.okgoto SetError
19+
20+
ifexist test2.ok (del /f /q test2.ok)
21+
"%FSI%"%fsi_flags% /shadowcopyreferences+< test2.fsx
22+
ifNOTEXIST test2.okgoto SetError
23+
24+
:Ok
25+
echo Ran fsharp%~f0 ok.
26+
endlocal
27+
exit /b0
28+
29+
:Skip
30+
echo Skipped%~f0
31+
endlocal
32+
exit /b0
33+
34+
35+
:Error
36+
endlocal
37+
exit /b%ERRORLEVEL%
38+
39+
:SETERROR
40+
set NonexistentErrorLevel2>nul
41+
goto Error
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
//Test #r with shadowcopy disabled
3+
//
4+
openSystem;;
5+
openSystem.Diagnostics;;
6+
7+
letcompiled wait=
8+
letc= Process.Start(Environment.GetEnvironmentVariable("FSC"),"Library1.fs --target:library")
9+
c.WaitForExit(wait)|> ignore
10+
if c.ExitCode=0thentrueelsefalse;;
11+
12+
// Build the library
13+
letfirst= compiled10000;;
14+
15+
//reference it will lock the assembly because FSI was started with --shadowcopyreferences-
16+
#r"Library1.dll";;
17+
18+
letnext= compiled10000;;
19+
20+
//compile will fail because shadow copy is disabled
21+
if next=falsethen
22+
printfn"Succeeded -- compile fail because file locked due to --shadowcopyreferences-"
23+
use os= System.IO.File.CreateText"test1.ok"
24+
os.Close();;
25+
#quit;;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
//Test #r with shadowcopy enabled
3+
//
4+
openSystem;;
5+
openSystem.Diagnostics;;
6+
7+
letcompiled wait=
8+
letc= Process.Start(Environment.GetEnvironmentVariable("FSC"),"Library1.fs --target:library")
9+
c.WaitForExit(wait)|> ignore
10+
if c.ExitCode=0thentrueelsefalse;;
11+
12+
// Build the library
13+
letfirst= compiled10000;;
14+
15+
//reference it will not lock the assembly because FSI was started with --shadowCopyReferences+
16+
#r"Library1.dll";;
17+
18+
letnext= compiled10000;;
19+
20+
//compile will succeed because shadow copy is enabled
21+
if next=truethen
22+
printfn"Succeeded -- compile worked because file not locked due to --shadowcopyReferences+"
23+
use os= System.IO.File.CreateText"test2.ok"
24+
os.Close();;
25+
#quit;;

‎tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,4 @@ Usage: Fsi.exe <options> [script.fsx [<arguments>]]
5959
--readline[+|-] Support TAB completionin console (on by
6060
default)
6161
--quotations-debug[+|-] Emit debug informationin quotations
62+
--shadowcopyreferences[+|-] Prevents references from being locked by the F# Interactive process

‎tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,4 @@ Usage: Fsi.exe <options> [script.fsx [<arguments>]]
6161
--readline[+|-] Support TAB completionin console (on by
6262
default)
6363
--quotations-debug[+|-] Emit debug informationin quotations
64+
--shadowcopyreferences[+|-] Prevents references from being locked by the F# Interactive process

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp