跳到正文
cccskills
免费在 GitHub 公开

Building

All documentation related to building and running Project or Tests

中文简介正在准备中。当前显示原文说明。

chemicallang/chemical星标 31(GitHub 31 + cccskills 0)

实测评分 未实测

查看安装方法

包含的文件(1)

  • SKILL.md16.8 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Building

Its likely user is using CLion, in this case in the root dir, you'll find cmake-build-debug where there are two compilers present

  • TCCCompiler (the compiler that embeds Tiny CC)
    • This compiler cannot create llvm ir, It translates Chemical to C and then compiles that using Tiny CC
    • This compiler is faster to build, faster at compilation but generates slower code.
  • Compiler (the compiler that embeds LLVM/Clang and Tiny CC)
    • This compiler can do anything TCCCompiler can do and more, It performs optimizations using LLVM. But you
    • can also tell it to use Tiny CC with flag --use-tcc or ask it to translate to C and then compile that using
    • clang with flag --use-c
    • This compiler takes time to build, slow at compilation but generates fast code

It's likely that you don't need to rebuild the compiler, because you are working on libraries (lang/libs/<library> or lang/compiled/<library>). To properly understand building of the compilers, You should analyze the CMakeLists.txt in the root of the repo.

If you are working on any code that doesn't interact with LLVM/Clang then you should not compile Compiler target. you should focus on TCCCompiler which would build faster and would compile faster.

Configuration

# Configure with LLVM support (default)
./scripts/configure.sh

# Configure without LLVM (TCCCompiler only)
./scripts/configure.sh --no-llvm

# Configure with AddressSanitizer enabled
cmake -S . -B cmake-build-debug -DENABLE_ASAN=ON

AddressSanitizer (ASAN)

ASAN detects memory errors at runtime: heap-buffer-overflow, use-after-free, stack-use-after-scope, new-delete-type-mismatch, and more.

How it works

ASAN is a compile-time instrumentation of the compiler binary itself. When enabled, the compiler's C++ code is instrumented so that every memory access is checked. The compiler can then be used normally — ASAN reports errors while the compiler processes your Chemical project.

Setup

# One-time: configure with ASAN
cmake -S . -B cmake-build-debug -DENABLE_ASAN=ON

# Build the compiler
./scripts/build.sh --tcc

Usage

# Run the compiler on any project — ASAN is active automatically
cmake-build-debug/TCCCompiler lang/compiled/cdm/chemical.mod -o lang/compiled/cdm/bin/cdm --mode debug_quick --no-cache

# Run on tests
cmake-build-debug/TCCCompiler lang/tests/build.lab -arg-minimal -bm -v --assertions --mode debug_complete --no-cache

# Suppress specific error types via environment variable
ASAN_OPTIONS=new_delete_type_mismatch=0 cmake-build-debug/TCCCompiler ...

Error types ASAN catches

ErrorWhat it means
heap-buffer-overflowWriting past the end of a heap allocation
stack-use-after-scopeReading a local variable after its scope ended
new-delete-type-mismatchdelete called with wrong type size (missing virtual destructor)
use-after-freeAccessing memory after it was freed
stack-buffer-overflowWriting past the end of a stack buffer

Tips

  • ASAN adds ~2x memory overhead and ~1.5x slowdown — acceptable for debugging
  • LeakSanitizer (part of ASAN) reports memory leaks at exit — these are often expected for arena allocators and long-lived compiler objects
  • Combine with ASAN_OPTIONS env var to suppress known/non-critical errors while focusing on the real bug
  • The ASAN binary is the same cmake-build-debug/TCCCompiler — no separate binary needed

Building Compiler

There are three CMake targets: TCCCompiler, Compiler, and ChemicalLsp.

Using build scripts (recommended)

./scripts/build.sh --tcc   # Build TCCCompiler only
./scripts/build.sh --llvm  # Build Compiler (LLVM/Clang backend)
./scripts/build.sh --lsp   # Build ChemicalLsp
./scripts/build.sh --all   # Build all targets
./scripts/build.sh --llvm -j 16  # Build with 16 parallel jobs

