ionide / fstoml

Lightweight TOML based F# project file
MIT License
36 stars 7 forks source link

fstoml spec draft v0.0.1 #4

Open cloudRoutine opened 8 years ago

cloudRoutine commented 8 years ago
#=======================================================#
# `.fstoml` F# Project File Specification Version 0.0.1 #
#=======================================================#

# Toplevel Only Properties/Keys

# FsTomlVersion   : string  - Semantic Version Number of fstoml spec compliance
# Name            : string
# AssemblyName    : string  # Name of the dll
# RootNamespace   : string
# Guid            : Guid
# OutputType      : Library | Exe | Winexe | Module
# FSharpCore      : string  - Version Number of FSharp.Core 
# ToolsVersion    : 4.0 | 10.0 | 12.0 | 14.0 | 15.0 # MsBuild version

FsTomlVersion   = '0.0.1.0' 
Name            = 'Library1'
AssemblyName    = 'Library1'
RootNamespace   = 'Library1'
Guid            = 'bb0c6f01-5e57-4575-a498-5de850d9fa6c'
OutputType      = 'Library'
FSharpCore      = '4.4.0.0'

# SrcFile : { (BuildAction : Compile|Content|Resource|EmbeddedResource|None) * (Path:string) 
#             Link : string 
#             Copy : Always|Never|Newest }
#   - { (Compile|Content|Resource|EmbeddedResource|None): string ; Link: string; Copy:(Always|Never|Newest) }
#
# Files - Array of inline tables representing SrcFiles listed in compilation order for the project 

Files = [
    { None = "paket.references" },
    { Compile = "src/file.fs" },
    { Compile = "src/file2.fs", Link = "src/uselessLink.fs" },
    { Compile = "src/file3.fs", Sig = "src/file3.fsi" },
    { None    = "src/script.fsx", Private = true },
]  

# Reference : { Include : string; HintPath:string; Name: string; SpecificVersion:bool, CopyLocal:bool } 
# References - Array of inline tables for dll and package references

References = [
    { Include = "System" },
    { Include = "FSharp.Core", CopyLocal = 'Always' },
    { Include = "Fable.Core" },
]

# ProjectRef : { Name : string; Project : Guid ; Private: bool }
# References - Array of inline tables of project dependencies 

ProjectReferences = [
    { Name = Arg, Project = "f3d0b372-3af7-49d9-98ed-5a78e9416098", Private = true },
]

# - Configuration Properties (can be overridden) - 
# Tailcalls : bool
# WarningsAsErrors : bool
# Constants : string []
# DebugType : None | PdbOnly | Full
# DebugSymbols : bool
# Optimize : bool
# Prefer32bit : bool
# WarningLevel : 1..5
# OutputPath : string
# DocumentationFile : str#ing
# NoWarn : int []
# OtherFlags : string [ ]

DebugSymbols = true
DebugType = 'full'
Optimize = false
NoWarn = [52, 40]
OtherFlags = [ '--warnon:1182' ]

#  - Configurations -
#   
# [ <TargetFrameworkIdentifier> . <TargetFrameworkVersion> . <Configuration> . <Platform> ]
#
#   Framework Ids   : net | netStandard | netcoreapp
#   Platform        : AnyCpu | x86 | x64
#
#   Framework Versions :
#       net         : v4.5 | v4.5.1 | v4.6 | v4.6.1 | v4.6.2 
#       netcoreapp  : 1.0
#       netstandard : v1.0 | v1.1 | v1.2 | v1.3 | v1.4 | v1.5 | v1.6
#
#   Configuration   : string (typically 'Debug' & 'Release' )

# - Configuration Examples -

