Seamless C++ Interoperability in Carbon: Call Existing C++ Code with Zero Overhead
Carbon’s interop lets you call existing C++ code directly with zero overhead. Use carbon::cpp and extern \"C++\" to import C++ symbols, and export to expose Carbon to C++. This blog shows a concrete example, explains ABI guarantees, and lists trade‑offs.
02 May 2026, 20:16 UTC

Concrete Problem: Legacy C++ Libraries & New Carbon Code
Modern teams often have a mix of C++ and Carbon files in the same repository. The question becomes: can we keep using a mature C++ library while writing new components in Carbon without adding a heavy wrapper layer? The answer is yes—Carbon’s built‑in interoperability makes this a matter of syntax, not a new runtime or ABI.
Thesis: Carbon’s carbon::cpp Namespace & extern \"C++\" Let You Call C++ Directly
Carbon ships with a carbon::cpp namespace that mirrors the host C++ compiler’s namespace layout. Combined with the extern \"C++\" block syntax, you can import any C++ type, function, or template into Carbon code. Because the same ABI is used, objects can be passed by value or reference across the boundary with zero overhead.
1. The Interop Model in Action
When you compile a Carbon file with the carbon-cpp driver, the toolchain automatically links against the standard C++ library and applies the same name mangling rules the host compiler uses. This means a std::string created in Carbon can be passed to a C++ function that expects a std::string argument, and vice‑versa.
Key points:
- Namespace mirroring:
carbon::cpp::std::stringis identical to C++’sstd::string. - No wrapper layer: The compiler generates the necessary glue code automatically.
- Zero runtime cost: Calls are compiled to the same machine code as pure C++.
2. Importing C++ into Carbon
Suppose you have a simple C++ header:
// add.hpp
#pragma once
int add(int a, int b) {
return a + b;
}
In a Carbon file, you can import and use this function as follows:
// main.carbon
extern \"C++\" {
int add(int, int);
}
int main() {
int sum = add(3, 4);
// Carbon's std::println is analogous to C++'s std::cout
std::println(\"Sum is {}\", sum);
return 0;
}
Build steps (run in a terminal with the Carbon compiler installed):
- Place
add.hppin a directory calledinclude. - Compile the Carbon file with the
carbon-cppdriver, pointing to the include path:carbon-cpp -Iinclude main.carbon -o main - Run the executable:
./main
Expected behaviour: the program prints Sum is 7. The actual output is not asserted here; you should verify it yourself.
3. Exposing Carbon to C++
Carbon can also expose its functions back to C++ using the export keyword. For example:
// util.carbon
export int multiply(int a, int b) {
return a * b;
}
In C++ you can then import it like this:
// main.cpp
extern int multiply(int, int);
int main() {
int product = multiply(6, 7);
std::cout << \"Product is \" << product << std::endl;
return 0;
}
Compile both files together with the same driver to ensure ABI consistency:
carbon-cpp main.cpp util.carbon -o mixed
Running ./mixed should print Product is 42. Again, verify the output yourself.
4. Trade‑offs & Limitations
- Incomplete C++ Feature Support: Carbon’s interop currently lacks full support for multiple inheritance, some advanced template metaprogramming patterns, and certain library extensions. If your C++ library relies on these, you may need a manual binding layer.
- Compiler Consistency: Because the interop layer depends on the underlying C++ compiler’s ABI, changing compiler versions or flags (e.g., switching from
gcctoclang) can break binary compatibility. Keep the same compiler and flags across all files. - Toolchain Setup: The
carbon-cppdriver must be available and correctly configured. If you use a custom build system, ensure it invokes the driver with the appropriate include paths and linking options.
Actionable Steps for Your Project
- Install the Carbon Toolchain: Follow the
README.mdin the Carbon GitHub repo to buildcarbon-cppfor your platform. - Add a Test Interop Example: Create a minimal C++ header and a Carbon file that imports it using
extern \"C++\". Build and run to confirm zero‑overhead calls. - Gradually Migrate: Replace one Carbon file at a time, keeping the rest in C++. Use
exportto expose new Carbon utilities to existing C++ code. - Maintain Compiler Consistency: Document the compiler version and flags used. Use a shared
Makefileor CMake script that invokescarbon-cppuniformly. - Monitor for Feature Gaps: If you hit a C++ feature that Carbon cannot wrap automatically, consider writing a thin C++ wrapper or flagging the issue for the Carbon project.
By following this approach, you can keep your legacy C++ libraries working while unlocking Carbon’s modern language features without paying a performance penalty.
Diagram Labels
| Carbon Code | C++ Code | ABI Compatibility | carbon‑cpp Driver |
|---|---|---|---|
| Direct use of C++ symbols | Calls into Carbon functions | Zero‑overhead passing | Handles name mangling & linking |
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.