Using make directly

make -C cmake-build-debug Compiler -j$(nproc)
make -C cmake-build-debug TCCCompiler -j$(nproc)
make -C cmake-build-debug ChemicalLsp -j$(nproc)

Notes

  • Prefer building one target at a time, not all.
  • The Makefile is at cmake-build-debug/Makefile (configured by CLion).
  • cmake is at /opt/clion/bin/cmake/linux/x64/bin/cmake (not in PATH).
  • out/host contains LLVM/Clang Libraries — do not overwrite.
  • If user doesn't have LLVM, use ./scripts/configure.sh --no-llvm (sets -DBUILD_COMPILER=OFF).

Building Tests

⚠️ AI agents must NOT run ./scripts/test.sh --all. It runs every suite and is only for a human doing a fresh-clone/new-machine sanity check; it takes a very long time (tls alone runs for minutes). Run the single suite relevant to your change instead and stop. If a human runs --all, note the slow tls suite is skipped unless --include-tls is passed.

Using test script (recommended)

# Build TCCCompiler, compile tests, run them
./scripts/test.sh --tcc

# Build Compiler, compile tests, run them
./scripts/test.sh --llvm

# Include library tests
./scripts/test.sh --tcc --plugins

# Process + environment library tests (no special system deps)
./scripts/test.sh --tcc --process

# Webview library tests (requires GTK3 + WebKit2GTK to link/run)
./scripts/test.sh --tcc --webview

# Universal component tests in a real WebView (#universal_test; needs a display)
./scripts/test.sh --tcc --universal

# Negative (compiler-failure verification) tests
./scripts/test.sh --tcc --negative

# Forward a target triple to the compiler (omitted unless specified)
./scripts/test.sh --tcc --process --target x86_64-linux-gnu

# Custom output path
./scripts/test.sh --tcc -o my_tests

# Build only (no run)
./scripts/test.sh --tcc --no-run

# Skip compiler rebuild, use existing binary
./scripts/test.sh --tcc --no-build

# Run tests under GDB batch mode to capture backtrace on crash:
./scripts/test.sh --tcc --bt          # gdb -batch, print bt full
./scripts/test.sh --tcc --bt-full     # gdb -batch with full bt, registers, disasm

🐛 -bt / -bt-full: These flags wrap the test executable in gdb -batch mode. On crash, they print a backtrace (and optionally registers, disassembly, locals). Implies -g automatically. Works for both compiled and interpretation modes.

  • -bt → gdb -batch -ex "run" -ex "bt full" --args <program>
  • -bt-full → gdb -batch -ex "run" -ex "thread apply all bt full" -ex "info registers" -ex "x/16i $pc" -ex "info locals" -ex "info args" --args <program>

⚠️ --no-build warning: This flag skips rebuilding the C++ compiler binary. Any changes to .cpp/.h files will NOT be reflected — the previously built binary is used as-is. Only use --no-build when iterating on .ch test files or Chemical library sources without any compiler C++ changes. To include C++ changes, omit --no-build (or run once without it to rebuild, then you can use --no-build for subsequent iterations).

Manual commands

# TCC backend
cmake-build-debug/TCCCompiler "lang/tests/build.lab" -o lang/tests/build/tests-tcc.exe --mode debug_quick --no-cache

# LLVM backend
cmake-build-debug/Compiler "lang/tests/build.lab" -o lang/tests/build/tests.exe --mode debug_complete --no-cache

Interpretation Tests

./scripts/test.sh --tcc --interpret        # Build TCC + run interpretation tests
./scripts/test.sh --tcc --interpret --no-build  # Skip rebuild

# Manual:
./chemical lang/tests/build.lab --arg-interpret --mode debug_complete --no-cache

