rust-qt / ritual

Use C++ libraries from Rust
Apache License 2.0
1.22k stars 49 forks source link

Why do static binaries require Qt shared libraries? #65

Closed micahflee closed 5 years ago

micahflee commented 6 years ago

I wrote a tiny hello world app that uses the qt_core and qt_widgets crates here: https://github.com/micahflee/rustqt-helloworld

Compiling this took about 25 minutes, and the resulting binary is 153mb, so it sure seems like it statically compiled all of Qt and included it in the binary. Here's a screenshot of what the app looks like when run:

screenshot_2017-11-21_13-04-13

However, if I copy this binary to a linux VM that doesn't have the Qt shared libraries installed and try running it, I get this error:

$ ./rustqt-helloworld 
./rustqt-helloworld: error while loading shared libraries: libQt5Widgets.so.5: cannot open shared object file: No such file or directory

I could make my software depend on the appropriate Qt packages being installed as dependencies in linux (or bundling the right DLLs in Windows or shared libraries in macOS), but this poses a number of problems. For example, what if I want to run this binary in an OS that doesn't have a new enough version of Qt available in the package manager?

But more importantly, why is it looking for the shared library at all to begin with? It sure seems like all of Qt is is getting statically built and included in the binary -- otherwise it wouldn't take so long to build, and the file size wouldn't be so large.

Is there some way I can make my resulting binary not require the Qt shared library at all?

Riateche commented 6 years ago

Basically any Qt package provided by a package manager or downloaded by Qt Installer contains only shared Qt libraries. It's not possible to create a binary that doesn't depend on shared libraries using these packages. This applies to any Qt applications, not just this project.

If you don't want to depend on shared Qt libraries, you need to build Qt as static libraries and link against them. See Build Standalone Qt Application for Windows, for example. There is currently no way to make cpp_to_rust perform linking to static Qt, but it's possible to implement.

micahflee commented 6 years ago

Thank you. So, I'm confused, if cpp_to_rust doesn't currently support static linking, why is the binary filesize so big?

Riateche commented 6 years ago

That's probably debug information. Or maybe the linker does not eliminate unused functions in debug mode. On my system, the hello world currently takes 157 MB in debug mode and 4.2 MB in release mode.

demurgos commented 6 years ago

Hi, I am also interested in this issue. Thanks for pointing out that the size problem was related to debug symbols.

Regarding the link error:

$ ./rustqt-helloworld 
./rustqt-helloworld: error while loading shared libraries: libQt5Widgets.so.5: cannot open shared object file: No such file or directory

Is there a way to use the Qt bindings with dynamic loading? I'd like to catch failures to load Qt and offer a fallback implementation.

Riateche commented 5 years ago

Dynamic loading is currently not supported. The generated crates link directly to Qt libraries, so .dll/.so/.dylib files must be provided in order to use them.