Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
4cf24c3
Rewrite rewatch in OCaml
cknitt Sep 22, 2026
fea06cb
Use the parent workspace's settings for OCaml rewatch member builds
cknitt Oct 10, 2026
5745945
Name OCaml rewatch namespaces with an entry like Rust rewatch
cknitt Oct 10, 2026
00c01e1
Handle SIGHUP and SIGQUIT in OCaml rewatch
cknitt Oct 10, 2026
1b65d53
Print plain OCaml rewatch usage errors when stderr is not a terminal
cknitt Oct 10, 2026
78aaac0
Support OCaml rewatch locks on filesystems without hard links
cknitt Oct 10, 2026
e1bd281
Add OCaml rewatch changelog fragments and remove its task brief
cknitt Oct 12, 2026
43c45ca
Test OCaml rewatch signal handling during a js-post-build hook
cknitt Oct 10, 2026
4444622
Accept only build-system executables as rewatch lock owners
cknitt Oct 10, 2026
ca44c0d
Separate OCaml rewatch config diagnostics from warnings like Rust
cknitt Oct 10, 2026
4ed946a
Compare the OCaml rewatch CLI help exactly in cli_help
cknitt Oct 10, 2026
21be5b4
Remove the Rust unit-test mapping check from OCaml rewatch CI
cknitt Oct 10, 2026
46e23c3
Add libuv's externally maintained parts to the rewatch notices
cknitt Oct 10, 2026
004c797
Copy the Cargo-built rewatch to rescript-rust.exe again
cknitt Oct 10, 2026
c643bd0
Clean up small OCaml rewatch review findings
cknitt Oct 10, 2026
4f53926
Rewrite the OCaml rewatch docs for maintainers
cknitt Oct 10, 2026
4fd5082
Reject non-standard JSON in rescript.json in OCaml rewatch
cknitt Oct 10, 2026
f80e11b
Name fields and accepted values in OCaml rewatch config errors
cknitt Oct 10, 2026
7e03b19
Honor -v for OCaml rewatch format and compiler-args
cknitt Oct 10, 2026
ab8dfcb
Restore Rust rewatch's project-context debug wording in OCaml rewatch
cknitt Oct 10, 2026
6bdce42
Describe created project contexts in plain words in both rewatches
cknitt Oct 10, 2026
8905eee
Tighten OCaml rewatch process lookups on Windows
cknitt Oct 10, 2026
c5552a4
Harden the OCaml rewatch Windows process launcher
cknitt Oct 10, 2026
a1db8a1
Clean up stale artifacts once for cleaned packages
cknitt Oct 10, 2026
7e74db5
Track removed modules once per attempt
cknitt Oct 10, 2026
07f8da8
Compare graph nodes when carrying dirtiness forward
cknitt Oct 10, 2026
f754a66
Simplify incremental preparation
cknitt Oct 10, 2026
5f298d1
Move the build kind into Build_report
cknitt Oct 10, 2026
89ae44d
Define build step labels once in Build_report
cknitt Oct 10, 2026
1cfc0d6
Remove unreachable build failure handling
cknitt Oct 10, 2026
ef34d80
Drop redundant once-guards in Build_attempt
cknitt Oct 10, 2026
1fe0812
Simplify package plans and preparation
cknitt Oct 10, 2026
571c90b
Require cleanup inventories in Build_artifacts.cleanup_stale
cknitt Oct 10, 2026
21619d2
Split parser and compiler flags
cknitt Oct 10, 2026
039672c
Reuse Compiler_info.clean_package in clean
cknitt Oct 10, 2026
8c72530
Reword session comments in build.ml
cknitt Oct 10, 2026
0013fe1
Report format's package name mismatch once
cknitt Oct 10, 2026
d67a8d7
Simplify watch snapshot comparison and walk
cknitt Oct 10, 2026
12e89bb
Share watcher rebuild and reconciliation steps
cknitt Oct 10, 2026
86598a4
Simplify CLI argument predicates and evaluation
cknitt Oct 10, 2026
82dc121
Reuse workspace_config_for in format's scope check
cknitt Oct 10, 2026
f60671a
Remove config_types.mli, which duplicated config_types.ml
cknitt Oct 10, 2026
d2abfba
Split Config.load into named decoders
cknitt Oct 10, 2026
425a52a
Simplify source discovery options
cknitt Oct 10, 2026
f32ad5c
Share watch scope's source directory check
cknitt Oct 10, 2026
924e48d
Remove small duplications in config, watch and traversal code
cknitt Oct 10, 2026
abd496b
Create native watchers by refreshing an empty watcher
cknitt Oct 10, 2026
931df41
Remove termination-signal deferral from rewatch-ocaml
cknitt Oct 10, 2026
209684f
Drop the unused root_reaped parameter of signal_process_tree
cknitt Oct 10, 2026
fdacf0d
Simplify fail_launch in process_child
cknitt Oct 10, 2026
2080d8b
Remove parameters that never vary in rewatch-ocaml
cknitt Oct 10, 2026
c35a5fd
Remove unused exports and trivial wrappers in rewatch-ocaml
cknitt Oct 10, 2026
8660913
Remove unreachable defensive errors in rewatch-ocaml
cknitt Oct 10, 2026
57c720d
Share the lock acquisition loop of with_build and with_watch
cknitt Oct 10, 2026
48feb16
Reject cyclic graphs in run_dependency_graph
cknitt Oct 10, 2026
9ed6327
Remove diagnostic bench scripts
cknitt Oct 10, 2026
07c51db
Remove orphaned Windows job stub check
cknitt Oct 10, 2026
84735de
Simplify run.sh setup and teardown
cknitt Oct 10, 2026
90754d9
Drop Package_traversal.For_test
cknitt Oct 10, 2026
8de0335
Factor repeated runs out of check_command_validation.sh
cknitt Oct 10, 2026
a36d775
Consolidate configuration unit tests
cknitt Oct 10, 2026
2a976fd
Drop run.sh cases duplicated by the shared suite
cknitt Oct 10, 2026
b7a28bf
Drop output tests that restate message formats
cknitt Oct 10, 2026
2e63b5f
Drop CLI precedence tests duplicated by command validation
cknitt Oct 10, 2026
37d5702
Drop self-checks from check_verbose_output.sh
cknitt Oct 10, 2026
0642069
Skip rewatch parity steps on the oldest-OCaml CI job
cknitt Oct 10, 2026
284171e
Run the Rust rewatch shared suite on linux-arm64 only
cknitt Oct 10, 2026
8a71f61
Ignore obsolete jsx.mode and jsx.v3-dependencies in OCaml rewatch
cknitt Oct 10, 2026
0314dde
Explain the process group escalation's PID reuse window
cknitt Oct 10, 2026
6c0b917
Don't let OCaml rewatch watch exit wait for another build's lock
cknitt Oct 10, 2026
86374d0
Port Rust rewatch's option descriptions to the OCaml CLI help
cknitt Oct 10, 2026
51685ac
Poll for watch handles instead of sleeping in OCaml rewatch tests
cknitt Oct 10, 2026
b4a3d5e
Don't republish the .cmi after an implementation with an interface
cknitt Oct 10, 2026
8f9bc68
Restore with_lock in OCaml rewatch for OCaml 5.0
cknitt Oct 10, 2026
729c498
Clear a killed watcher's build lock in the Windows command checks
cknitt Oct 10, 2026
82c04cc
Name the failing command in OCaml rewatch's focused tests under bash
cknitt Oct 10, 2026
d9d3c67
Show the bytes behind Windows output mismatches in OCaml rewatch tests
cknitt Oct 10, 2026
7a0cffc
Don't format-check an LF fixture in OCaml rewatch's focused tests
cknitt Oct 10, 2026
69b54cc
Report why OCaml rewatch's watcher exits, as Rust does
cknitt Oct 11, 2026
c61db85
Lock the test proxy's call log so Windows appends don't collide
cknitt Oct 11, 2026
a23715c
Lock a separate file for the test proxy's call log
cknitt Oct 11, 2026
b238f51
Only warn when Rust's inverted watch filter doesn't reproduce
cknitt Oct 11, 2026
14635e2
Use the same, longer waits on every platform in rewatch tests
cknitt Oct 12, 2026
21a9b71
Test OCaml rewatch's module names against Rust's new cases
cknitt Oct 12, 2026
b6a04f9
Remove a partial destination when an OCaml rewatch copy fails
cknitt Oct 12, 2026
eb8257e
Print watcher output when the dependency-fallback test times out
cknitt Oct 12, 2026
e9f4642
Rehash files modified just before a watch snapshot
cknitt Oct 12, 2026
642ff89
Test that the build schema lists OCaml rewatch's config fields
cknitt Oct 13, 2026
7ef4770
Share the OCaml rewatch test scripts' wait and link helpers
cknitt Oct 13, 2026
bb33784
Drop the package-specs rebuild from OCaml rewatch's Rust differences
cknitt Oct 14, 2026
a61a061
Test removing a deleted dependency source's output on a package-specs…
cknitt Oct 14, 2026
5244a6a
Watch for dependencies missing from an ancestor's node_modules
cknitt Oct 14, 2026
002d5dd
Resolve dot-relative PPX paths against the package directory
cknitt Oct 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
19 changes: 17 additions & 2 deletions .github/actions/setup-ocaml/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ runs:
run: |
dependency_flags_key="${DEPENDENCY_FLAGS//--/}"
dependency_flags_key="${dependency_flags_key// /_}"
key="$CACHE_PREFIX-$OS-3.9.0-$COMPILER-$dependency_flags_key-${{ hashFiles('*.opam') }}"
dependency_hash="${{ hashFiles('*.opam', '.github/opam-repository/repo', '.github/opam-repository/packages/**') }}"
key="$CACHE_PREFIX-$OS-3.9.0-$COMPILER-$dependency_flags_key-$dependency_hash"
echo "value=${key//,/-}" >> "$GITHUB_OUTPUT"
echo "setup-version=3.9.0" >> "$GITHUB_OUTPUT"