[ 'netcore'.1.6'.Release ]
    Constants = [ 'RELEASE', 'FABLE' ]
    DebugSymbols = false
    DebugType = 'pdb'
    Optimize = true

[ 'netcore'.'1.6'.Release.x86 ]
    OutputPath = "bin/Release/x86"

[ 'netcore'.'1.6'.Release.x64 ]
    OutputPath = "bin/Release/x64"

# - KEY OVERRIDE CONVENTION -
# 
#    keys defined in config apply to all descendents, 
#    but can be overwritten in nested tables 

# - KEY SUBSTITUTION CONVENTION -
#
#    `%(keyName)` or `%keyName` can be used to substitute in the value of any key that's already been defined

# -  ARRAY OPERATOR CONVENTION -
#
#    Arrays have a special prefix operator modification convention

Constants = [ 'FABLE', 'FUNSCRIPT' ]

[ 'netcore'.'v1.6'.Debug ]
    # adds the constant to the values of the existing key
    '+Constants' = [ 'DEBUG' ]
    # removes the constant from the values of the existing key
    '-Constants' = [ 'FUNSCRIPT' ]

Open Questions

alfonsogarciacaro commented 8 years ago

Fantastic job! :clap: Maybe we should state also which key-value pairs are absolutely mandatory?

How to indicate that certain files should only be accessible under a subset of configurations

It just occurred to me that the only times I did something similar I always conditioning the file presence to a compile constant. Maybe we could include something like (name Constraint is tentative):

Files = [
    { Compile = "src/file.fs", Constraint = "DEBUG" }
  ] 

Which would translate to:

<ItemGroup Condition="$(DefineConstants.Contains('DEBUG'))">
  <Compile Include="src/file.fs" />
</ItemGroup>
matthid commented 8 years ago

@cloudRoutine Looks good to me. Nice starting point. Here my 2 cents:

cloudRoutine commented 8 years ago

FSharpCore and Guid are msbuild properties, the way this is going to work for a while is the toml file is going to be used to generate an fsproj. Also the FSharpCore property is what determines how the IDE checks against the src file. In the project I have open in the screenshot I have the core version set to 4.1 while the actual core dll I'm referencing is 4.0, the IDE treats it like 4.1 as you can see from the struct record

ProjectReferences only have guids that refer to the project's unique identifier. The projecttype guids are a small set of guids that are pretty easy to recognize once you're familiar with them. also they're not a necessary property, the project's guid is.

yea it's a typo

Framework Ids : net | netStandard | netcoreapp

the actual framework ids are up there

There would not be a new target framework specifier for Fable, there's no reason for there to be one for it either. Those are for .net

We can't make projectreferences like normal references, the way they work and are processed are totally different. If you look inside a solution file you can see that the projects are referenced only by their guids, like so -

    GlobalSection(NestedProjects) = preSolution
        {83F16175-43B1-4C90-A1EE-8E351C33435D} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}
        {8E6D5255-776D-4B61-85F9-73C37AA1FB9A} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}
        {B8B3F011-54F3-43D3-BC94-3ECBE5A3770C} = {ED8079DD-2B06-4030-9F0F-DC548F98E1C4}
    EndGlobalSection

A reference without a hintpath is always resolved from the GAC

We're not trying to create a totally new project system whole cloth. This is a slimmed down, more easily usable, declarative subset of msbuild that contains just the data that FCS and FSC need.

matthid commented 8 years ago

FSharpCore and Guid are msbuild properties, the way this is going to work for a while is the toml file is going to be used to generate an fsproj. Also the FSharpCore property is what determines how the IDE checks against the src file.

So it's a complete implementation detail and should be figured out automatically in the fsproj generation process (by looking at the actual FSharp.Core reference)?

A reference without a hintpath is always resolved from the GAC

Yeah I never liked that anyway. I saw situations where this lead to really really hard to find errors...

We're not trying to create a totally new project system whole cloth. This is a slimmed down, more easily usable, declarative subset of msbuild that contains just the data that FCS and FSC need.

Ok :)

cloudRoutine commented 8 years ago

it can't always be figured out automatically because the fsharp.core reference can be defined as such

    <Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
      <Private>True</Private>
    </Reference>

or in toml form (something like)

References = [
  { Include = "FSharp.Core",  Version = %(FSharpCore), CopyLocal = 'Always' },
]

Yeah I never liked that anyway. I saw situations where this lead to really really hard to find errors...

Well with netcore you'll never have that issue again :stuck_out_tongue_winking_eye: