diff --git a/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj b/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj index 68983105861..d3e78c9f637 100644 --- a/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj +++ b/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj @@ -93,6 +93,12 @@ LexYaccRuntime/prim-parsing.fs + + Utilities/PathMap.fsi + + + Utilities/PathMap.fs + Utilities/ResizeArray.fsi diff --git a/src/absil/ilwrite.fs b/src/absil/ilwrite.fs index 65904d2aa5d..5d6bfd3ee06 100644 --- a/src/absil/ilwrite.fs +++ b/src/absil/ilwrite.fs @@ -3515,8 +3515,8 @@ let writeDirectory os dict = let writeBytes (os: BinaryWriter) (chunk: byte[]) = os.Write(chunk, 0, chunk.Length) let writeBinaryAndReportMappings (outfile, - ilg: ILGlobals, pdbfile: string option, signer: ILStrongNameSigner option, portablePDB, embeddedPDB, - embedAllSource, embedSourceList, sourceLink, emitTailcalls, deterministic, showTimes, dumpDebugInfo ) + ilg: ILGlobals, pdbfile: string option, signer: ILStrongNameSigner option, portablePDB, embeddedPDB, + embedAllSource, embedSourceList, sourceLink, emitTailcalls, deterministic, showTimes, dumpDebugInfo, pathMap) modul normalizeAssemblyRefs = // Store the public key from the signer into the manifest. This means it will be written // to the binary and also acts as an indicator to leave space for delay sign @@ -3671,7 +3671,7 @@ let writeBinaryAndReportMappings (outfile, match portablePDB with | true -> let (uncompressedLength, contentId, stream) as pdbStream = - generatePortablePdb embedAllSource embedSourceList sourceLink showTimes pdbData deterministic + generatePortablePdb embedAllSource embedSourceList sourceLink showTimes pdbData deterministic pathMap if embeddedPDB then Some (compressPortablePdbStream uncompressedLength contentId stream) else Some pdbStream @@ -4211,7 +4211,7 @@ let writeBinaryAndReportMappings (outfile, if embeddedPDB then embedPortablePdbInfo originalLength contentId stream showTimes fpdb debugDataChunk debugEmbeddedPdbChunk else - writePortablePdbInfo contentId stream showTimes fpdb debugDataChunk + writePortablePdbInfo contentId stream showTimes fpdb pathMap debugDataChunk | None -> #if FX_NO_PDB_WRITER Array.empty @@ -4284,10 +4284,11 @@ type options = emitTailcalls : bool deterministic : bool showTimes: bool - dumpDebugInfo: bool } + dumpDebugInfo: bool + pathMap: PathMap } let WriteILBinary (outfile, (args: options), modul, normalizeAssemblyRefs) = writeBinaryAndReportMappings (outfile, args.ilg, args.pdbfile, args.signer, args.portablePDB, args.embeddedPDB, args.embedAllSource, - args.embedSourceList, args.sourceLink, args.emitTailcalls, args.deterministic, args.showTimes, args.dumpDebugInfo) modul normalizeAssemblyRefs + args.embedSourceList, args.sourceLink, args.emitTailcalls, args.deterministic, args.showTimes, args.dumpDebugInfo, args.pathMap) modul normalizeAssemblyRefs |> ignore diff --git a/src/absil/ilwrite.fsi b/src/absil/ilwrite.fsi index e7b2aaf3f4f..f1955f82a20 100644 --- a/src/absil/ilwrite.fsi +++ b/src/absil/ilwrite.fsi @@ -3,6 +3,7 @@ /// The IL Binary writer. module internal FSharp.Compiler.AbstractIL.ILBinaryWriter +open Internal.Utilities open FSharp.Compiler.AbstractIL open FSharp.Compiler.AbstractIL.Internal open FSharp.Compiler.AbstractIL.IL @@ -27,7 +28,8 @@ type options = emitTailcalls: bool deterministic: bool showTimes : bool - dumpDebugInfo : bool } + dumpDebugInfo : bool + pathMap : PathMap } /// Write a binary to the file system. Extra configuration parameters can also be specified. val WriteILBinary: filename: string * options: options * input: ILModuleDef * (ILAssemblyRef -> ILAssemblyRef) -> unit diff --git a/src/absil/ilwritepdb.fs b/src/absil/ilwritepdb.fs index 756181dafe9..260ccbe238e 100644 --- a/src/absil/ilwritepdb.fs +++ b/src/absil/ilwritepdb.fs @@ -219,7 +219,7 @@ let getRowCounts tableRowCounts = tableRowCounts |> Seq.iter(fun x -> builder.Add x) builder.MoveToImmutable() -let generatePortablePdb (embedAllSource: bool) (embedSourceList: string list) (sourceLink: string) showTimes (info: PdbData) isDeterministic = +let generatePortablePdb (embedAllSource: bool) (embedSourceList: string list) (sourceLink: string) showTimes (info: PdbData) isDeterministic (pathMap: PathMap) = sortMethods showTimes info let externalRowCounts = getRowCounts info.TableRowCounts let docs = @@ -229,6 +229,7 @@ let generatePortablePdb (embedAllSource: bool) (embedSourceList: string list) (s let metadata = MetadataBuilder() let serializeDocumentName (name: string) = + let name = PathMap.apply pathMap name let count s c = s |> Seq.filter(fun ch -> if c = ch then true else false) |> Seq.length let s1, s2 = '/', '\\' @@ -501,12 +502,12 @@ let compressPortablePdbStream (uncompressedLength: int64) (contentId: BlobConten stream.WriteTo compressionStream (uncompressedLength, contentId, compressedStream) -let writePortablePdbInfo (contentId: BlobContentId) (stream: MemoryStream) showTimes fpdb cvChunk = +let writePortablePdbInfo (contentId: BlobContentId) (stream: MemoryStream) showTimes fpdb pathMap cvChunk = try FileSystem.FileDelete fpdb with _ -> () use pdbFile = new FileStream(fpdb, FileMode.Create, FileAccess.ReadWrite) stream.WriteTo pdbFile reportTime showTimes "PDB: Closed" - pdbGetDebugInfo (contentId.Guid.ToByteArray()) (int32 (contentId.Stamp)) fpdb cvChunk None 0L None + pdbGetDebugInfo (contentId.Guid.ToByteArray()) (int32 (contentId.Stamp)) (PathMap.apply pathMap fpdb) cvChunk None 0L None let embedPortablePdbInfo (uncompressedLength: int64) (contentId: BlobContentId) (stream: MemoryStream) showTimes fpdb cvChunk pdbChunk = reportTime showTimes "PDB: Closed" diff --git a/src/absil/ilwritepdb.fsi b/src/absil/ilwritepdb.fsi index a291ce4667d..2713d9769b2 100644 --- a/src/absil/ilwritepdb.fsi +++ b/src/absil/ilwritepdb.fsi @@ -3,6 +3,7 @@ /// The ILPdbWriter module internal FSharp.Compiler.AbstractIL.ILPdbWriter +open Internal.Utilities open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.ErrorLogger open FSharp.Compiler.Range @@ -82,10 +83,10 @@ type idd = iddData: byte[]; iddChunk: BinaryChunk } -val generatePortablePdb : embedAllSource:bool -> embedSourceList:string list -> sourceLink: string -> showTimes:bool -> info:PdbData -> isDeterministic:bool -> (int64 * BlobContentId * MemoryStream) +val generatePortablePdb : embedAllSource:bool -> embedSourceList:string list -> sourceLink: string -> showTimes:bool -> info:PdbData -> isDeterministic:bool -> pathMap:PathMap -> (int64 * BlobContentId * MemoryStream) val compressPortablePdbStream : uncompressedLength:int64 -> contentId:BlobContentId -> stream:MemoryStream -> (int64 * BlobContentId * MemoryStream) val embedPortablePdbInfo : uncompressedLength:int64 -> contentId:BlobContentId -> stream:MemoryStream -> showTimes:bool -> fpdb:string -> cvChunk:BinaryChunk -> pdbChunk:BinaryChunk -> idd[] -val writePortablePdbInfo : contentId:BlobContentId -> stream:MemoryStream -> showTimes:bool -> fpdb:string -> cvChunk:BinaryChunk -> idd[] +val writePortablePdbInfo : contentId:BlobContentId -> stream:MemoryStream -> showTimes:bool -> fpdb:string -> pathMap:PathMap -> cvChunk:BinaryChunk -> idd[] #if !FX_NO_PDB_WRITER val writePdbInfo : showTimes:bool -> f:string -> fpdb:string -> info:PdbData -> cvChunk:BinaryChunk -> idd[] diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index a930e4027cc..74da1750b42 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -2150,6 +2150,8 @@ type TcConfigBuilder = mutable internalTestSpanStackReferring: bool mutable noConditionalErasure: bool + + mutable pathMap: PathMap } static member Initial = @@ -2285,6 +2287,7 @@ type TcConfigBuilder = tryGetMetadataSnapshot = (fun _ -> None) internalTestSpanStackReferring = false noConditionalErasure = false + pathMap = PathMap.empty } static member CreateNew(legacyReferenceResolver, defaultFSharpBinariesDir, reduceMemoryUsage, implicitIncludeDir, @@ -2408,6 +2411,9 @@ type TcConfigBuilder = member tcConfigB.RemoveReferencedAssemblyByPath (m, path) = tcConfigB.referencedDLLs <- tcConfigB.referencedDLLs |> List.filter (fun ar -> not (Range.equals ar.Range m) || ar.Text <> path) + + member tcConfigB.AddPathMapping (oldPrefix, newPrefix) = + tcConfigB.pathMap <- tcConfigB.pathMap |> PathMap.addMapping oldPrefix newPrefix static member SplitCommandLineResourceInfo (ri: string) = let p = ri.IndexOf ',' @@ -2730,6 +2736,7 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member x.optSettings = data.optSettings member x.emitTailcalls = data.emitTailcalls member x.deterministic = data.deterministic + member x.pathMap = data.pathMap member x.preferredUiLang = data.preferredUiLang member x.lcid = data.lcid member x.optsOn = data.optsOn @@ -3407,7 +3414,7 @@ let ParseOneInputLexbuf (tcConfig: TcConfig, lexResourceManager, conditionalComp try let skip = true in (* don't report whitespace from lexer *) let lightSyntaxStatus = LightSyntaxStatus (tcConfig.ComputeLightSyntaxInitialStatus filename, true) - let lexargs = mkLexargs (filename, conditionalCompilationDefines@tcConfig.conditionalCompilationDefines, lightSyntaxStatus, lexResourceManager, ref [], errorLogger) + let lexargs = mkLexargs (filename, conditionalCompilationDefines@tcConfig.conditionalCompilationDefines, lightSyntaxStatus, lexResourceManager, ref [], errorLogger, tcConfig.pathMap) let shortFilename = SanitizeFileName filename tcConfig.implicitIncludeDir let input = Lexhelp.usingLexbufForParsing (lexbuf, filename) (fun lexbuf -> @@ -3607,7 +3614,9 @@ let MakeILResource rname bytes = CustomAttrsStored = storeILCustomAttrs emptyILCustomAttrs MetadataIndex = NoMetadataIdx } -let PickleToResource inMem file g scope rname p x = +let PickleToResource inMem file (g: TcGlobals) scope rname p x = + let file = PathMap.apply g.pathMap file + { Name = rname Location = (let bytes = pickleObjWithDanglingCcus inMem file g scope p x in ILResourceLocation.LocalOut bytes) Access = ILResourceAccess.Public @@ -3617,15 +3626,23 @@ let PickleToResource inMem file g scope rname p x = let GetSignatureData (file, ilScopeRef, ilModule, byteReader) : PickledDataWithReferences = unpickleObjWithDanglingCcus file ilScopeRef ilModule unpickleCcuInfo (byteReader()) -let WriteSignatureData (tcConfig: TcConfig, tcGlobals, exportRemapping, ccu: CcuThunk, file, inMem) : ILResource = +let WriteSignatureData (tcConfig: TcConfig, tcGlobals, exportRemapping, ccu: CcuThunk, file, inMem) : ILResource = let mspec = ccu.Contents let mspec = ApplyExportRemappingToEntity tcGlobals exportRemapping mspec // For historical reasons, we use a different resource name for FSharp.Core, so older F# compilers // don't complain when they see the resource. - let rname = if ccu.AssemblyName = getFSharpCoreLibraryName then FSharpSignatureDataResourceName2 else FSharpSignatureDataResourceName + let rname = if ccu.AssemblyName = getFSharpCoreLibraryName then FSharpSignatureDataResourceName2 else FSharpSignatureDataResourceName + + let includeDir = + if String.IsNullOrEmpty tcConfig.implicitIncludeDir then "" + else + tcConfig.implicitIncludeDir + |> System.IO.Path.GetFullPath + |> PathMap.applyDir tcGlobals.pathMap + PickleToResource inMem file tcGlobals ccu (rname+ccu.AssemblyName) pickleCcuInfo { mspec=mspec - compileTimeWorkingDir=tcConfig.implicitIncludeDir + compileTimeWorkingDir=includeDir usesQuotations = ccu.UsesFSharp20PlusQuotations } let GetOptimizationData (file, ilScopeRef, ilModule, byteReader) = @@ -4626,8 +4643,9 @@ type TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolu // OK, now we have both mscorlib.dll and FSharp.Core.dll we can create TcGlobals let tcGlobals = TcGlobals(tcConfig.compilingFslib, ilGlobals, fslibCcu, - tcConfig.implicitIncludeDir, tcConfig.mlCompatibility, - tcConfig.isInteractive, tryFindSysTypeCcu, tcConfig.emitDebugInfoInQuotations, tcConfig.noDebugData ) + tcConfig.implicitIncludeDir, tcConfig.mlCompatibility, + tcConfig.isInteractive, tryFindSysTypeCcu, tcConfig.emitDebugInfoInQuotations, + tcConfig.noDebugData, tcConfig.pathMap) #if DEBUG // the global_g reference cell is used only for debug printing diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi old mode 100755 new mode 100644 index 3a2dfba549d..94d9bf53713 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -6,6 +6,7 @@ module internal FSharp.Compiler.CompileOps open System open System.Text open System.Collections.Generic +open Internal.Utilities open FSharp.Compiler.AbstractIL open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.AbstractIL.ILBinaryReader @@ -373,6 +374,7 @@ type TcConfigBuilder = /// Prevent erasure of conditional attributes and methods so tooling is able analyse them. mutable noConditionalErasure: bool + mutable pathMap : PathMap } static member Initial: TcConfigBuilder @@ -396,7 +398,8 @@ type TcConfigBuilder = member RemoveReferencedAssemblyByPath: range * string -> unit member AddEmbeddedSourceFile: string -> unit member AddEmbeddedResource: string -> unit - + member AddPathMapping: oldPrefix: string * newPrefix: string -> unit + static member SplitCommandLineResourceInfo: string -> string * string * ILResourceAccess [] @@ -496,6 +499,7 @@ type TcConfig = member optSettings : Optimizer.OptimizationSettings member emitTailcalls: bool member deterministic: bool + member pathMap: PathMap member preferredUiLang: string option member optsOn : bool member productNameForBannerText: string diff --git a/src/fsharp/CompileOptions.fs b/src/fsharp/CompileOptions.fs index b5584f88ee0..3a30ed50077 100644 --- a/src/fsharp/CompileOptions.fs +++ b/src/fsharp/CompileOptions.fs @@ -407,6 +407,13 @@ let SetTailcallSwitch (tcConfigB: TcConfigBuilder) switch = let SetDeterministicSwitch (tcConfigB: TcConfigBuilder) switch = tcConfigB.deterministic <- (switch = OptionSwitch.On) +let AddPathMapping (tcConfigB: TcConfigBuilder) (pathPair: string) = + match pathPair.Split([|'='|], 2) with + | [| oldPrefix; newPrefix |] -> + tcConfigB.AddPathMapping (oldPrefix, newPrefix) + | _ -> + error(Error(FSComp.SR.optsInvalidPathMapFormat(), rangeCmdArgs)) + let jitoptimizeSwitch (tcConfigB: TcConfigBuilder) switch = tcConfigB.optSettings <- { tcConfigB.optSettings with jitOptUser = Some (switch = OptionSwitch.On) } @@ -516,6 +523,7 @@ let tagWarnList = "" let tagSymbolList = "" let tagAddress = "
" let tagInt = "" +let tagPathMap = "" let tagNone = "" // PrintOptionInfo @@ -786,7 +794,12 @@ let codeGenerationFlags isFsi (tcConfigB: TcConfigBuilder) = ("deterministic", tagNone, OptionSwitch (SetDeterministicSwitch tcConfigB), None, Some (FSComp.SR.optsDeterministic())) - + + CompilerOption + ("pathmap", tagPathMap, + OptionStringList (AddPathMapping tcConfigB), None, + Some (FSComp.SR.optsPathMap())) + CompilerOption ("crossoptimize", tagNone, OptionSwitch (crossOptimizeSwitch tcConfigB), None, diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index ae6570ae776..a2ccece829e 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -860,6 +860,7 @@ optsDebug,"Specify debugging type: full, portable, embedded, pdbonly. ('%s' is t optsOptimize,"Enable optimizations (Short form: -O)" optsTailcalls,"Enable or disable tailcalls" optsDeterministic,"Produce a deterministic assembly (including module version GUID and timestamp)" +optsPathMap,"Maps physical paths to source path names output by the compiler" optsCrossoptimize,"Enable or disable cross-module optimizations" optsWarnaserrorPM,"Report all warnings as errors" optsWarnaserror,"Report specific warnings as errors" @@ -1140,7 +1141,9 @@ fscTooManyErrors,"Exiting - too many errors" 2023,fscResxSourceFileDeprecated,"Passing a .resx file (%s) as a source file to the compiler is deprecated. Use resgen.exe to transform the .resx file into a .resources file to pass as a --resource option. If you are using MSBuild, this can be done via an item in the .fsproj project file." 2024,fscStaticLinkingNoProfileMismatches,"Static linking may not be used on an assembly referencing mscorlib (e.g. a .NET Framework assembly) when generating an assembly that references System.Runtime (e.g. a .NET Core or Portable assembly)." 2025,fscAssemblyWildcardAndDeterminism,"An %s specified version '%s', but this value is a wildcard, and you have requested a deterministic build, these are in conflict." -2026,fscDeterministicDebugRequiresPortablePdb,"Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded)" +2026,fscDeterministicDebugRequiresPortablePdb,"Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded)" +2027,fscPathMapDebugRequiresPortablePdb,"--pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded)" +2028,optsInvalidPathMapFormat,"Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath'" 3000,etIllegalCharactersInNamespaceName,"Character '%s' is not allowed in provided namespace name '%s'" 3001,etNullOrEmptyMemberName,"The provided type '%s' returned a member with a null or empty member name" 3002,etNullMember,"The provided type '%s' returned a null member" diff --git a/src/fsharp/FSharp.Build/Fsc.fs b/src/fsharp/FSharp.Build/Fsc.fs index d1f0ea78d94..a3803f4b449 100644 --- a/src/fsharp/FSharp.Build/Fsc.fs +++ b/src/fsharp/FSharp.Build/Fsc.fs @@ -41,7 +41,8 @@ type public Fsc () as this = let mutable noFramework = false let mutable optimize : bool = true let mutable otherFlags : string = null - let mutable outputAssembly : string = null + let mutable outputAssembly : string = null + let mutable pathMap : string = null let mutable pdbFile : string = null let mutable platform : string = null let mutable prefer32bit : bool = false @@ -233,6 +234,10 @@ type public Fsc () as this = builder.AppendSwitchIfNotNull("--targetprofile:", targetProfile) builder.AppendSwitch("--nocopyfsharpcore") + + match pathMap with + | null -> () + | _ -> builder.AppendSwitchIfNotNull("--pathmap:", pathMap.Split([|';'; ','|], StringSplitOptions.RemoveEmptyEntries), ",") // OtherFlags - must be second-to-last builder.AppendSwitchUnquotedIfNotNull("", otherFlags) @@ -346,6 +351,11 @@ type public Fsc () as this = with get() = outputAssembly and set(s) = outputAssembly <- s + // --pathmap : Paths to rewrite when producing deterministic builds + member fsc.PathMap + with get() = pathMap + and set(s) = pathMap <- s + // --pdb : // Name the debug output file member fsc.PdbFile diff --git a/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets b/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets index 19f9843e4ae..ff1cfbb9b50 100644 --- a/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets +++ b/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets @@ -294,6 +294,7 @@ this file. Optimize="$(Optimize)" OtherFlags="$(FscOtherFlags)" OutputAssembly="@(IntermediateAssembly)" + PathMap="$(PathMap)" PdbFile="$(PdbFile)" Platform="$(PlatformTarget)" Prefer32Bit="$(Actual32Bit)" diff --git a/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj b/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj index 9fef6d27589..b4e55930431 100644 --- a/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj +++ b/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj @@ -174,6 +174,12 @@ Utilities\rational.fs + + Utilities\PathMap.fsi + + + Utilities\PathMap.fs + ErrorLogging\range.fsi diff --git a/src/fsharp/TastPickle.fs b/src/fsharp/TastPickle.fs index 6b548ef7b1b..da6906cf33c 100644 --- a/src/fsharp/TastPickle.fs +++ b/src/fsharp/TastPickle.fs @@ -1315,7 +1315,11 @@ let u_qlist uv = u_wrap QueueList.ofList (u_list uv) let u_namemap u = u_Map u_string u let p_pos (x: pos) st = p_tup2 p_int p_int (x.Line, x.Column) st -let p_range (x: range) st = p_tup3 p_string p_pos p_pos (x.FileName, x.Start, x.End) st + +let p_range (x: range) st = + let fileName = PathMap.apply st.oglobals.pathMap x.FileName + p_tup3 p_string p_pos p_pos (fileName, x.Start, x.End) st + let p_dummy_range : range pickler = fun _x _st -> () let p_ident (x: Ident) st = p_tup2 p_string p_range (x.idText, x.idRange) st let p_xmldoc (XmlDoc x) st = p_array p_string x st diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs index 376cd0d3c8b..337205632e3 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -179,7 +179,8 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d mlCompatibility: bool, isInteractive:bool, // The helper to find system types amongst referenced DLLs tryFindSysTypeCcu, - emitDebugInfoInQuotations: bool, noDebugData: bool) = + emitDebugInfoInQuotations: bool, noDebugData: bool, + pathMap: PathMap) = let vara = NewRigidTypar "a" envRange let varb = NewRigidTypar "b" envRange @@ -901,6 +902,7 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d member __.mlCompatibility = mlCompatibility member __.emitDebugInfoInQuotations = emitDebugInfoInQuotations member __.directoryToResolveRelativePaths= directoryToResolveRelativePaths + member __.pathMap = pathMap member __.unionCaseRefEq x y = primUnionCaseRefEq compilingFslib fslibCcu x y member __.valRefEq x y = primValRefEq compilingFslib fslibCcu x y member __.fslibCcu = fslibCcu diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index d5eb78f5284..66267dbe148 100644 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -10170,7 +10170,8 @@ and TcMethodApplication | CallerLineNumber, _ when typeEquiv cenv.g currCalledArgTy cenv.g.int_ty -> emptyPreBinder, Expr.Const (Const.Int32(mMethExpr.StartLine), mMethExpr, currCalledArgTy) | CallerFilePath, _ when typeEquiv cenv.g currCalledArgTy cenv.g.string_ty -> - emptyPreBinder, Expr.Const (Const.String(FileSystem.GetFullPathShim(mMethExpr.FileName)), mMethExpr, currCalledArgTy) + let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply cenv.g.pathMap + emptyPreBinder, Expr.Const (Const.String fileName, mMethExpr, currCalledArgTy) | CallerMemberName, Some callerName when (typeEquiv cenv.g currCalledArgTy cenv.g.string_ty) -> emptyPreBinder, Expr.Const (Const.String callerName, mMethExpr, currCalledArgTy) | _ -> @@ -10209,7 +10210,8 @@ and TcMethodApplication let lineExpr = Expr.Const(Const.Int32 mMethExpr.StartLine, mMethExpr, calledNonOptTy) emptyPreBinder, mkSome cenv.g calledNonOptTy lineExpr mMethExpr | CallerFilePath, _ when typeEquiv cenv.g calledNonOptTy cenv.g.string_ty -> - let filePathExpr = Expr.Const (Const.String (FileSystem.GetFullPathShim(mMethExpr.FileName)), mMethExpr, calledNonOptTy) + let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply cenv.g.pathMap + let filePathExpr = Expr.Const (Const.String(fileName), mMethExpr, calledNonOptTy) emptyPreBinder, mkSome cenv.g calledNonOptTy filePathExpr mMethExpr | CallerMemberName, Some(callerName) when typeEquiv cenv.g calledNonOptTy cenv.g.string_ty -> let memberNameExpr = Expr.Const (Const.String callerName, mMethExpr, calledNonOptTy) diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 568773a361c..89b2d6ec395 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -264,8 +264,12 @@ let ProcessCommandLineFlags (tcConfigB: TcConfigBuilder, setProcessThreadLocals, if not (String.IsNullOrEmpty(tcConfigB.sourceLink)) then error(Error(FSComp.SR.optsSourceLinkRequirePortablePDBs(), rangeCmdArgs)) - if tcConfigB.deterministic && tcConfigB.debuginfo && (tcConfigB.portablePDB = false) then - error(Error(FSComp.SR.fscDeterministicDebugRequiresPortablePdb(), rangeCmdArgs)) + if tcConfigB.debuginfo && not tcConfigB.portablePDB then + if tcConfigB.deterministic then + error(Error(FSComp.SR.fscDeterministicDebugRequiresPortablePdb(), rangeCmdArgs)) + + if tcConfigB.pathMap <> PathMap.empty then + error(Error(FSComp.SR.fscPathMapDebugRequiresPortablePdb(), rangeCmdArgs)) let inputFiles = List.rev !inputFilesRef @@ -2142,7 +2146,8 @@ let main4 dynamicAssemblyCreator (Args (ctok, tcConfig, tcImports: TcImports, t embedSourceList = tcConfig.embedSourceList sourceLink = tcConfig.sourceLink signer = GetStrongNameSigner signingInfo - dumpDebugInfo = tcConfig.dumpDebugInfo }, + dumpDebugInfo = tcConfig.dumpDebugInfo + pathMap = tcConfig.pathMap }, ilxMainModule, normalizeAssemblyRefs ) diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 0dc4cacc031..4660b2e4817 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -1739,8 +1739,8 @@ type internal FsiStdinLexerProvider Lexhelp.resetLexbufPos sourceFileName lexbuf let skip = true // don't report whitespace from lexer - let defines = "INTERACTIVE":: tcConfigB.conditionalCompilationDefines - let lexargs = mkLexargs (sourceFileName,defines, interactiveInputLightSyntaxStatus, lexResourceManager, ref [], errorLogger) + let defines = "INTERACTIVE"::tcConfigB.conditionalCompilationDefines + let lexargs = mkLexargs (sourceFileName,defines, interactiveInputLightSyntaxStatus, lexResourceManager, ref [], errorLogger, PathMap.empty) let tokenizer = LexFilter.LexFilter(interactiveInputLightSyntaxStatus, tcConfigB.compilingFslib, Lexer.token lexargs skip, lexbuf) tokenizer diff --git a/src/fsharp/lexhelp.fs b/src/fsharp/lexhelp.fs index 3d2db02c78d..e966678486e 100644 --- a/src/fsharp/lexhelp.fs +++ b/src/fsharp/lexhelp.fs @@ -57,7 +57,8 @@ type lexargs = resourceManager: LexResourceManager lightSyntaxStatus : LightSyntaxStatus errorLogger: ErrorLogger - applyLineDirectives: bool } + applyLineDirectives: bool + pathMap: PathMap } /// possible results of lexing a long unicode escape sequence in a string literal, e.g. "\UDEADBEEF" type LongUnicodeLexResult = @@ -65,13 +66,14 @@ type LongUnicodeLexResult = | SingleChar of uint16 | Invalid -let mkLexargs (_filename, defines, lightSyntaxStatus, resourceManager, ifdefStack, errorLogger) = +let mkLexargs (_filename, defines, lightSyntaxStatus, resourceManager, ifdefStack, errorLogger, pathMap:PathMap) = { defines = defines ifdefStack= ifdefStack lightSyntaxStatus=lightSyntaxStatus resourceManager=resourceManager errorLogger=errorLogger - applyLineDirectives=true } + applyLineDirectives=true + pathMap=pathMap } /// Register the lexbuf and call the given function let reusingLexbufForParsing lexbuf f = @@ -326,16 +328,19 @@ module Keywords = match s with | "__SOURCE_DIRECTORY__" -> let filename = fileOfFileIndex lexbuf.StartPos.FileIndex - let dirname = + let dirname = if String.IsNullOrWhiteSpace(filename) then String.Empty else if filename = stdinMockFilename then System.IO.Directory.GetCurrentDirectory() else - filename + filename |> FileSystem.GetFullPathShim (* asserts that path is already absolute *) |> System.IO.Path.GetDirectoryName - KEYWORD_STRING dirname + + if String.IsNullOrEmpty dirname then dirname + else PathMap.applyDir args.pathMap dirname + |> KEYWORD_STRING | "__SOURCE_FILE__" -> KEYWORD_STRING (System.IO.Path.GetFileName((fileOfFileIndex lexbuf.StartPos.FileIndex))) | "__LINE__" -> @@ -438,4 +443,4 @@ module Keywords = "<@", FSComp.SR.keywordDescriptionTypedQuotation() "@>", FSComp.SR.keywordDescriptionTypedQuotation() "<@@", FSComp.SR.keywordDescriptionUntypedQuotation() - "@@>", FSComp.SR.keywordDescriptionUntypedQuotation() ] \ No newline at end of file + "@@>", FSComp.SR.keywordDescriptionUntypedQuotation() ] diff --git a/src/fsharp/lexhelp.fsi b/src/fsharp/lexhelp.fsi index 9518b97d0c0..0ccb18d0db7 100644 --- a/src/fsharp/lexhelp.fsi +++ b/src/fsharp/lexhelp.fsi @@ -33,7 +33,8 @@ type lexargs = resourceManager: LexResourceManager lightSyntaxStatus : LightSyntaxStatus errorLogger: ErrorLogger - applyLineDirectives: bool } + applyLineDirectives: bool + pathMap: PathMap } type LongUnicodeLexResult = | SurrogatePair of uint16 * uint16 @@ -41,7 +42,7 @@ type LongUnicodeLexResult = | Invalid val resetLexbufPos : string -> UnicodeLexing.Lexbuf -> unit -val mkLexargs : 'a * string list * LightSyntaxStatus * LexResourceManager * LexerIfdefStack * ErrorLogger -> lexargs +val mkLexargs : 'a * string list * LightSyntaxStatus * LexResourceManager * LexerIfdefStack * ErrorLogger * PathMap -> lexargs val reusingLexbufForParsing : UnicodeLexing.Lexbuf -> (unit -> 'a) -> 'a val usingLexbufForParsing : UnicodeLexing.Lexbuf * string -> (UnicodeLexing.Lexbuf -> 'a) -> 'a diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs old mode 100755 new mode 100644 index 6bce527178b..a03c1deeffb --- a/src/fsharp/service/ServiceLexing.fs +++ b/src/fsharp/service/ServiceLexing.fs @@ -17,6 +17,7 @@ open FSharp.Compiler.Ast open FSharp.Compiler.ErrorLogger open FSharp.Compiler.Lexhelp open FSharp.Compiler.Lib +open Internal.Utilities type Position = int * int type Range = Position * Position @@ -768,8 +769,8 @@ type FSharpLineTokenizer(lexbuf: UnicodeLexing.Lexbuf, type FSharpSourceTokenizer(defineConstants: string list, filename: string option) = let lexResourceManager = new Lexhelp.LexResourceManager() - let lexArgsLightOn = mkLexargs(filename, defineConstants, LightSyntaxStatus(true, false), lexResourceManager, ref [], DiscardErrorsLogger) - let lexArgsLightOff = mkLexargs(filename, defineConstants, LightSyntaxStatus(false, false), lexResourceManager, ref [], DiscardErrorsLogger) + let lexArgsLightOn = mkLexargs(filename, defineConstants, LightSyntaxStatus(true, false), lexResourceManager, ref [], DiscardErrorsLogger, PathMap.empty) + let lexArgsLightOff = mkLexargs(filename, defineConstants, LightSyntaxStatus(false, false), lexResourceManager, ref [], DiscardErrorsLogger, PathMap.empty) member this.CreateLineTokenizer(lineText: string) = let lexbuf = UnicodeLexing.StringAsLexbuf lineText diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 6ffeb0b8de4..ea4de105c7f 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -1527,7 +1527,8 @@ module internal Parser = let lexResourceManager = new Lexhelp.LexResourceManager() // When analyzing files using ParseOneFile, i.e. for the use of editing clients, we do not apply line directives. - let lexargs = mkLexargs(fileName, defines, lightSyntaxStatus, lexResourceManager, ref [], errHandler.ErrorLogger) + // TODO(pathmap): expose PathMap on the service API, and thread it through here + let lexargs = mkLexargs(fileName, defines, lightSyntaxStatus, lexResourceManager, ref [], errHandler.ErrorLogger, PathMap.empty) let lexargs = { lexargs with applyLineDirectives = false } let tokenizer = LexFilter.LexFilter(lightSyntaxStatus, options.CompilingFsLib, Lexer.token lexargs true, lexbuf) diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 2315ad7fee3..395c6bd5dd5 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Deterministická sestavení podporují jenom soubory PDB typu Portable (--debug:portable nebo --debug:embedded). + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Deterministická sestavení podporují jenom soubory PDB typu Portable (--debug:portable nebo --debug:embedded). @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 239a4204745..17d71833636 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Deterministische Builds unterstützen nur portierbare PDbs ("--debug:portable" oder "--debug:embedded"). + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Deterministische Builds unterstützen nur portierbare PDbs ("--debug:portable" oder "--debug:embedded"). @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 38474743bf3..76deac66bef 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Las compilaciones deterministas solo admiten PDB portátiles (--debug:portable o --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Las compilaciones deterministas solo admiten PDB portátiles (--debug:portable o --debug:embedded) @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 30dd74a4468..3e0e8b6ee4a 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Les builds déterministes ne prennent en charge que les fichiers PDB portables (--debug:portable ou --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Les builds déterministes ne prennent en charge que les fichiers PDB portables (--debug:portable ou --debug:embedded) @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index fbf6514bcd2..c893964f15b 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Le compilazioni deterministiche supportano solo file PDB portatili (--debug:portable o --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Le compilazioni deterministiche supportano solo file PDB portatili (--debug:portable o --debug:embedded) @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 1a0b4c97ad9..468f1b8f424 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -5545,8 +5545,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - 決定論的ビルドはポータブル PDB のみをサポートします (--debug:portable または --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + 決定論的ビルドはポータブル PDB のみをサポートします (--debug:portable または --debug:embedded) @@ -7159,6 +7159,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index b5df3ae2e62..2794ed6aa89 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - 결정적 빌드는 이식 가능한 PDB만 지원합니다(--debug:portable 또는 --debug:embedded). + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + 결정적 빌드는 이식 가능한 PDB만 지원합니다(--debug:portable 또는 --debug:embedded). @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 5f46bf09e84..f07889db24a 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Kompilacje deterministyczne obsługują tylko przenośne pliki PDB (--debug:portable lub --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Kompilacje deterministyczne obsługują tylko przenośne pliki PDB (--debug:portable lub --debug:embedded) @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index dfd69dab7c1..2c635827ce9 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Compilações determinísticas dão suporte somente a PDBs portáteis (--debug:portable ou --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Compilações determinísticas dão suporte somente a PDBs portáteis (--debug:portable ou --debug:embedded) @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 8b7fc126b59..cfe52fe5712 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Детерминированные сборки поддерживают только переносимые PDB-файлы (--debug:portable или --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Детерминированные сборки поддерживают только переносимые PDB-файлы (--debug:portable или --debug:embedded) @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index f3aa876b53a..396f2c70e7a 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - Belirleyici derlemeler yalnızca taşınabilir PDB'leri (--debug:portable veya --debug:embedded) destekler + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + Belirleyici derlemeler yalnızca taşınabilir PDB'leri (--debug:portable veya --debug:embedded) destekler @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 33bef4332ee..70acb1cb4d3 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - 确定性的生成仅支持可移植 PDB (--debug:portable 或 --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + 确定性的生成仅支持可移植 PDB (--debug:portable 或 --debug:embedded) @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index c494db6287d..6abf504d25e 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -5543,8 +5543,8 @@ - Determinstic builds only support portable PDBs (--debug:portable or --debug:embedded) - 確定性組建僅支援可攜式 PDB (--debug:portable 或 --debug:embedded) + Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded) + 確定性組建僅支援可攜式 PDB (--debug:portable 或 --debug:embedded) @@ -7157,6 +7157,21 @@ No implementation was given for those members (some results omitted): {0}Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. + + Maps physical paths to source path names output by the compiler + Maps physical paths to source path names output by the compiler + + + + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + --pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded) + + + + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath' + + \ No newline at end of file diff --git a/src/utils/PathMap.fs b/src/utils/PathMap.fs new file mode 100644 index 00000000000..3e4f6fad96c --- /dev/null +++ b/src/utils/PathMap.fs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +/// Functions to map real paths to paths to be written to PDB/IL +namespace Internal.Utilities + +open System +open System.IO + +type PathMap = PathMap of Map + +[] +module internal PathMap = + + let dirSepStr = Path.DirectorySeparatorChar.ToString() + + let empty = PathMap Map.empty + + let addMapping (src : string) (dst : string) (PathMap map) : PathMap = + // Normalise the path + let normalSrc = Path.GetFullPath src + + let oldPrefix = + if normalSrc.EndsWith dirSepStr then normalSrc + else normalSrc + dirSepStr + + // Always add a path separator + map |> Map.add oldPrefix dst |> PathMap + + // Map a file path with its replacement. + // This logic replicates C#'s PathUtilities.NormalizePathPrefix + let apply (PathMap map) (filePath : string) : string = + // Find the first key in the path map that matches a prefix of the + // normalized path. We expect the client to use consistent capitalization; + // we use ordinal (case-sensitive) comparisons. + map + |> Map.tryPick (fun oldPrefix replacementPrefix -> + // oldPrefix always ends with a path separator, so there's no need + // to check if it was a partial match + // e.g. for the map /goo=/bar and filename /goooo + if filePath.StartsWith(oldPrefix, StringComparison.Ordinal) then + let replacement = replacementPrefix + filePath.Substring (oldPrefix.Length - 1) + + // Normalize the path separators if used uniformly in the replacement + let hasSlash = replacementPrefix.IndexOf '/' >= 0 + let hasBackslash = replacementPrefix.IndexOf '\\' >= 0 + + if hasSlash && not hasBackslash then replacement.Replace('\\', '/') + elif hasBackslash && not hasSlash then replacement.Replace('/', '\\') + else replacement + |> Some + else + None + ) + |> Option.defaultValue filePath + + let applyDir pathMap (dirName : string) : string = + if dirName.EndsWith dirSepStr then apply pathMap dirName + else + let mapped = apply pathMap (dirName + dirSepStr) + mapped.TrimEnd (Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) diff --git a/src/utils/PathMap.fsi b/src/utils/PathMap.fsi new file mode 100644 index 00000000000..8cf4e2f2485 --- /dev/null +++ b/src/utils/PathMap.fsi @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +/// Functions to map real paths to paths to be written to PDB/IL +namespace Internal.Utilities + +type PathMap + +[] +module internal PathMap = + + val empty : PathMap + + /// Add a path mapping to the map. + val addMapping : string -> string -> PathMap -> PathMap + + /// Map a file path with its replacement. + /// Prefixes are compared case sensitively. + val apply : PathMap -> string -> string + + /// Map a directory name with its replacement. + /// Prefixes are compared case sensitively. + val applyDir : PathMap -> string -> string diff --git a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs index 8893ca68e70..91d7bfcb8d6 100644 --- a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs +++ b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs @@ -14,6 +14,7 @@ open FSharp.Compiler.Lexhelp open FSharp.Compiler.ErrorLogger open FSharp.Compiler.ErrorLogger open FSharp.Compiler.Ast +open Internal.Utilities [] type HashIfExpression() = @@ -63,7 +64,7 @@ type HashIfExpression() = let resourceManager = LexResourceManager () let defines = [] let startPos = Position.Empty - let args = mkLexargs ("dummy", defines, lightSyntax, resourceManager, stack, errorLogger) + let args = mkLexargs ("dummy", defines, lightSyntax, resourceManager, stack, errorLogger, PathMap.empty) CompileThreadStatic.ErrorLogger <- errorLogger diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/PathMap1/pathmap.fs b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/PathMap1/pathmap.fs new file mode 100644 index 00000000000..a5cdf2d0239 --- /dev/null +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/PathMap1/pathmap.fs @@ -0,0 +1,43 @@ +// #NoMT #CompilerOptions #Deterministic +// +// +// IMPORTANT: PathMap1/pathmap.fs and PathMap2/pathmap.fs must be identical! +module TestPathMap + +open System.Runtime.CompilerServices + +type SomeType () = + static member GetCallerFilePath ([] ?filePath : string) = + match filePath with + | None -> "(Unknown)" + | Some filePath -> filePath + +[] +let main argv = + let srcDir = __SOURCE_DIRECTORY__ + printfn "Current __SOURCE_DIRECTORY__ = %s" srcDir + if srcDir <> "/src" then exit 1 + + let srcFile = __SOURCE_FILE__ + printfn "Current __SOURCE_FILE__ = %s" srcDir + if srcFile <> "pathmap.fs" then exit 1 + + let callerFilePath = SomeType.GetCallerFilePath () + printfn "Current CallerFilePath = %s" srcDir + if callerFilePath <> "/src/pathmap.fs" then exit 1 + +#line 2 @"F:/foo/SomethingElse.fs" + + let srcDir = __SOURCE_DIRECTORY__ + printfn "Changed __SOURCE_DIRECTORY__ = %s" srcDir + if srcDir <> "/etc/foo" then exit 1 + + let srcFile = __SOURCE_FILE__ + printfn "Changed __SOURCE_FILE__ = %s" srcDir + if srcFile <> "SomethingElse.fs" then exit 1 + + let callerFilePath = SomeType.GetCallerFilePath () + printfn "Changed CallerFilePath = %s" srcDir + if callerFilePath <> "/etc/foo/SomethingElse.fs" then exit 1 + + 0 diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/PathMap2/pathmap.fs b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/PathMap2/pathmap.fs new file mode 100644 index 00000000000..a5cdf2d0239 --- /dev/null +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/PathMap2/pathmap.fs @@ -0,0 +1,43 @@ +// #NoMT #CompilerOptions #Deterministic +// +// +// IMPORTANT: PathMap1/pathmap.fs and PathMap2/pathmap.fs must be identical! +module TestPathMap + +open System.Runtime.CompilerServices + +type SomeType () = + static member GetCallerFilePath ([] ?filePath : string) = + match filePath with + | None -> "(Unknown)" + | Some filePath -> filePath + +[] +let main argv = + let srcDir = __SOURCE_DIRECTORY__ + printfn "Current __SOURCE_DIRECTORY__ = %s" srcDir + if srcDir <> "/src" then exit 1 + + let srcFile = __SOURCE_FILE__ + printfn "Current __SOURCE_FILE__ = %s" srcDir + if srcFile <> "pathmap.fs" then exit 1 + + let callerFilePath = SomeType.GetCallerFilePath () + printfn "Current CallerFilePath = %s" srcDir + if callerFilePath <> "/src/pathmap.fs" then exit 1 + +#line 2 @"F:/foo/SomethingElse.fs" + + let srcDir = __SOURCE_DIRECTORY__ + printfn "Changed __SOURCE_DIRECTORY__ = %s" srcDir + if srcDir <> "/etc/foo" then exit 1 + + let srcFile = __SOURCE_FILE__ + printfn "Changed __SOURCE_FILE__ = %s" srcDir + if srcFile <> "SomethingElse.fs" then exit 1 + + let callerFilePath = SomeType.GetCallerFilePath () + printfn "Changed CallerFilePath = %s" srcDir + if callerFilePath <> "/etc/foo/SomethingElse.fs" then exit 1 + + 0 diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/binaryCompare.fsx b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/binaryCompare.fsx index c70512bb866..7d68f167a3f 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/binaryCompare.fsx +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/binaryCompare.fsx @@ -1,24 +1,30 @@ -// sgiven 'dummy' and 'dummy2', and 'dummy.exe' and 'dummy.pdb' exist in the current directory -// this will check 'dummy.exe' and 'dummy2.exe are exactly the same, and the same for the 'pdb' files -// expects 1 arg: whether files should be exactly the same -let shouldBeSame = bool.Parse fsi.CommandLineArgs.[1] - -let areSame (first,second) = +let areSame (first,second) = let load = System.IO.File.ReadAllBytes (load first) = (load second) -let filePairsToCheck = - System.IO.Directory.EnumerateFiles(__SOURCE_DIRECTORY__, "dummy.*") - |> Seq.filter (fun s -> s.EndsWith(".fs") |> not ) // Don't check the source code - |> Seq.map (fun f -> f, f.Replace("dummy","dummy2")) - -let compareFiles pair = - let correct = (areSame pair = shouldBeSame) - if correct then - printfn "Good, %s and %s were %s" (fst pair) (snd pair) (if shouldBeSame then "same" else "different") - else +let compareFiles shouldBeSame pair = + let correct = areSame pair = shouldBeSame + if not correct then printfn "Expected %s and %s to be %s" (fst pair) (snd pair) (if shouldBeSame then "same" else "different") correct // Check all pairs of files are exactly the same -exit (if filePairsToCheck |> Seq.forall compareFiles then 0 else 1) +let shouldBeSame, filePairsToCheck = + match fsi.CommandLineArgs with + | [| _; shouldBeSame |] -> + // given 'dummy' and 'dummy2', and 'dummy.exe' and 'dummy.pdb' exist in the current directory + // this will check 'dummy.exe' and 'dummy2.exe are exactly the same, and the same for the 'pdb' files + // expects 1 arg: whether files should be exactly the same + + bool.Parse shouldBeSame, System.IO.Directory.EnumerateFiles(__SOURCE_DIRECTORY__, "dummy.*") + |> Seq.filter (fun s -> s.EndsWith(".fs") |> not ) // Don't check the source code + |> Seq.map (fun f -> f, f.Replace("dummy","dummy2")) + | args when args.Length >= 3 -> + true, args + |> Seq.pairwise + |> Seq.indexed + |> Seq.choose (fun (i, pair) -> if i % 2 = 1 then Some pair else None) + | args -> + failwithf "Expected '' or ' '" + +exit (if filePairsToCheck |> Seq.forall (compareFiles shouldBeSame) then 0 else 1) diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/dummy.fs b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/dummy.fs index 431026692aa..a6ada9f55fa 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/dummy.fs +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/dummy.fs @@ -1,3 +1,3 @@ // #NoMT #CompilerOptions #Deterministic -module TestDeterminsticCompilation +module TestDeterministicCompilation exit 0 diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/env.lst b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/env.lst index 870f3a95619..082e76dec6a 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/env.lst +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/env.lst @@ -1,7 +1,22 @@ +# Path mapping with embedded PDBs + SOURCE=PathMap1\\pathmap.fs SCFLAGS="--pathmap:\$CWD\\PathMap1=/src,F:\\=/etc --deterministic --embed --debug:embedded --out:PathMap1\\pathmap.exe" + SOURCE=PathMap2\\pathmap.fs SCFLAGS="--pathmap:\$CWD\\PathMap2=/src,F:\\=/etc --deterministic --embed --debug:embedded --out:PathMap2\\pathmap.exe" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx PathMap1\\pathmap.exe PathMap2\\pathmap.exe" + +# Path mapping with portable PDBs + SOURCE=PathMap1\\pathmap.fs SCFLAGS="--pathmap:\$CWD\\PathMap1=/src,F:\\=/etc --deterministic --embed --debug:portable --pdb:PathMap1\\pathmap.pdb --out:PathMap1\\pathmap.exe" + SOURCE=PathMap2\\pathmap.fs SCFLAGS="--pathmap:\$CWD\\PathMap2=/src,F:\\=/etc --deterministic --embed --debug:portable --pdb:PathMap2\\pathmap.pdb --out:PathMap2\\pathmap.exe" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx PathMap1\\pathmap.exe PathMap2\\pathmap.exe PathMap1\\pathmap.pdb PathMap2\\pathmap.pdb" + +# Confirm only portable and embedded debug PDBs are supported with pathmap, not full or pdbonly + SOURCE=pathmapRequiresPortablePdb.fs SCFLAGS="--pathmap:C:\\=/ --debug:full" + SOURCE=pathmapRequiresPortablePdb.fs SCFLAGS="--pathmap:C:\\=/ --debug:pdbonly" + +# Pathmap argument requires maps to be of the format 'path=sourcePath' + SOURCE=pathmapValid.fs SCFLAGS="--pathmap:C:\\NoOtherPath --debug:embedded" + # Sanity check - simply check that the option is valid - SOURCE=dummy.fs SCFLAGS="--deterministic" - SOURCE=dummy.fs SCFLAGS="--deterministic+" - SOURCE=dummy.fs SCFLAGS="--deterministic-" + SOURCE=dummy.fs SCFLAGS="--deterministic" + SOURCE=dummy.fs SCFLAGS="--deterministic+" + SOURCE=dummy.fs SCFLAGS="--deterministic-" SOURCE=dummy.fs SCFLAGS="--deterministic" FSIMODE=EXEC COMPILE_ONLY=1 SOURCE=dummy.fs SCFLAGS="--deterministic+" FSIMODE=EXEC COMPILE_ONLY=1 SOURCE=dummy.fs SCFLAGS="--deterministic-" FSIMODE=EXEC COMPILE_ONLY=1 @@ -12,19 +27,19 @@ # Confirm specific versions are allowed SOURCE=specificVersionSpecifed.fs SCFLAGS="--deterministic" -# Confirm in normal not-determinstic mode, the same file compiled twice leads to different exes & pdbs +# Confirm in normal not-deterministic mode, the same file compiled twice leads to different exes & pdbs # NOTE: we need to use the timeout because non-determinism in fsc is due to datetime, so we need to guarentee at least 1 sec difference - SOURCE=dummy.fs PRECMD="\$FSC_PIPE dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx false" - SOURCE=dummy.fs SCFLAGS="--debug:full" PRECMD="\$FSC_PIPE --debug:full dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx false" - SOURCE=dummy.fs SCFLAGS="--debug:pdbonly" PRECMD="\$FSC_PIPE --debug:pdbonly dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx false" + SOURCE=dummy.fs PRECMD="\$FSC_PIPE dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx false" + SOURCE=dummy.fs SCFLAGS="--debug:full" PRECMD="\$FSC_PIPE --debug:full dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx false" + SOURCE=dummy.fs SCFLAGS="--debug:pdbonly" PRECMD="\$FSC_PIPE --debug:pdbonly dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx false" SOURCE=dummy.fs SCFLAGS="--debug:portable" PRECMD="\$FSC_PIPE --debug:portable dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx false" SOURCE=dummy.fs SCFLAGS="--debug:embedded" PRECMD="\$FSC_PIPE --debug:embedded dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx false" -# Confirm in determinstic mode, the same file compiled twice leads to exactly the same exe & pdbs +# Confirm in deterministic mode, the same file compiled twice leads to exactly the same exe & pdbs SOURCE=dummy.fs SCFLAGS="--deterministic" PRECMD="\$FSC_PIPE --deterministic dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx true" SOURCE=dummy.fs SCFLAGS="--deterministic --debug:portable" PRECMD="\$FSC_PIPE --deterministic --debug:portable dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx true" SOURCE=dummy.fs SCFLAGS="--deterministic --debug:embedded" PRECMD="\$FSC_PIPE --deterministic --debug:embedded dummy.fs && \$FSI_PIPE copyArtifacts.fsx" POSTCMD="\$FSI_PIPE --nologo --quiet --exec binaryCompare.fsx true" -# Confirm only portable and embeded debug PDBs are supported under determinstic build, not full or pdbonly +# Confirm only portable and embedded debug PDBs are supported under deterministic build, not full or pdbonly SOURCE=portablePdbOnly.fs SCFLAGS="--deterministic --debug:full" SOURCE=portablePdbOnly.fs SCFLAGS="--deterministic --debug:pdbonly" diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/keep.lst b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/keep.lst new file mode 100644 index 00000000000..f59ec20aabf --- /dev/null +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/keep.lst @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/pathmapRequiresPortablePdb.fs b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/pathmapRequiresPortablePdb.fs new file mode 100644 index 00000000000..80243879471 --- /dev/null +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/pathmapRequiresPortablePdb.fs @@ -0,0 +1,3 @@ +// #NoMT #CompilerOptions #Determinism +//--pathmap can only be used with portable PDBs \(--debug:portable or --debug:embedded\) +exit 0 diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/pathmapValid.fs b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/pathmapValid.fs new file mode 100644 index 00000000000..1ec61fc9a8f --- /dev/null +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/pathmapValid.fs @@ -0,0 +1,3 @@ +// #NoMT #CompilerOptions #Determinism +//Invalid path map\. Mappings must be comma separated and of the format 'path=sourcePath' +exit 0 diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/portablePdbOnly.fs b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/portablePdbOnly.fs index c1b99e6a41e..d5c358b34f6 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/portablePdbOnly.fs +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/determinism/portablePdbOnly.fs @@ -1,3 +1,3 @@ // #NoMT #CompilerOptions #Determinism -//Determinstic builds only support portable PDBs +//Deterministic builds only support portable PDBs exit 0 diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl index 1014e10ca6a..b0fd6746810 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl @@ -80,6 +80,8 @@ Copyright (c) Microsoft Corporation. All Rights Reserved. --deterministic[+|-] Produce a deterministic assembly (including module version GUID and timestamp) +--pathmap: Maps physical paths to source path + names output by the compiler --crossoptimize[+|-] Enable or disable cross-module optimizations diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/pdb/env.lst b/tests/fsharpqa/Source/CompilerOptions/fsc/pdb/env.lst index 938bd76d2e7..1fd2562d4f0 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/pdb/env.lst +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/pdb/env.lst @@ -14,7 +14,7 @@ NOMONO SOURCE=pdb01.fs SCFLAGS="--debug --pdb:.\\pdb01.pdb" PRECMD="IF EXIST pd NOMONO SOURCE=pdb01.fs SCFLAGS="-g --debug:embedded --pdb:.\\pdbembedded.pdb" PRECMD="IF EXIST pdbembedded.pdb DEL pdbembedded.pdb" POSTCMD="IF EXIST pdbembedded.pdb dir pdbembedded.pdb&EXIT 1" # If pdb file exists then it didn't embed so fail. -NOMONO SOURCE=pdb01.fs SCFLAGS="-g --debug:portable --embed:pdb01.fs --pdb:.\\pdbportable.pdb" PRECMD="IF EXIST pdbportable.pdb DEL pdbportable.pdb" POSTCMD="IF not EXIST pdbportable.pdb dir pdbportable.pdb&EXIT 1" # If pdb file doesn't exist then it failed to generate portable pdb with embeded source. +NOMONO SOURCE=pdb01.fs SCFLAGS="-g --debug:portable --embed:pdb01.fs --pdb:.\\pdbportable.pdb" PRECMD="IF EXIST pdbportable.pdb DEL pdbportable.pdb" POSTCMD="IF not EXIST pdbportable.pdb dir pdbportable.pdb&EXIT 1" # If pdb file doesn't exist then it failed to generate portable pdb with embedded source. NOMONO SOURCE=pdb01.fs SCFLAGS="-g --out:pdbembedded.exe --debug:embedded --embed:pdb01.fs PRECMD="IF EXIST pdbembedded.exe DEL pdbembedded.exe" POSTCMD="IF NOT EXIST pdbembedded.exe dir pdbembedded.exe &EXIT 1" # If pdb file doesn't exist then it failed to embedded a pdb with embedded source. NOMONO SOURCE=pdb05.fs SCFLAGS="-g --debug:full --embed" # --embed with --debug:full is build error diff --git a/tests/fsharpqa/Source/CompilerOptions/fsi/exename/help40.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsi/exename/help40.437.1033.bsl index aab81bde226..d19a024e300 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsi/exename/help40.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsi/exename/help40.437.1033.bsl @@ -31,6 +31,8 @@ Usage: fsharpi [script.fsx []] --deterministic[+|-] Produce a deterministic assembly (including module version GUID and timestamp) +--pathmap: Maps physical paths to source path + names output by the compiler --crossoptimize[+|-] Enable or disable cross-module optimizations diff --git a/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl index 4346db21448..242cb274d2d 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl @@ -31,6 +31,8 @@ Usage: fsi.exe [script.fsx []] --deterministic[+|-] Produce a deterministic assembly (including module version GUID and timestamp) +--pathmap: Maps physical paths to source path + names output by the compiler --crossoptimize[+|-] Enable or disable cross-module optimizations diff --git a/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl index a57b389a873..34d28e5f70b 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl @@ -33,6 +33,8 @@ Usage: fsi.exe [script.fsx []] --deterministic[+|-] Produce a deterministic assembly (including module version GUID and timestamp) +--pathmap: Maps physical paths to source path + names output by the compiler --crossoptimize[+|-] Enable or disable cross-module optimizations diff --git a/tests/fsharpqa/Source/run.pl b/tests/fsharpqa/Source/run.pl index de780ea0c86..2f15bcdbdde 100644 --- a/tests/fsharpqa/Source/run.pl +++ b/tests/fsharpqa/Source/run.pl @@ -75,7 +75,10 @@ $VerifyStrongName = 1 if ($ENV{VERIFYSTRONGNAME} =~ /TRUE/i); # Check for any compiler flags -my $SCFLAGS = $ENV{SCFLAGS}; +my $CWD = cwd(); +$_ = $ENV{SCFLAGS}; +s/\$CWD/$CWD/g; +my $SCFLAGS = $_; # Check for any compiler 'tail' flags my $TAILFLAGS = $ENV{TAILFLAGS}; @@ -492,11 +495,9 @@ sub RunCommand { # GetSrc -- Find the source file to build # sub GetSrc() { - my $cwd = cwd(); - # The environment SOURCE var usually defines what to compile $_ = $ENV{SOURCE}; - s/\$CWD/$cwd/; + s/\$CWD/$CWD/; my $source = $_; return($source) if defined($source); diff --git a/tests/fsharpqa/fsharpqafiles.csproj b/tests/fsharpqa/fsharpqafiles.csproj index d014c7a3096..6e6ef645b38 100644 --- a/tests/fsharpqa/fsharpqafiles.csproj +++ b/tests/fsharpqa/fsharpqafiles.csproj @@ -10,6 +10,7 @@ + diff --git a/tests/fsharpqa/run.fsharpqa.test.fsx b/tests/fsharpqa/run.fsharpqa.test.fsx index 101e41f7a2d..a29a242625b 100644 --- a/tests/fsharpqa/run.fsharpqa.test.fsx +++ b/tests/fsharpqa/run.fsharpqa.test.fsx @@ -6,41 +6,53 @@ open System.Diagnostics let releaseOrDebug = "Debug" let setEnvVar name value = - System.Environment.SetEnvironmentVariable(name, value) + System.Environment.SetEnvironmentVariable(name, value) let addToPath path = - let currentPath = System.Environment.GetEnvironmentVariable "PATH" - - let splits = currentPath.Split(Path.PathSeparator) - if not(Array.contains path splits) then - setEnvVar "PATH" (path + (string Path.PathSeparator) + currentPath) + let currentPath = System.Environment.GetEnvironmentVariable "PATH" + let splits = currentPath.Split(Path.PathSeparator) + if not(Array.contains path splits) then + setEnvVar "PATH" (path + (string Path.PathSeparator) + currentPath) + +let nugetCache = Path.Combine(System.Environment.GetEnvironmentVariable "USERPROFILE", ".nuget", "packages") let rootFolder = Path.Combine(__SOURCE_DIRECTORY__, "..", "..") -let compilerBinFolder = Path.Combine(rootFolder, releaseOrDebug, "net40", "bin") -setEnvVar "CSC_PIPE" (Path.Combine(rootFolder, "packages", "Microsoft.Net.Compilers.2.7.0", "tools", "csc.exe")) +let compilerBinFolder = Path.Combine(rootFolder, "artifacts", "bin", "fsc", releaseOrDebug, "net472") +setEnvVar "CSC_PIPE" (Path.Combine(nugetCache, "Microsoft.Net.Compilers", "2.7.0", "tools", "csc.exe")) setEnvVar "FSC" (Path.Combine(compilerBinFolder, "fsc.exe")) setEnvVar "FSCOREDLLPATH" (Path.Combine(compilerBinFolder, "FSharp.Core.dll")) addToPath compilerBinFolder let runPerl arguments = - // a bit expeditive, but does the deed - Process.GetProcessesByName("perl") |> Array.iter (fun p -> p.Kill()) - use perlProcess = new Process() - perlProcess.StartInfo.set_FileName (Path.Combine(rootFolder, "packages", "StrawberryPerl64.5.22.2.1", "Tools", "perl", "bin", "perl.exe")) - perlProcess.StartInfo.set_Arguments (arguments |> Array.map(fun a -> @"""" + a + @"""") |> String.concat " ") - perlProcess.StartInfo.set_WorkingDirectory (Path.Combine(rootFolder, "tests", "fsharpqa", "source")) - perlProcess.StartInfo.set_RedirectStandardOutput true - perlProcess.StartInfo.set_RedirectStandardError true - perlProcess.StartInfo.set_UseShellExecute false - perlProcess.Start() |> ignore - while (not perlProcess.StandardOutput.EndOfStream) do - perlProcess.StandardOutput.ReadLine() |> printfn "%s" - while (not perlProcess.StandardError.EndOfStream) do - perlProcess.StandardError.ReadLine() |> printfn "%s" - perlProcess.WaitForExit() - if perlProcess.ExitCode <> 0 then - failwithf "exit code: %i" perlProcess.ExitCode + // Kill all Perl processes, and their children + ProcessStartInfo( + FileName = "taskkill", + Arguments = "/im perl.exe /f /t", + CreateNoWindow = true, + UseShellExecute = false + ) + |> Process.Start + |> fun p -> p.WaitForExit() + + use perlProcess = + ProcessStartInfo( + FileName = Path.Combine(nugetCache, "StrawberryPerl64", "5.22.2.1", "Tools", "perl", "bin", "perl.exe"), + Arguments = (arguments |> Array.map(fun a -> @"""" + a + @"""") |> String.concat " "), + WorkingDirectory = Path.Combine(rootFolder, "tests", "fsharpqa", "source"), + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + ) + |> Process.Start + + while (not perlProcess.StandardOutput.EndOfStream) do + perlProcess.StandardOutput.ReadLine() |> printfn "%s" + while (not perlProcess.StandardError.EndOfStream) do + perlProcess.StandardError.ReadLine() |> printfn "%s" + perlProcess.WaitForExit() + if perlProcess.ExitCode <> 0 then + failwithf "exit code: %i" perlProcess.ExitCode let testResultDir = Path.Combine(rootFolder, "tests", "TestResults") let perlScript = Path.Combine(rootFolder, "tests", "fsharpqa", "testenv", "bin", "runall.pl") -runPerl [|perlScript; "-resultsroot";testResultDir ;"-ttags:Conformance06"|] \ No newline at end of file +runPerl [|perlScript; "-resultsroot";testResultDir ;"-ttags:Determinism"|] \ No newline at end of file