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

Build error when adding Rust integration tests to a cargo_without_cmake project #770

Open
VelorumS opened this issue Dec 26, 2023 · 9 comments
Labels
🪲 bug Something isn't working 🔨 build system Issues related to integrating CXX-Qt into CMake/Cargo 🤔 discussion Feedback welcome

Comments

@VelorumS
Copy link

It's more of a Cargo problem...

If you want to add Rust integration tests (a tests/ dir alongside the src/):

cargo_without_cmake
├── build.rs
├── Cargo.toml
├── qml
│   └── main.qml
├── src
│   ├── cxxqt_object.rs
│   └── main.rs
└── tests
    └── integrationtest.rs

then there is a linker error when running cargo test:

   Compiling qml-minimal-no-cmake v0.1.0 (/home/user/programs/cargo_without_cmake)
error: linking with `cc` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="/usr/lib64/rustlib/x86_64-unknown-linux-gnu/bin:/home/user/.local/bin:/usr/condabin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/cuda/bin:/opt/cuda/nsight_compute:/opt/cuda/nsight_systems/bin:/var/lib/flatpak/exports/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin" VSLANG="1033" "cc" "-m64" "/tmp/rustcZHPvoe/symbols.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.19anblkgpug4hgip.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.2nutpir1uyrhrpc3.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.2rxnk7n1ew8g7xk5.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.3lwzj3hj347wpu0n.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.3o3mxpc2rq5yjl13.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.3r89k4p8v6a429e9.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.41481foc2wnchejk.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.43nsfu0dm474mbua.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.48eg3kq8iwvj2s0s.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.4mng40gdrb7ye3xl.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.4nrn7p3waraf2wvr.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.4v81w8bb51jaw2qg.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.4xvf2py8m5u0pjmy.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.4y0bjrw1fguta9zj.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.4z5vd2etofng2n86.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.91mludg9sfo3ml.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.ow3w9lwhohuj1yx.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.x1qj6ctictl0fuz.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.xd0tgzci1u4dloi.rcgu.o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb.41n1h9rzcsy4bry6.rcgu.o" "-Wl,--as-needed" "-L" "/home/user/programs/cargo_without_cmake/target/debug/deps" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out" "-L" "/home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out" "-L" "/home/user/programs/cargo_without_cmake/target/debug/build/cxx-d07c81dd81c15556/out" "-L" "/home/user/programs/cargo_without_cmake/target/debug/build/link-cplusplus-86f2ece339eddd9e/out" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/usr/lib" "-L" "/home/user/programs/cargo_without_cmake/target/debug/build/cxx-qt-lib-7248bd24a098bd16/out" "-L" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bdynamic" "-lQt6Qml" "-lQt6Network" "-lQt6Gui" "-lQt6Core" "-lGLX" "-lOpenGL" "-Wl,-Bstatic" "-Wl,--whole-archive" "-lqt-static-initializers" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "-lcxx-qt-generated" "-Wl,--no-whole-archive" "-Wl,-Bdynamic" "-lstdc++" "-Wl,-Bstatic" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libtest-6723ffdf45e0c77a.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libgetopts-00f4ddaf78f28f5d.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libunicode_width-359f1da55006986c.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_std-1c504f7c9149e3f1.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libstd-535331ff8d183b16.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-83939951b5f9ca2b.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libobject-2792585c57f4c6e4.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-f2ce8644ec2a7967.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-7fc047e246b2adb6.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-d39e4457138093ea.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-e9b762c4847a0e11.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-b52c3d668c14ddd9.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-d0385c8db45ddbee.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-a31aa09f6e1b2333.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-8ae1469e4adf77e7.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libadler-8279ae5d66c90454.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-61bb80d5e366629a.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-d733e609406251ec.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-fb65a7e225f08116.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-07f355446a788533.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-7f68b09987b30acc.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libcore-929e9257d5cc7f1d.rlib" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-3562e7ef6ead1498.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/usr/lib64/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/user/programs/cargo_without_cmake/target/debug/deps/integrationtest-6deb4ec9578819bb" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "-fuse-ld=gold"
  = note: /home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out/cxx-qt-gen/src/qobject.cxx.cpp:417: error: undefined reference to 'cxxbridge1$MyObject$number'
          /home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out/cxx-qt-gen/src/qobject.cxx.cpp:421: error: undefined reference to 'cxxbridge1$MyObject$set_number'
          /home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out/cxx-qt-gen/src/qobject.cxx.cpp:425: error: undefined reference to 'cxxbridge1$MyObject$string'
          /home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out/cxx-qt-gen/src/qobject.cxx.cpp:430: error: undefined reference to 'cxxbridge1$MyObject$set_string'
          /home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out/cxx-qt-gen/src/qobject.cxx.cpp:456: error: undefined reference to 'cxxbridge1$MyObject$increment_number'
          /home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out/cxx-qt-gen/src/qobject.cxx.cpp:460: error: undefined reference to 'cxxbridge1$MyObject$say_hi'
          /home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out/cxx-qt-gen/src/qobject.cxx.cpp:465: error: undefined reference to 'cxx_qt_my_object$cxxbridge1$create_rs_my_object_rust'
          /home/user/programs/cargo_without_cmake/target/debug/build/qml-minimal-no-cmake-0864b211f8cb53d0/out/cxx-qt-gen/src/qobject.cxx.cpp:487: error: undefined reference to 'cxxbridge1$box$MyObjectRust$drop'
          collect2: error: ld returned 1 exit status
          
  = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
  = note: use the `-l` flag to specify native libraries to link
  = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)

error: could not compile `qml-minimal-no-cmake` (test "integrationtest") due to previous error
warning: build failed, waiting for other jobs to finish...

