Q+ 文档

Q+ Quick Start (10 minutes)

This guide takes you from a source checkout to a running Q+ program, including a native ELF build, on a Linux x86-64 machine with gcc and bash. It takes about ten minutes, most of which is reading.

The commands below are for Q+ Language 1.1.0-dev (language specification v4.36). Run them from the repository root (the directory that contains tools/ and src/), or set QPLUS_ROOT to the repository root if you run from elsewhere.

1. Get the source

Use the release source archive:

tar xzf qplus-language-1.1.0-dev-release.tar.gz
cd qplus-language-1.1.0-dev

or a Git clone of the repository:

git clone <repository-url> qplus
cd qplus

The directory name does not matter; everything below uses paths relative to the repository root.

2. Build the toolchain

tools/build.sh

The script builds the bytecode VM from C sources, self-hosts the compiler with a two-step bootstrap, and rebuilds the AOT toolchain. It takes about 20–30 seconds on a typical machine and prints the SHA-256 checksums of the artifacts:

ArtifactPurpose
build/bqvmBytecode virtual machine
build/qboot.qbcSelf-hosted compiler
build/cgtest.qbc / build/cgtest_aotAOT compiler / ELF backend
build/stage0.qbcCapacity-only bootstrap compiler
build/bqvm_smallSmall-heap VM used by the heap-exhaustion regression

On the reference Linux x86-64 toolchain a clean build produces:

build/bqvm        c94042851edc62bb04d30bbf2cee32fa4b650a6816806991ed3a910459321fe0
build/qboot.qbc   378f5f858d8553760ae4b55aecac7773cdbec6386a6a986dd34a51d722175b34
build/cgtest.qbc  f2f24e897891cb48159d784bce282909820c2f7974eeee574f2e3d431cd6eec1
build/cgtest_aot  7ca041362c45bd8759077595abdc68429e8961ef3cc0ca01ddbf147e0ebdb316

build/qboot.qbc is deterministic and is the reproducibility anchor; if it does not match, see BUILDING.en.md. The checksum of build/bqvm can legitimately differ with a different host C toolchain.

3. Write your first program

Create a file named hello.q in the repository root:

fn main() -> i32 {
    print("Hello, Q+!\n")
    return 0
}

Execution starts at fn main. By convention the entry point is declared fn main() -> i32; the integer it returns becomes the process exit status. print is a language builtin: it writes its argument without adding a newline, which is why the example includes the "\n" explicitly.

4. Compile it

build/bqvm --timeout-ms 0 build/qboot.qbc hello.q -o hello.qbc

The compiler prints its phases (lexer, parser, code generation) and exits with status 0. A non-zero status means compilation failed; see common errors.

5. Run it

build/bqvm hello.qbc

Output:

Hello, Q+!

The compiled program is an ordinary file; you can copy hello.qbc to another machine and run it with the same build/bqvm binary.

Check the exit status of main:

cat > status.q <<'EOF'
fn main() -> i32 {
    return 42
}
EOF
build/bqvm --timeout-ms 0 build/qboot.qbc status.q -o status.qbc
build/bqvm status.qbc
echo $?          # 42

Two details that surprise new users:

6. Build a native ELF

build/cgtest_aot hello.qbc hello.elf
chmod +x hello.elf      # the AOT tool writes the file, not its executable bit
./hello.elf

The ELF backend is independent of the VM and produces a standalone native binary for the same QBC. Its stdout and exit status match the VM's for supported features; runtime errors also print a stderr traceback with real source lines.

The AOT backend is deliberately loud about unsupported features: it rejects programs that reference VM service builtins, extern "C" FFI shims, or std.panic at compile time with exit status 5, and writes no ELF. In particular, importing std.io pulls in VM service builtins, so AOT-friendly programs should use the print builtin as in this example. Async/thread primitives are the exception: the ELF builds, and executing such a primitive traps at runtime (AOT: async primitives unsupported, exit status 1).

# Example loud failure: std.io is a VM-service module.
cat > io_hello.q <<'EOF'
use std.io
fn main() -> i32 {
    println_str("Hello from the VM")
    return 0
}
EOF
build/bqvm --timeout-ms 0 build/qboot.qbc io_hello.q -o io_hello.qbc
build/cgtest_aot io_hello.qbc io_hello.elf   # exit status 5, no io_hello.elf

7. Explore

# Compile and run one of the 193 bundled examples.
build/bqvm --timeout-ms 0 build/qboot.qbc src/examples/fib.q -o /tmp/fib.qbc
build/bqvm /tmp/fib.qbc          # prints 6765

