Files
explorer/Makefile
zooqueen f3bf55b0b9 feat(ffi): run Blockscout-rs explorer services in-process via cgo (single binary)
Make the explorer ONE binary that runs the Rust Blockscout-rs services
in-process via FFI — not by rewriting them in Go and not by exec'ing
subprocesses. The real Rust service entrypoints run on their own Tokio
runtime threads inside the Go binary.

- ffi/ — one C-ABI staticlib (crate-type=["staticlib"]) wrapping the
  service crates by path (../../explorer-rs/<svc>). One staticlib = one
  Rust std/panic runtime, no duplicate-symbol conflicts. A `service!`
  macro is the single place that bridges a service: parse Settings JSON,
  spawn a dedicated OS thread with a multi-thread Tokio runtime, run the
  service's real entrypoint. Exports lux_explorer_start_<svc>() +
  lux_explorer_start_all(). Disabled services still export their symbol
  and return LUX_FFI_ERR_DISABLED so the Go side links identically.
  sig-provider is wired and proven first (stateless, fastest to build);
  the other four services' deps/features/service! blocks are written out
  commented with confirmed entrypoint signatures for mechanical scale-out.

- ffi_on.go (//go:build ffi) — cgo preamble (-llux_explorer_ffi + the
  darwin/linux system libs the Rust graph needs) + extern decls;
  startFFIServices() launches the services at startup from main().
- ffi_off.go (//go:build !ffi) — no-op fallback so plain `go build ./...`
  compiles WITHOUT the staticlib present.

- Makefile `make single` = cargo build --release in ffi/ then
  go build -tags ffi. ffi/README.md documents the C ABI, the protoc /
  protoc-gen-openapiv2 build-tool prereqs, the seeded Cargo.lock, and the
  one-service-at-a-time scale-out recipe.

Verified: default `go build ./...` exits 0; ffi/ staticlib compiles with
sig-provider linked (.a 7.9MB shim -> 58MB with service); cgo -tags ffi
links it into the binary (symbols present via nm); the single binary boots
and logs `[ffi] start sig-provider -> ok (0)` with the service running
in-process. go vet clean under both build tags.
2026-06-23 21:06:50 -07:00

48 lines
1.5 KiB
Makefile

# Lux explorer build.
#
# Two binaries from one source tree, selected by the `ffi` build tag:
#
# make build Default Go-native explorer (indexer + graph + SPA + realtime).
# No Rust, no cgo. This is what `go build ./...` produces.
#
# make single THE single all-in-one binary: builds the Rust FFI staticlib
# (ffi/ -> liblux_explorer_ffi.a) then links it into the Go
# binary with cgo (-tags ffi), so the Blockscout-rs services
# (sig-provider, …) run IN-PROCESS. One binary runs everything.
#
# Scale services out by enabling more cargo features (see ffi/README.md):
# make single FFI_FEATURES=sig-provider,stats,visualizer
BIN ?= explorer
FFI_DIR := ffi
FFI_LIB := $(FFI_DIR)/target/release/liblux_explorer_ffi.a
# Cargo features = which Rust services get compiled into the staticlib.
# `all` = every wired service. Override on the CLI to scope the build.
FFI_FEATURES ?= all
.PHONY: build single ffi-lib clean test fmt
build:
go build -o $(BIN) .
# Step 1: build the Rust staticlib with the requested services.
ffi-lib:
cd $(FFI_DIR) && cargo build --release --features $(FFI_FEATURES)
# Step 2: link it into the Go binary via cgo. The -tags ffi build compiles
# ffi_on.go (cgo preamble + extern decls) instead of the ffi_off.go stub.
single: ffi-lib
go build -tags ffi -o $(BIN) .
@echo "built single all-in-one binary: ./$(BIN) (features: $(FFI_FEATURES))"
test:
go test ./...
fmt:
go fmt ./...
cd $(FFI_DIR) && cargo fmt
clean:
rm -f $(BIN)
cd $(FFI_DIR) && cargo clean