Test itself (integrationtest.rs):

#[cfg(test)]
mod tests {
    #[test]
    fn integration_test() -> Result<(), Box<dyn std::error::Error>> {
        Ok(())
    }
}

The goal of the integration tests is to launch the qml-minimal-no-cmake binary, simulate inputs, examine outputs. No cxx-qt dependency needed.

So the test build is somehow incompatible with the build.rs.

Is there a way to make it just work by default without putting the tests in a separate crate?

@ahayzen-kdab ahayzen-kdab added 🪲 bug Something isn't working 🤔 discussion Feedback welcome 🔨 build system Issues related to integrating CXX-Qt into CMake/Cargo labels Jan 4, 2024
@ahayzen-kdab
Copy link
Collaborator

Interesting I can reproduce this as well. Wonder how this is supposed to work as we need the build script for the crate to work.

Does it work if you move the tests into another crate and then depend on qml-minimal-no-cmake as a crate? As i've seen that suggested as a solution in some places 🤔

@klochowicz
Copy link

I've run it as well; in my setup, I don't have any integration tests depending on the bridge crate, but I happen to have both a cxx and cxx_qt bridge crates that I export as a single static library (to be able to link against it in my CMake project).

I sort of got around my issue by hiding cxx_qt bridge crate behind a feature flag, but it would be nice if there was a better option :)

@LeonMatthesKDAB
Copy link
Collaborator

I can reproduce this as well. The issue is that the build.rs script compiles our generated C++ code and links it. This is the correct behavior to build the binary.
Our main.rs file uses mod cxxqt_object; to ensure the bridge is built on the Rust side as well, which generates the functions you are missing.

As the integration test only builds the public interface, cargo test doesn't include the mod cxxqt_object;, as that's only in main.rs.
You can fix this by adding a lib.rs file:

mod cxxqt_object;

Which should fix cargo test.

However, I've noticed that this somehow causes issues with qrc...
When I then cargo run, I get:

Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `/home/kdab/Documents/projects/3371-Rust-RnD/cxx-qt/target/debug/qml-minimal-no-cmake`
QQmlApplicationEngine failed to load component
qrc:/qt/qml/com/kdab/cxx_qt/demo/qml/main.qml: No such file or directory

And the app doesn't load the window...

That issue disappears when I remove the lib.rs file again.

@kristof-mattei
Copy link
Contributor

I can reproduce this as well. The issue is that the build.rs script compiles our generated C++ code and links it. This is the correct behavior to build the binary. Our main.rs file uses mod cxxqt_object; to ensure the bridge is built on the Rust side as well, which generates the functions you are missing.

As the integration test only builds the public interface, cargo test doesn't include the mod cxxqt_object;, as that's only in main.rs. You can fix this by adding a lib.rs file:

mod cxxqt_object;

Which should fix cargo test.

However, I've noticed that this somehow causes issues with qrc... When I then cargo run, I get:

Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `/home/kdab/Documents/projects/3371-Rust-RnD/cxx-qt/target/debug/qml-minimal-no-cmake`
QQmlApplicationEngine failed to load component
qrc:/qt/qml/com/kdab/cxx_qt/demo/qml/main.qml: No such file or directory

And the app doesn't load the window...

That issue disappears when I remove the lib.rs file again.

I wonder if this has something to do with a missing Q_INIT_RESOURCE(). If we run the code with lib.rs it seems that from the Rust side the main function links against the lib. It's not that it is actually a recompilation of the whole code.

@kristof-mattei
Copy link
Contributor

I created a repo with a repro: https://github.com/kristof-mattei/cxx-qt-lib-test

As-is (with src/lib.rs) it gives the following error:

  = note: init.cpp:5: error: undefined reference to 'qInitResources_qml_module_resources_qrc()'
          collect2: error: ld returned 1 exit status

which I traced to cxx-qt-generated. I tried to link it in build.rs but that doesn't help.

If you comment out shared::init_resources(); in src/main.rs:9 the error changes to:

QQmlApplicationEngine failed to load component
qrc:/qt/qml/cxx_qt_lib_test/qml/main.qml: No such file or directory

Now, if you remove src/lib.rs it works, with our without the init_resources() call.

@kristof-mattei
Copy link
Contributor

https://github.com/kristof-mattei/cxx-qt-lib-test

The build.rs generates a single function that imports all plugins defined. Works on cargo run and cargo test

@LeonMatthesKDAB
Copy link
Collaborator

@kristof-mattei Thank you for investigating this further and providing a workaround.

@ahayzen-kdab We should try to integrate this into our build system, so that this happens automatically.
I have the suspicion something like this already happens in our build system for the main binary, but potentially not in the integration tests 🤔

@kristof-mattei
Copy link
Contributor

@LeonMatthesKDAB the Q_IMPORT_PLUGIN string occurs in your code base. That's where I got the inspiration from, as Q_INIT_RESOURCES generates the same lines.

But there is a difference between runtime not finding the qml, which can be fixed with the import plugin hack I wrote, or the build error you get under certain conditions.

I think certain code gets thrown away in the latter condition because we're not calling it. Which is why we need that call in the tests just to make sure the linker understands the components are needed.

But that feels like a weird workaround. It's not Rust-like to have to do that. But I'm unsure how to tell the linker to retain stuff.

@ahayzen-kdab
Copy link
Collaborator

Note that unused things being thrown away by the compiler we've hit before and was solved by putting those parts of the code into their own lib which are linked with WHOLE_ARCHIVE or +whole-archive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🪲 bug Something isn't working 🔨 build system Issues related to integrating CXX-Qt into CMake/Cargo 🤔 discussion Feedback welcome
Projects
None yet
Development

No branches or pull requests

5 participants