deterministic/relative paths in CallerFilePath
I'm trying to get CallerFilePath to output relative paths using the ideas from the first answer here: https://stackoverflow.com/questions/65935784/is-it-possible-to-remove-the-full-paths-from-net-assemblies-created-with-dotnet.
It suggests that adding config like the following to an fsproj or Directory.Build.props file should result in relative paths being produced:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Deterministic>true</Deterministic>
<DeterministicSourcePaths>true</DeterministicSourcePaths>
<PathMap>$(MSBuildThisFileDirectory)=.</PathMap>
</PropertyGroup>
<ItemGroup>
<SourceRoot Include="$(MSBuildThisFileDirectory)/"/>
</ItemGroup>
I've tried a few variations of this but always get absolute paths in my generated js. I see some references to PathMap in the fable source, but not sure if it's currently a supported feature. This is a nice feature to have to add source locations to logs, and generate stable ids based on source definitions for debugging.
Using fsc along with test code like:
type Log =
static member inline info
(
message: string,
[<CallerMemberName; Optional; DefaultParameterValue("")>] name: string,
[<CallerFilePath; Optional; DefaultParameterValue("")>] path: string
)
=
printfn $"%s{path}:%s{name}: %s{message}"
Log.info ("test")
The output is
./Api/Program.fs:main: test
Hello,
I didn't investigate this error but in Glutinum I do something similar using this code:
let errorOrigin =
let filePath =
let index = filePath.IndexOf("src/Glutinum.Converter")
"./" + filePath.Substring(index)
$"%s{filePath}(%d{fileLine})".Replace("\\", "/")
This don't work in all situation but the assumption here is that I am able to identify a "unique enough" section of the path to decide to remove everything before that path.
You could imagine initialization the logger with the __SOURCE_DIRECTORY__ of the top level file for example.
This is mostly a workaround, and if we can support PathMap not to difficulty we should give it a try. But this would probably be limited to Fable (.NET) version as Fable (JavaScript) don't really understand MSBuild.
My assumption would have been that FCS was responsible to provide the correct path in this situation but I can be wrong.
Thanks for the example. I did think about doing that but I still ship code to a mobile decide with lots of long strings and the extra string manipulation operations. Perhaps I could use a babel plugin to remove them for now.
Im also experimenting with a fable plugin for autogenerating ids for zedux atom names as a workaround where I use the MemberRef info to grab the FullName of the identifier. It’s just a bit brittle since fable compiler plugins can’t influence the type of the Fsharp code, so I have to return a function and coerce with ‘!!’ to the actual return type.
@joprice Could you please tell me how do you invoke FCS directly?
Also, I tried to use the configuration you describe and was not able to get the same result as you, I get /_//src/quicktest/QuickTest.fs:.cctor: test
I changed src\quicktest\QuickTest.fsproj to :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<RollForward>Major</RollForward>
<LangVersion>Preview</LangVersion>
<Deterministic>true</Deterministic>
<DeterministicSourcePaths>true</DeterministicSourcePaths>
<PathMap>$(MSBuildThisFileDirectory)=.</PathMap>
</PropertyGroup>
<ItemGroup>
<SourceRoot Include="$(MSBuildThisFileDirectory)/"/>
<Compile Include="QuickTest.fs" />
<Content Include="quicktest.fs.js" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Fable.Core/Fable.Core.fsproj" />
</ItemGroup>
</Project>
and run dotnet watch run --no-hot-reload from src\quicktest.
I also changed the Quicktest.fs file use your snippet.
Note: I tried to force passing args to FCS from here:
https://github.com/fable-compiler/Fable/blob/34ca900b23d564b503a1260f8984d29398432db8/src/Fable.Compiler/ProjectCracker.fs#L333-L349
But for some reason, even if I am able to modify the output when running dotnet run, it seems like the changes are not reflected for Fable. This is strange because I don't find any places where Fable would do something to modify CallerFilePath. It seems be all handled internally by FCS.
By FCS, I meant building with dotnet command instead of fable, not calling it directly. So to me, the issue seemed to be something with the parsing of the fsproj file. With some configurations I also saw a leading _/ prefix on the dotnet side as well. I'm not sure what rules determine the full path and perhaps it's a 8/9 sdk difference? Either way, fable producing the full path hints at some sort of missing extraction on the fable side of the fsproj info. Maybe looking at the full commands in verbose mode would show something it's passing to the fcs dll?
I think let getBasicCompilerArgs () = is the right place to pass CLI arguments to FCS at least for debugging purpose for now.
Because the option listed in in this list match with the options on this page.