Calling C++ Functions from Carbon Using Bidirectional Interoperability
Learn how to call a C++ function from Carbon by creating an extern "C" wrapper, compiling it to an object file, and linking with carbonc --link-with.
29 Dec 2025, 15:45 UTC

Desired outcome
You want to reuse an existing C++ function (for example, std::strlen) from a Carbon source file and obtain its result as a Carbon integer.
Prerequisites
- Carbon toolchain installed (experimental release r0.1 or later). The
carboncexecutable must be on yourPATH. - A working C++ compiler that matches the Carbon toolchain’s ABI expectations (Clang or GCC).
- Write permission in the directory where you will create source files and object files.
- Basic familiarity with a command‑line build process.
Procedure
- Create a C++ header that declares the function with
extern \"C\"linkage.This ensures the symbol uses the C calling convention, which Carbon can reliably link against.
/* strlen.h */ #ifdef __cplusplus extern \"C\" { #endif size_t c_strlen(const char* s); #ifdef __cplusplus } #endif - Implement the function in a C++ source file.
The implementation can call any C++ standard library routine; the wrapper preserves
extern \"C\"linkage./* strlen.cpp */ #include #include "strlen.h" size_t c_strlen(const char* s) { return std::strlen(s); } - Compile the C++ source to an object file.
Run the command in a terminal where you have write access to the current directory.
# Replace with clang++ or g++ as appropriate -c -o strlen.o strlen.cppCheck that the object file was created (
ls -l strlen.o) and that it exports the expected symbol. - Write a Carbon file that imports the C++ function via the
cppnamespace.Use the
importdirective to bring in the header; the Carbon compiler will treat the imported name as a foreign function./* main.carbon */ package api sample; import "strlen.h" as cpp; fn Main() -> i32 { let msg: *CChar = "hello"; let len: usize = cpp.c_strlen(msg); Print("%\n", len); return 0; } - Link the Carbon source with the C++ object file and produce an executable.
The
--link-withflag tellscarboncto include the object file in the final link step.carbonc --link-with=strlen.o main.carbon -o demoYou need execute permission on the output file to run it.
- Run the resulting program and verify the result.
./demoIf the link succeeded, the program prints the length of the string literal (for the example above, the expected output is
5).
Expected checks
- The Carbon compiler (
carbonc) should finish without error messages. - The linker step (invoked by
carbonc) must resolve the symbolc_strlenfromstrlen.o; no \"undefined reference\" messages should appear. - Running the executable should produce the integer length of the supplied string, confirming that the foreign call returned a usable value.
Recovery options and limitations
- Linking failures: Use
nm -C strlen.oto verify that the symbolc_strlenis present and has the expected type. If it is missing, ensure the C++ source was compiled withextern \"C\"and that the object file matches the ABI expected by your Carbon toolchain. - Calling convention mismatches: Only plain C functions or C++ functions declared with
extern \"C\"are reliably supported. Complex C++ features (templates, exceptions, overloaded functions, classes with non‑trivial destructors) may not work. - ABI stability: Carbon’s C++ interoperability is still evolving; guarantees apply only to the specific toolchain version used. When upgrading the Carbon compiler, rebuild both the C++ object file and the Carbon source.
- Cleaning up: If you need to revert the build, delete the generated files (
strlen.o,demo, and any intermediate files). This does not affect source files.
Practical verification
To confirm that the interoperability works as intended, perform the following steps:
- Create the three files (
strlen.h,strlen.cpp,main.carbon) exactly as shown above. - Compile the C++ source to an object file with your C++ compiler.
- Run
carbonc --link-with=strlen.o main.carbon -o demo. - Execute
./demoand observe the printed number. - Change the string literal in
main.carbon(e.g., to \"Carbon\") and repeat steps 3‑5; the output should change accordingly (to 6).
If the output matches the expected length for each test, the bidirectional call succeeded. Any deviation indicates a linking or ABI issue that should be investigated using the recovery steps above.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.