Decompilation
Thorn includes a built-in reverse decompiler capable of reading an existing build.ninja or Makefile and synthesizing an equivalent, idiomatic build.thorn specification script.
CLI Usage
# Decompile build.ninja and print specification to stdout
thorn decompile build.ninja
# Decompile Makefile directly to a specification file
thorn decompile Makefile -o build.thorn
Reverse Engineering Capabilities
The decompiler performs heuristic AST analysis on backend rules and targets:
- Target Recovery: Detects targets, outputs, and classifies whether they are executables (
engine.exe), static archives (engine.static_lib), or shared objects (engine.shared_lib). - Source Mapping: Maps compiled object files back to their
.c,.s, and.Ssource files. - Flags & Includes: Extracts
-Iinclude flags intoengine.add_include(), compiler options intoengine.add_cflag(), and assembly flags intoengine.add_asflag(). - Linker Flags: Extracts library links (
-l,-L) intoengine.add_ldflag(). - Custom Commands: Recovers custom build edges into
engine.add_command(), transforming Make automatic variables ($@,$<) back into Thorn’s portable tokens ($out,$in). - Backend Recognition: Automatically emits
engine.backend("ninja")orengine.backend("make")based on the ingested file format.
Hookable Decompiler API (Pith & C FFI)
In addition to CLI usage, Thorn exposes a standalone, hookable decompiler API (decompile.*) designed for advanced build-system transformations and automated migrations (such as thornk for Linux Kbuild translation):
Configuration & Filtering
decompile.reset(): Clear the current decompiler graph state.decompile.set_project(name: str): Set the project name for the synthesized spec.decompile.set_compiler(cc: str): Override the target compiler.decompile.set_ar(ar: str): Override the target archiver.decompile.ignore_target(pattern: str): Filter out unwanted targets (e.g. tests, firmware blobs).decompile.keep_target(pattern: str): Whitelist specific targets.
Flag Manipulation
decompile.strip_cflag(pattern: str): Remove specific compiler flags (e.g. unsupported GCC internal flags).decompile.inject_cflag(target_pattern: str, flag: str): Ingest custom compiler flags (e.g.-nostdinc,-D__KERNEL__).decompile.inject_include(target_pattern: str, include_dir: str): Inject include paths into matching targets.decompile.remap_target(old_name: str, new_name: str): Rename targets in the synthesized graph.
Extraction & Synthesis
decompile.parse_file(path: str): Ingest a Ninja or Makefile from disk.decompile.target_count() -> int: Returns the number of recovered targets.decompile.to_thorn() -> str: Returns the synthesizedbuild.thornspecification as a string.decompile.emit_thorn(path: str): Writes the synthesizedbuild.thorndirectly to disk.
Byte-Identical Roundtripping
Thorn’s forward emitter and reverse decompiler are verified against each other:
- A project emits
build.ninjavia Thorn. thorn decompile build.ninja -o build_recovered.thorngenerates a recovered spec.- Running
thorn build_recovered.thornregenerates a byte-identicalbuild.ninja.
This ensures deterministic, lossless migration from legacy Ninja or Make setups into Thorn.