-
Notifications
You must be signed in to change notification settings - Fork 232
Executing F* code
By default F* only verifies the input code, it does not compile or execute it.
To execute F* code one needs to translate for instance to OCaml or F#, using
F*'s code extraction facility---this is invoked using the command line
argument --codegen OCaml
or --codegen FSharp
. Code written in a
C-like shallowly embedded DSL can be extracted to
C
or WASM
by the KreMLin tool,
and code written in an ASM-like deeply embedded DSL can be extracted
to ASM by the Vale tool,
but none of that is not discussed on this page.
Also since F# extraction is plagued by some bugs and lags quite a bit behind OCaml extraction
(eg. #1096,
#1087 and
more),
the rest of this page is really only about OCaml extraction.
The OCaml extractor will produce <ModuleName>.ml
files for each F*
module in the code; whereas the F# version will emit <ModuleName>.fs
. These files will be located in the directory specified with --odir
; if no output directory is specified, the files are written out in the current directory.
The extracted code often relies on a support library, providing, for
example, implementations of various primitive functions provided by
F*'s standard library. The sources for this support library are in
ulib/ml
(for OCaml) and ulib/fs
(for F#). To build and install the support
library for OCaml, run the following command in the F* directory:
$ make -C ulib install
To compile the extracted code further and obtain an executable, you will need to link it with the support library.
This also means that some modules (e.g. FStar.List
) should not be extracted (because we provide an optimized implementation written in ML that uses, say, Batteries
). For that purpose, a --no-codegen FStar.List
flag should be passed when extracting.
To simplify things, a generic Makefile is provided in ulib/ml/Makefile.include
; it provides a pre-set invocation of F* where all the --no-codegen
flags have been added. Furthermore, to speed up build times, make -C ulib/ml
now builds a .cmxa
file in addition to the individual .cmx
files. You may want to link against that to simplify your build scripts, rather than copying ml
files. The examples/hello
directory provides an example.
Several examples of how this process works can be found in the repository.
Reminder: run make -C ulib/ml
before proceeding to any of the OCaml extraction examples.
-
examples/hello
provideshello.fst
and aMakefile
that compiles and executes a hello world program in OCaml. You can try that out via:$ make -C examples/hello hello
(There is also an attempt to extract this to F# and run it, but it doesn't currently work.)
-
doc/tutorial/code/exercises
provides a simplistic example of access control on files inEx1a.fst
The make targetEx01a-ocaml
illustrates how to extract this to OCaml and run it:$ make -C doc/tutorial/code/exercises Ex01a-ocaml
-
examples/crypto
providesRPC.fst
andCntProtocol.fst
and aMakefile
with therpc-test
andcnt-test
targets providing a way to run a small, verified example of remote procedure calls in OCaml (while linking with OpenSSL). This example relies onucontrib/Platform/ml
which only works with OCaml 4.05.$ opam switch 4.05.0 $ eval $(opam env) $ make -C examples/crypto rpc-test $ make -C examples/crypto cnt-test
If the last commands fail because of errors in
ucontrib/CoreCrypto/ml
then read theINSTALL.md
file there on how to install dependencies like OpenSSL on various platforms. Anyway, building this is not for the faint of heart. -
src/ocaml-output
provides aMakefile
which we use to bootstrap the F* compiler in OCaml.
Advanced:
By default, Foo.Bar.fst
gets extracted as a module Foo_Bar.ml
; references to Foo.Bar
become ML references to Foo_Bar
. If you provide an F* interface for Foo.Bar
via an .fsti only, then there will be no Foo_Bar.ml
generated, you're expected to provide your own realization. So far, so good.
It may be the case that you have both Foo.Bar.fsti
and Foo.Baz.fsti
, which share the same namespace Foo
. In order to simplify your life, --codegen-lib Foo
will ensure that references to Foo.Bar
are extracted as references to Foo.Bar
(instead of Foo_Bar
) and references to Foo.Baz
are extracted to Foo.Baz
(instead of Foo_Baz
), so that you can use OCaml's module system to encapsulate your realized modules.