The --arg-interpret flag causes build.lab to create a LabJobType::Interpretation job. The compiler calls do_interpretation_job() in compiler/lab/LabBuildCompiler.cpp, which:

  • Parses, symres, and typechecks interpret/ + common/ modules
  • Initializes module-level VarInitStmt variables on the global scope
  • Calls main() via the AST interpreter directly — no object code generated

How Tests Work

Tests use a common framework at lang/tests/common/src/test.ch that works in both modes:

comptime if(intrinsics::is_interpretation()) {
    intrinsics::expr_println(`${ANSI_COLOR_GREEN}Test ${total_tests + 1} [${name}] succeeded${ANSI_COLOR_RESET}`);
} else {
    printf("%sTest %d [%s] succeeded %s\n", ANSI_COLOR_GREEN, total_tests + 1, name, ANSI_COLOR_RESET);
}
  • Interpretation path: intrinsics::expr_println(expr: %expressive_string) walks the expressive string's parts — StringValue literals go directly to std::cout, ${} expressions are evaluated and printed via RepresentationVisitor with interpret_representation = true (no quotes).
  • Compiled path: Standard printf with ANSI escape string constants.

Compiler flags explained

  • --mode debug_quick — quickly compile the project with debug info
  • --mode debug_complete — full debug mode for LLVM backend
  • --no-cache — do not rely on previously generated objects
  • --emit-c — write the Translated.c file to the build directory
  • --arg-interpret — run in interpretation mode (interpret AST directly, no codegen)
  • --arg-test-plugins — build library tests executable
  • -frecompile-plugins — recompile compiler plugins

Building Library Tests

We test most libraries in the tests above (lang/tests/build.lab) but some libraries like:

  • html_cbi, css_cbi, js_cbi, components
  • universal_cbi

These are compiler plugins, tested via a separate executable:

# Using test script
./scripts/test.sh --tcc --plugins

# Manual
cmake-build-debug/TCCCompiler "lang/tests/build.lab" -o lang/tests/build/lib-tests-tcc.exe --mode debug_quick --no-cache --arg-test-plugins -frecompile-plugins

Helpful flags:

  • --plugin-mode debug_complete — compile plugins in debug mode for full stack traces
  • --arg-test-html, --arg-test-css, etc. — individual library tests

Building LSP

If you modify anything inside the server directory, note that it's part of the LSP target.

These modules are all LSP-related and require the LSP server running to verify:

  • html_ide, css_ide, js_ide, universal_ide, md_ide
# Build LSP
./scripts/build.sh --lsp

LSP target name is ChemicalLsp. Read CMakeLists.txt before building the LSP target.

Developing Comptime Tests

Test Structure

Interpret tests run via --arg-interpret and execute the AST interpreter directly. The entry point is:

// lang/tests/interpret/src/main.ch
public func main() {
    run_common_tests();        // Tests 1-97 (core language features)
    run_native_common_tests(); // Pointer arithmetic, casts, comptime pointers
    print_test_stats();
}
ModuleLocationWhat it tests
common_testslang/tests/common/Core features (arithmetic, loops, structs, variants, inc/dec)
native_common_testslang/tests/native_common/Pointer operations, casts, comptime pointer arithmetic
interpret_testslang/tests/interpret/Wrapper that imports both and runs main()

Comptime Test Files (in lang/tests/src/comptime/)

FileTests
basic.chBasic comptime: sum, structs, strings, enums, constructors, get_child_fn, get_line_no
features.chComptime features: bitwise ops, loops, casting, logical ops, for-in, struct mutation, destructors
expressions.chcomptime { } block expressions: arithmetic in comptime blocks
satisfies.chintrinsics::satisfies<T, U>() type relationship tests
is_value.chintrinsics::is_same_type() and is operator type identity tests
vector.chintrinsics::vector<T>() vector operations

Running Tests

# Quick iteration (interpret only, skip rebuild)
./scripts/test.sh --tcc --interpret --no-build

# Full compiled test run
./scripts/test.sh --tcc --no-build

