-
-
Notifications
You must be signed in to change notification settings - Fork 108
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
corrosion_add_cxxbridge: Allow circular dependencies between bridge/Rust/C++ #580
corrosion_add_cxxbridge: Allow circular dependencies between bridge/Rust/C++ #580
Conversation
6693b5d
to
f26b053
Compare
Is this also a problem when using
Wouldn't the second option be preferable here? We could check if |
Unfortunately I don't know on which linkers specifically the argument order is important, I believe e.g. mold doesn't have this issue, but I'm unsure about lld. I think dynamic libraries may be able to sort this issue out, as they're resolving dependencies at runtime, but I haven't tried this
It might well be. I will add another commit to try this. |
3f96705
to
da33960
Compare
@jschwe I'm somewhat hesitant about adding back the target_link_libraries call... Anyway, It's of course your decision @jschwe . |
Enforcing a link between the bridge and the crate has turned out to be problematic if the dependency between the C++ and Rust code is circular. Example: A reasonable way to build a CXX-enabled crate is to build 3 static libraries: 1. my_crate_cpp - contains the C++ code, which may access Rust via CXX 2. my_crate_rust - contains the Rust code, which may access C++ via CXX * Note here that corrosion creates an additional my_crate_rust-static target for the actual static library, my_crate_rust is an INTERFACE target that links to this -static target. 3. my_crate_bridge - bridge code (generated via corrosion_add_cxxbridge) As the point of CXX is to freely communicate between C++ and Rust, these 3 libraries sort off act as one in the end and the dependencies between them may be circular. In CMake 3.24+, cirular dependencies can be resolved via a LINK_GROUP. With corrosion, the right call would be: ```cmake target_link_libraries(my_crate_rust INTERFACE "$<LINK_GROUP:RESCAN,my_crate_cpp,my_crate_bridge,my_crate_rust-static>" ) ``` Which would allow C++ to call Rust feely and vice-versa. The result would be an interface target my_crate_rust, which corresponds to the Rust crate imported by corrosion and contains all 3 static libraries. However, this only works when removing the target_link_libraries call from the bridge target to the crate target. As otherwise, CMake complains that it cannot resolve the dependencies, as the bridge already depends on the _rust target, which also already depends on the `_rust-static` target, etc. We also cannot create a LINK_GROUP that includes the my_crate_rust target, as link groups are only allowed on STATIC library targets, and the my_crate_rust is an INTERFACE target. So this either needs to be left up to the user, or the target_link_libraries call must be changed to link to the `-static` target, instead of the INTERFACE target, as that is compatible with the LINK_GROUP call.
5798bb2
to
ee6ba2b
Compare
This includes a fix in corrosion_add_cxxbridge, to force generation of the header files for all upstream dependencies, which is important in this circular setup.
This is a convenience for the user, as this is usually needed anyway.
ee6ba2b
to
d3d27c4
Compare
Sorry for the slow review.
Thanks!
We could add an option to
Yeah, that is indeed a bit strange. How about we merge this PR as-is for now? We could still discuss whether we should call target_link_libraries by default in a separate issue / PR. |
@jschwe Thank you for the review :) From my side, I'm okay to merge this PR with the link_libraries call included. |
Hi @jschwe , While I still think this is the right thing to do, this change caused an error in a downstream dependency that one of the generated header files could not be found: - CMake Error at ...../CMakeLists.txt:61 (target_link_libraries):
- Cannot find source file:
-
- ...../corrosion_generated/..../somefile.h
-
- Tried extensions .c .C .c++ .cc .cpp .cxx .cu .mpp .m .M .mm .ixx .cppm
- .ccm .cxxm .c++m .h .hh .h++ .hm .hpp .hxx .in .txx .f .F .for .f77 .f90
- .f95 .f03 .hip .ispc This is strange because CMake should know that this file is generated, and that this therefore shouldn't be an issue. It turned out that in older versions of CMake the So if anyone encounters this issue, it's easy enough to fix by calling: Unfortunately this must be done in all (transitive) downstream dependencies CMakeLists.txt that link to the bridge target, so cannot be done from within corrosion. I hope this won't cause too much trouble... |
@LeonMatthesKDAB Could you perhaps open a PR to add the error and solution to the Common issues page in our book? The source is under |
As described in corrosion-rs#580, this error may be encountered when using corrosion_add_cxxbridge, now that the generated headers are added as `PUBLIC` sources.
As described in #580, this error may be encountered when using corrosion_add_cxxbridge, now that the generated headers are added as `PUBLIC` sources.
Enforcing a link between the bridge and the crate has turned out
to be problematic if the dependency between the C++ and Rust code is
circular.
Example:
A reasonable way to build a CXX-enabled crate is to build 3 static
libraries:
target for the actual static library, my_crate_rust is an INTERFACE
target that links to this -static target.
As the point of CXX is to freely communicate between C++ and Rust, these
3 libraries sort off act as one in the end and the dependencies between
them may be circular.
In CMake 3.24+, cirular dependencies can be resolved via a LINK_GROUP.
With corrosion, the right call would be:
Which would allow C++ to call Rust feely and vice-versa.
The result would be an interface target my_crate_rust, which corresponds
to the Rust crate imported by corrosion and contains all 3 static
libraries.
However, this only works when removing the target_link_libraries call
from the bridge target to the crate target.
As otherwise, CMake complains that it cannot resolve the dependencies,
as the bridge already depends on the _rust target, which also already
depends on the
_rust-static
target, etc.We also cannot create a LINK_GROUP that includes the my_crate_rust
target, as link groups are only allowed on STATIC library targets, and
the my_crate_rust is an INTERFACE target.
So this either needs to be left up to the user, or the
target_link_libraries call must be changed to link to the
-static
target, instead of the INTERFACE target, as that is compatible with the
LINK_GROUP call.