# Run the language regression suite (builds first if build/ is missing).
tools/test.sh                    # ends with QPLUS_LANGUAGE_TESTS_PASS

# Optional: benchmark VM vs AOT ELF vs C reference kernels.
bench/run.sh 3

Concurrency notes for v4.18 (P2-C10 safety fixes):

Common errors

MessageExit codeCause and fix
Error: expected token N got M at line L2Syntax error. Check braces and semicolons first. if and match are statements, not expressions: let x = if ... and let x = match ... do not parse. Use the cond ? a : b ternary at expression level.
Error: unknown module in 'use' ...2Only use std.<module> (or use std::<module>) is supported. Use a module that exists under stdlib/std/, and run from the repository root or set QPLUS_ROOT.
[TC1] line 5 want=i32 got=string (or [TC4], [TC2]) followed by === Compilation aborted: type errors above ===4Static type error. The message names the expected (want=) and actual (got=) types. Fix the annotation or the expression.
Error: integer literal out of range at line N type=u8 range=[0..255] [TC15]4A literal does not fit its annotated small-integer type. Small integers are checked; choose a wider type or a valid value.
Error: undefined function called at line L3A function is not visible. Add the missing use std.<module> line, check spelling, and check the argument count.
Error: failed to load QBC: unsupported extern function: <name>1The program calls an extern "C" function that is not in the VM shim whitelist (puts, strlen in this release).
Runtime error: division_by_zero: division by zero1Runtime abort. Q+ has no exceptions; guard divisors before dividing.
Runtime error: index_out_of_bounds: ...1Runtime abort. Check the index against len(array) before indexing.
Runtime error: overflow: integer overflow1A value exceeded the range of its small-integer type. Use a wider type or checked conversion.
Runtime error: assert_failed: assertion failed1The builtin assert(cond) received a falsy condition.
Runtime error: panic: <msg> (with a preceding PANIC: <msg> line)1panic() or Result unwrap on an Err was reached. Handle Result values explicitly if termination is not intended.
Runtime error: execution timeout exceeded1The program exceeded its execution limit (60 s by default). Raise or disable it with --timeout-ms 0 before the QBC argument, and check for infinite loops. Since v4.18 this also interrupts a thread blocked in a channel send/receive (reported as Runtime error: timeout: execution timeout exceeded).
Runtime error: runtime_error: thread: spawn limit exceeded (max 16 threads)1The program tried to create more than 16 threads. The limit is loud instead of returning a silent -1; reuse threads or restructure the work.
thread: join already in progress on this tid (with a [thread <tid>] prefix when raised inside a worker)1 or worker errorTwo threads tried to join the same thread concurrently. Join each thread from one owner; a repeated join from the same thread after a successful join is idempotent and returns the recorded result.
[thread <tid>] Runtime error: runtime_error: async: tasks are not supported in worker threadsprocess continuesA worker thread called an async primitive. The stackful task scheduler is main-thread-only; coordinate workers with channels and keep async tasks on the main thread.
AOT_UNSUPPORTED_BUILTIN: ... / AOT_UNSUPPORTED_OPCODE: ... from build/cgtest_aot5The ELF AOT backend does not support a feature the program references (VM service builtin such as std.io, FFI shim, panic/sys_abort, or an unsupported constant). Run on the VM or rewrite the AOT target.
Runtime error: runtime_error: AOT: async primitives unsupported (VM-only)1The ELF builds, but it executed an async/task/thread/channel primitive; those are VM-only in this release.
AOT_UNSUPPORTED_I64_CONST: integer constant outside AOT tagged-int range [-2^60, 2^60-1]5The AOT build saw an i64 constant outside the exact tagged range (v4.29), including a negative literal whose magnitude exceeds 2^60-1. No ELF is written; the VM still supports the full i64 range.
AOT_UNSUPPORTED_OPCODE: code=115A5 Stage1 supports u64 constants/print/arithmetic/comparisons in AOT; programs using A5 Stage2/3 features (casts/bitwise/std.u64/full containers) stay loud (no ELF). p05_a2_context (code=125) is such a Stage2 case.
Error: no QBC file specified1You ran bqvm without a program file, for example after a compile failed. Check that the .qbc file exists and pass it as the first argument.
gcc: command not found / a missing source: build errorvariesThe C toolchain or checkout is incomplete. Install gcc and bash, re-extract the release, and rerun tools/build.sh.
Permission denied when running a script126Run bash tools/build.sh or chmod +x tools/build.sh tools/test.sh.

If a command still fails, collect the exact command, the full output, the output of build/bqvm --version, and your gcc --version, then open an issue using the repository's issue template.

← Q+ Hub