BuildInfer
A dynamic build-system analyser that uses ptrace to record system calls during a build, then analyses the event log to automatically transpile build scripts from any build system to Buck or Bazel.
BuildInfer is a tool that automatically transpiles one build system to another. Give it a CMake project and it produces a Buck or Bazel build — without requiring manual annotation or deep knowledge of the source build system.
It was built to solve a real problem: migrating C++ projects to Buckaroo and Buck/Bazel required rewriting build files by hand. BuildInfer automated that migration.
How It Works
BuildInfer operates in three stages: Record, Analyze, and Transpile.
1. Record — ptrace at the Core
Build systems are orchestrators. They spawn compilers, linkers, and other tools in a specific order. BuildInfer's insight is that you don't need to understand the build system — you just need to observe what it does.
It does this using ptrace: the same Linux system call used by debuggers like GDB. By attaching to the build process and tracing every execve, openat, and related syscall, BuildInfer produces a complete, timestamped event log of everything that happened during the build.
A typical entry looks like this:
1532620392.776879 execve("/usr/bin/c++", ["/usr/bin/c++",
"-I/.../llvm/build/lib/Transforms/Scalar", "-std=c++11",
"-o", "CMakeFiles/LLVMScalarOpts.dir/Scalarizer.cpp.o",
"-c", ".../llvm/lib/Transforms/Scalar/Scalarizer.cpp"], ...) = 0
1532620392.791455 openat(AT_FDCWD,
".../llvm/include/llvm/ADT/SmallVector.h", O_RDONLY|O_NOCTTY) = 4
1532620394.751159 openat(AT_FDCWD,
".../llvm/lib/Transforms/Scalar/Scalarizer.cpp", O_RDONLY) = 10This records that Scalarizer.cpp was compiled into Scalarizer.cpp.o, reading SmallVector.h as a header. For a large project like LLVM, this event log can exceed 2 GB.
2. Analyze — From Processes to Targets
The raw event log is a flat stream of syscalls. The analysis stage transforms it through three representations:

- Process Graph: who spawned whom, what files were read and written
- Dependency Analysis: verify graph connectivity, remove noise (e.g.
cpandmvoperations are rewired so the graph reflects logical dependencies, not filesystem mechanics) - Target Graph: compiler invocations are grouped into libraries and executables, compiler flags are reconciled across translation units, glob expressions are computed to describe target inputs, and bash commands are rewritten to use relative paths
3. Transpile — Generating Build Files
The target graph is a build-system-agnostic description of the project. The transpile stage renders it into concrete build files — currently Buck, with Bazel support. It also computes precompiled header rules automatically.
Real-World Results
BuildInfer was used to migrate several large C++ open-source projects:
| Project | Result |
|---|---|
| Mapnik | Safe parallelism via Buck reduced build time from 30 minutes → 6 minutes |
| OpenCV | Identified sub-modules that violated module boundaries (PR accepted upstream) |
| LLVM | Enabled correct incremental builds after configuration changes |
Why This Approach Works
Most build-system migration tools work by parsing build files — reading CMakeLists.txt and trying to understand what it means. This is fragile: build files use macros, conditionals, and generator expressions that are hard to interpret statically.
BuildInfer works at the execution level instead. It doesn't care whether the build is driven by CMake, Make, SCons, or shell scripts. It only observes what the build actually does, which is the ground truth. This makes it generic: any build system that runs on Linux can be recorded.
Related
- Buckaroo — The package manager BuildInfer was built to support.
- BuildInfer slides — A walkthrough of the architecture and real-world results.