]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - library-bundler
radiant/vfs: rework vfs loading, attempt to load wads and paks, ref #139
[xonotic/netradiant.git] / library-bundler
index cdf2e960bae0206e4eeb75693df1f36bf0e69de0..d5a439716aa88b950d24cd85b165a7a5e196faf2 100755 (executable)
@@ -1,7 +1,9 @@
 #! /usr/bin/env bash
 
+set -e
+
 Common::noOp () {
-       printf ''
+       true
 }
 
 Common::getPath () {
@@ -24,7 +26,8 @@ Common::getPath () {
                else
                        printf '%s\n' "${file_path}"
                fi
-       fi
+       fi \
+       | sed -e 's|/*$||'
 }
 
 Common::grepLdd () {
@@ -38,8 +41,16 @@ Common::stripLdd () {
 Multi::excludeLdd () {
        case "${system_name}" in
                'linux')
-                       egrep -v '/libc\./|/libX|/libxcb|/libGL' \
-                       | egrep -v '/libbsd\.|/libICE\.|/libselinux\.|/libSM.\.'
+                       # - always rely on up-to-date x11 and gl libraries, bundling them will break on future distros
+                       # - gtk is not easily bundlable on linux because it looks for harcoded system path to optional
+                       #   shared libraries like image codecs, theme engines, sound notification system, etc.
+                       #   so expect user to install gtk first
+                       # - since we ask user to instal gtk, we can also ask them to install gtkglext,
+                       #   which is likely to pull gtk itself, x11 and gl dependencies
+                       # - old fontconfig does not work correctly if newer fontconfig configuration is installed
+                       # - if gtk and fontconfig is installed, pango and freetype are
+                       egrep -v '/libc\.|/libstdc\+\+\.|/libdl\.|/libm\.|/libX|/libxcb|/libGL|/libICE\.|/libSM\.|/libpthread\.' \
+                       | egrep -v '/libatk|/libgdk|/libgtk|/libgio|/libglib|/libgmodule|/libgobject|/libcairo|/libpango|/libfontconfig|/libfreetype'
                        ;;
                'windows')
                        egrep -i '\.dll => [A-Z]:\\msys64\\' \
@@ -99,7 +110,7 @@ Multi::getRootPrefix () {
                        ;;
                'windows')
                        basename "${lib_file}" \
-                       | xargs -n1 -P 1 which \
+                       | xargs -n1 -P1 which \
                        | cut -f2 -d'/'
                        ;;
        esac
@@ -119,6 +130,29 @@ Multi::getLibPrefix () {
        esac
 }
 
+Multi::getGtkDeps () {
+       local lib_prefix="${1}"
+       local gtk_theme_name="${2}"
+
+       cat <<-EOF
+       share/themes/${gtk_theme_name}/gtk-2.0
+       share/icons/hicolor
+       ${lib_prefix}/gdk-pixbuf-2.0
+       ${lib_prefix}/gtk-2.0
+       EOF
+
+       case "${system_name}" in
+               'linux')
+                       cat <<-EOF
+                       ${lib_prefix}/libatk-bridge-2.0.so.0
+                       ${lib_prefix}/libcanberra-0.30
+                       ${lib_prefix}/libcanberra.so.0
+                       ${lib_prefix}/libcanberra-gtk.so.0
+                       EOF
+                       ;;
+       esac
+}
+
 Multi::bundleGtkDepsFromFile () {
        local lib_file="${1}"
 
@@ -131,19 +165,16 @@ Multi::bundleGtkDepsFromFile () {
                lib_prefix="$(Multi::getLibPrefix "${lib_file}")"
                gtk_theme_name="$(Multi::getGtkThemeName)"
 
-               for component_dir in \
-                       'share/themes/'"${gtk_theme_name}"'/gtk-2.0' \
-                       'share/icons/hicolor' \
-                       "${lib_prefix}"'/gdk-pixbuf-2.0' \
-                       "${lib_prefix}"'/gtk-2.0'
+               for component_dir in $(Multi::getGtkDeps "${lib_prefix}" "${gtk_theme_name}")
                do
-                       if ! [ -d "${bundle_dir}/${component_dir}" ]
+                       bundle_component_dir="$(echo "${component_dir}" | sed -e 's|^'"${lib_prefix}"'|lib|')"
+                       if ! [ -e "${bundle_dir}/${bundle_component_dir}" ]
                        then
-                               mkdir --parents "${bundle_dir}/$(dirname "${component_dir}")"
+                               mkdir --parents "${bundle_dir}/$(dirname "${bundle_component_dir}")"
 
-                               cp -r --preserve=timestamps \
+                               cp -H -r --preserve=timestamps \
                                        "/${root_prefix}/${component_dir}" \
-                                       "${bundle_dir}/${component_dir}"
+                                       "${bundle_dir}/${bundle_component_dir}"
                        fi
                done
        fi
@@ -158,7 +189,7 @@ Multi::bundleLibFromFile () {
        do
                lib_basename="$(basename "${lib_file}")"
 
-               if [ -f "${bundle_dir}/${lib_basename}" ]
+               if [ -f "${lib_dir}/${lib_basename}" ]
                then
                        continue
                fi
@@ -183,24 +214,61 @@ Multi::cleanUp () {
                -exec rm {} \;
 
        find "${bundle_dir}/lib" \
-               -type d \
                -depth \
+               -type d \
                -exec rmdir --ignore-fail-on-non-empty {} \;
 }
 
+Linux::getRpath () {
+       local exe_file="${1}"
+
+       local exe_dir="$(dirname "${exe_file}")"
+       local path_start="$(printf '%s' "${bundle_dir}" | wc -c)"
+       path_start="$((${path_start} + 1))"
+
+       local exe_subdir="$(echo "${exe_dir}" | cut -c "${path_start}-" | sed -e 's|//*|/|;s|^/||')"
+
+       local rpath_origin='$ORIGIN'
+
+       if [ "${exe_subdir}" = '' ]
+       then
+               printf '%s/lib\n' "${rpath_origin}"
+       else
+               if [ "${exe_subdir}" = 'lib' ]
+               then
+                       printf '%s\n' "${rpath_origin}"
+               else
+                       local num_parent_dir="$(echo "${exe_subdir}" | tr '/' '\n' | wc -l)"
+                       local rpath_subdir
+                       local i=0
+                       while [ "${i}" -lt "${num_parent_dir}" ]
+                       do
+                               rpath_subdir="${rpath_subdir}/.."
+                               i="$((${i} + 1))"
+                       done
+                       printf '%s%s/lib\n' "${rpath_origin}" "${rpath_subdir}"
+               fi
+       fi
+}
+
 Linux::patchExe () {
        local exe_file="${1}"
 
-       patchelf --set-rpath "${rpath_string}" "${exe_file}"
+       local linux_rpath_string=$"$(Linux::getRpath "${exe_file}")"
+       patchelf --set-rpath "${linux_rpath_string}" "${exe_file}"
 }
 
 Linux::patchLib () {
        local lib_dir="${1}"
+       local exe_file
 
        find "${lib_dir}" \
                -type f \
                -name '*.so*' \
-               -exec patchelf --set-rpath "${rpath_string}" {} \;
+       | while read exe_file
+       do
+               Linux::patchExe "${exe_file}"
+       done
 }
 
 Windows::listLibForManifest () {
@@ -229,7 +297,11 @@ Windows::writeManifest () {
 
 system_name="${1}"; shift
 bundle_dir="${1}"; shift
-exe_file="${1}"; shift
+
+if ! [ -z "${1}" ]
+then
+       exe_file="${1}"; shift
+fi
 
 bundle_dir="$(Common::getPath "${bundle_dir}")"
 registry_dir="${bundle_dir}/registry"
@@ -237,8 +309,6 @@ lib_dir="${bundle_dir}/lib"
 
 manifest_file="${lib_dir}/lib.manifest"
 
-rpath_string='@executable_path:lib'
-
 exe_action='Common::noOp'
 lib_action='Common::noOp'