Expand All @@ -104,6 +105,11 @@ runs:
uses: ocaml/setup-ocaml@v3.9.0
with:
ocaml-compiler: ${{ inputs.compiler }}
# Use the HTTP repository to prevent intermittent CI setup failures:
# the Git-backed default can race with detached Git maintenance while
# OPAM scans it (https://github.com/ocaml/opam/issues/7031).
opam-repositories: |
default: https://opam.ocaml.org
opam-pin: false
cache: false

Expand All @@ -125,12 +131,21 @@ runs:
env:
DEPENDENCY_FLAGS: ${{ inputs.dependency-flags }}
run: |
opam repository add rescript-overrides "$GITHUB_WORKSPACE/.github/opam-repository"
read -ra dependency_flags <<< "$DEPENDENCY_FLAGS"
if [[ "$RUNNER_OS" == "Windows" ]]; then
export AR=x86_64-w64-mingw32-ar
export RANLIB=x86_64-w64-mingw32-ranlib
export STRIP=x86_64-w64-mingw32-strip
export NM=x86_64-w64-mingw32-nm
export DLLTOOL=x86_64-w64-mingw32-dlltool
export OBJDUMP=x86_64-w64-mingw32-objdump
fi
opam install . "${dependency_flags[@]}"

- name: Cache OPAM environment
# Caches created by pull_request runs are scoped to that PR's merge ref
# and cannot seed other PRs or branches. Only pushes create shared caches.
# and cannot seed other PRs or branches, so only push runs save them.
if: steps.cache.outputs.cache-hit != 'true' && github.event_name == 'push'
uses: actions/cache/save@v6
with:
Expand Down
14 changes: 14 additions & 0 deletions .github/opam-repository/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# ReScript opam overrides

