Open TheAssassin opened 6 years ago
Or maybe just add those libraries as a parameter to -bundle-dynamic-libraries, like extra-plugins? It would also be good if those parameters could just work on every file in a certain directory, I think.
Well, I'd rather have it bundle them automatically. When bundling dynamic dependencies, you need to check every library, executable, etc. for the library names. Packagers don't know much about most of those libraries in my experience, so they can't compile a complete list of libraries that need to be bundled.
True.
I have an application with a bunch of dynamically loaded plugins, and I can't find a way to bundle the plugins with the application. Without plugins, my app is very limited in its functions. The plugins don't even have any special dependencies not already bundled for the main executable. Is there a way to bundle the specified .so files into AppImage?
In case we are talking about Qt plugins,
-extra-plugins=<list> : List of extra plugins which should be deployed,
separated by comma.
sounds like what you need. The plugins deployed are from the Qt installation pointed out by qmake -v. You can deploy entire plugin directories, a specific directory or a mix of both.
Usage examples:
-extra-plugins=sqldrivers/libqmsql.so,iconengines/libqsvgicon.so
-extra-plugins=sqldrivers,iconengines/libqsvgicon.so
-extra-plugins=sqldrivers,iconengines,mediaservice,gamepads
@probonopd : no, quite the opposite. They are my own plugins built from my code. A bunch of .so
files located in the same dir with the main executable. My application loads them at runtime with dlopen()
. At first I thought -extra-plugins
is what I need, but it can't be used for bundling arbitrary non-qt shared libraries.
In this case, copy your .so files into the AppDir (e.g., in usr/lib/
) and supply them to linuxdeployqt like this:
linuxdeployqt \
-executable=appdir/usr/lib/mylib.so \
-executable=appdir/usr/lib/myotherlib.so \
appdir/usr/share/*desktop -appimage
This will make sure that the extra libraries can be loaded and that their dependencies, too, will be deployed.
(Edited above to reflect the missing =
.)
@probonopd: oh, so easy! Could definitely use this bit of info in the main README. Thanks!
Can you send a pull request for the README please? Thank you @VioletGiraffe
@probonopd: I would, as soon as I figure out how it all actually works. I don't have an AppDir, I'm using linuxdeployqt
with -appimage
flag to create a bundle image directly with no extra hassle. I have a binary, let's call it AppBinary
, I have a .desktop
file that refers to it, and I have a bunch of .so files in the same directory with the main binary. So I'm doing the following, with the current dir being the main executable directory:
~/Downloads/linuxdeployqt -executable libshared1.so -executable libshared2.so install/app.desktop -appimage
And I'm getting an error:
ERROR: Unknown argument: "libshared.so"
Can you please advise?
Sorry I missed the =
.
Arrange your files like this:
appdir/usr/bin/AppBinary
appdir/usr/share/app.desktop
appdir/usr/share/icons/hicolor/512x512/app.png
appdir/usr/lib/libshared1.so
appdir/usr/lib/libshared2.so
Ideally,
qmake CONFIG+=release PREFIX=/usr
make -j$(nproc)
make INSTALL_ROOT=appdir -j$(nproc) install
does this for you. This structure is called an "FHS-like" AppDir.
Then, run
linuxdeployqt \
-executable=appdir/usr/lib/mylib.so \
-executable=appdir/usr/lib/myotherlib.so \
appdir/usr/share/*desktop -appimage
Do I really need to create the AppDir structure manually? The whole reason of running linuxdeployqt -appimage
is to cut down on the manual work. I already have the shared libraries right here, I'm specifying them with -executable
, can't linuxdeployqt pick them up without me having to copy them elsewhere, wasting CPU time, electricity, disk space, and my time writing the scripts to do all this?
I tried this way:
linuxdeployqt -executable libshared1.so -executable libshared2.so installation/share/applications/myapp.desktop -appimage
Got this error:
ERROR: Unknown argument: "installation/share/applications/myapp.desktop"
Your build script (Makefile, QMake file, CMake file) should be able to create the FHS-like structure. If it can't do that, then yes, you need to do it manually. Please see the README.md
.
I tried as you suggested (almost - I don't see the point of using /usr/
subdir, surely it can't be required?):
~/Downloads/linuxdeployqt-6-x86_64.AppImage -executable=installation/lib/libshared1.so.1.0 -executable==installation/lib/libshared2.so.1.0 installation/share/applications/myapp.desktop -appimage
Same error:
ERROR: Unknown argument: "installation/share/applications/myapp.desktop"
What's wrong?
By the way, these dependencies are static, they are linked at compile time with the -l
linker flag despite being shared libraries. I'm not loading them with dlopen()
. Isn't linuxdeployqt
and/or appimagetool
supposed to pick them up automatically? They're not being bundled even with -bundle-everything
.
Looks like by deviating from https://github.com/probonopd/linuxdeployqt#using-linuxdeployqt-with-travis-ci you are making it harder for yourself than need be. Please just follow the example more or less 1:1. Which project are you working on? If you like, I can send you a pull request.
@probonopd, unfortunately, it's not an open-source project. But I don't understand where I'm deviating from the manual you've linked to (and I've read it all over by now, I think)! I moved my bundle directory one level down into /usr/
in case that's required, and I specified the desktop file using *.desktop
syntax. No change. What am I doing wrong??? I'm about to start pulling my hair out (and there's very little left from my previous encounters with Linux).
New milestone: after copying shared libraries into /usr/lib/
manually and removing all -executable=
from command line, I finally get an AppImage, but it prints this when I try to run it:
execv error: No such file or directory
Can you post a full linuxdeployqt
log?
@probonopd : here's the output with verbose=3, is that what you meant? ldq.log
Please post the log when it fails. This one succeeded.
@probonopd : launching this appimage failed with "execv error: No such file or directory". Surely, it's not supposed to happen?
That is not supposed to happen indeed. Can you mail me the AppImage for analysis? probono at puredarwin dot org.
@probonopd: done, e-mail sent. Thanks in advance!
Did you get a chance to look into it? I desperately want to bundle my application into AppImage (it seems to be the only way to deploy applications on Linux without major headache), but I need to add dynamically loaded plugins and last time I tried, we couldn't make it work.
@VioletGiraffe
Hello.
I hope that I'm not overstepping my license, by posting an opinion on the problem you seem to have encountered. But I think that your problem has largely been misidentified in this thread. The question isn't so much, How can the dynamically-loaded libraries be bundled, as much as, Why isn't the program finding them?
The application can be designed in HFS mode or not so, where HFS mode is the mode, that has the large, well-structured directory-layout. The following link describes how to switch:
Not Populating? Use CMake to help.
Alternatively, a blank AppDir can first be initialized with 'linuxdeploy', so that afterward, it can be processed with 'linuxdeployqt'.
It would be perfectly possible to bundle the libraries in non-HFS mode, by creating a folder named, say, ${APPDIR}/etc, and placing the libraries there. But I think that the key to solving your problem can be found here:
I think this applies equally in HFS mode as it does in non-HFS mode.
Long story short, your program decides at run-time, where to find the libraries. How can it distinguish between paths that belong to the AppDir, and paths that belong to the host machine? The AppDir is mounted at a (SquashFS) mountpoint. The program has some way to read in the value of the environment variable ${APPDIR}. In non-HFS mode, append '/etc' and then the name of the library to that. In HFS mode, append '/usr/lib/
Just remember, in HFS mode, to give the 'linuxdeployqt' tool the '-bundle-non-qt-libs' option.
#include <dlfcn.h>
#include <QString>
#include <QByteArray>
QString libname = QString("libshared1.so");
QString libpath = QString::fromLocal8Bit(qgetenv("APPDIR")) += "/usr/lib/" += libname;
QByteArray libpath_ba = libpath.toLocal8Bit();
void *handle = dlopen(libpath_ba.data(), RTLD_LAZY);
Dirk
@dirkmittler Hello Dirk, thank you for the insight and a bunch of useful information. Indeed, it is just as important to find the libraries as it is to deploy them into the AppImage. However, with the latest versions of linuxdeployqt
the problem has gone, I can successfully bundle extra .so
files by specifying -executable=
. I did not have to modify the path at which the main application looks for the plugins - I'm successfully using qApp->applicationDirPath()
on all platforms regardless of whether it runs from AppImage container or if I'm just debugging the application from IDE without bundling.
This is how it is intended to work @VioletGiraffe.
A long time problem we've been looking for a solution for is how to bundle libraries opened by
dlopen()
calls.A naive attempt would be to just run the app via
strace
and look for libraries opened by the application. However, apps depending on e.g., system components (the desktop environment for example, or the sound system), or expect a parameter, and otherwise showing a help text. In all these cases, it's impossible to detect all the libraries opened by the software, and even worse, those applications might alter the system, which is undesirable, too.Instead of executing an application with
strace
, I thought it should suffice to read the executable or library file, extract all strings, filter those with given patterns (^.+\.so\..+$
worked well for the beginning, we should also use^.+\.so$
), and bundle those files.I made a first attempt with
strings
andgrep
:The solution isn't perfect, though. Some tools might just include library names in help texts, etc., but I'd expect it to work well, given the results of a couple of libraries I tried with this method. Some libaries might not be a hard dependency, but in many cases, bundling one library too much is better than bundling too few. Also, our excludelist is pretty solid, so I wouldn't worry too much about this.
As this is a bit speculative, I would offer this functionality only when the user specifies a special parameter, e.g.,
-bundle-dynamic-libraries
.What do you think?