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

linuxdeployqt overrides RPATH while running on Linux #556

Open
GilfoyleProger opened this issue Oct 14, 2022 · 7 comments
Open

linuxdeployqt overrides RPATH while running on Linux #556

GilfoyleProger opened this issue Oct 14, 2022 · 7 comments

Comments

@GilfoyleProger
Copy link

GilfoyleProger commented Oct 14, 2022

Hi,
We use linuxdeployqt to automatically deploy our Qt project in Ubuntu 20.04.
Here is an example of qmake config:
deploy.commands = $$PWD/../installer/linuxdeployqt-continuous-x86_64.AppImage \"PROD_NAME\"
deploy.commands += -qmldir=$$QML_DIR
deploy.commands += -qmake=$$QMAKE_QMAKE
deploy.commands += -always-overwrite
...
deploy.commands += -appimage

I have shared libraries (.so) of Boost, "some private lib", which are dynamically loaded by another dynamic library.
It seems to me that after running linuxdeployqt, the RPATH is overwritten and as a result:

  1. The generated .AppImage while running gives a message that the .so files of this libraries cannot be found.
  2. Even when launching the project directly from Qt Creator the libraries cannot be found (linuxdeployqt also runs when I start the project in release mode)

When linuxdeployqt calling is commented out in qmake, the libraries are successfully found when I run the program from Qt Creator.
Can you tell me please, is there any way to avoid overwriting the RPATH variable? I used the "QMAKE_LFLAGS += "-Wl,-rpath,'$$ORIGIN/libs'"" flag, but it is also overwritten after running linuxdeployqt. Is there any way to handle this in qmake or it is a linuxdeployqt bug?
Let me know if you need more information.

@GilfoyleProger GilfoyleProger changed the title linuxdeployqt overrides rpath while running on Linux linuxdeployqt overrides RPATH while running on Linux Oct 14, 2022
@probonopd
Copy link
Owner

Rewriting the rpath is not optional, it is key to how linuxdeployqt works.
If all goes well, linuxdeployqt should find all required libraries using ldd and deploy them into the AppDir. If that is not happening, it is most likely due to one of two things, or both:

  1. Libraries on the build system are not in the "usual" path (e.g., in some subdirectory of /usr/lib/x86_64/). If this is the case, try moving or copying such libraries to the standard library location (e.g., /usr/lib/x86_64/ before running linuxdeployqt
  2. Libraries are opened using dlopen() rather than being defined as a hard dependency in the ELF executable or library. If this is the case, try adding a hard dependency on the library using patchelf --add-needed ... before running linuxdeployqt.

If the above still does not help: Can you post a link to your build script which is calling linuxdeployqt?

@GilfoyleProger
Copy link
Author

GilfoyleProger commented Oct 15, 2022

Thank you for your reply.

  1. There is no problem with the standard system libraries. The problem is only with external libraries. After deploying "somePrivateLib" (which is successfully opened by dlopen) can't find: libboost_system-mt, libboost_thread-mt and "someChildPrivateLib". These child libraries are dynamically loaded internally by "somePrivateLib".
  2. It seems to me that using patchelf --add-needed ... is not quite appropriate because it is not a default tool. Deployment of the project should be universal, we also build it on Jenkins. Please correct me if I'm wrong and the patchelf tool can be used another way.

Unfortunately, I can't send you the build script due to privacy, but I will try to describe some output information:

  1. Before deploying, all the required libraries are copied to the main folder, where linuxdeployqt is then started.
  2. If I first open the Boost, "someChildPrivateLib" libraries via dlopen, and then open "somePrivateLib" via dlopen, all libraries are successfully found by "somePrivateLib".
  3. When I unpacked the .AppImage after deployment, all the necessary libraries are there.

So, the problem is only related to linking.

@probonopd
Copy link
Owner

probonopd commented Oct 15, 2022

Thing is, linuxdeployqt has no way of knowing about the existence of libraries that are loaded via dlopen, and hence does not deploy its dependencies. Does someChildPrivateLib depend on libraries that are not part of the AppImage? Is the rpath in someChildPrivateLib set in such a way that it can find its dependencies? Try passing linuxdeployqt -executable=/path/in/AppDir/to/someChildPrivateLib.so ... which should result in linuxdeployqt try to deploy the dependencies of someChildPrivateLib as well.

Also, where are you dlopening the library from? You'd need to construct an absolute path to someChildPrivateLib based on readlink /proc/self/exe or something like that. Otherwise dlopen has no chance to know where to find that library.

@GilfoyleProger
Copy link
Author

GilfoyleProger commented Oct 15, 2022

All someChildPrivateLib dependencies exist in AppImage. Using the command "linuxdeployqt -executable" is unnecessary because all dependencies are fully collected in AppImage (I already checked it).
I checked the RPATH of these external libraries with "patchelf" - the RPATH was empty.
For test, I used the "dlopen" command with relative path and "QMAKE_LFLAGS += "-Wl,-rpath,'$$ORIGIN/libs'"" to open Boost, "someChildPrivateLib" libraries.
But this is not just an AppImage problem. If the AppImage linking problem is solved, it won't fix the problem of running the program from Qt Creator as described in the first comment.

And please can you tell me how linuxdeployqt overwrites the RPATH (which path is set)? Because I can't find information about it anywhere.

@probonopd
Copy link
Owner

You can use patchelf --print-rpath to see what rpath gets set by linuxdeployqt in the executables and libraries deployed by linuxdeployqt in the AppDir.

I think that in its present form linuxdeployqt is unable to do what you need; so you need to do some manual fixes before/after AppDir creation. Such as setting rpaths manually.

@GilfoyleProger
Copy link
Author

GilfoyleProger commented Oct 15, 2022

Thanks for advice. And I have one more question. I tried the patchelf --print-rpath command with binaries after deployment and got this result: $ORIGIN/lib
Why did linuxdeployqt add the "lib" folder to RPATH if the "lib" folder doesn't exist in our project?
Please could you provide more information on how linuxdeployqt generates RPATH for the binaries?

@probonopd
Copy link
Owner

Looks like we hardcoded lib:

if(fhsLikeMode == false){
libraryPath = QFileInfo(applicationBundle.binaryPath).dir().filePath("lib/" + bundleLibraryDirectory);
} else {
libraryPath = QFileInfo(applicationBundle.binaryPath).dir().filePath("../lib/" + bundleLibraryDirectory);

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

2 participants