cxx icon indicating copy to clipboard operation
cxx copied to clipboard

a way of exposing unmangled symbols directly from my shared library without requiring linking to any glue code

Open strike-ntzachar opened this issue 2 months ago • 5 comments

a way of exposing unmangled symbols directly from my shared library without requiring linking to any glue code

Would the cxx_gen::Opt::cxx_impl_annotations option help in your scenario without requiring manually-authored glue code with hardcoded mangled names?

As far as I understand this option, no. I'll try to explain further. Say I have the following:

#[cxx::bridge(namespace = "alpine")]
pub mod ffi {
   extern "Rust" {
      fn init() -> i32;
   }
}

I then compile my crate as cdynlib. This results in a shared library, with the following symbol exported: alpine$cxxbridge1$190$init As far as I understand, this option will not help (not to mention that I have no idea how to use it...)

Originally posted by @strike-ntzachar in https://github.com/dtolnay/cxx/issues/1665#issuecomment-3603269909

strike-ntzachar avatar Dec 02 '25 18:12 strike-ntzachar

To further clarify, I am loading the shared library from a separate c++ codebase and dl-loading symbols from the shared library. So, my issue is that every time the cxx library gets updated, I need to change the symbols I load, as the version number gets embedded into them... I need to be able to disable this behavior. As far as compatibility between the shared library and the c++ part, I am building at the same time, using the generated headers in my c++ build, so this is not an issue for me.

strike-ntzachar avatar Dec 02 '25 18:12 strike-ntzachar

If you are using cxx-generated C++ headers in your C++ build, where is the cxx-generated C++ non-header code in all of this?

  1. It does not sound like it is inside the shared library because then you would be using those symbols as the exported interface of the shared library instead of our internal symbols.

  2. It does not sound like it is outside the shared library because then using dlopen to manipulate the internal symbols by name would not be part of this, unless you were implementing a custom loader that wires the dependencies together across the shared library interface.

  3. It does not sound like you are dealing with a custom loader because then cxx's mangled symbol names would not be getting hardcoded into your codebase and arbitrarily named symbols including a version number would be no obstacle.

Generating symbols for use from C++ without cxx's C++ code generator is not in scope for cxx.

You will either need to find a different approach without cxx or select any one of the above 3 to pursue.

dtolnay avatar Dec 02 '25 19:12 dtolnay

The c++ generated non-headers are no help, as the are not hot-loading (dlsym) my exported functions. It will not help me to directly interface with them.

I have an absolute requirement that my rust code be in a shared library (.so), and I need to be able to dlload this library from c++ and then get symbols using dlsym - such that I right now I need to know the mangled names.. (as the unmangeled names in the generated non-headers is just a thin wrapper, this is safe from my perspective).

As long as the exported symbols' names did not contain the version number, I had no issue. Now, every time cxx updates, I need to bump my internal symbols' names.

The easiest solution is to pin cxx version, but this is ugly... I would rather have a way of controlling the exported names.

strike-ntzachar avatar Dec 02 '25 19:12 strike-ntzachar

The c++ generated non-headers are no help, as the are not hot-loading (dlsym) my exported functions. It will not help me to directly interface with them.

The point of option 1 is that it does help. You link them into the shared library. Since you need a symbol that can be resolved and called using dlsym, that is the only supported approach.

The signature of internal symbols also changes occasionally from release to release, not only the symbol name, so assuming a particular mapping of Rust signature to internal symbol C signature is not a good idea.

dtolnay avatar Dec 02 '25 20:12 dtolnay

Ok, how to do that? How can i link the generated non headers to my rust dynlib?

strike-ntzachar avatar Dec 02 '25 20:12 strike-ntzachar

managed to get the cpp generated files linked. Changed my build.rs script:

use std::env;
use std::path::PathBuf;


fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let mut generated_path = PathBuf::from(out_dir);
    generated_path.push("cxxbridge");
    generated_path.push("sources");
    generated_path.push("everest");
    generated_path.push("src");
    generated_path.push("lib.rs.cc");

    cxx_build::bridge("src/lib.rs")
        .std("c++17")
        .file(generated_path)
        .compile("everest-demo");

    println!("cargo:rerun-if-changed=src/lib.rs");
}

However, I now face a different problem.... The generated files do not wrap the non-namespace enclosed function with an extern "C" clause. I get mangled names for my functions. So, I dont have any option of exporting a stable function name to dlload.

strike-ntzachar avatar Dec 03 '25 07:12 strike-ntzachar