# AGENTS.md ## Project Overview This project is a small Rust common library and runtime built without Cargo. CMake invokes `rustc` directly. The library provides a low-footprint subset of standard-library-like functionality: - `Result`, `Duration`, and formatting from `core` - `Vec`, `String`, `vec![]`, and `format!` from `alloc` - project-local `print!` and `println!` macros - direct platform stdout, heap calls, and busy-wait sleep The project contains: - `src/lib.rs`: the `#![no_std]` common library API - `src/io.rs`: the `core::fmt::Write` stdout backend - `src/runtime.rs`: allocator, async polling, monotonic sleep, and platform entry helpers - `macros/src/lib.rs`: host-side `#[rslibc_macros::main]` attribute macro - `runtime/main.rs`: minimal example entry point - `cmake/RustLSP.cmake`: generates `rust-project.json` for rust-analyzer - `CMakeLists.txt`: direct `rustc` library, macro, and executable commands ## No-Std Design - Keep `#![no_std]` in both the library and runtime. - Do not add Rust `std` to the target library or runtime, and do not add Cargo unless explicitly requested. - The host-side procedural macro may use `proc_macro` and host libraries; it is not linked into the target executable. - `core` is allowed and is the foundation for `Result`, formatting, slices, and other basic language-library functionality. - `alloc` is allowed through `extern crate alloc`; it supplies `Vec` and related heap-backed types. - The final runtime must provide its own global allocator and panic handler; `rslibc::entry!` supplies them to an executable. - Keep OS integration in small FFI modules. Do not pull in a general-purpose runtime or C I/O layer for basic output. - `rslibc_macros::main` can wrap `async fn main()` with the small `block_on` executor. It is only a polling loop and does not provide Tokio-style I/O or a reactor; delays use the busy-wait `rslibc::runtime::sleep`. - Keep unsafe code inside small safe wrappers. Application code should be able to use calls such as: ```rust let values = rslibc::vec![1, 2, 3]; rslibc::println!("values = {:?}", values); ``` ## Platform Runtime - Unix stdout calls libc `write` with file descriptor `1`. - Windows stdout calls `GetStdHandle` and `WriteFile` through `kernel32`. - Windows allocation calls `HeapAlloc` and `HeapFree` through the system heap. - Sleep uses a monotonic clock: `clock_gettime` on Unix and `QueryPerformanceCounter` on Windows. - The Windows runtime dynamically links only the platform support needed by `alloc` and the compiler runtime. Do not statically link the full C runtime. - Keep `panic=abort` enabled. ## Build System CMake is configured with `LANGUAGES NONE` and invokes `rustc` through three custom commands. CMake 4.4's experimental native Rust support (`CMAKE_EXPERIMENTAL_RUST`) was evaluated and rejected: it compiles each source file as its own crate, so multi-module crates break; it links Rust libraries into executables as native `.lib` inputs instead of `--extern`; and it has no `proc-macro` crate type. Keep the direct `rustc` commands. The three custom commands are: 1. Compile `macros/src/lib.rs` as a host procedural macro. 2. Compile `src/lib.rs` and its modules to `librslibc.rlib`. 3. Compile the minimal `runtime/main.rs` and link it against that rlib. Configure and build a release executable with Ninja: ```sh cmake -S . -B build -GNinja -DCMAKE_BUILD_TYPE=Release cmake --build build ``` Build only the host macro with: ```sh cmake --build build --target rslibc_macros ``` Build only the common library with: ```sh cmake --build build --target rslibc_library ``` Run it on Unix: ```sh ./build/rslibc_example ``` Run it on Windows: ```powershell .\build\rslibc_example.exe ``` `CMAKE_BUILD_TYPE` is translated explicitly to rustc flags: - `Release`: `-C opt-level=3 -C debuginfo=0` - `RelWithDebInfo`: `-C opt-level=3 -C debuginfo=2` - Other or unset configurations: `-C opt-level=0 -C debuginfo=2` ## LSP rust-analyzer works without Cargo through a generated manifest: - `cmake/RustLSP.cmake` runs on every configure and writes `rust-project.json` (git-ignored) describing the three crates and the toolchain sysroot, so `core`, `alloc`, and proc-macro attributes resolve. - Requires the rustup components: `rustup component add rust-analyzer rust-src`. - Open the repository root in the editor so rust-analyzer picks up `rust-project.json`. Re-run CMake configure after changing the crate layout or switching toolchains. ## Verification After changing the source or build configuration, run a clean release build and execute the example: ```sh rm -rf build cmake -S . -B build -GNinja -DCMAKE_BUILD_TYPE=Release cmake --build build ./build/rslibc_example ``` On Windows, use `Remove-Item -Recurse -Force build` and run `build\\rslibc_example.exe` instead. Confirm that stdout contains `100% done`. When size matters, inspect the Windows executable after a release build. Avoid adding formatting, allocation, or OS dependencies unless they are needed by the library API. ## Commit Messages - Follow the 50/72 rule: subject lines are at most 50 characters and body lines are wrapped at 72 characters. - Use conventional prefixes such as `feat:`, `fix:`, `docs:`, `chore:`, and `ci:`. - Separate the subject from the body with a blank line. - Keep commit messages concise. - Include a `Co-Authored-By:` trailer for every agent or model that contributed to the commit, one trailer per co-author: ```text Co-Authored-By: qwen (lmstudio/qwen3.6-27b-mtp): wrote tests + build Co-Authored-By: luna (openrouter/openai/gpt-5.6-luna): reviewed edge cases ``` ## Editing Guidelines - Keep changes minimal and directly related to the request. - Use four-space indentation in Rust and CMake. - Keep normal text in Markdown within 80 columns where practical. - Do not add speculative abstractions or dependencies. - Update this file when the build workflow, library API, supported platforms, or source layout changes.