← SuperJ Manual

The Build System

SuperJ ships a Cargo-inspired build tool built into the superj binary. For a single file you can still call superj compile … && clang … by hand (see Getting Started), but for anything with more than one source file or a dependency, use the build system: it owns the project layout, dependency resolution, linking, and a reproducible lockfile, so you never write a clang line yourself.

The build tool is superj itself — there is no separate toolchain to install and nothing else to run. It compiles your project in SuperJ, in-process, and links with your system C compiler. superj --help lists every command.

This page is the how-to; superj --help lists every subcommand and flag.

A first project

superj new hello
cd hello
superj run

superj new scaffolds:

hello/
  Build.sj                 # the manifest (see below)
  src/hello/Main.sj        # package hello; public class Main { … main … }
  .gitignore               # ignores target/

superj run builds to target/debug/hello and executes it. superj build just builds; superj build --release uses the release profile.

The manifest — Build.sj

The manifest is ordinary SuperJ source at the project root, read by parsing (never executing) a public class Build for well-known static final fields:

public class Build {
    static final String   name    = "hello";
    static final String   version = "0.1.0";
    static final String   spec    = "1.0";              // language spec version targeted
    static final String   entry   = "hello.Main";       // fully-qualified main class

    // dependencies (all optional; see "Dependencies")
    static final String[] dependencies    = { "util", "../util" };                    // path
    static final String[] gitDependencies = { "json", "http://…/sj-json", "v1.0.0" }; // git

    // release-profile knobs
    static final String   releaseSimd        = "avx2";
    static final boolean  releaseBoundsCheck = false;
    static final int      releaseOpt         = 3;
}

Source lives under src/, with the usual package x.y; ⇔ path rule (src/hello/Main.sjpackage hello;). Unknown manifest fields are ignored, so newer manifests stay readable by older toolchains.

Commands

CommandWhat it does
superj new <name>Scaffold a new project.
superj build [--release] [--enterprise]Compile + link to target/{debug,release}/<name>.
superj run [--release] [-- <args>]Build, then run the binary (args after -- are forwarded).
superj checkType-check the whole project — no codegen or link.
superj test [-p <member>]Compile the package's library into each // UNIT suite under test/ and run them (see Writing & Running Tests).
superj add <name> <path>Add a path dependency to Build.sj. (--git <url> --rev <rev> for a git dep.)
superj cleanRemove target/.
superj --helpList every compiler and build-system command.

Dependencies

SuperJ compiles whole-program: a dependency's source is compiled into your program (there is no per-package binary ABI — that is why deps ship as source). Two kinds, both resolved into one merged compile:

Each resolved dependency — its path or git url+commit, and a content hash — is recorded in superj.lock, which you commit for reproducible builds.

(A package registry — and superj publish — is intentionally out of scope: it's a separate project. Use path and git dependencies.)

Workspaces

Group several packages under one repository. Declare members in a root Build.sj (which has no name/entry of its own — just the member list):

public class Build {
    static final String[] workspaceMembers = { "app", "libs/util" };
}

superj build/check/test from the workspace root act on all members (or one with -p <member>); superj run from the root needs -p <member> (or a single-member workspace). Run any command from inside a member directory and it acts on just that member, exactly like a standalone project. Members depend on each other as ordinary path deps, and a member that is a library (no entry) is type-checked rather than linked (it has no runnable artifact under whole-program compilation — it links into its consumers as source).

Profiles

dev (the default) builds with array bounds checks on and portable SIMD. --release applies the manifest's release* fields: releaseSimd--simd, releaseBoundsCheck = false--no-bounds-check, and releaseOpt → the link optimization level (clang -O<n>, clamped 0–3). The compiler always passes -O3 to clang at link time (unless --debug); releaseOpt is reserved for future fine-grained control.

Enterprise (whole-program LTO)

--enterprise enables whole-program optimization: the compiler emits the SDK external, then llvm-links the prebuilt sdk.ll with your IR and clang -O3s the merged module — cross-CU inlining and devirtualization across the SDK boundary. Best runtime performance, slower link time.

superj build --enterprise                # dev + LTO
superj build --release --enterprise      # release profile + LTO (max performance)

The build tool auto-detects the installed SDK variant from what's in $SJ_HOME/sdk/build/: libsuperj_sdk.a → community, sdk.ll → enterprise, neither → vip (--sdk-source). An explicit --enterprise overrides auto-detection. You normally don't need to think about it — superj build/run emit the correct link line for whichever variant you installed.

Build hooks (code generation)

Set buildScript = "tools/Gen.sj" to a standalone SuperJ program (with a main, living outside src/). Before each build it is compiled and run with the path to a generated-sources directory; every .sj it writes there is folded into the build. The hook is cached by its source hash. (This is the only place build code runs — the manifest itself is never executed.)

Feature flags

Conditionally compile optional source directories:

static final String[] features        = { "json", "features/json", "tls", "features/tls" };
static final String[] defaultFeatures = { "json" };

An enabled feature's directory joins the build. Select with --features a,b, --no-default-features, or --all-features. (Granularity is whole source files, not in-file #[cfg].)

SDK linking

The standard library is an implicit, toolchain-pinned dependency. The build tool picks the SDK mode for you — the community archive by default, or --enterprise for whole-program LTO — and emits the correct, OS-specific link line. You never spell out clang or the runtime objects.

SuperJ — manual · generated from build-system.md at pack time