Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling "portable" profiles in projects #10

Closed
dsyme opened this issue Dec 15, 2015 · 17 comments
Closed

Enabling "portable" profiles in projects #10

dsyme opened this issue Dec 15, 2015 · 17 comments

Comments

@dsyme
Copy link
Contributor

dsyme commented Dec 15, 2015

We should gradually make more "fsprojects" and other F# community libraries available as portable libraries (profile 7, 78 or 259). Portable libraries are consumable by both .NET Core and .NET Framework projects, as well as Windows apps and so on. Looking ahead it seems pretty important that we maximize the reach of F# libraries where possible. This will be a fairly long process but it will be worth it.

For example, we made FSharp.Control.AsyncSeq available as both a .NET 4.5 and Profile7 PCL in this PR. We could have made it only a Profile7 but decided to do both for the moment.

@dsyme
Copy link
Contributor Author

dsyme commented Dec 15, 2015

This table can be used to record the current state of which "fsprojects" libraries are PCL. However in many cases moving to .NET Core will not be immediately possible due to non-portability or dependencies.

Libraries:

✅ FSharp.Core.Fluent
FSharp.Control.AsyncSeq
FSharp.Collections.ParallelSeq
FSharp.Quotations.Evaluator
✅ FSharp.Control.Reactive
✅ Tamarin

  • Amazon.CloudWatch.Selector
  • Amazon.SimpleWorkflow.Extensions
  • Cricket
  • DynamoDb.SQL
  • ExcelFinancialFunctions
  • Filbert
  • Foq
  • FSharp.Compatibility
  • FSharp.Data.Toolbox
  • FSharp.Linq.ComposableQuery
  • FSharp.ViewModule
  • FSharpLint
  • Oxen
  • Chessie
  • FSharpx.Extras
  • FSharp.CloudAgent
  • FSharp.Interop.Dynamic

Other Libraries (not in fsprojects, mentioned in the comments thread):

✅ Unquote
✅ FParsec

Tools in fsprojects (needs case-by-case consideration about if/how to make portable or .NET Core friendly)

  • FsBlog
  • FsLexYacc
  • FsReveal
  • Paket
  • FsUnit
  • FAKE.*

Intrinsically Non-PCL and/or non-cross-platform

💥 FSharp.Compiler.CodeDom
💥 [ ] FSharp.Desktop.UI

Type providers (not yet possible to make these portable)

  • ApiaryProvider
  • FsXaml
  • AzureStorageTypeProvider
  • ExcelProvider
  • FSharp.Text.RegexProvider
  • FSharp.Management
  • FSharp.TypeProviders.StarterPack
  • FSharp.ComProvider
  • FSharp.Configuration
  • DynamicsCRMProvider
  • DynamicsNAVProvider
  • FSharp.Data.DbPedia
  • FSharp.Data.Experimental.XenomorphProvider
  • GraphProvider
  • S3Provider
  • SQLProvider
  • FSharp.Data.HiveProvider
  • FSharp.Data.SqlClient

Dormant projects

  • FSharp.Numerics.FuzzyIntervals
  • FnuPlot
  • Foogle.Charts
  • FSharpx.Observable

@dsyme
Copy link
Contributor Author

dsyme commented Dec 15, 2015

Here are the approximate steps to add a PCL Portable build of an otherwise unremarkable F# library called FSharp.Foo targeting .NET 4.x.

The aim is to make a nuget package containing both your existing .NET 4.x DLL and a portable DLL containing essentially the same functionality.

These notes were prepared on projects using FAKE and/or Paket. They should be basically valid with other build tools.

Note that we copy, edit and prepare project files directly. If you're not comfortable doing that then stop reading.

1 - Create directory src\FSharp.Foo.Portable and copy src\FSharp.Foo\FSharp.Foo.fsproj to src\FSharp.Foo.Portable\FSharp.Foo.Portable.fsproj

2 - Edit the portable project file to contain these magic lines, replacing corresponding existing lines

