6 export LANGUAGE="${LANG}"
9 case "${system_name}" in
20 case "${system_name}" in
22 gcp -R --preserve=timestamps -H -L "${1}" "${2}"
25 cp -R --preserve=timestamps -H -L "${1}" "${2}"
35 local file_path="${1}"
37 if command -v cygpath >/dev/null
39 if [ "${file_path}" = '-' ]
45 cygpath --unix "${file_path}"
48 if [ "${file_path}" = '-' ]
52 printf '%s\n' "${file_path}"
59 case "${system_name}" in
70 case "${system_name}" in
72 _sed -e 's/^\t\(.*\) (compatibility version .*/\1/'
75 _sed -e 's/ (0x[0-9a-f]*)$//;s/^.* => //'
80 Multi::excludeLdd () {
81 case "${system_name}" in
83 # - always bundle built-in libraries
84 # - always rely on up-to-date x11 and gl libraries, bundling them will break on future distros
85 # - gtk is not easily bundlable on linux because it looks for harcoded system path to optional
86 # shared libraries like image codecs, theme engines, sound notification system, etc.
87 # so expect user to install gtk first
88 # - since we ask user to instal gtk, we can also ask them to install gtkglext,
89 # which is likely to pull gtk itself, x11 and gl dependencies
90 # - old fontconfig does not work correctly if newer fontconfig configuration is installed
91 # - if gtk and fontconfig is installed, pango and freetype are
95 if echo "${ldd_line}" | egrep '/builtins/'
98 elif echo "${ldd_line}" \
99 | egrep -q '/libc\.|/libstdc\+\+\.|/libdl\.|/libm\.|/libX|/libxcb|/libGL|/libICE\.|/libSM\.|/libpthread\.'
102 elif echo "${ldd_line}" \
103 | egrep -q '/libatk|/libgdk|/libgtk|/libgio|/libglib|/libgmodule|/libgobject|/libcairo|/libpango|/libfontconfig|/libfreetype'
107 elif echo "${ldd_line}" \
108 | egrep -q '/libc\+\+|/libgxxrt'
117 egrep -i '\.dll => [A-Z]:\\msys64\\'
120 egrep -v '^\t/System/|^\t/usr/lib/'
125 Multi::filterLib () {
127 | Multi::excludeLdd \
133 local exe_file="${1}"
135 case "${system_name}" in
140 ntldd --recursive "${exe_file}"
143 otool -L "${exe_file}"
147 Multi::getGtkThemeName () {
148 case "${system_name}" in
161 Multi::getGtkLibName () {
162 case "${system_name}" in
164 echo 'libgtk-x11-2.0.so.0'
167 echo 'libgtk-win32-2.0-0.dll'
170 echo 'libgtk-quartz-2.0.0.dylib'
175 Multi::getRootPrefix () {
176 local lib_file="${1}"
178 case "${system_name}" in
186 basename "${lib_file}" \
187 | xargs -n1 -P1 which \
193 Multi::getLibPrefix () {
194 local lib_file="${1}"
196 case "${system_name}" in
198 dirname "${lib_file}" \
210 Multi::getGtkDeps () {
211 local lib_prefix="${1}"
212 local gtk_theme_name="${2}"
214 case "${system_name}" in
215 'linux'|'freebsd'|'windows')
217 share/themes/${gtk_theme_name}/gtk-2.0
219 ${lib_prefix}/gdk-pixbuf-2.0
220 ${lib_prefix}/gtk-2.0
226 share/themes/${gtk_theme_name}/gtk-2.0
230 ${lib_prefix}/gdk-pixbuf-2.0
231 ${lib_prefix}/gtk-2.0
236 case "${system_name}" in
239 ${lib_prefix}/libatk-bridge-2.0.so.0
240 ${lib_prefix}/libcanberra-0.30
241 ${lib_prefix}/libcanberra.so.0
242 ${lib_prefix}/libcanberra-gtk.so.0
248 Multi::rewriteLoadersCache () {
249 local bundle_component_path="${1}"
252 find "${bundle_component_path}" \
255 -name 'loaders.cache' \
256 -o -name 'immodules.cache' \
258 | while read cache_file
261 -e 's|^"/[^"]*/lib/|"lib/|;s| "/[^"]*/share/| "share/|;/^# ModulesPath = /d;/^# Created by /d;/^#$/d' \
266 Multi::bundleGtkDepsFromFile () {
267 local lib_file="${1}"
269 local real_component_dir
270 local bundle_component_dir
272 lib_basename="$(basename "${lib_file}")"
274 gtk_lib_name="$(Multi::getGtkLibName)"
275 if [ "${lib_basename}" = "${gtk_lib_name}" ]
277 root_prefix="$(Multi::getRootPrefix "${lib_file}")"
278 lib_prefix="$(Multi::getLibPrefix "${lib_file}")"
279 gtk_theme_name="$(Multi::getGtkThemeName)"
281 for component_dir in $(Multi::getGtkDeps "${lib_prefix}" "${gtk_theme_name}")
283 bundle_component_dir="$(echo "${component_dir}" | _sed -e 's|^'"${lib_prefix}"'|lib|')"
284 if ! [ -e "${bundle_dir}/${bundle_component_dir}" ]
286 real_component_dir="$(realpath "/${root_prefix}/${component_dir}")"
288 mkdir -p "${bundle_dir}/$(dirname "${bundle_component_dir}")"
291 "${real_component_dir}" \
292 "${bundle_dir}/${bundle_component_dir}"
294 Multi::rewriteLoadersCache "${bundle_dir}/${bundle_component_dir}"
300 Multi::bundleLibFromFile () {
301 local exe_file="${1}"
304 Multi::printLdd "${exe_file}" \
306 | while read lib_file
308 if [ "${lib_file}" = 'not found' ]
310 printf 'ERROR: library not found while bundling %s (but link worked)\n' "${exe_file}" >&2
311 Multi::printLdd "${exe_file}" | grep 'not found'
314 lib_basename="$(basename "${lib_file}")"
316 if [ -f "${lib_dir}/${lib_basename}" ]
323 "${lib_dir}/${lib_basename}"
325 Multi::bundleGtkDepsFromFile "${lib_file}"
327 case "${system_name}" in
329 Multi::bundleLibFromFile "${lib_file}"
336 # Remove from bundle things that useless to be distributed,
337 # like headers or static libraries, also remove
339 find "${bundle_dir}/lib" \
344 find "${bundle_dir}/lib" \
349 find "${bundle_dir}/lib" \
357 local exe_file="${1}"
359 local exe_dir="$(dirname "${exe_file}")"
360 local path_start="$(printf '%s' "${bundle_dir}" | wc -c)"
361 path_start="$((${path_start} + 1))"
363 local exe_subdir="$(echo "${exe_dir}" | cut -c "${path_start}-" | _sed -e 's|//*|/|;s|^/||')"
365 local rpath_origin='$ORIGIN'
367 if [ "${exe_subdir}" = '' ]
369 printf '%s/lib\n' "${rpath_origin}"
371 if [ "${exe_subdir}" = 'lib' ]
373 printf '%s\n' "${rpath_origin}"
375 local num_parent_dir="$(echo "${exe_subdir}" | tr '/' '\n' | wc -l)"
378 while [ "${i}" -lt "${num_parent_dir}" ]
380 rpath_subdir="${rpath_subdir}/.."
383 printf '%s%s/lib\n' "${rpath_origin}" "${rpath_subdir}"
389 local exe_file="${1}"
391 local linux_rpath_string=$"$(Linux::getRpath "${exe_file}")"
392 chmod u+w,go-w "${exe_file}"
393 patchelf --set-rpath "${linux_rpath_string}" "${exe_file}"
403 | while read exe_file
405 Linux::patchExe "${exe_file}"
406 chmod ugo-x "${exe_file}"
410 Darwin::patchExe () {
411 local exe_file="${1}"
413 Multi::printLdd "${exe_file}" \
415 | while read lib_file
417 new_path="$(echo "${lib_file}" | _sed -e 's|^/.*/lib/|@executable_path/lib/|')"
418 id_name="$(echo "${lib_file}" | _sed -e 's|.*/||g')"
419 chmod u+w,go-w "${exe_file}"
420 install_name_tool -change "${lib_file}" "${new_path}" "${exe_file}"
421 install_name_tool -id "${id_name}" "${exe_file}"
425 Darwin::patchLib () {
435 | while read exe_file
437 Darwin::patchExe "${exe_file}"
438 chmod ugo-x "${exe_file}"
442 Windows::listLibForManifest () {
449 -exec basename {} \; \
451 | xargs -0 -P1 -I{} \
452 printf ' <file name="{}"/>\n'
455 Windows::writeManifest () {
458 cat > "${manifest_file}" <<-EOF
459 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
460 <assemblyIdentity type="win32" name="lib" version="1.0.0.0"/>
461 $(Windows::listLibForManifest "${lib_dir}")
466 system_name="${1}"; shift
467 bundle_dir="${1}"; shift
471 exe_file="${1}"; shift
474 bundle_dir="$(Common::getPath "${bundle_dir}")"
475 registry_dir="${bundle_dir}/registry"
476 lib_dir="${bundle_dir}/lib"
478 manifest_file="${lib_dir}/lib.manifest"
480 exe_action='Common::noOp'
481 lib_action='Common::noOp'
483 case "${system_name}" in
485 mkdir -p "${registry_dir}"
486 Common::getPath "${exe_file}" > "${registry_dir}/$(uuidgen)"
490 exe_action='Linux::patchExe'
491 lib_action='Linux::patchLib'
494 lib_action='Windows::writeManifest'
497 exe_action='Darwin::patchExe'
498 lib_action='Darwin::patchLib'
501 printf 'ERROR: unsupported system: %s\n' "${system_name}" >&2
506 mkdir -p "${lib_dir}"
508 if [ -d "${registry_dir}" ]
510 for registry_entry in "${registry_dir}"/*
512 exe_file="$(cat "${registry_entry}")"
514 Multi::bundleLibFromFile "${exe_file}"
516 "${exe_action}" "${exe_file}"
518 rm "${registry_entry}"
520 "${exe_action}" "${exe_file}"
523 rmdir "${registry_dir}"
526 "${lib_action}" "${lib_dir}"