# Both in sequence
./scripts/test.sh --tcc --interpret --no-build && ./scripts/test.sh --tcc --no-build

Adding a New Comptime Test

  1. Create the test source in lang/tests/src/comptime/ or lang/tests/common/src/:

    // lang/tests/src/comptime/my_feature.ch
    comptime func my_feature(a : int, b : int) : int {
        return a * b + a;
    }
    
    func test_my_feature() {
        test("my feature works", () => {
            return my_feature(3, 4) == 15;
        });
    }
    
  2. Register the test by calling the function from the appropriate runner:

    • For tests shared with runs: Add test_my_feature(); to run_common_tests() in lang/tests/common/src/main.ch
    • For tests with pointer arithmetic: Add to run_native_common_tests() in lang/tests/native_common/src/main.ch
    • For compiled-only tests: Add to main() in lang/tests/src/tests.ch
  3. Build and test: Use the commands above.

Common Interpreter Pitfalls

  • Pointer bounds: The interpreter tracks ahead/behind on PointerValues. Dereferencing past bounds returns null (not crash). Tests with pointer arithmetic reaching one-past-end may fail.
  • Struct pointers (&raw struct_val): Not supported in interpreter (returns error). Use &mut struct_val (ReferenceOfValue) instead, or parameter passing by reference.
  • Function references as parameters: Functions passed as (params) => return_type are called via FunctionDeclaration::call(). If the function reference can't be resolved, a non-fatal "function not found" error appears.
  • Float/Double casts: float→int and double→int are supported. Other float/double combinations work via standard arithmetic.
  • Destructors: Structs with @delete destructors have their destructor body interpreted when the scope exits. Empty destructors work fine.

Debugging Interpret Test Failures

  1. Check the test output for [InterpretError] messages — these indicate exact failures
  2. Look for "cannot dereference pointer" — pointer went past allocated bounds
  3. Look for "function call" — a function reference couldn't be resolved
  4. Look for "Operation between values" — an operation between incompatible types
  5. Add std::cerr << "[DEBUG] ..." << std::endl; to interpreter source files to trace specific operations
  6. The worst failures ("RUNTIME ERROR: invalid memory access") happen when deref() itself crashes — we've made this non-fatal by returning getNullValue() instead

Debugging with a Single Test File

Running the full test suite on every iteration is slow. Instead of working through the entire test suite, isolate the failing test by copying its source code (plus the types/functions it depends on) into a single file at lang/compiled/temp.ch. The lang/compiled/ directory is in .gitignore, so nothing there will be committed.

Workflow

  1. Copy the test — put the failing test's code into lang/compiled/temp.ch
  2. Rebuild the compiler after any C++ changes:
    ./scripts/build.sh --tcc      # For TCCCompiler
    ./scripts/build.sh --llvm     # For Compiler (LLVM)
    
  3. Compile the single file (choose one):
    • LLVM IR inspection (Compiler target):
      cmake-build-debug/Compiler "lang/compiled/temp.ch" --out-ll-all --build-dir "lang/compiled" \
          -o "lang/compiled/temp.exe" --mode debug_complete --debug-ir -v --assertions -fno-unwind-tables
      
      LLVM IR is emitted at lang/compiled/modules/main/llvm_ir.ll
    • C translation (TCCCompiler target):
      # Produce .c output:
      cmake-build-debug/TCCCompiler "lang/compiled/temp.ch" -o "lang/compiled/temp.c" -v -bm-modules
      # Or produce an executable:
      cmake-build-debug/TCCCompiler "lang/compiled/temp.ch" -o "lang/compiled/temp.exe" -v -bm-modules
      
  4. Run the executable: ./lang/compiled/temp.exe
  5. Inspect the generated IR / C to diagnose codegen bugs
  6. Add debug logs to the compiler source, rebuild, and repeat

Flags Explained

  • --mode debug_complete — maximum debug info in LLVM IR; omit for cleaner IR without metadata
  • --mode debug_quick — minimal debug info (good for TCCCompiler)
  • --debug-ir — don't crash on potentially bad IR
  • --assertions — verify the generated IR is valid
  • -fno-unwind-tables — cleaner IR (removes unwind data on Windows)
  • -v — verbose output
  • -bm-modules — emit build module information

⚠️ Always rebuild the compiler (./scripts/build.sh --tcc or --llvm) after changing .cpp/.h files. The previously built binary is used otherwise and your changes won't be reflected.

Related Skills

  • Build System (.agents/skills/build_system/SKILL.md) — Detailed internals of the Lab build system, job execution, plugin compilation, caching, dependency management
  • Performance (.agents/skills/performance/SKILL.md) — Compiler optimization patterns, parallelization strategies, arena allocation
  • Testing Guide (.agents/skills/testing/SKILL.md) — Test infrastructure, writing tests, how tests are wired in lang/tests/build.lab

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Comprehensive guide to the Chemical compiler's annotation system (`@name`, `@name(args)`) — how annotations are lexed, parsed, registered in the `AnnotationController`, stored and queried centrally, consumed by the compiler and CBI plugins, and how to add a new one. Load when working on annotations, `AnnotationController`, compiler plugins that define/read annotations, or node attribute flags such as `@extern`, `@test`, `@make`, `@deprecated`, `@no_mangle`, `@inline`, and `@volatile`.

中文简介正在准备中。当前显示原文说明。

chemicallang/chemical312026年10月26日 更新

The C++ AST node framework of the Chemical compiler — the ASTAny/ASTNode/Value/BaseType hierarchy, node/value/type kind enums and range predicates, the visitor dispatch framework, the arena allocator, TypeBuilder canonicalization, member containers, and cross-reference resolution. Load when adding or modifying AST nodes, writing compiler passes/codegen visitors, debugging kind mismatches or arena/lifetime issues, or extending the compiler API bindings.

中文简介正在准备中。当前显示原文说明。

chemicallang/chemical312026年10月26日 更新

The Chemical compiler benchmark & release analytics system — how the static GitHub Pages dashboard works, the JSON data model (manifest/daily/release records), the bash collection scripts (bench-*.sh), the GitHub Actions workflows (benchmark-daily/release), and the critical pitfalls (hidden upload dirs, worktree submodules, gh-pages-only data). Load when working on the dashboard, benchmark collection, or analytics workflows.

中文简介正在准备中。当前显示原文说明。

chemicallang/chemical312026年10月26日 更新

Comprehensive deep-dive into the Chemical build pipeline — how chemical.mod is converted to build.lab, how build scripts are JIT-compiled via TinyCC, how jobs are created and executed, and how ASTProcessor orchestrates the parallel compilation passes.

中文简介正在准备中。当前显示原文说明。

chemicallang/chemical312026年10月26日 更新

Comprehensive guide to the C translation backend (2c) — how Chemical AST is translated to C code, key patterns, gotchas, and optimization strategies.

中文简介正在准备中。当前显示原文说明。

chemicallang/chemical312026年10月26日 更新

The compiler-side machinery of the Chemical Compiler Binding Interface (CBI) — the CompilerBinder/CBIData/CBIFunctionIndex model, the full CBIFunctionType hook enum and where each fires, the extern "C" bindings dispatch tables in CBI.cpp, ASTBuilder/ASTCBI/PtrVec/BatchAllocator/SourceProvider/ASTDiagnoser wrappers, the TinyCC JIT bridge and LabBuildCompiler plugin compilation/indexing, the enum-sync rule, and how to add a new CBI binding. Load when modifying the CBI model/bindings layer, adding compiler hooks or bindings, debugging plugin ABI/symbol issues, or trying to understand how the compiler calls into Chemical plugin code.

中文简介正在准备中。当前显示原文说明。

chemicallang/chemical312026年10月26日 更新

查看 chemicallang 的全部技能

报告此技能的问题