]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - library-bundler
bundle: do not bundle libstdc++, pango, and some remaining X11 stuff on Linux
[xonotic/netradiant.git] / library-bundler
1 #! /usr/bin/env bash
2
3 Common::noOp () {
4         printf ''
5 }
6
7 Common::getPath () {
8         local file_path="${1}"
9
10         if command -v cygpath >/dev/null
11         then
12                 if [ "${file_path}" = '-' ]
13                 then
14                         tr '\n' '\0' \
15                         | xargs -0 -n1 -P1 -I{} \
16                                 cygpath --unix '{}'
17                 else
18                         cygpath --unix "${file_path}"
19                 fi
20         else
21                 if [ "${file_path}" = '-' ]
22                 then
23                         cat
24                 else
25                         printf '%s\n' "${file_path}"
26                 fi
27         fi
28 }
29
30 Common::grepLdd () {
31         egrep ' => '
32 }
33
34 Common::stripLdd () {
35         sed -e 's/ (0x[0-9a-f]*)$//;s/^.* => //'
36 }
37
38 Multi::excludeLdd () {
39         case "${system_name}" in
40                 'linux')
41                         # - always rely on up-to-date x11 and gl libraries, bundling them will break on future distros
42                         # - gtk is not easily bundlable on linux because it looks for harcoded system path to optional
43                         #   shared libraries like image codecs, theme engines, sound notification system, etc.
44                         #   so expect user to install gtk first
45                         # - since we ask user to instal gtk, we can also ask them to install gtkglext,
46                         #   which is likely to pull gtk itself, x11 and gl dependencies
47                         # - old fontconfig does not work correctly if newer fontconfig configuration is installed
48                         # - if gtk and fontconfig is installed, pango and freetype are
49                         egrep -v '/libc\.|/libstdc\+\+\.|/libdl\.|/libm\.|/libX|/libxcb|/libGL|/libICE\.|/libSM\.' \
50                         | egrep -v '/libatk|/libgdk|/libgtk|/libgio|/libglib|/libgmodule|/libgobject|/libpango|/libfontconfig|/libfreetype'
51                         ;;
52                 'windows')
53                         egrep -i '\.dll => [A-Z]:\\msys64\\' \
54                         ;;
55         esac
56 }
57
58 Multi::filterLib () {
59         Common::grepLdd \
60         | Multi::excludeLdd \
61         | Common::stripLdd \
62         | Common::getPath -
63 }
64
65 Multi::printLdd () {
66         local exe_file="${1}"
67
68         case "${system_name}" in
69                 'linux')
70                         ldd "${exe_file}"
71                         ;;
72                 'windows')
73                         ntldd --recursive "${exe_file}"
74                         ;;
75         esac
76 }
77
78 Multi::getGtkThemeName () {
79         case "${system_name}" in
80                 'linux')
81                         echo 'Adwaita'
82                         ;;
83                 'windows')
84                         echo 'MS-Windows'
85                         ;;
86         esac
87 }
88
89 Multi::getGtkLibName () {
90         case "${system_name}" in
91                 'linux')
92                         echo 'libgtk-x11-2.0.so.0'
93                         ;;
94                 'windows')
95                         echo 'libgtk-win32-2.0-0.dll'
96                         ;;
97         esac
98 }
99
100 Multi::getRootPrefix () {
101         local lib_file="${1}"
102
103         case "${system_name}" in
104                 'linux')
105                         echo "${lib_file}" \
106                         | cut -f2 -d'/'
107                         ;;
108                 'windows')
109                         basename "${lib_file}" \
110                         | xargs -n1 -P 1 which \
111                         | cut -f2 -d'/'
112                         ;;
113         esac
114 }
115
116 Multi::getLibPrefix () {
117         local lib_file="${1}"
118
119         case "${system_name}" in
120                 'linux')
121                         dirname "${lib_file}" \
122                         | cut -f3- -d'/'
123                         ;;
124                 'windows')
125                         echo 'lib'
126                         ;;
127         esac
128 }
129
130 Multi::getGtkDeps () {
131         local lib_prefix="${1}"
132         local gtk_theme_name="${2}"
133
134         cat <<-EOF
135         share/themes/${gtk_theme_name}/gtk-2.0
136         share/icons/hicolor
137         ${lib_prefix}/gdk-pixbuf-2.0
138         ${lib_prefix}/gtk-2.0
139         EOF
140
141         case "${system_name}" in
142                 'linux')
143                         cat <<-EOF
144                         ${lib_prefix}/libatk-bridge-2.0.so.0
145                         ${lib_prefix}/libcanberra-0.30
146                         ${lib_prefix}/libcanberra.so.0
147                         ${lib_prefix}/libcanberra-gtk.so.0
148                         EOF
149                         ;;
150         esac
151 }
152
153 Multi::bundleGtkDepsFromFile () {
154         local lib_file="${1}"
155
156         lib_basename="$(basename "${lib_file}")"
157
158         gtk_lib_name="$(Multi::getGtkLibName)"
159         if [ "${lib_basename}" = "${gtk_lib_name}" ]
160         then
161                 root_prefix="$(Multi::getRootPrefix "${lib_file}")"
162                 lib_prefix="$(Multi::getLibPrefix "${lib_file}")"
163                 gtk_theme_name="$(Multi::getGtkThemeName)"
164
165                 for component_dir in $(Multi::getGtkDeps "${lib_prefix}" "${gtk_theme_name}")
166                 do
167                         bundle_component_dir="$(echo "${component_dir}" | sed -e 's|^'"${lib_prefix}"'|lib|')"
168                         if ! [ -e "${bundle_dir}/${bundle_component_dir}" ]
169                         then
170                                 mkdir --parents "${bundle_dir}/$(dirname "${bundle_component_dir}")"
171
172                                 cp -H -r --preserve=timestamps \
173                                         "/${root_prefix}/${component_dir}" \
174                                         "${bundle_dir}/${bundle_component_dir}"
175                         fi
176                 done
177         fi
178 }
179
180 Multi::bundleLibFromFile () {
181         local exe_file="${1}"
182
183         Multi::printLdd "${exe_file}" \
184         | Multi::filterLib \
185         | while read lib_file
186         do
187                 lib_basename="$(basename "${lib_file}")"
188
189                 if [ -f "${bundle_dir}/${lib_basename}" ]
190                 then
191                         continue
192                 fi
193
194                 cp --preserve=timestamps \
195                         "${lib_file}" \
196                         "${lib_dir}/${lib_basename}"
197
198                 Multi::bundleGtkDepsFromFile "${lib_file}"
199         done
200 }
201
202 Multi::cleanUp () {
203         find "${bundle_dir}/lib" \
204                 -type f \
205                 -name '*.a' \
206                 -exec rm {} \;
207
208         find "${bundle_dir}/lib" \
209                 -type f \
210                 -name '*.h' \
211                 -exec rm {} \;
212
213         find "${bundle_dir}/lib" \
214                 -type d \
215                 -depth \
216                 -exec rmdir --ignore-fail-on-non-empty {} \;
217 }
218
219 Linux::patchExe () {
220         local exe_file="${1}"
221
222         patchelf --set-rpath "${rpath_string}" "${exe_file}"
223 }
224
225 Linux::patchLib () {
226         local lib_dir="${1}"
227
228         find "${lib_dir}" \
229                 -type f \
230                 -name '*.so*' \
231                 -exec patchelf --set-rpath "${rpath_string}" {} \;
232 }
233
234 Windows::listLibForManifest () {
235         local lib_dir="${1}"
236
237         find "${lib_dir}" \
238                 -maxdepth 1 \
239                 -type f \
240                 -name '*.dll' \
241                 -exec basename {} \; \
242         | tr '\n' '\0' \
243         | xargs -0 -n1 -P1 -I{} \
244                 printf '  <file name="{}"/>\n'
245 }
246
247 Windows::writeManifest () {
248         local lib_dir="${1}"
249
250         cat > "${manifest_file}" <<-EOF
251         <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
252           <assemblyIdentity type="win32" name="lib" version="1.0.0.0"/>
253         $(Windows::listLibForManifest "${lib_dir}")
254         </assembly>
255         EOF
256 }
257
258 system_name="${1}"; shift
259 bundle_dir="${1}"; shift
260 exe_file="${1}"; shift
261
262 bundle_dir="$(Common::getPath "${bundle_dir}")"
263 registry_dir="${bundle_dir}/registry"
264 lib_dir="${bundle_dir}/lib"
265
266 manifest_file="${lib_dir}/lib.manifest"
267
268 rpath_string='@executable_path:lib'
269
270 exe_action='Common::noOp'
271 lib_action='Common::noOp'
272
273 case "${system_name}" in
274         'register')
275                 mkdir --parents "${registry_dir}"
276                 Common::getPath "${exe_file}" > "${registry_dir}/$(uuidgen)"
277                 exit
278                 ;;
279         'linux')
280                 exe_action='Linux::patchExe'
281                 lib_action='Linux::patchLib'
282                 ;;
283         'windows')
284                 lib_action='Windows::writeManifest'
285                 ;;
286         *)
287                 printf 'ERROR: unsupported system: %s\n' "${system_name}" >&2
288                 exit 1
289                 ;;
290 esac
291
292 mkdir --parents "${lib_dir}"
293
294 if [ -d "${registry_dir}" ]
295 then
296         for registry_entry in "${registry_dir}"/*
297         do
298                 exe_file="$(cat "${registry_entry}")"
299
300                 Multi::bundleLibFromFile "${exe_file}"
301
302                 "${exe_action}" "${exe_file}"
303
304                 rm "${registry_entry}"
305
306                 "${exe_action}" "${exe_file}"
307         done
308
309         rmdir "${registry_dir}"
310 fi
311
312 "${lib_action}" "${lib_dir}"
313
314 Multi::cleanUp