diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c73a62e623..7c815abbc2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,40 +1,75 @@ # Contributing -Thanks for your help! Due to ReScript's nature, the contribution setup isn't all straightforward. If something isn't working, please file an issue! +Welcome to the ReScript compiler project! + +This documet will give you guidance on how to get up and running to work on the ReScript compiler and toolchain. + +We tried to keep the installation process as simple as possible. In case you are having issues or get stuck in the process, please let us know in the issue tracker. + +Happy hacking! ## Prerequisites -- [NodeJS](https://nodejs.org/) -- C compiler toolchain (you probably already have it installed) -- OS: Mac/Linux (ReScript works on Windows, but developing the repo using Windows isn't tested. Contribution welcome!) +> We are mainly working on Apple machines, so all our instructions are currently MacOS / Linux centric. Contributions for Windows development welcome! -## Install native OCaml compiler +- [NodeJS v16](https://nodejs.org/) +- C compiler toolchain (usually installed with `xcode` on Mac) +- `opam` (OCaml Package Manager) +- VSCode (+ [OCaml Platform Extension](https://marketplace.visualstudio.com/items?itemName=ocamllabs.ocaml-platform)) -If you are familiar with OCaml toolchain, you can use +## Install native OCaml compiler, dune, testing utilities -``` -opam switch 4.06.1+rescript -eval $(opam env) -``` +The ReScript compiler compiles with any recent OCaml compiler. We are using `dune` as a build system for easy workflows and proper IDE support. -If you don't want to bother with opam, we provided a vendored compiler, you can use it directly ``` -node ./scripts/buildocaml.js -# make sure the built compiler is in your PATH, checkout native directory +brew install opam +opam init + +# Install build system +opam install dune + +# Install language server for IDE support +opam install ocaml-lsp-server + +# Any recent OCaml version works as a development compiler +opam switch create 4.12.1 + +# We use NodeJS to run our test suites and other utilities. +npm install ``` +## Configure and Build the Compiler (`ninja` workflow) -## Build +> Note: These instructions allow you to do full builds of the project. In case you only want to build the project for development purposes, you can use the `dune` workflow. + +The ReScript project is built with a vendored version of `ninja`. It requires build files to correctly detect, compile and link all the OCaml files within our project. The build files are generated and managed by a NodeJS script (`./scripts/ninja.js`). ```sh -npm install # install some JS tools for testing purposes -./scripts/ninja.js config # the repo is build with Ninja. Generate the ninja build files -./scripts/ninja.js build # runs `ninja` under the hood against the generated ninja build files +# Generate all the necessary ninja build files +./scripts/ninja.js config + +# Run ninja to read and execute the generated build files +./scripts/ninja.js build + +# Clean (remove) all ninja build files +./scripts/ninja.js clean ``` -Whenever you edit a file, run `./scripts/ninja.js build` to rebuild. Optional watcher to auto-rebuild on file changes: `node scripts/tasks.js`. +Whenever you edit a file, run `./scripts/ninja.js build` to rebuild the ReScript compiler. There's also an optional watcher to auto-rebuild on file changes: `node scripts/tasks.js`. + +## Building the Project During Development (`dune` workflow) + +When working on a project you may want to use `dune` to compile all the files you've been working on. This is especially important for full IDE support, including auto-completion and showing compilation errors. + +``` +# One off build +dune build + +# Watch mode +dune build -w +``` -In the rare case there you're making changes to the vendored OCaml fork, rebuild the fork with `node scripts/buildocaml.js` then run `./scripts/ninja.js cleanbuild`. `cleanbuild` (aka `clean` + `build`) is necessary since the binary artifacts between versions of compiler may be incompatible. +> Please note that `dune` will not build the final `rescript` binaries. Use the aforementioned `ninja` workflow if you want to build, test and distribute the final product. ### Troubleshoot Broken Build diff --git a/dummy.opam b/dummy.opam new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dune b/dune new file mode 100644 index 0000000000..e4f11d99bc --- /dev/null +++ b/dune @@ -0,0 +1 @@ +(dirs jscomp) diff --git a/dune-project b/dune-project new file mode 100644 index 0000000000..ced758a39a --- /dev/null +++ b/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.0) + (name rescript) + \ No newline at end of file diff --git a/jscomp/dune b/jscomp/dune new file mode 100644 index 0000000000..fc22f130cf --- /dev/null +++ b/jscomp/dune @@ -0,0 +1,31 @@ +(copy_files# ext/*.{ml,mli}) +(copy_files# ml/*.{ml,mli}) +(copy_files# napkin/*.{ml,mli}) +(copy_files# stubs/*.{ml,mli,c}) +(copy_files# js_parser/*.{ml,mli}) +(copy_files# depends/*.{ml,mli}) +(copy_files# common/*.{ml,mli}) +(copy_files# core/*.{ml,mli}) +(copy_files# frontend/*.{ml,mli}) +(copy_files# outcome_printer/*.{ml,mli}) +(copy_files# super_errors/*.{ml,mli}) +(copy_files# main/*.{ml,mli}) +( + executable + (public_name bsc.exe) + + ; The main module that will become the binary. + (name Rescript_compiler_main) + + (flags "-w" "+26+27+32+33+39") + + ; Depends on: + (libraries unix str) + + (modules_without_implementation Jscmj_main Lam_pass_unused_params Lam_runtime) + (foreign_stubs + (language c) + (names ext_basic_hash_stubs) + (flags ) + ) +) diff --git a/scripts/ninja.js b/scripts/ninja.js index b6c95d940d..70cd175d81 100755 --- a/scripts/ninja.js +++ b/scripts/ninja.js @@ -4,6 +4,7 @@ var fs = require("fs"); var path = require("path"); var cp = require("child_process"); +var semver = require("semver"); var jscompDir = path.join(__dirname, "..", "jscomp"); var runtimeDir = path.join(jscompDir, "runtime"); @@ -34,6 +35,15 @@ var my_target = var vendorNinjaPath = path.join(__dirname, "..", my_target, "ninja.exe"); +// Let's enforce a Node version >= 16 to make sure M1 users don't trip up on +// cryptic issues caused by mismatching assembly architectures Node 16 ships +// with a native arm64 binary, and will set process.arch to "arm64" (instead of +// Rosetta emulated "x86") +if(semver.lt(process.version, "16.0.0")) { + console.error("Requires node version 16 or above... Abort.") + process.exit(1); +} + exports.vendorNinjaPath = vendorNinjaPath; /** * By default we use vendored,