c++rustbinding

Compiler not finding included c++ file


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)

Device Info

macOS Sequoia 15.0.1 (24A348)
cargo 1.82.0 (8f40fc59f 2024-08-21)

Project Contents

Directory Structure

cxx-hello
 |- build.rs
 |- Cargo.toml
 |- include
     |- hello.h
     |- hello_a.h
 |- src
     |- hello.cc
     |- hello_a.cc
     |- ffi.rs
     |- main.rs

build.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 }

Cargo.toml

    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"

include/hello.h

    1 #pragma once
    2 #include <string>
    3
    4 std::string hello_world();

include/hello_a.h

    1 #pragma once
    2 #include "cxx-hello/include/hello.h"
    3 #include "rust/cxx.h"
    4
    5 rust::String hello_world_adapter();

src/hello.cc

    1 #include "cxx-hello/include/hello.h"
    2
    3 std::String hello_world() {
    4     return std::String("Hello World");
    5 }

src/hello_a.cc

    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 }

src/ffi.rs

    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 }

src/main.rs

    1 mod ffi;
    2
    3 fn main() {
    4     let greeting = ffi::hello_world();
    5     println!("From c++: {}", greeting);
    6 }

Solution

  • 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");