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 @@
-
- Deterministická sestavení podporují jenom soubory PDB typu Portable (--debug:portable nebo --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
+
+
+
+
+ --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'
+
+