|
| 1 | +# The Translation Pipeline |
| 2 | + |
| 3 | +<style>pre.mermaid { text-align: center; }</style> |
| 4 | + |
| 5 | +```mermaid |
| 6 | +flowchart TD |
| 7 | + driver["<b>cpp2rust</b><br/><code>cpp2rust/cpp2rust.cpp</code>"] |
| 8 | + lib["<b>TranspileSrc / TranspileDir</b><br/><code>cpp2rust/cpp2rust_lib.cpp</code>"] |
| 9 | + action["<b>FrontendAction, ASTConsumer</b><br/><code>cpp2rust/ast_consumer.cpp</code>"] |
| 10 | + factory["<b>CreateConverter</b><br/><code>cpp2rust/converter/factory.cpp</code>"] |
| 11 | + mapper["<b>Mapper::LoadTranslationRules</b><br/><code>cpp2rust/converter/mapper.cpp</code>"] |
| 12 | + conv["<b>Converter / ConverterRefCount</b><br/><code>cpp2rust/converter/</code>"] |
| 13 | + out["<b>output file</b><br/>rustfmt"] |
| 14 | + driver -->|"source or compilation database"| lib |
| 15 | + lib -->|"one per translation unit"| action |
| 16 | + action --> factory |
| 17 | + factory -.->|"first call only"| mapper |
| 18 | + factory --> conv |
| 19 | + conv -->|"rs_code"| out |
| 20 | +``` |
| 21 | + |
| 22 | +## The stages |
| 23 | + |
| 24 | +1. `cpp2rust` (`cpp2rust/cpp2rust.cpp`) parses the flags, resolves the rules |
| 25 | + directory (see |
| 26 | + [Loading and Matching](../rules/loading.md#finding-the-rules-directory)), and |
| 27 | + calls `TranspileSrc` for `--file` or `TranspileDir` for `--dir`. |
| 28 | +2. `TranspileSrc` / `TranspileDir` (`cpp2rust/cpp2rust_lib.cpp`) run clang |
| 29 | + tooling over the source or over every file in `compile_commands.json`, with |
| 30 | + one `FrontendAction` per translation unit. |
| 31 | +3. `ASTConsumer::HandleTranslationUnit` calls `CreateConverter` |
| 32 | + (`cpp2rust/converter/factory.cpp`), which loads the translation rules on its |
| 33 | + first call and constructs a `Converter` (`--model=unsafe`) or a |
| 34 | + `ConverterRefCount` (`--model=refcount`). |
| 35 | +4. The converter emits the file preamble if this is the first unit, then |
| 36 | + traverses the unit and appends Rust text to `rs_code`. |
| 37 | +5. The driver writes `rs_code` to the `-o` path and runs `rustfmt` on it. |
| 38 | + |
| 39 | +## Gotchas |
| 40 | + |
| 41 | +- Every unit is parsed with the platform flags from |
| 42 | + `cpp2rust/compat/platform_flags.h`, which put the |
| 43 | + [compat headers](../rules/compat.md) ahead of the system headers and set |
| 44 | + `-D_FORTIFY_SOURCE=0`, so macro-heavy libc APIs reach the converter as plain |
| 45 | + function calls. |
| 46 | +- In `--dir` mode `__FILE__` is redefined to the file's basename, so the |
| 47 | + generated code does not embed the absolute paths of the build machine. |
| 48 | +- Rules are loaded once per process, and the file preamble is emitted once, by |
| 49 | + the first unit; the bookkeeping that spans units (which declarations and |
| 50 | + records have already been emitted) is kept in `static` members of `Converter`. |
| 51 | +- After the last unit, `Converter::EmitOpaqueRecords` appends `pub struct Name;` |
| 52 | + for every record type that was referenced but never defined, so types only |
| 53 | + used behind pointers still compile. |
| 54 | +- A failing `rustfmt` is reported as an error, but the unformatted file stays on |
| 55 | + disk for inspection. |
0 commit comments