fflat - F# native script compiler on bflat
# install the dependencies (on a debian-based system)
apt install -y libc++-dev
# install the global tool
dotnet tool install --global fflat
see ./Dockerfile
for a self-contained example
fflat script.fsx # about 1.4M, no debug/globalization/symbols
fflat script.fsx --small # about 1MB, no reflection/exceptions, no printfn!
run fflat --help
for a list of options
arm64 executable
fflat script.fsx --arch arm64 # 1.4MB and runs on raspberry pi! 👍
using fflat to as an interface to the F# compiler
fflat ./mylibrary.fsx build-il --watch ## quickly recompiles mylibrary.dll on every change
fflat ./helloworld.fsx --small --os windows ## ... etc
fflat script.fsx [--small] build-shared
MAIN:
<script> .fsx script file path (first argument)
SUBCOMMANDS:
build <options> compile to native with bflat [default]
build-il <options> compile to IL (using fsc)
build-shared <options>
compile to shared library
Use 'fflat <subcommand> --help' for additional information.
OPTIONS:
--verbose, -v verbose output
--version version of application
--ldflags <string> <ldflags>
--noreflection disable reflection
--arch <unknown|arm|arm64|x64|x86|wasm32|loongarch64>
<x64|arm64>
--os <unknown|windows|linux|uefi>
<linux|windows|uefi>
--optimize <none|prefersize|blended|preferspeed>
<preferspeed|prefersize>
--small, -s omits most useful features like reflection, exceptions, but produces smaller binaries
--output, -o <outputFile>
output executable path
--help display this list of options.
Why?
there is almost a 1000x difference in startup time for dotnet fsi scripts using nuget!
there is also FSharpPacker for .fsx scripts, which compiles .fsx scripts to native executables using the standard MSBuild pipeline (PublishAOT), but bflat can produce significantly smaller executables or even omit the .NET runtime/GC all together.
What's the smallest executable I can get?
there is a sample in ./samples/zerolib_16kb.fsx
that produces a 16kb executable with the
zerolib standard library. This excludes almost all of .NET and the F# core library. however it's not very useful and you'll have to write implementations for even basic features like for
loops.
TypeInitialization_Type_NoTypeAvailable
errors
don't use --small
, --small
will crash if your script uses any
reflection features.
there's many untrimmable features in the F# core library like printfn, quotations and linq. substituting all printfn calls with stdout.WriteLine will produce significantly smaller binaries as well.
Have fun!