linuxdeploy / linuxdeploy-plugin-gstreamer

Bundles GStreamer plugins into AppDirs. Experimental code, please expect issues! Help welcome!
3 stars 11 forks source link

Use linuxdeploy to deploy dependencies for gstreamer plugins #3

Closed Stivius closed 3 years ago

Stivius commented 4 years ago

The current problem When I was trying to use this plugin to pack gstreamer plugins into my AppImage I got into some troubles. Current implementation just copies all plugins to usr/lib/gstreamer-1.0 folder, however, some plugins can have additional dependencies which are not listed in the executable itself.

The first approach to solve it Rather straightforward approach is to use linuxdeploy again inside the plugin. I've found that $LINUXDEPLOY environment variable is accessible in plugin. So after plugins are copied to appropriate folder I'm running something like this. $LINUXDEPLOY --appdir $APPDIR This method is good enough - it deploys all dependencies for plugins but still one issue exists: rpath is not set correctly. It's specified as $ORIGIN while it should point to one directory lower ($ORIGIN/..).

Second attempt Another possible solution could be to deploy dependencies only for gstreamer plugins. Plugins still should be copied in advance. It could be done like this:

gstreamer_plugins=""
for i in "$plugins_target_dir"/*; do
    [ -d "$i" ] && continue

    gstreamer_plugins+="--deploy-deps-only=$i "
done

$LINUXDEPLOY --appdir $APPDIR $gstreamer_plugins

However, the problem is that firtsly linuxdeploy executes deployDependenciesForExistingFiles and after that it executes deployDependenciesOnlyForElfFile. Basically it means that it deployDependenciesOnlyForElfFile sets the correct rpath ($ORIGIN/..) while deployDependenciesForExistingFiles overwrites it with $ORIGIN rpath.

Third attempt Probably we could rid of manual copying and use -l flag to deploy the library with its dependencies.

gstreamer_plugins=""
for i in "$plugins_dir"/*; do
    [ -d "$i" ] && continue

    gstreamer_plugins+="-l $i "
done

$LINUXDEPLOY --appdir $APPDIR $gstreamer_plugins

The problem is that it will copy all plugins in usr/lib instead of usr/lib/gstreamer-1.0 and moreover the issue with $ORIGIN rpath will remain.

Final solution To tell the truth, each of this attempt can be fixed by patching linuxdeploy tool but I decided not to do it for personal use. The first attempt was almost perfect apart from rpath issue, so I've tuned it a little bit:

$LINUXDEPLOY --appdir $APPDIR

for i in "$plugins_target_dir"/*; do
    [ -d "$i" ] && continue

    patchelf --set-rpath '$ORIGIN/..:$ORIGIN' $i
    echo "Manually setting rpath for $i"
done

This means that after linuxdeploy execution I'm setting correct rpath manually to all this files.

More generalized approach (based on first attempt) Probably this approach will give more benefit but it requires linuxdeploy patching. In method deployDependenciesForExistingFiles for shared libraries we're always using $ORIGIN rpath which implies that all dependencies for libraries are placed in usr/lib. However, as I stated at the beginning there could be situation when some libs are placed in different folder (gstreamer-1.0 in our case) but are still using dependencies from usr/lib. So the solution would be to change rpath calculation a little.

for (const auto& sharedLibrary : listSharedLibraries()) {
    if (bf::is_symlink(sharedLibrary))
        continue;

    if (!d->deployElfDependencies(sharedLibrary))
        return false;

    std::string rpath = "$ORIGIN";

    auto libraryDir = bf::absolute(d->appDirPath) / "usr" /
                      PrivateData::getLibraryDirName(sharedLibrary);
    if (sharedLibrary.parent_path() != libraryDir) {
      rpath = PrivateData::calculateRelativeRPath(libraryDir,
                                                  sharedLibrary.parent_path());
    }

    d->setElfRPathOperations[sharedLibrary] = rpath;
}

Actually, it's just a possible fix, so I haven't tested it properly due to my decision to stay in *-plugin-*.sh domain. If you like the above mentioned solution we could implement it in linuxdeploy tool otherwise this PR has already fixed my issues for gstreamer.

TheAssassin commented 3 years ago

Are you fine with me fixing the rest of this? I see you're working on a Xibo Linux player, which I'd like to try out.

TheAssassin commented 3 years ago

Thanks!