bsb-native4.0.1100 • Public • Published
Bsb-native is a fork of bsb that compiles to native OCaml instead.
# Install bsb-nativenpm install --save-dev bsb-native# Add a bsconfig.jsonnpx bsb --init .
"name" : "NameOfLibrary""sources" : "src""entries":"backend": "bytecode""main-module": "Index" // Capitalized name of module (not a path)
See the full schema below.
npx bsb -make-world (or add an npm script that runs
That will build the first entry and use its
backend to build all other entries targeting that
e.g if you have multiple
bytecode targets, they'll all get built but not the
js ones nor
native ones. If you want to build to all targets you need to run the build command multiple times with different
Useful command line flags
-make-world flag builds all of the dependencies and the project.
-clean-world flag cleans all of the build artifacts.
-w enabled the watch mode which will rebuild on any source file change.
-backend [js|bytecode|native] flag tells
bsb-native to build all entries in the
bsconfig.json which match the backend
The build artifacts are put into the folder
lib/bs. The bytecode executable would be at
lib/bs/bytecode/index.byte and the native one at
lib/bs/native/index.native for example.
-build-library flag takes a module name and will pack everything in the current project that depends on it into a library file. Cool trick: you can use this to implement hot reloading for any sort of app, simply call bsb-native with this flag and use the built-in module
Dynlink to load the file bsb-native generates.
Opam package support
bsb-native supports opam packages (see ocamlfind example).
BUT you need to be on the switch
4.02.3+buckle-master (which you can get to by running
opam switch 4.02.3+buckle-master && eval $(opam env)).
"name" : "NameOfLibrary""sources" : "src""ocamlfind-dependencies": "lwt.unix" "lwt.ppx""entries":"backend": "bytecode""main-module": "Index"
// All of the bsb fields will work as expected.// See the bucklescript schema://// Below are just the bsb-native specific features.// Contains only the added fields, the rest is the same as bsb."sources":// Extra field added to tell bsb-native that a folder contains the// source for a ppx."type": "ppx"// Array of ppx to run on all files in this directory. If it's a// relative path, it's relative to `node_modules`, if it's a module// name it's a local ppx."ppx": "Myppx" "theirPpx/theirPpx.exe"// Restrict a folder to being built to only one target. Can be a// string or an array of strings."backend": "native"// Entries is an array of targets to be built.// When running `bsb -backend bytecode`, bsb will filter this array for// all the entries compiling to bytecode and compile _all_ of those."entries":// Can be an array of string or a string: "bytecode" (ocamlc), "js"// (bsc) or "native" (ocamlopt)."backend": "bytecode"// The entry point module. Has to be capitalized."main-module": "MainModule"// Custom executable name."output-name": "snake.exe"// Array of opam dependencies."ocamlfind-dependencies": "lwt.unix"// Array of built-in ocaml dependencies that are not Pervasives (ie not// linked by default).// This is useful for making a ppx, where you need "compiler-libs".// All of these except "compiler-libs" is linked by default, so you don't// have to worry about it. That said it does increase the binary size so// you can remove unused things here."ocaml-dependencies": "bigarray" "unix" "threads" "compiler-libs"// Array of flags to pass the OCaml compiler. This shouldn't be needed for// most things."ocaml-flags": "-bin-annot"// Array of flags passed to ocaml only at the linking phase"ocaml-linker-flags": "-output-obj"// This allows you to write JS specific packages (for example) and depend// on them without bsb choking on them when building to another platform.// If you have `MyLibJs` which exposes a module `Bla`, and `MyLibNative`// which also exposes `Bla`, the compiler will use the native `Bla` when// compiling to native and the JS `Bla` when compiling to JS thanks to this// flag.//// Can be a string or an array, with the same values as "entries"."allowed-build-kinds": "js"// List of relative paths (relative from library dir) to be linked at the// end. Bsb-native doesn't care how those were generated as long as they// are there at the linking stage. Generally you can use `build-script` to// build those."static-libraries": "lib/c/my_lib.o"// File built and ran at compile time. Very useful for generating object files// that are then linked into the app.// See the C compilation section below for more details about the API exposed."build-script": "build_script.re"// List of flags to be passed to the C linker at the linking stage."c-linker-flags": "-L/path/to/folder/with/linker/stuff"
bsb-native allows C compilation, that works the same way on all platforms, through an OCaml/Reason file. To expose that file to bsb you can add
"build-script": "build_script.re" to your
Bsb expose to that file a module called
Bsb_internals which contains helpers to compile C code.
/* Command that'll synchronously compile a C file to an object file (or not if `c=false` is passed).c:bool Equivalent to the `-c` flag passed to gcc. true by default.include_ocaml:bool Automatically add an include flag for the ocaml runtime. true by default.flags:array(string) Array of flags passed directly to gcc.includes:array(string) Array of paths to folders that will be included during compilation.string The output file.array(string) The input files.*/let gcc : (?c:bool, ?include_ocaml:bool, ?flags:array(string), ?includes:array(string), string, array(string)) => unit;/* Contains an absolute path to the current project's node_modules. */let node_modules : string;
Here is a simple example of a
gcc function exposed to the
build-script file uses a vendored mingw compiler, which works on all platforms (linux, osx, windows).
bsb-native actually supports building Reason/OCaml to JS as well as to native/bytecode. What that enables is cross platform code that depends only on an interface, and bsb-native will choose the right implementation depending on what you target.
For example, you can write code that depends on the module Reasongl, and bsb-native will use
ReasonglNative as the implementation for Reasongl when building to native/bytecode or it'll use
ReasonglWeb when building to JS.
Currently the way this works is to have each platform specific dependency expose a module with the same name and rely on the field
allowed-build-kinds in the
bsconfig.json to tell bsb-native which one of platform specific dep you want to build, given that you want to build the whole project to a specific target. Say you target JS, then ReasonglWeb will get built which exposes its own Reasongl module.
If you would like to have all your code in the same package, you can use BuckleScript's conditional compilation. To do so, place
#if BSB_BACKEND = "bytecode" theninclude MyModule_Native#elif BSB_BACKEND = "native" theninclude MyModule_Native#elseinclude MyModule_Js#end(* We support Darwin, Linux, Windows compile time checks *)#if OS_TYPE = "Darwin" thenexternal fabs : float -> float = "fabs"#end
inside a file called
BSB_BACKEND = "js"), that module will use the
MyModule_Js implementation (see example). Same for
BSB_BACKEND = "native" and
BSB_BACKEND = "bytecode".
BSB_BACKEND value will be filled automatically by
bsb-native, so you just need to use it at will with the language-level static
Platform specific files (like
MyModule_Native) should be added to a folder that is only built for that specific backend (
native, in the
MyModule_Native case). You can do that by adding this to your
"sources":"dir": "src""subdirs":"dir": "native""backend": "native"
Note: BuckleScript's conditional compilation doesn't work with Reason yet, so any usage of conditional compilation will have to be implemented in OCaml
We support running ppxes on the whole codebase, like bucklescript with
"ppx-flags", but also per
"source" directory. You can add
ppx: ["my_ppx/my_ppx.exe"] to any
"source" directory to run that ppx on the files inside that directory.
You can also make your own ppx inside you project. To keep things contained, you have to put the code in its own folder which you'll list under
"sources" with the extra key
"type": "ppx". Then add an entry like you would for building a binary, to bytecode specifically, and similarly add to the entry
"type": "ppx". Finally add to the
"sources" that contain the files on which to run that ppx
"ppx": ["Myppx"] (notice it's just a module name, that tells bsb-native it's a local ppx).
- add folder to
- add entry built to bytecode with
"ppx"field to right
"sources"object for files that use that ppx
- (optional) bsb-native passes to the ppx a command line argument called
-bsb-backendfollowed by the current backend, which is either
You can't build ppxes to bytecode or js for now. You also can't have a ppx depend on another ppx. You can't put the ppx code alongside your app code. The ppx will always be built even if you never reference it.