4 ms·
FSharpPacker – compile F# scripts to executables
- Multicomp 2y agoNice work shipping this! I enjoy and prefer f# to c# but never gave scripts much care because I could never do this, fsi and the repl was not enough. Now? Hmmm I have options !
- neonsunset 2y agoA few of notes regarding AOT compilation if you would like to have the best experience: 1. print* functions with "%A" format do not work because "structured output" uses reflection patterns that the linker cannot analyze. You can easily replace them with string interpolation that F# now has. I carry around these bindings: open System let println s = Console.WriteLine s let print s = Console.Write(x: string) and use them as println $"Hello, {thing}" 2. AOT compilation is not a scripting environment so accessing fsi args does not work, here's the snippet that I use for it: open System // Detect fsi, if not - slice appropriately // You do not need this if you know that you will be // only compiling the script or only running it with fsi // just use the offset of 2 or 1 respectively :) let args = let args = Environment.GetCommandLineArgs() if args[0].Contains "fsi.dll" then args[2..] else args[1..] // Use args in some way args |> Array.iter println 3. For quickly publishing script files you may want to define a (fish) shell function like this: function fspk set name (string replace '.fsx' '' $argv[1]) fspack $argv[1] -f net9.0 --aot -o . \ /p:InvariantGlobalization=true \ /p:OptimizationPreference=Size && rm -rf ./$name.dbg ./$name.dSYM end This will reduce the binary size and will give you just a single executable for every `fspk my_script.fsx`. The binaries do start at ~4MB but beyond that - they scale efficiently with dependencies. 4. Except what is explicitly noted in repo, other scripting features work like referencing nuget packages or importing files. I did not expect to like this as much as I did, it's incredibly productive and you can just throw a few files together while having fully statically typed scripting environment and built-in package manager. You can also get Ionide for VS Code for language server, autocomplete and debugging support.
- fire_lake 2y agoGiven these limitations, isn’t it easier to create a small dotnet project?
- neonsunset 2y agoIt might be! I'd expect that at some point this would be a natural progression. However, very often you don't need that - you can just compile individual script files which merge together code, package and file references. No need to maintain a separate folder with a separate .fsproj - simply #open some_utils.fsx, #r "nuget: FsHttp" or #r "SomePackage.dll" and 'fspk my_script.fsx'. Initially, I did not know this existed, but it turned out a friend of mine wrote this tool and I have been using it ever since.
- Alifatisk 2y agoI am a huge fan of keeping things as standalone executable, good work!
- raphinou 2y agoFSharpPacker works on scripts (with extension .fsx) written with F# and usually run with `dotnet fsi`. For the F# advent calendar [1] I recently blogged about how those scripts are a viable starting point for developing an application in F#. Actually, it's even possible to easily maintain a scripted version and a compiled version of the same F# app, with basically the same code. For those interested, it's at https://www.asfaload.com/blog/fsharp-fsx-starting-point/ https://www.asfaload.com/blog/fsharp-fsx-starting-point/ 1: https://sergeytihon.com/2024/10/26/f-advent-calendar-in-english-2024/ https://sergeytihon.com/2024/10/26/f-advent-calendar-in-engl...
- nickpeterson 2y agoAny reason to prefer this or fflat (bflat)?
- neonsunset 2y agoFflat does not work on macOS and does not support .NET 9. Unfortunately, I had issues with making it work on Windows and Linux too. This one works like a charm.