<PropertyGroup>
  <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>  
  <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>  
  <TargetProfile>netcore</TargetProfile>  
  <TargetFSharpCoreVersion>3.3.1.0</TargetFSharpCoreVersion>  
 </PropertyGroup>

...
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
   <OutputPath>..\..\bin\portable</OutputPath>
...
  <DocumentationFile>..\..\bin\portable\FSharp.Collections.ParallelSeq.xml</DocumentationFile>
 </PropertyGroup>
 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    ...
    <OutputPath>..\..\bin\portable</OutputPath>
    ...
    <DocumentationFile>..\..\bin\portable\FSharp.Collections.ParallelSeq.xml</DocumentationFile>
</PropertyGroup>

<Reference Include="FSharp.Core">  
    <Name>FSharp.Core</Name>  
    <AssemblyName>FSharp.Core.dll</AssemblyName>  
    <HintPath>$(MSBuildExtensionsPath32)\..\Reference Assemblies\Microsoft\FSharp\.NETCore\$(TargetFSharpCoreVersion)\FSharp.Core.dll</HintPath>  
</Reference>  

....

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.Portable.FSharp.Targets" />   

Also change the file-references in the project file to be links referring across a directory, e.g. like this, e.g.

 <Compile Include="Tools.fs">  

becomes

<Compile Include="../FSharp.Foo/Tools.fs">  
   <Link>Tools.fs</Link>   
</Compile>  

3 - Add the portable project to the solution, either using IDE tooling or like this

4 - Build your project. If it doesn't build then your project may not be portable. Or you may need to use "reshaped reflection" if your project uses reflection, for example these helpers taken from FSharp.Core. There may be a better version of these helpers around for you to use.

5 - If you're game, try adjusting to Profile78 or Profile259. These are "even more portable" profiles, and may be necessary if you want your project consumable by most Xamarin tooling. The TargetFSharpCoreVersion changes as follows (and you must change the moniker in the nuget package).

     <TargetFSharpCoreVersion>3.78.3.1</TargetFSharpCoreVersion>  

     <TargetFSharpCoreVersion>3.259.3.1</TargetFSharpCoreVersion>  

6 - Add the portable outputs to the nuget package using the correct moniker, like this if using nuget.exe and like this if using paket.exe. The monikers to use in the subdirectory in the nuget packages are

Profile7  - portable-net45+netcore45+MonoAndroid1+MonoTouch1
Profile78 - portable-net45+netcore45+wp8+MonoAndroid1+MonoTouch1
Profile259 - portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1

7 - Check your nuget package. Try using it from a new F# portable profile 7 library (which should be able to refer to either profile 78 or profile 259 libraries too)

8 - Push your new nuget package

Note that it may be possible (and much nicer) to remove the .NET 4.x version of your package after you've made your PCL package. However test that path carefully and ensure that your portable version doesn't contain any less functionality

@OnurGumus
Copy link

