/rules_reason

📐Reason/OCaml rules and tools for Bazel

Primary LanguagePythonMIT LicenseMIT

ReasonML / BuckleScript Rules

https://travis-ci.org/ostera/rules_reason.svg?branch=master

A collection of OCaml, ReasonML, and BuckleScript rules and tools for Bazel.

Note: this is alpha software! I'm building it to properly integrate a ReasonML application into a bigger project that builds with Bazel.

This projet relies on two prerequisites:

  1. nix, the purely functional package manager, which is used for installing the ReasonML tooling (refmt specifically), opam, yarn and node in an hermetic-ish fashion. At least you don't need to handle those yourself :)
  2. bazel, naturally.

If you just cloned this repo and you have both those tools installed, feel free to start with a bazel build //... to get everything warmed up.

The examples works a separate workspace so you will need to run bazel build //... there as well if you wish to play around with them.

WARNING: because this rules handle all of their dependencies hermetically, a clean install takes a good ~10 minutes on an early 2015 Macbook Pro.

Begin by adding the following to your WORKSPACE:

workspace(name = "retool")

###
### Reason Rules!
###

rules_reason_version = "f8b956b147bfcf22c90480e7ebea32e6769c1fe0" # HEAD

http_archive(
    name = "com_github_ostera_rules_reason",
    sha256 = "",
    strip_prefix = "rules_reason-%s" % (rules_reason_version,),
    urls = ["https://github.com/ostera/rules_reason/archive/%s.zip" % (rules_reason_version,)],
    )

###
### Nix Repositories
###

load(
    "@com_github_ostera_rules_reason//reason/repositories:nix.bzl",
    "nix_repositories",
)

nix_repositories(
    nix_sha256 = "28121f6eb3d6c5b4c1fc9f716953ce8b0a793b841d0e9de095977b3ade06f92d",
    nix_version = "20a78f74f8ac70d1099ff0d214cd00b25820da03",
)

###
### Register Reason Toolchain
###

load(
    "@com_github_ostera_rules_reason//reason:def.bzl",
    "reason_register_toolchains",
)

reason_register_toolchains(
    bs_sha256 = "db3f37eb27bc1653c3045e97adaa83e800dff55ce093d78ddfe85e85165e2125",
    bs_version = "939ef1e1e874c80ff9df74b16dab1dbe2e2df289",
    nixpkgs_revision = "d91a8a6ece07f5a6df82aa5dc02030d9c6724c27",
    nixpkgs_sha256 = "0c5291bcf7d909cc4b18a24effef03f717d6374de377f91324725c646d494857",
)

################################################################################
#
#   Declare dependencies
#
################################################################################

load(
    "//3rdparty:load.bzl",
    "declare_dependencies"
)

declare_dependencies()

Use reason_module to compile a group of .re and .rei files into their corresponding .ml and .mli counterparts.

Further consume these outputs with ocaml_module, bs_module, ocaml_bytecode_binary, or ocaml_native_binary.

You can use bs_module to turn any ML source target into Javascript, this includes the outputs from a reason_module rule too.

Unfortunately bsc requires a bsconfig.json file at the place where you call it. This means that you need to have that file at the root of your project.

# BUILD file at //...
filegroup(
  name = "bsconfig",
  srcs = ["bsconfig.json"],
)

# BUILD file somewhere in your sources!
reason_module(
  name = "srcs.re",
  srcs = glob(["*.re"]),
)

bs_module(
  name = "srcs.js",
  config = ["//:bsconfig"],
  srcs = [":srcs.re"],
  deps = [":deps"],
)

You can use ocaml_native_binary and ocaml_bytecode_binary to compile your ML sources into native or bytecode binaries, and yes you can use your reason_module targets as sources!

# BUILD file somewhere in your sources!
reason_module(
    name = "srcs",
    srcs = glob(["*.re"]),
    )

ocaml_native_binary(
    name = "native",
    srcs = [":srcs"],
  )

ocaml_bytecode_binary(
    name = "bytecode",
    srcs = [":srcs"],
  )

In no particular order:

  1. DevFlow: Top-Level
  2. DevFlow: Dependencies
  3. DevFlow: Generating Merlin and pointing IDEs to the right places
  4. Rules: *_test
  5. DevFlow: Auto-rebuild
  6. Rules: node_binary
  7. < your suggestion here! >

This compiles down ReasonML code into a representation that is friendly for BuckleScript or the default Ocaml compiler.

Which one will it be compatible with is determined by how you write your ReasonML code.

Name Type Default value
name string mandatory value
A unique name for this rule.
srcs string_list mandatory value

The sources of this library.

The name of the sources will be preserved, and the outputs will replace the .re or .rei extension with .ml or .mli correspondingly.

