I’m working on creating Rust bindings for a C++ project using CXX. Ideally, I’d like to keep the bindings in separate files to avoid modifying the original C++ source code directly.
As a starting point, I tried to set up bindings for a basic Hello World program. However, I’m encountering an error about undefined symbols, and I haven’t been able to figure out how to fix this. I am extremely new to C++, so any help is apperciated.
= note: Undefined symbols for architecture x86_64:
"hello_world()", referenced from:
hello_world_adapter() in libcxx-hello.a[3](2e40c9e35e9506f4-hello_a.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
macOS Sequoia 15.0.1 (24A348)
cargo 1.82.0 (8f40fc59f 2024-08-21)
cxx-hello
|- build.rs
|- Cargo.toml
|- include
|- hello.h
|- hello_a.h
|- src
|- hello.cc
|- hello_a.cc
|- ffi.rs
|- main.rs
1 fn main() {
2 cxx_build::bridge("src/ffi.rs")
3 .file("src/hello_a.cc")
4 .compile("cxx-hello");
5
6 println!("cargo:rerun-if-changed=src/ffi.rs");
7 println!("cargo:rerun-if-changed=src/hello.cc");
8 println!("cargo:rerun-if-changed=src/hello_a.cc");
9 println!("cargo:rerun-if-changed=include/hello.h");
10 println!("cargo:rerun-if-changed=include/hello_a.h");
11 }
1 [package]
2 name = "cxx-hello"
3 version = "0.1.0"
4 edition = "2021"
5
6 [dependencies]
7 cxx = "1.0"
8
9 [build-dependencies]
10 cxx-build = "1.0"
1 #pragma once
2 #include <string>
3
4 std::string hello_world();
1 #pragma once
2 #include "cxx-hello/include/hello.h"
3 #include "rust/cxx.h"
4
5 rust::String hello_world_adapter();
1 #include "cxx-hello/include/hello.h"
2
3 std::String hello_world() {
4 return std::String("Hello World");
5 }
1 #include "cxx-hello/include/hello_a.h"
2 #include "rust/cxx.h"
3
4 rust::String hello_world_adapter() {
5 return rust::String(::hello_world());
6 }
1 #[cxx::bridge]
2 mod ffi {
3 unsafe extern "C++" {
4 include!("cxx-hello/include/hello_a.h");
5
6 fn hello_world_adapter() -> String;
7 }
8 }
9
10 pub fn hello_world() -> String {
11 ffi::hello_world_adapter()
12 }
1 mod ffi;
2
3 fn main() {
4 let greeting = ffi::hello_world();
5 println!("From c++: {}", greeting);
6 }
You are not compiling hello.cc
. Add it to your CXX build config:
cxx_build::bridge("src/ffi.rs")
.file("src/hello_a.cc")
.file("src/hello.cc") // <----------
.compile("cxx-hello");