fsprojects / FSharp.Compiler.PortaCode

The PortaCode F# code format and corresponding interpreter. Used by Fabulous and others.
Other
42 stars 11 forks source link

Recompile with configured compiler symbols (DEBUG, NETSTANDARD, ...) #12

Closed TimLariviere closed 3 years ago

TimLariviere commented 5 years ago

Would it be possible to use the same flags, when recompiling, as those defined in the fsproj? Or at least be able to define custom symbols to use when launching the watcher.

For instance, this code will evaluate differently between MSBuild and the Interpreter when the symbol WITH_TRACE is defined in the fsproj.

let updateData () =
    (...)
#if WITH_TRACE
    do sendTraceToExternalService()
#endif

I know it can be difficult because it depends on the configuration (Debug, Release) and platform (Android, iOS) used when running the project with the IDE.

But without it, it makes using the interpreter really complicated on bigger than small projects.

A better example that made me realize this:

I'm trying to use Fabulous.LiveUpdate with ElmishContacts (a Fabulous app) The interpreter doesn't like SQLite and prints a compilation error (no member found). Ok, why not, maybe it's asking too much.

So I made a "design time" mock for data access, switching the 2 relies on a custom symbol (ENABLE_LIVEUPDATE) But this doesn't work as the interpreter will remove the #if ENABLE_LIVEUPDATE block. A workaround can be using the negative #if !ENABLE_LIVEUPDATE but for more advanced scenario where an actual symbol is expected, it won't be possible.

dsyme commented 5 years ago

Would it be possible to use the same flags, when recompiling, as those defined in the fsproj?

It's odd, I thought we did this. We should for sure

dsyme commented 5 years ago

Ah yes, of course we don't for projects. The ProjectCracker we use doesn't give us that.

The ideal would be get a FSC command line invocation out of dotnet build. I don't know if there's a standard way to intercept that yet, there are some hacks that can be used.

dsyme commented 5 years ago

cc @enricosada who might know if it's possible to get the F# command line from a project

enricosada commented 5 years ago

Depends on scenario, but in FSAC and fable we use https://github.com/enricosada/dotnet-proj-info/

You can use it as library or command line tool, see below but is battle tested from .net core sdk 1.0 preview (so years ago).

@dsyme HAPPY TO HELP INTEGRATE IT, JUST PING ME

It call msbuild (msbuild or dotnet msbuild) as process to ask for information (props, fsc-args, net-fw assembly location, installed framework etc, see --help) instead of using msbuild as library (like projectcracker), so will work with msbuild version installed, and info is the same as dotnet build (because will call the same msbuild). support .net and .net core

It support both old fsproj (verbose fsproj) and .net sdk (slim fsproj):

About scenario, depends if you want:

All are supported, but with different functions.

as tool

For local usage, you can use dotnet-proj global tool.

>dotnet tool install --global dotnet-proj --version 0.33.0  

and to get fsc args, just use dotnet proj fsc-args

>dotnet proj fsc-args
-o:obj\Debug\net461\example1.exe
-g
--debug:portable
--noframework
--define:TRACE
--define:DEBUG
--define:NETFRAMEWORK
...

support usual args of dotnet commands, so specify a path to fsproj (otherwise search in working dir), -c Release, -f net461, custom properties etc.

as library

You can use low level Dotnet.Proj.Info + some code to visit the fsprojs graph to initialize the FCS FSharpProjectOptions (like fable )

That's the current used by FSAC and Fable, battle tested but a bit hard to add.

But that way is annoying because that visiting code is copied in both FSAC/Fable etc and is not good and not easy to use. What you really want usually is an easy to use fsprojPath -> FSharpProjectOptions or slnPath -> FSharpProjectOptions list

So i wrapped that code and improved in a new library new library Dotnet.Proj.Info.Workspace and Dotnet.Proj.Info.Workspace.FCS

I am finalizing the testing of that, but is ok, will be soon used as default in FSAC.

Both are aimed to be high level and give additional feature (notification of loading, add custom properties, get custom properties) and more soon (solution explorer like treeview info, watch for changes with notifications) to be useful as run-once (for tools like linter/fable) or load-and-watch-for-changes (like editors)

if you want to initialize FCS

If you want to initialize FCS, use Dotnet.Proj.Info.Workspace.FCS and api is like

// find msbuild installed (.NET and .NET Core)
let msbuildLocator = MSBuildLocator()

// let lib choose defaults, otherwise you can specify paths of MSBuild to use (default is dotnet in path and latest msbuild
let config = LoaderConfig.Default msbuildLocator
let loader = Loader.Create(config)

// let's load some info about .NET Framework installed once (so path of GAC for tfms et)
let netFwconfig = NetFWInfoConfig.Default msbuildLocator
let netFwInfo = NetFWInfo.Create(netFwconfig)

// fcs instance
let fcs = FCS_Checker.Create ( .. )

// manager for workspace
let fcsBinder = FCSBinder(netFwInfo, loader, fcs)

// load project infos
loader.LoadProjects [ projPath ] //or .LoadSln

// get FSharpProjectOptions ready for FCS
let fcsPoOpt = fcsBinder.GetProjectOptions(projPath)

more examples in the test suite https://github.com/enricosada/dotnet-proj-info/blob/master/test/Dotnet.ProjInfo.Workspace.FCS.Tests/Tests.fs#L242-L250

for just fcs args

let msbuildLocator = MSBuildLocator()
let config = LoaderConfig.Default msbuildLocator
let loader = Loader.Create(config)

loader.LoadProjects [projPath]

let parsed = loader.Projects

the parsed is a dictionary with all projects info (fcs args and useful properties like tfm, etc)

more info in https://github.com/enricosada/dotnet-proj-info/blob/master/test/Dotnet.ProjInfo.Workspace.Tests/Tests.fs#L241

dsyme commented 5 years ago

@dsyme HAPPY TO HELP INTEGRATE IT, JUST PING ME

@enricosada It would be great to integrate/update and make use of latest functionality. We do integrate an early version I think, see here https://github.com/fsprojects/FSharp.Compiler.PortaCode/blob/master/src/FSharp.Compiler.PortaCode.fsproj#L17

dsyme commented 3 years ago

I believe this is fixed in #25 where we are now picking up DefineConstants