Other bs_module rules can depend on this library to compile it down to Javascript code.

toolchain label
value:"//reason/toolchain:bs-platform"

The toolchain to use when building this rule.

It should include both refmt, bsc and a filegroup containing the BuckleScript stdlib.

Example:

# //my_app/BUILD
load(
    "@com_github_ostera_rules_reason//reason:def.bzl",
    "reason_module",
)

reason_module(
    name = "my_app",
    srcs = glob(["*.re", "*.rei"])
    visibility = ["//my_app:__subpackages__"],
  )

Compile Ocaml code into Javascript.

Name Type Default value
name string mandatory value
A unique name for this rule.
config label mandatory value

The bsconfig.json file.

The file must be located at the root of your WORKSPACE. Currently looking to work around this.

srcs string_list mandatory value

The ML sources of this library.

The name of the sources will be preserved, and the outputs will replace the .ml by their compilation counterparts (.cmi, .cmj, .cmt, etc) and the .js output.

Other bs_module rules can depend on this library to compile it down to Javascript code.

deps label_list
value:[]
Dependencies of this library, must include BsModuleInfo providers.
toolchain label
value:"//reason/toolchain:bs-platform"

The toolchain to use when building this rule.

It should include both refmt, bsc and a filegroup containing the BuckleScript stdlib.

Example:

load(
    "@com_github_ostera_rules_reason//reason:def.bzl",
    "reason_module",
    "bs_module"
)

reason_module(
    name = "my_app",
    srcs = glob(["*.re", "*.rei"]),
    )

bs_module(
    visibility = ["//examples/app:__subpackages__"],
    name = "my_app.js",
    config = "//:bs_config",
    srcs = [ ":my_app" ],
    deps = [ "//examples/some/dependency" ],
    )

Compile ML code into bytecode or native binaries. For bytecode binaries it will copmile them including the runtime, rather than separately. This is something that I'd like to change in the future.

Name Type Default value
name string mandatory value
A unique name for this rule, used as the name of the output binary
srcs string_list mandatory value
The ML sources of this library.
deps label_list
value:[]
Dependencies of this library, must include ReasonModuleInfo providers.
toolchain label
value:"//reason/toolchain:bs-platform"

The toolchain to use when building this rule.

It should include both ocamlc, ocamlopt, ocamldep, ocamlrun, and a filegroup containing the Ocaml stdlib.

Example:

load(
    "@com_github_ostera_rules_reason//reason:def.bzl",
    "reason_module",
    "ocaml_native_binary",
)

# BUILD file somewhere in your sources!
reason_module(
    name = "srcs",
    srcs = glob(["*.re"]),
    )

# replace native with bytecode in the rule name and you get a bytecode binary
ocaml_native_binary(
    name = "my_bin_name",
    srcs = [":srcs"],
  )

There is a ToolchainInfo that describes the fields required throughout the build rules to successfully compile from ReasonML down to Javascript.

Feel free to register your own toolchain or use the default toolchain that will be managed completely within Bazel.

Name Type
bsc File
The BuckleScript compiler file.
refmt File
The ReasonML Formatter file.
bs_stdlib Filegroup
A Filegroup with all the source and compiled files for the BuckleScript standard library that will be used for compiling Ocaml into Javascript
ocamlc File
The Ocaml bytecode compiler.
ocamlopt File
The Ocaml native compiler.
ocamldep File
The Ocaml dependency tool.
ocamlrun File
The Ocaml bytecode interpreter.
   
ocaml_stdlib Filegroup
A Filegroup with Ocaml standard library.

There are 2 providers included, that will carry information for the different stages of the build process.

This provider is the output of the reason_module rule, and it represents a compilation unit from ReasonML to Ocaml.

Name Type
name string
The name of your the colletion of files
srcs depset(File)
A depset of all the ReasonML files that will be compiled to ML
outs depset(File)
A depset of all the target ML files that will be generated

This provider is the output of the bs_module rule, and it represents a compilation unit from Ocaml to Javascript.

Name Type
name string
The name of your the colletion of files
srcs depset(File)
A depset of all the Ocaml files that will be compiled to Javascript
outs depset(File)
A depset of all the target ML and Js files that will be generated
deps depset(File)
A depset of all the BuckleScript modules files that the srcs depend on

This provider is the output of the bs_module rule, and it represents a compilation unit from Ocaml to Javascript.

Name Type
name string
The name of your the colletion of files
srcs depset(File)
A depset of all the Ocaml files that will to be compiled.
outs depset(File)
A depset of all the target binary files.
deps depset(File)
A depset of all the Ocaml modules files that the srcs depend on
target "native" | "bytecode"
Whether this module is being compiled natively or as bytecode.