Symbol mismatch with cxxbridge-cmd in Bazel
In my build, the linker was looking for symbols like _twitter_text$cxxbridge1$0$autolink_all but the Rust static library contained symbols like _twitter_text$cxxbridge1$189$autolink_all. This happened because:
- The
cxxbridge-cmdtool generates C++ bridge code with version$0$when processing standalone.rsfiles - The Rust compiler embeds the actual cxx crate version (1.0.189, hence
$189$) into symbols when building the library
How do you build cxxbridge-cmd? Is your build environment correctly emulating Cargo when building cxxbridge-cmd? In particular does your build environment set CARGO_PKG_VERSION_PATCH when building cxxbridge-cmd?
Since https://github.com/dtolnay/cxx/pull/1665 the symbols generated by cxx include the value of CARGO_PKG_VERSION_PATCH - see https://github.com/dtolnay/cxx/blob/95eef18e72fa27aad1e5d88468d4b72167d8e0cc/syntax/mangle.rs#L78
I got the same issue.
In my project, I have:
[dependencies]
cxx = { version = "1.0", default-features = false, features = ["alloc"] }
and in the build.rs of my project, I invoked the cxxbridge command, which is installed by cargo install, and the generated cpp file contains the $190 part (CARGO_PKG_VERSION_PATCH).
Then I get the error:
rust-lld: error: undefined symbol: cxxbridge1$coverage_new
If I change to specify the specific patch version
[dependencies]
cxx = { version = "1.0.190", default-features = false, features = ["alloc"] }
It seems to work without error.
However, this is not a good user experience! Probably should write somewhere in the documentation that one shold specify the patch version when using cxx as a dependency.
I got the same issue.
It seems that in your case the build is managed by cargo rather than by Bazel, so it seems to be a separate issue. Can we therefore move this discussion to a separate issue please?
in the build.rs of my project, I invoked the
cxxbridgecommand, which is installed by cargo install
Does your issue go away if you avoid depending on cxxbridge that is installed system-wide (potentially at a different version than the one resolved by cargo from Cargo.toml)? https://cxx.rs/build/cargo.html describes how this can be done.
However, this is not a good user experience!
Yeah, we can together try to improve the experience. At the same time note that the error you are seeing exposes a pre-existing problem/risk - you get undefined behavior if one side of FFI uses a version of cxx that expects different ABI that the other side of FFI (if the other side uses a different cxx version). For example - the exact parameters of thunks generated by cxx are an internal implementation detail that can change in any patch-version-update. Therefore keeping both sides of the FFI boundary in-sync is important to prevent undefined behavior.
Thanks for the reply, I understand now. It is indeed necessary to ensure consistency between the two versions to prevent undefined behavior.
How do you build
cxxbridge-cmd?
In MODULE.bazel
#
# The codegen tool needed by cxx.
#
http_archive(
name = "cxxbridge-cmd",
build_file_content = """
load("@rules_rust//rust:defs.bzl", "rust_binary")
load("@cxxbridge_cmd_deps//:defs.bzl", "aliases", "all_crate_deps")
rust_binary(
name = "cxxbridge-cmd",
srcs = glob(["src/**/*.rs"]),
aliases = aliases(),
compile_data = glob(["src/gen/**/*.h"]),
edition = "2021",
visibility = ["//visibility:public"],
deps = all_crate_deps(
normal = True,
),
)
""",
sha256 = "6a368ed4a0fd83ebd3f2808613842d942a409c41cc24cd9d83f1696a00d78afe",
strip_prefix = "cxxbridge-cmd-1.0.189",
type = "tar.gz",
urls = ["https://static.crates.io/crates/cxxbridge-cmd/cxxbridge-cmd-1.0.189.crate"],
)
cxxbridge_cmd_deps = use_extension("@rules_rust//crate_universe:extensions.bzl", "crate")
cxxbridge_cmd_deps.splicing_config(
repositories = ["cxxbridge_cmd_deps"],
resolver_version = "2",
)
cxxbridge_cmd_deps.from_cargo(
name = "cxxbridge_cmd_deps",
cargo_lockfile = "//3rdparty/cxxbridge:Cargo.lock",
manifests = ["@cxxbridge-cmd//:Cargo.toml"],
)
use_repo(
cxxbridge_cmd_deps,
"cxxbridge_cmd_deps",
)
I have a workaround for it, but it's pretty gross.
genrule(
name = "twitter_text_h",
srcs = [
"//rust/twitter-text:twitter_text_ffi",
],
outs = ["twitter-text.h"],
cmd = "$(location @cxxbridge-cmd//:cxxbridge-cmd) --header $(location //rust/twitter-text:twitter_text_ffi) | sed 's/\\$$cxxbridge1\\$$0\\$$/\\$$cxxbridge1\\$$190\\$$/g' > $(location twitter-text.h)",
tools = ["@cxxbridge-cmd//:cxxbridge-cmd"],
)
RE: https://github.com/dtolnay/cxx/issues/1676#issuecomment-3613784904
I think you need to also provide version in your rust_binary rule.
OK, this works now. Maybe the docs use this as an example? It's pretty sparse right now.
#
# The codegen tool needed by cxx.
#
CXX_BRIDGE_VERSION = "1.0.190"
http_archive(
name = "cxxbridge-cmd",
build_file_content = """
load("@rules_rust//rust:defs.bzl", "rust_binary")
load("@cxxbridge_cmd_deps//:defs.bzl", "aliases", "all_crate_deps")
rust_binary(
name = "cxxbridge-cmd",
srcs = glob(["src/**/*.rs"]),
aliases = aliases(),
compile_data = glob(["src/gen/**/*.h"]),
edition = "2021",
visibility = ["//visibility:public"],
deps = all_crate_deps(
normal = True,
),
version = "%s",
)
""" % CXX_BRIDGE_VERSION,
sha256 = "b1f29a879d35f7906e3c9b77d7a1005a6a0787d330c09dfe4ffb5f617728cb44",
strip_prefix = "cxxbridge-cmd-" + CXX_BRIDGE_VERSION,
type = "tar.gz",
urls = ["https://static.crates.io/crates/cxxbridge-cmd/cxxbridge-cmd-" + CXX_BRIDGE_VERSION + ".crate"],
)
cxxbridge_cmd_deps = use_extension("@rules_rust//crate_universe:extensions.bzl", "crate")
cxxbridge_cmd_deps.splicing_config(
repositories = ["cxxbridge_cmd_deps"],
resolver_version = "2",
)
cxxbridge_cmd_deps.from_cargo(
name = "cxxbridge_cmd_deps",
cargo_lockfile = "//3rdparty/cxxbridge:Cargo.lock",
manifests = ["@cxxbridge-cmd//:Cargo.toml"],
)
use_repo(
cxxbridge_cmd_deps,
"cxxbridge_cmd_deps",
)
OK, this works now.
Thanks. I guess this issue can be marked as closed now.
Maybe the docs use this as an example? It's pretty sparse right now.
Maybe https://github.com/dtolnay/cxx/pull/1679 will help a little (it highlights how the same version is used across cxxbridge, cxxbridge-macro, and cxx targets), but I don't use Bazel often myself, so I hope that if there are other doc improvements possible, then Bazel experts can chime in with PRs of their own.