Calling C++ Functions from Carbon and Vice Versa: A Step‑by‑Step Guide
Learn how to call C++ functions from Carbon and vice‑versa using the language’s bidirectional interoperability, with compile, link, and verification steps.
06 Aug 2026, 02:01 UTC

Desired outcome
Successfully build and run a program where a Carbon source file calls a C++ function and a C++ source file calls a Carbon function, demonstrating bidirectional interoperability without wrapper code.
Prerequisites
- A recent Clang compiler (version 15 or newer) for compiling C++ and linking.
- The Carbon compiler
carboncfrom a pre‑1.0 release (e.g., version 0.5). - Basic knowledge of C++ function signatures and Carbon syntax.
- A working terminal with access to
clang++,carbonc, andllvm-disfor inspection.
Procedure
- Write the C++ component. Create
myfunc.cpp:#include <iostream> // Function that will be called from Carbon extern "C" void cpp_greet(const char* name) { std::cout << "Hello from C++: " << name << '\n'; } // Function that calls a Carbon function extern "C" void carbon_caller(); int main() { cpp_greet("world"); // C++ → Carbon via indirect call carbon_caller(); // direct call to Carbon return 0; } - Write the Carbon component. Create
myfunc.carbon:package demo.api; // Declare the C++ function with C linkage extern "C" fn cpp_greet(name: *const i8); // Define a Carbon function that C++ can call export fn carbon_caller() { cpp_greet("Carbon\0" as *const i8); } // Optional: a Carbon function called from C++ export fn carbon_greet(name: *const i8) { // Simple echo; in real code you might do more work // This function is not used in this example but shows the reverse direction. } - Compile each translation unit to an object file.
# Compile C++ to object clang++ -c -std=c++20 -O2 myfunc.cpp -o myfunc_cpp.o # Compile Carbon to object carbonc -c -O2 myfunc.carbon -o myfunc_carbon.oRun these commands in the directory containing the source files. Ensure you have write permission for the current directory.
- Link the objects into an executable.
clang++ myfunc_cpp.o myfunc_carbon.o -o demoThe linker uses the host C++ compiler’s ABI, which matches Carbon’s emitted LLVM IR.
- Run the program and verify output.
./demoExpected console output (order may vary):
Hello from C++: world Hello from Carbon
If you see similar lines, the bidirectional call succeeded.
Expected checks
- Execution check. The program exits with status 0 and prints the expected greetings.
- Symbol inspection (optional). Run
llvm-dis -show-anonymous-instructions -o - myfunc_carbon.o | grep cpp_greetto confirm that the Carbon object uses the same mangling as the C++ object (typically_Z11cpp_greetPKcfor theextern "C"symbol). No extra thunk symbols should appear. - Incremental build test. Touch only
myfunc.carbon, re‑run the Carbon compile and link steps, and verify that the C++ object is not recompiled.
Recovery options
- Undefined reference errors. If linking reports missing symbols, verify that both objects were compiled with the same ABI settings (e.g., same
-std=c++version and-fno-rttiif used). Re‑compile withclang++ -vto see the exact command line. - Mismatched name mangling. Ensure that any function intended to be called across the boundary is declared with
extern "C"in both languages. Carbon’sextern "C"maps directly to the host compiler’s C linkage. - Toolchain version mismatch. The Carbon compiler’s LLVM IR version must be compatible with the Clang version used for linking. Consult the Carbon release notes for the supported LLVM version; downgrade or upgrade Clang accordingly.
- Limited C++ features. If you need to use templates, multiple inheritance, or RTTI, wrap those constructs in a C++ façade that exposes only
extern "C"functions, then call the façade from Carbon.
Limitations
Carbon’s bidirectional interoperability is stable only for a subset of C++: trivial types, move‑only types, and functions with C linkage. Features such as C++ templates, exception propagation across languages, and runtime type information are not yet supported and may require abstraction layers. Additionally, the Carbon toolchain is pre‑1.0, so ABI guarantees are not final; future compiler updates could break existing object files.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.