Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generated Binding fails to compile due to due to redefinition as different kind of symbol Error #1350

Open
johnoneil opened this issue Dec 19, 2023 · 1 comment

Comments

@johnoneil
Copy link

johnoneil commented Dec 19, 2023

I've Edited this description as more info on this bug has come to light

Description of the Bug

We've been using autocxx for a few months to generate Rust bindings to a Google graphics library, but bumping the graphics library to a new version is resulting in binding code that fails to compile.

I believe the problem is that the updated API has some subtle C++ constructs that autocxx is choking on, and it's in a place where we can't to my knowledge disable code generation.

Please see the reproduce section below to reproduce the issue, but I'll try to describe it at a high level here.

  1. We are working with an API largely driven by a single class. Relevant API calls are nonstatic members of the class.
// This is our primary class of interest.
// This represents our primary API.
class MyPrimaryClass {
public:
    uint32_t method_one();
    uint32_t method_two();
};
  1. An API update introduced a class member which serves as an argument in the API. This api argument is a C++11 type alias using xxx = yyy in another class. See Variant in the following:
class MyProblematicClass {
    public:
    MyProblematicClass() {}

    using Variant = std::variant<std::shared_ptr<X>,
                               std::shared_ptr<Y>,
                               std::shared_ptr<Z>,
                               Rect>;
};
  1. When this problematic class is referred to in the API, namespace management in the autocxx generated code breaks with an error redefinition as different kind of symbol.
// add a new method to the API referring to the `Variant` above
class MyPrimaryClass {
public:
    uint32_t method_one();
    uint32_t method_two();
#if 1
    // Problem arises when obscure class above pollutes the API
    uint32_t method_broken(const MyProblematicClass::Variant& variant);
#endif
};

The actual build error seen as:

[autocxx-namespace-example 0.26.0] cargo:warning=/home/johnoneil/code/autocxx/examples/namespace/target/debug/build/autocxx-namespace-example-5428364b4c6d6e85/out/autocxx-build-dir/cxx/gen0.cxx:121:13: error: redefinition of 'MyProblematicClass' as different kind of symbol
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=  namespace MyProblematicClass {
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=            ^
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=src/input.h:25:7: note: previous definition is here
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=class MyProblematicClass {
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning= 

Which arises because the following code is generated in gen0.cxx:

namespace my_namespace {
  namespace MyProblematicClass {
    using Variant = ::my_namespace::MyProblematicClass::Variant;
  }
}
  1. Workarounds don't seem possible (at least not yet).

To handle this situation my first inclination is to disable the problematic new API method, and write some Rust/C++ to access the API indirectly (or something) , but this doesn't seem possible via the autocxx block! macro.

include_cpp! {
    #include "input.h"
    safety!(unsafe_ffi)

    ....

    // Our primary class of interest. This defines the API we're using.
    generate!("my_namespace::MyPrimaryClass")

    // Being able to do this would help with this issue I think (or something analogous).
    //block!("my_namespace::MyPrimaryClass::method_broken")
}

Reproducing the Bug

I've put together the following test case which reproduces the issue:

https://github.com/johnoneil/autocxx/tree/wb/johnoneil/namespace-issue

to reproduce:

cd examples/namespace
cargo -vvv build 2>&1 | tee build.log

You should see an error in the build.log

[autocxx-namespace-example 0.26.0] cargo:warning=/home/johnoneil/code/autocxx/examples/namespace/target/debug/build/autocxx-namespace-example-5428364b4c6d6e85/out/autocxx-build-dir/cxx/gen0.cxx:121:13: error: redefinition of 'MyProblematicClass' as different kind of symbol
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=  namespace MyProblematicClass {
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=            ^
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=src/input.h:25:7: note: previous definition is here
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=class MyProblematicClass {
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=      ^
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] cargo:warning=1 warning and 1 error generated.
[autocxx-namespace-example 0.26.0] 
[autocxx-namespace-example 0.26.0] exit status: 1

Summary And Approaches to Fixing

  • I believe just talking this through with the autocxx team could result in some suggestions to work around this issue. There seems to be more in autocxx and cxx that we're not using.
  • If there are no alternate ways to work around this, perhaps an update to the block! macro might be warranted so that individual methods on generated classes could be blocked. I've been trying this, but so far without success.
  • Another alternative might be to re-write the primary API binding we're using to just use cxx (i.e. manually write it). I don't know if this is the best alternative.

I've learned some about about using autocxx and cxx while investigating this, but have a long way to go, so getting some advice from someone with more experience is vital.

@johnoneil
Copy link
Author

I've been able to work around this issue by disabling bindings entirely on the problematic class, but the issue is still present.
I'm going to keep this open in case it rears its head again and we can't work around it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant