首页 · ← SuperJ 手册 中文|EN

构建系统

SuperJ 在 superj 二进制中内置了一个受 Cargo 启发的构建工具。对于单文件,你仍然可以手动调用 superj compile … && clang …(见 快速开始),但对于多于一个源文件或带依赖的任何项目,请使用构建系统:它掌管项目布局、依赖解析、链接,以及一个可复现的 lockfile,所以你永远不需要自己写一行 clang

构建工具就是 superj 本身 — 没有独立的工具链要装,也没有别的东西要跑。它在进程内用 SuperJ 编译你的项目,并用你系统的 C 编译器链接。superj --help 列出每条命令。

本页是操作指南;superj --help 列出每个子命令与标志。

第一个项目

superj new hello
cd hello
superj run

superj new 生成脚手架:

hello/
  Build.sj                 # 清单(见下文)
  src/hello/Main.sj        # package hello; public class Main { … main … }
  .gitignore               # 忽略 target/

superj run 构建到 target/debug/hello 并执行它。superj build 只构建;superj build --release 使用 release profile。

清单 — Build.sj

清单是项目根目录下的普通 SuperJ 源码,通过解析(绝不执行)一个 public class Build 中的已知 static final 字段来读取:

public class Build {
    static final String   name    = "hello";
    static final String   version = "0.1.0";
    static final String   spec    = "1.0";              // 目标语言规格版本
    static final String   entry   = "hello.Main";       // 全限定主类

    // 依赖(全部可选;见"依赖")
    static final String[] dependencies    = { "util", "../util" };                    // 路径
    static final String[] gitDependencies = { "json", "http://…/sj-json", "v1.0.0" }; // git

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

源码位于 src/ 下,遵循通常的 package x.y; ⇔ 路径规则(src/hello/Main.sjpackage hello;)。未知的清单字段被忽略,所以较新的清单仍能被较旧的工具链读取。

命令

命令作用
superj new <name>搭建新项目。
superj build [--release] [--enterprise]编译 + 链接到 target/{debug,release}/<name>
superj run [--release] [-- <args>]构建,然后运行二进制(-- 之后的参数被转发)。
superj check对整个项目做类型检查 — 无代码生成或链接。
superj test [-p <member>]把包的库编译进 test/ 下每个 // UNIT 套件并运行(见 编写与运行测试)。
superj add <name> <path>Build.sj 添加路径依赖。(--git <url> --rev <rev> 用于 git 依赖。)
superj clean删除 target/
superj --help列出每个编译器与构建系统命令。

依赖

SuperJ 做全程序编译:依赖的源码被编译进你的程序(没有按包的二进制 ABI — 这就是依赖以源码形式发布的原因)。两种依赖,都解析进一次合并编译:

每个解析后的依赖 — 其路径或 git url+commit,以及一个内容哈希 — 都记录在 superj.lock 中,你提交它以获得可复现的构建。

(包注册中心 — 以及 superj publish — 刻意不在范围内:它是一个独立项目。请使用路径与 git 依赖。)

工作区

在一个仓库下将多个包分组。在根 Build.sj 中声明成员(它没有自己的 name/entry — 只有成员列表):

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

从工作区根目录执行 superj build/check/test 作用于所有成员(或用 -p <member> 指定一个);从根目录执行 superj run 需要 -p <member>(或单成员工作区)。从成员目录内部执行任何命令时,它只作用于该成员,完全像一个独立项目。成员之间作为普通路径依赖相互依赖,而一个成员(无 entry)只做类型检查而非链接(在全程序编译下它没有可运行产物 — 它以源码形式链接进其消费者)。

Profile

dev(默认)构建时开启数组越界检查并使用可移植 SIMD。--release 应用清单的 release* 字段:releaseSimd--simdreleaseBoundsCheck = false--no-bounds-checkreleaseOpt → 链接优化级别(clang -O<n>,钳制在 0–3)。编译器在链接时始终向 clang 传入 -O3(除非 --debug);releaseOpt 保留给将来的细粒度控制。

Enterprise(全程序 LTO)

--enterprise 启用全程序优化:编译器把 SDK 作为外部发出,然后 llvm-link 预构建的 sdk.ll 与你的 IR,再 clang -O3 合并后的模块 — 跨 SDK 边界的跨编译单元内联与去虚化。最佳运行时性能,链接时间较慢。

superj build --enterprise                # dev + LTO
superj build --release --enterprise      # release profile + LTO(最大性能)

构建工具会从 $SJ_HOME/sdk/build/ 中的内容自动检测已安装的 SDK 变体:libsuperj_sdk.a → community,sdk.ll → enterprise,两者皆无 → vip(--sdk-source)。显式的 --enterprise 覆盖自动检测。你通常不需要操心 — superj build/run 会为你安装的变体发出正确的链接行。

构建钩子(代码生成)

设置 buildScript = "tools/Gen.sj" 为一个独立的 SuperJ 程序(带 main,位于 src/ 之外)。每次构建前它被编译并运行,传入一个生成源码目录的路径;它写入那里的每个 .sj 都被纳入构建。钩子按其源码哈希缓存。(这是构建代码运行的唯一位置 — 清单本身从不被执行。)

Feature flag

有条件地编译可选源码目录:

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

启用的 feature 的目录加入构建。用 --features a,b--no-default-features--all-features 选择。(粒度是整个源码文件,不是文件内的 #[cfg]。)

SDK 链接

标准库是一个隐式的、由工具链锁定的依赖。构建工具为你选择 SDK 模式 — 默认是 community 归档,或 --enterprise 做全程序 LTO — 并发出正确的、针对 OS 的链接行。你永远不需要写明 clang 或运行时对象。

SuperJ — manual · generated from build-system.md at pack time · Powered by superJ — this site is served by superj_web 中文|EN