This repository contains narrowly scoped dependency fixes needed by CI before
they are available from the main opam repository.

The Luv 0.5.14 override preserves the ARM64 musl compiler's
`-mno-outline-atomics` requirement while building vendored libuv. Without it,
the static executable fails to link because libuv refers to glibc's internal
`__getauxval` symbol. The patch should be contributed upstream and this
override removed once a fixed Luv release is available.

Luv 0.5.14 also vendors libuv 1.48.0. Evaluating and contributing an update to
a current libuv 1.x release is a separate upstream follow-up; changing the
vendored library is intentionally outside the OCaml rewatch port.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--- a/src/c/dune
+++ b/src/c/dune
@@ -82,8 +82,14 @@
(action (progn
(bash "cp -r vendor/configure/* vendor/libuv/")
(chdir vendor/libuv (progn
(bash
- "sh configure --host `ocamlc -config | awk '/^host:/ {print $NF}'` \
- 'CC=%{cc}' CFLAGS=-DNDEBUG --silent --enable-silent-rules")
+ "architecture=`ocamlc -config-var architecture`
+ c_compiler=`ocamlc -config-var c_compiler`
+ extra_cflags=
+ case \"$architecture:$c_compiler\" in
+ arm64:*musl*) extra_cflags=-mno-outline-atomics ;;
+ esac
+ sh configure --host `ocamlc -config | awk '/^host:/ {print $NF}'` \
+ 'CC=%{cc}' CFLAGS=\"-DNDEBUG $extra_cflags\" --silent --enable-silent-rules")
(ignore-outputs (bash
"$([ '%{os_type}' = Unix ] && echo %{make} || echo make) V=0 -j 4 \
-o aclocal.m4 -o Makefile.in -o configure \
42 changes: 42 additions & 0 deletions .github/opam-repository/packages/luv/luv.0.5.14/opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
opam-version: "2.0"
name: "luv"
version: "0.5.14"
synopsis: "Binding to libuv: cross-platform asynchronous I/O"
description: """\
Luv is a binding to libuv, the cross-platform C library that does
asynchronous I/O in Node.js and runs its main loop.

Besides asynchronous I/O, libuv also supports multiprocessing and
multithreading. Multiple event loops can be run in different threads. libuv also
exposes a lot of other functionality, amounting to a full OS API, and an
alternative to the standard module Unix."""
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
authors: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
homepage: "https://github.com/aantron/luv"
doc: "https://aantron.github.io/luv"
bug-reports: "https://github.com/aantron/luv/issues"
depends: [
"base-unix" {build}
"ctypes" {>= "0.14.0"}
"dune" {>= "2.7.0"}
"ocaml" {>= "4.03.0"}
"alcotest" {with-test & >= "0.8.1"}
"base-unix" {with-test}
"odoc" {with-doc & = "2.4.0"}
]
build: ["dune" "build" "-p" name "-j" jobs]
patches: ["arm64-musl-outline-atomics.patch"]
extra-files: [
[
"arm64-musl-outline-atomics.patch"
"sha256=c15c4c4d34c9b545197c5160e19c69a128cc186b65a54e0e9a779c2543528a4f"
]
]
dev-repo: "git+https://github.com/aantron/luv.git"
url {
src:
"https://github.com/aantron/luv/releases/download/0.5.14/luv-0.5.14.tar.gz"
checksum:
"sha256=8e01b4a50c8876cdd98d8e245c0687c4dc4d883aed161ad9c5ace1fb1fdaae99"
}
1 change: 1 addition & 0 deletions .github/opam-repository/repo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
opam-version: "2.0"
62 changes: 60 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ jobs:
dune-profile: release

# Verify that the compiler still builds with the oldest OCaml version we support.
# Steps comparing OCaml and Rust rewatch are skipped on this job; the
# first linux-x64 job runs them.
- os: ubuntu-24.04
ocaml_compiler: ocaml-variants.5.0.0+options,ocaml-option-static
node-target: linux-x64
Expand Down Expand Up @@ -218,8 +220,64 @@ jobs:
run: echo "C:\Program Files\Git\bin" >> $GITHUB_PATH
shell: bash

- name: Run rewatch tests
run: ./rewatch/tests/suite.sh rewatch/target/release/rescript
- name: Run OCaml rewatch parity tests
if: ${{ !contains(matrix.ocaml_compiler, '5.0.0') }}
timeout-minutes: 20
run: |
bash rewatch-ocaml/tests/check_canonical_test_coverage.sh
bash rewatch-ocaml/tests/check_config_acceptance.sh \
packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \
packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
bash rewatch-ocaml/tests/check_command_validation.sh \
packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \
packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

- name: Run OCaml rewatch interactive output tests
# Terminal rendering depends on the host OS, not the CPU architecture.
# Use the faster ARM runners for one Linux and one macOS check. Windows
# does not provide a reliable native equivalent of the `script` PTY.
if: matrix.node-target == 'linux-arm64' || matrix.node-target == 'darwin-arm64'
timeout-minutes: 15
run: |
bash rewatch-ocaml/tests/check_interactive_output.sh \
packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \
packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

- name: Run OCaml rewatch verbose output tests
if: ${{ !contains(matrix.ocaml_compiler, '5.0.0') }}
timeout-minutes: 10
run: |
bash rewatch-ocaml/tests/check_verbose_output.sh \
packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \
packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

- name: Run OCaml rewatch unit tests
timeout-minutes: 10
run: |
opam exec -- dune build tests/rewatch_ounit_tests/rewatch_ounit_tests_main.exe
# Run the executable directly so a stuck test leaves live progress;
# dune otherwise buffers the test output until the action exits.
opam exec -- ./_build/default/tests/rewatch_ounit_tests/rewatch_ounit_tests_main.exe -runner sequential
shell: bash

- name: Run OCaml rewatch focused integration tests
timeout-minutes: 30
run: |
sh rewatch-ocaml/tests/run.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

- name: Run OCaml rewatch canonical tests
run: ./rewatch/tests/suite.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

# The Rust implementation is kept for comparison. One platform runs its
# shared suite; the parity steps exercise it on every platform.
- name: Run Rust rewatch reference tests
if: matrix.node-target == 'linux-arm64'
run: ./rewatch/tests/suite.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe
shell: bash

- name: Run syntax benchmarks
Expand Down
11 changes: 7 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ The Makefile’s targets build on each other in this order:

1. `yarn-install` runs automatically for targets that need JavaScript tooling (lib, playground, tests, formatting, etc.).
2. `build` (default target) builds the toolchain binaries (all copied into `packages/@rescript/<platform>/bin`):
- `compiler` builds the dune executables (`bsc`, `rescript-*`, `ounit_tests`, etc.).
- `rewatch` builds the Rust-based ReScript build system and CLI.
- `compiler` builds the dune executables (`bsc`, `rescript-*`, `ounit_tests`, etc.), including the OCaml build system and CLI (`rescript`).
- `rewatch` builds the Rust implementation of the build system (`rescript-rust`).
3. `lib` uses those toolchain outputs to build the runtime sources.
4. Test targets (`make test`, `make test-syntax`, etc.) reuse everything above.

## Area guidance

Before changing a subsystem, read its local agent instructions and area guide.
For compiler changes, read [compiler/AGENTS.md](compiler/AGENTS.md). For build
system changes, read [rewatch/AGENTS.md](rewatch/AGENTS.md). These apply even
system changes, read [rewatch-ocaml/AGENTS.md](rewatch-ocaml/AGENTS.md) for the
OCaml implementation and [rewatch/AGENTS.md](rewatch/AGENTS.md) for the Rust
one. These apply even
when the task starts at the repository root. Changes spanning areas need the
relevant guidance from each.

Expand All @@ -45,7 +47,8 @@ relevant guidance from each.
- [`compiler/core/README.md`](compiler/core/README.md) for Lambda
optimization and JavaScript generation
- [`analysis/README.md`](analysis/README.md) for editor analysis
- [`rewatch/README.md`](rewatch/README.md) for the build system
- [`rewatch-ocaml/README.md`](rewatch-ocaml/README.md) and
[`rewatch/README.md`](rewatch/README.md) for the build system
- [`tools/README.md`](tools/README.md) for `rescript-tools`

## Coding guidelines
Expand Down
20 changes: 13 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ $(YARN_INSTALL_STAMP): $(YARN_INSTALL_SOURCES)

REWATCH_SOURCES = $(shell find rewatch/src -name '*.rs') rewatch/Cargo.toml rewatch/Cargo.lock
RESCRIPT_EXE = $(BIN_DIR)/rescript.exe
RESCRIPT_RUST_EXE := $(BIN_DIR)/rescript-rust.exe
PACKAGED_RUST_EXE := $(RESCRIPT_RUST_EXE)
ifdef CI
REWATCH_PROFILE := release
REWATCH_CARGO_FLAGS := --release
Expand All @@ -88,22 +90,22 @@ else
endif
REWATCH_TARGET := rewatch/target/$(REWATCH_PROFILE)/rescript$(PLATFORM_EXE_EXT)

rewatch: $(RESCRIPT_EXE)
rewatch: $(PACKAGED_RUST_EXE)

$(RESCRIPT_EXE): $(REWATCH_TARGET)
$(PACKAGED_RUST_EXE): $(REWATCH_TARGET)
$(call COPY_EXE,$<,$@)

$(REWATCH_TARGET): $(REWATCH_SOURCES)
cargo build --manifest-path rewatch/Cargo.toml $(REWATCH_CARGO_FLAGS)

clean-rewatch:
cargo clean --manifest-path rewatch/Cargo.toml && rm -rf rewatch/target && rm -f $(RESCRIPT_EXE)
cargo clean --manifest-path rewatch/Cargo.toml && rm -rf rewatch/target && rm -f $(PACKAGED_RUST_EXE)

# Compiler

COMPILER_SOURCE_DIRS := compiler tests analysis tools
COMPILER_SOURCES = $(shell find $(COMPILER_SOURCE_DIRS) -type f \( -name '*.ml' -o -name '*.mli' -o -name '*.dune' -o -name dune -o -name dune-project \))
COMPILER_BIN_NAMES := bsc rescript-editor-analysis rescript-tools
COMPILER_SOURCE_DIRS := compiler tests analysis tools rewatch-ocaml
COMPILER_SOURCES = $(shell find $(COMPILER_SOURCE_DIRS) -type f \( -name '*.ml' -o -name '*.mli' -o -name '*.c' -o -name '*.h' -o -name '*.dune' -o -name dune -o -name dune-project \))
COMPILER_BIN_NAMES := bsc rescript-editor-analysis rescript-tools rescript
COMPILER_EXES := $(addsuffix .exe,$(addprefix $(BIN_DIR)/,$(COMPILER_BIN_NAMES)))

compiler: $(COMPILER_EXES)
Expand Down Expand Up @@ -279,9 +281,13 @@ COVERAGE_TEST_ENV := BISECT_FILE=$(COVERAGE_BISECT_PREFIX) BISECT_SILENT=YES
.PHONY: coverage-build
coverage-build: | $(YARN_INSTALL_STAMP)
dune build --instrument-with bisect_ppx
@$(foreach bin,$(COMPILER_BIN_NAMES), \
@$(foreach bin,$(filter-out rescript,$(COMPILER_BIN_NAMES)), \
cp $(DUNE_BIN_DIR)/$(bin)$(PLATFORM_EXE_EXT) $(BIN_DIR)/$(bin).exe && \
chmod 755 $(BIN_DIR)/$(bin).exe;)
ifneq ($(OS),Windows_NT)
cp _build/default/rewatch-ocaml/rescript_ocaml.exe $(RESCRIPT_EXE)
chmod 755 $(RESCRIPT_EXE)
endif

.PHONY: coverage-prepare
coverage-prepare: clean-coverage coverage-build
Expand Down
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"!**/tests/tests/**/src",
"!**/tests/tools_tests/**/src",
"!**/rewatch",
"!**/rewatch-ocaml",
"!**/lib/es6",
"!**/lib/js",
"!**/lib/bs",
Expand Down
1 change: 1 addition & 0 deletions changes/ocaml-rewatch-strict-config.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- The OCaml build system rejects duplicate keys in `rescript.json` maps, a `namespace-entry` without a namespace, and a value after `--no-timing`. https://github.com/rescript-lang/rescript/pull/8780
1 change: 1 addition & 0 deletions changes/ocaml-rewatch.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- `rescript` now runs a build system rewritten in OCaml; the Rust implementation remains available as `rescript-rust`. https://github.com/rescript-lang/rescript/pull/8780
1 change: 1 addition & 0 deletions cli/common/bins.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ exports.rescript_editor_analysis_exe = path.join(
);
exports.rescript_tools_exe = path.join(binDir, "rescript-tools.exe");
exports.rescript_exe = path.join(binDir, "rescript.exe");
exports.rescript_rust_exe = path.join(binDir, "rescript-rust.exe");

function checkNodeVersionSupported() {
if (
Expand Down
1 change: 1 addition & 0 deletions cli/common/bins.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export {
bsc_exe,
rescript_editor_analysis_exe,
rescript_exe,
rescript_rust_exe,
rescript_tools_exe,
} from "./bins.cjs";
72 changes: 72 additions & 0 deletions cli/common/runBuildSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// @ts-check

import * as child_process from "node:child_process";
import { runtimePath } from "./runtime.js";

/** @type {Record<string, number>} */
const signalToNumber = { SIGINT: 2, SIGTERM: 15, SIGHUP: 1, SIGQUIT: 3 };

/**
* Run a build-system executable with the package runtime and forward terminal
* signals so watch mode can clean up before the Node launcher exits.
*
* @param {string} executable
*/
export function runBuildSystem(executable) {
const child = child_process.spawn(executable, process.argv.slice(2), {
stdio: "inherit",
env: { ...process.env, RESCRIPT_RUNTIME: runtimePath },
});

let forwardedSignal = false;
/** @param {NodeJS.Signals} signal */
const handleSignal = signal => {
if (forwardedSignal) return;
forwardedSignal = true;
// Ctrl+C is delivered to every process attached to the Windows console.
// child.kill("SIGINT") uses TerminateProcess there and can kill the build
// system before its console handler releases locks and owned descendants.
if (process.platform === "win32" && signal === "SIGINT") return;
try {
if (child.exitCode === null && child.signalCode == null) {
child.kill(signal);
}
} catch {
// Signal forwarding is best effort if the child exited concurrently.
}
};

process.on("SIGINT", handleSignal);
process.on("SIGTERM", handleSignal);
process.on("SIGHUP", handleSignal);
process.on("SIGQUIT", handleSignal);

process.on("exit", () => {
if (child.exitCode === null && child.signalCode == null) {
try {
child.kill("SIGTERM");
} catch {
// The child may already have exited.
}
}
});

child.on("exit", (code, signal) => {
process.removeListener("SIGINT", handleSignal);
process.removeListener("SIGTERM", handleSignal);
process.removeListener("SIGHUP", handleSignal);
process.removeListener("SIGQUIT", handleSignal);

if (signal) {
const number = signalToNumber[signal];
process.exit(typeof number === "number" ? 128 + number : 1);
} else {
process.exit(typeof code === "number" ? code : 0);
}
});

child.on("error", error => {
console.error(error?.message ?? String(error));
process.exit(1);
});
}
8 changes: 8 additions & 0 deletions cli/rescript-rust.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env node

// @ts-check

import { rescript_rust_exe } from "./common/bins.js";
import { runBuildSystem } from "./common/runBuildSystem.js";

runBuildSystem(rescript_rust_exe);
Loading
Loading