Don't forget fparsec. I think it is already converted to PCL. Though again without .NET native support we won't be able to run them as UWP apps :(

@dsyme
Copy link
Contributor Author

dsyme commented Dec 16, 2015

@Reverseblade This thread only deals with "fsprojects" projects.

It would be great to make a more complete table, e.g. of everything under http://fsharp.org/community/projects. Also of the major C# libraries that F# community work sits on (e.g. Math.NET Numerics).

@kolektiv
Copy link

FParsec already is, although I have to admit I'm struggling to understand the relationships between NuGet monikers, profiles, etc. I've followed The Don Guide in sentiment rather than exactly, and ended up with Profile259 assemblies, although it is fiddly, and i'm not looking forward to trying this with a large many project codebase (Freya).

@TheAngryByrd
Copy link

I do have a PR for FSharp.Control.Reactive that makes it Profile259. It needs a second pair of eyes. fsprojects/FSharp.Control.Reactive#65

@cloudRoutine
Copy link
Member

@jchidley
Copy link

Here's the background research that I did on this topic, to save anyone else the effort:

  1. Slightly longer explanation about Portable Class Library Profiles from the same source as referenced by cloudRoutine: http://blog.stephencleary.com/2012/05/framework-profiles-in-net.html
  2. "Cross-Platform Development with the Portable Class Library" https://msdn.microsoft.com/en-us/library/gg597391(v=vs.110).aspx
  3. "Walkthrough: Creating a Portable F# Library" https://msdn.microsoft.com/en-us/library/hh913781.aspx
  4. F# for Windows Universal Apps on Windows 10 requires .net Native support which depends on CoreCLR.

@stephen-swensen
Copy link

FYI - Unquote has builds targeting .NET 4.0, .NET 4.5, and Portable Profile 259.

@dsyme
Copy link
Contributor Author

dsyme commented Jan 17, 2016

@stephen-swensen Great!

@haf
Copy link
Member

haf commented Aug 5, 2016

How do PCLs interact w/ .Net Core/CoreCLR?

@dsyme
Copy link
Contributor Author

dsyme commented Aug 5, 2016

THis is non-authoritative, but basically the important thing is

Profile259 =>  Profile78 => Profile7 => ".NET Standard 1.5+" => .NET Core 1.x+ and .NET Framework 4.5x+

So making something into a PCL 259/78/7 means it can be referenced from a .NET Standard library, and can be sued on both .NET Core and ,NET Framework.

Likewise making something into a .NET Standard library means it can be used on both .NET Core and ,NET Framework.

That's not authoritative, just my understanding of how things work. Eventually I'd expect most F# libraries to just be .NET Standard 1.something.

@OnurGumus
Copy link

I believe currently the most 'ideal' profile is profile 151 at the moment.

@haf
Copy link
Member

haf commented Aug 5, 2016

Why can't the compiler handle this complexity? It could make it the 'most compatible' by default?

@dsyme
Copy link
Contributor Author

dsyme commented Aug 6, 2016

@haf The F# compiler (fsc.ex) doesn't really change much, the caller just points the compiler at different sets of reference binaries.

The complexity and churn here is unfortunate and really a question for the .NET designers. They've iterated on this multiple times, only recently settling on .NET Standard as the way of binary code sharing - and there will be another iteration on that.

@haf
Copy link
Member

haf commented Aug 6, 2016

@dsyme That's what I mean; can't the compiler than know about those sets without heavy-handed xml generated by opaque tooling. I'd like to specify a single input the to the compiler; e.g. a list of target "profiles": ["netcore15"; "most-portable-pcl"; "full-framework"]?

@enricosada
Copy link

enricosada commented Sep 2, 2016

@haf the tooling just resolve the path of assemblies (from gac or packages).

now all references are passed as normal file references, no more magic. there is a switch for --simpleresolution in fcs.

For example the response file of the compiler (the arguments) to build net46:

--temp-output:e:\temp\test78\obj\Debug\net46\
--out:e:\temp\test78\bin\Debug\net46\test78.dll
--define:DEBUG
--define:TRACE
--define:NET46
--optimize:False
--debug-type:portable
--output-name:test78
--file-version:1.0.0.0
--version:1.0.0.0
--informational-version:1.0.0
--target-framework:.NETFramework,Version=v4.6
--reference:C:\Users\e.sada\.nuget\packages\FSharp.Core\4.0.1.7-alpha\lib\net40\FSharp.Core.dll
--reference:C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\mscorlib.dll
--reference:C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\System.dll
--reference:C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\System.Core.dll
--reference:C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Microsoft.CSharp.dll
e:\temp\test78\Library.fs

running fsc @responsefile.rsp is going to build the lib

but for netstandard the list of referenced assemblies change too.. so something (the tooling) should choose. be that project.json with dotnet core sdk, msbuild or a bat file running fsc

The idea is netstandard is an upgraded version of pcl, so no more intersection of api (115, 259, etc), but an incremental api surface (netstandard1.0 -> netstandard1.6), see https://gist.github.com/davidfowl/8939f305567e1755412d6dc0b8baf1b7

@dsyme dsyme closed this as completed Mar 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants