diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..81dfa4e7 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,34 @@ +name: Deploy docs + +on: + push: + branches: [master] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install mdbook + run: cargo install mdbook + - name: Build book + run: mdbook build docs + - uses: actions/upload-pages-artifact@v3 + with: + path: docs/book + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..7585238e --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +book diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 00000000..80f20dcf --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,16 @@ +[book] +title = "Cpp2Rust" +description = "Developer documentation for Cpp2Rust, an automatic C++ to safe Rust translator." +authors = ["The Cpp2Rust Authors"] +language = "en" + +[build] +create-missing = false + +[output.html] +git-repository-url = "https://github.com/cpp2rust/cpp2rust" +edit-url-template = "https://github.com/cpp2rust/cpp2rust/edit/master/docs/{path}" + +[output.html.fold] +enable = true +level = 1 diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 00000000..101b03d7 --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,16 @@ +# Summary + +# The Project + +* [Introduction](./project/introduction.md) +* [Building](./project/building.md) +* [Usage](./project/usage.md) +* [Test Suite](./project/test-suite.md) + +# Translation Rules + +* [Overview](./rules/overview.md) + +# Code Generation + +* [Overview](./codegen/overview.md) diff --git a/docs/src/codegen/overview.md b/docs/src/codegen/overview.md new file mode 100644 index 00000000..fb3916d3 --- /dev/null +++ b/docs/src/codegen/overview.md @@ -0,0 +1,4 @@ +# Overview + +This part of the book documents the internals of the code generator: how the +clang AST is traversed and how Rust code is emitted. diff --git a/docs/src/project/building.md b/docs/src/project/building.md new file mode 100644 index 00000000..02ce260b --- /dev/null +++ b/docs/src/project/building.md @@ -0,0 +1,20 @@ +# Building + +## Requirements + +On Ubuntu, install the required dependencies with: + +```bash +sudo apt install libclang-22-dev clang++-22 ninja-build cmake +pip install ruff==0.15.22 +``` + +## Build + +```bash +mkdir build +cd build +cmake -GNinja .. +ninja +ninja check +``` diff --git a/docs/src/project/introduction.md b/docs/src/project/introduction.md new file mode 100644 index 00000000..404920d7 --- /dev/null +++ b/docs/src/project/introduction.md @@ -0,0 +1,29 @@ +# Introduction + +Cpp2Rust translates C++ to fully safe Rust automatically. It is a syntax-driven +translator based on clang's AST. + +Cpp2Rust's algorithm is described in the paper +[Cpp2Rust: Automatic Translation of C++ to Safe Rust](https://web.ist.utl.pt/nuno.lopes/pubs/cpp2rust-pldi26.pdf) +published at PLDI 2026. + +## Overview + +Cpp2Rust first parses the input C++ file(s) with clang and produces an AST. +It then traverses the AST and emits Rust code as strings, inserting +calls to the `libcc2rs` runtime library where needed (e.g., for raw pointer +semantics). +Finally, the Rust code is pretty-printed using `rustfmt` to a single `.rs` file. + +By default the *reference counting model* is used, which produces fully safe +Rust. +A generator of unsafe Rust is also available through the `--model=unsafe` +command line argument for debugging and performance comparisons. + +## Runtime library (`libcc2rs`) + +The generated code relies on a runtime library designed to simplify the +translation process. +C pointers are converted into the `Ptr` type provided by `libcc2rs`. +`Ptr` models C pointer semantics, including null, arithmetic, and aliasing, +while satisfying Rust's borrow checker through checked run-time operations. diff --git a/docs/src/project/test-suite.md b/docs/src/project/test-suite.md new file mode 100644 index 00000000..a93dd5ea --- /dev/null +++ b/docs/src/project/test-suite.md @@ -0,0 +1,18 @@ +# Test Suite + +```bash +# Run all tests +ninja check + +# Run only the unit tests +ninja check-unit + +# Run libcc2rs unit tests +ninja check-libcc2rs + +# Run libcc2rs-macros unit tests +ninja check-libcc2rs-macros + +# Regenerate expected output for unit tests after intentional changes +REPLACE_EXPECTED=1 ninja check-unit +``` diff --git a/docs/src/project/usage.md b/docs/src/project/usage.md new file mode 100644 index 00000000..64a110cc --- /dev/null +++ b/docs/src/project/usage.md @@ -0,0 +1,61 @@ +# Usage + +## Translate a single file + +```bash +./build/cpp2rust/cpp2rust --file=.cpp -o=.rs +``` + +By default, the reference counting model is used (fully safe output). +To generate unsafe Rust instead: + +```bash +./build/cpp2rust/cpp2rust --file=.cpp -o=.rs --model=unsafe +``` + +**Minimal example.** Given `hello.cpp`: + +```cpp +#include +int main() { + printf("hello world\n"); + return 0; +} +``` + +Running `./build/cpp2rust/cpp2rust --file=hello.cpp -o=hello.rs` produces: + +```rust +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + println!("hello world"); + return 0; +} +``` + +Compile and run with: + +```bash +rustc hello.rs -L ../libcc2rs/target/debug +./hello +``` + +## Translate a whole program + +First generate a +[`compile_commands.json`](https://clang.llvm.org/docs/JSONCompilationDatabase.html) +for your project. With CMake this is one extra flag: + +```bash +cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. +``` + +Then run: + +```bash +./build/cpp2rust/cpp2rust --dir= -o .rs +``` + +`` must be the directory that contains `compile_commands.json`. diff --git a/docs/src/rules/overview.md b/docs/src/rules/overview.md new file mode 100644 index 00000000..dbdacce6 --- /dev/null +++ b/docs/src/rules/overview.md @@ -0,0 +1,8 @@ +# Overview + +Translation rules describe how C++ library APIs are mapped to Rust. +Each rule module lives in the `rules/` directory and pairs a C++ source file +(`src.cpp`) with its Rust translation for each model (`tgt_refcount.rs` and +`tgt_unsafe.rs`). + +This part of the book explains how rules work and how to write new ones.