Try to fix building the GTK flavor OS X app.
[metze/wireshark/wip.git] / packaging / macosx / osx-app.sh
1 #!/bin/bash
2 #
3 # $Id$
4 #
5 # USAGE
6 # osx-app [-s] [-l /path/to/libraries] -bp /path/to/wireshark/bin -p /path/to/Info.plist
7 #
8 # This script attempts to build an Wireshark.app package for OS X, resolving
9 # dynamic libraries, etc.
10 # It strips the executable and libraries if '-s' is given.
11 # It adds python modules if the '-py option' is given
12 # The Info.plist file can be found in the base wireshark directory once
13 # configure has been run.
14 #
15 # AUTHORS
16 #                Kees Cook <kees@outflux.net>
17 #                Michael Wybrow <mjwybrow@users.sourceforge.net>
18 #                Jean-Olivier Irisson <jo.irisson@gmail.com>
19 #
20 # Copyright (C) 2005 Kees Cook
21 # Copyright (C) 2005-2007 Michael Wybrow
22 # Copyright (C) 2007 Jean-Olivier Irisson
23 #
24 # Released under GNU GPL, read the file 'COPYING' for more information
25 #
26 # Thanks to GNUnet's "build_app" script for help with library dep resolution.
27 #               https://gnunet.org/svn/GNUnet/contrib/OSX/build_app
28 #
29 # NB:
30 # This originally came from Inkscape; Inkscape's configure script has an
31 # "--enable-osxapp", which causes some of Inkscape's installation data
32 # files to have OS X-ish paths under Contents/Resources of the package
33 # or under /Library/Application Support.  We don't have such an option;
34 # we just put them in "bin", "etc", "lib", and "share" directories
35 # under Contents/Resources, rather than in the "bin", "etc", "lib",
36 # and "share" directories under the installation directory.
37 #
38
39 # Defaults
40 strip=false
41 binary_path="/tmp/inst/bin"
42 plist="./Info.plist"
43 util_dir="./Utilities"
44 cli_dir="$util_dir/Command Line"
45 chmodbpf_dir="$util_dir/ChmodBPF"
46
47 # "qt" or "gtk"
48 ui_toolkit="gtk"
49 # Name of the Wireshark executable
50 wireshark_bin_name="wireshark"
51
52 binary_list="
53         capinfos
54         dftest
55         dumpcap
56         editcap
57         mergecap
58         randpkt
59         rawshark
60         text2pcap
61         tshark
62 "
63
64 # Location for libraries (macosx-setup.sh defaults to whatever the
65 # various support libraries use as their standard installation location,
66 # which is /usr/local)
67 if [ -z $LIBPREFIX ]; then
68         LIBPREFIX="/usr/local"
69 fi
70
71
72 # Help message
73 #----------------------------------------------------------
74 help()
75 {
76 echo -e "
77 Create an app bundle for OS X
78
79 USAGE
80         $0 [-s] [-l /path/to/libraries] [-qt] -bp /path/to/wireshark/binaries -p /path/to/Info.plist
81
82 OPTIONS
83         -h,--help
84                 display this help message
85         -s
86                 strip the libraries and executables from debugging symbols
87         -l,--libraries
88                 specify the path to the libraries Wireshark depends on
89                 (typically /sw or /opt/local).  By default it is
90                 /usr/local.
91         -bp,--binary-path
92                 specify the path to the Wireshark binaries. By default it
93                 is /tmp/inst/bin.
94         -p,--plist
95                 specify the path to Info.plist. Info.plist can be found
96                 in the base directory of the source code once configure
97                 has been run.
98         -sdkroot
99                 specify the root of the SDK to use
100         -qt,--qt-flavor
101                 use the Qt flavor
102
103 EXAMPLE
104         $0 -s -l /opt/local -bp ../../Build/bin -p Info.plist -sdkroot /Developer/SDKs/MacOSX10.5.sdk
105 "
106 }
107
108
109 # Parse command line arguments
110 #----------------------------------------------------------
111 while [ "$1" != "" ]
112 do
113         case $1 in
114                 -s)
115                         strip=true ;;
116                 -l|--libraries)
117                         LIBPREFIX="$2"
118                         shift 1 ;;
119                 -bp|--binary-path)
120                         binary_path="$2"
121                         shift 1 ;;
122                 -p|--plist)
123                         plist="$2"
124                         shift 1 ;;
125                 -qt|--qt-flavor)
126                         ui_toolkit="qt"
127                         wireshark_bin_name="wireshark-qt"
128                         ;;
129                 -h|--help)
130                         help
131                         exit 0 ;;
132                 -sdkroot)
133                         sdkroot="$2"
134                         shift 1 ;;
135                 *)
136                         echo "Invalid command line option: $1"
137                         exit 2 ;;
138         esac
139         shift 1
140 done
141
142 echo -e "\nCREATE WIRESHARK APP BUNDLE\n"
143
144 # Safety tests
145 if [ ! -e "$LIBPREFIX" ]; then
146         echo "Cannot find the directory containing the libraries: $LIBPREFIX" >&2
147         exit 1
148 fi
149
150 for binary in $wireshark_bin_name $binary_list ; do
151         if [ ! -x "$binary_path/$binary" ]; then
152                 echo "Couldn't find $binary (or it's not executable)" >&2
153                 exit 1
154         fi
155 done
156
157 if [ ! -f "$plist" ]; then
158         echo "Need plist file" >&2
159         exit 1
160 fi
161
162
163 # Handle some version specific details.
164 VERSION=`/usr/bin/sw_vers | grep ProductVersion | cut -f2 -d'.'`
165 if [ "$VERSION" -ge "4" ]; then
166         # We're on Tiger (10.4) or later.
167         # XCode behaves a little differently in Tiger and later.
168         XCODEFLAGS="-configuration Deployment"
169         SCRIPTEXECDIR="ScriptExec/build/Deployment/ScriptExec.app/Contents/MacOS"
170         EXTRALIBS=""
171 else
172         # Panther (10.3) or earlier.
173         XCODEFLAGS="-buildstyle Deployment"
174         SCRIPTEXECDIR="ScriptExec/build/ScriptExec.app/Contents/MacOS"
175         EXTRALIBS=""
176 fi
177
178 # Set the SDK root, if an SDK was specified.
179 # (-sdk is only supported by the xcodebuild in the version of the
180 # developer tools that came with Snow Leopard and later versions)
181 if [ ! -z "$sdkroot" ]
182 then
183         XCODEFLAGS="$XCODEFLAGS SDKROOT=$sdkroot"
184 fi
185
186 # Package always has the same name. Version information is stored in
187 # the Info.plist file which is filled in by the configure script.
188 package="Wireshark.app"
189
190 # Remove a previously existing package if necessary
191 if [ -d $package ]; then
192         echo "Removing previous Wireshark.app"
193         rm -Rf $package
194 fi
195
196 # Remove a previously existing utility directory if necessary
197 if [ -d "$util_dir" ]; then
198         echo "Removing $util_dir directory"
199         rm -Rf "$util_dir"
200 fi
201
202 # Set the 'macosx' directory, usually the current directory.
203 resdir=`pwd`
204
205
206 # Prepare Package
207 #----------------------------------------------------------
208 pkgexec="$package/Contents/MacOS"
209 pkgres="$package/Contents/Resources"
210 pkgbin="$pkgexec"
211 if [ "$ui_toolkit" = "gtk" ] ; then
212         pkgbin="$pkgres/bin"
213 fi
214 # Should pkglib be Contents/Frameworks instead?
215 #pkglib="$pkgres/lib"
216 pkglib="$package/Contents/Frameworks"
217 pkgqtplugin="$package/Contents/PlugIns"
218 pkgplugin="$pkglib/wireshark/plugins"
219 pkgpython="$pkglib/wireshark/python"
220
221 mkdir -p "$pkgexec"
222 mkdir -p "$pkgbin"
223 mkdir -p "$pkgqtplugin"
224 mkdir -p "$pkgplugin"
225 mkdir -p "$pkgpython"
226
227 mkdir -p "$cli_dir"
228
229 if [ "$ui_toolkit" = "qt" ] ; then
230         cp "$binary_path/$wireshark_bin_name" "$pkgexec/Wireshark"
231 else
232 # Build and add the launcher
233 #----------------------------------------------------------
234         (
235                 # Build fails if CC happens to be set (to anything other than CompileC)
236                 unset CC
237
238                 cd "$resdir/ScriptExec"
239                 echo -e "Building launcher...\n"
240                 xcodebuild $XCODEFLAGS clean build
241         )
242         cp "$resdir/$SCRIPTEXECDIR/ScriptExec" "$pkgexec/Wireshark"
243
244 fi
245
246 # Copy all files into the bundle
247 #----------------------------------------------------------
248 echo -e "\nFilling app bundle and utility directory...\n"
249
250 # Wireshark executables
251 if [ "$ui_toolkit" = "gtk" ] ; then
252         cp -v utility-launcher "$cli_dir/$binary"
253         for binary in $binary_list wireshark ; do
254                 # Copy the binary to its destination
255                 dest_path="$pkgbin/$binary-bin"
256                 cp -v "$binary_path/$binary" "$dest_path"
257                 # TODO Add a "$verbose" variable and command line switch, which sets wether these commands are verbose or not
258
259                 if [ "$binary" != "wireshark" ] ; then
260                         ln -sv ./wireshark "$pkgbin/$binary"
261                         ln -sv ./wireshark "$cli_dir/$binary"
262                 fi
263         done
264 elif [ "$ui_toolkit" = "qt" ] ; then
265         for binary in $binary_list ; do
266                 # Copy the binary to its destination
267                 cp -v "$binary_path/$binary" "$pkgexec"
268         done
269 fi
270
271 # ChmodBPF
272 mkdir -p "$chmodbpf_dir"
273 cp -v ChmodBPF/* "$chmodbpf_dir"
274 chmod -R g-w "$chmodbpf_dir"
275
276 # The rest of the Wireshark installation (we handled bin above)
277 rsync -av \
278         --exclude bin/ \
279         --exclude lib/ \
280         "$binary_path/.."/* "$pkgres"
281
282 rsync -av $binary_path/../lib/*.dylib "$pkglib/"
283
284 # Remove the version number from the plugin path
285 find "$binary_path/../lib/wireshark/plugins" -type f \
286         -exec cp -fv "{}" "$pkgplugin/" \;
287
288 # Remove the version number from the python path
289 find "$binary_path/../lib/wireshark/python" -type f \
290         -exec cp -fv "{}" "$pkgpython/" \;
291
292 cp "$plist" "$package/Contents/Info.plist"
293
294 # Icons and the rest of the script framework
295 res_list="
296         Wireshark.icns
297         Wiresharkdoc.icns
298         bin
299         openDoc
300 "
301
302 if [ "$ui_toolkit" = "gtk" ] ; then
303         res_list="
304                 $res_list
305                 etc
306                 script
307                 MenuBar.nib
308                 ProgressWindow.nib
309                 themes
310         "
311 fi
312
313 for rl_entry in $res_list ; do
314         rsync -av "$resdir"/Resources/$rl_entry "$package"/Contents/Resources/
315 done
316
317 # PkgInfo must match bundle type and creator code from Info.plist
318 echo "APPLWshk" > $package/Contents/PkgInfo
319
320 if [ "$ui_toolkit" = "gtk" ] ; then
321
322         # Pull in extra requirements for Pango and GTK
323         pkgetc="$package/Contents/Resources/etc"
324         mkdir -p $pkgetc/pango
325         cp $LIBPREFIX/etc/pango/pangox.aliases $pkgetc/pango/
326         # Need to adjust path and quote in case of spaces in path.
327         sed -e "s,$LIBPREFIX,\"\${CWD},g" -e 's,\.so ,.so" ,g' $LIBPREFIX/etc/pango/pango.modules > $pkgetc/pango/pango.modules
328         cat > $pkgetc/pango/pangorc <<END_PANGO
329 [Pango]
330 ModuleFiles=\${HOME}/.wireshark-etc/pango.modules
331 [PangoX]
332 AliasFiles=\${HOME}/.wireshark-etc/pangox.aliases
333 END_PANGO
334
335         # We use a modified fonts.conf file so only need the dtd
336         mkdir -p $pkgetc/fonts
337         cp $LIBPREFIX/etc/fonts/fonts.dtd $pkgetc/fonts/
338         cp -r $LIBPREFIX/etc/fonts/conf.avail $pkgetc/fonts/
339         cp -r $LIBPREFIX/etc/fonts/conf.d $pkgetc/fonts/
340
341         mkdir -p $pkgetc/gtk-2.0
342         #
343         # In newer versions of GTK+, the gdk-pixbuf library was split off from
344         # GTK+, and the gdk-pixbuf.loaders file moved, so we check for its
345         # existence here.
346         #
347         # The file is ultimately copied to the user's home directory, with
348         # the pathnames adjusted to refer to the installed package, so we
349         # always put it in the same location in the installed package,
350         # regardless of where it lives in the machine on which it's built.
351         #
352         if [ -e $LIBPREFIX/etc/gtk-2.0/gdk-pixbuf.loaders ]
353         then
354                 sed -e "s,$LIBPREFIX,\${CWD},g" $LIBPREFIX/etc/gtk-2.0/gdk-pixbuf.loaders > $pkgetc/gtk-2.0/gdk-pixbuf.loaders
355         fi
356         sed -e "s,$LIBPREFIX,\${CWD},g" $LIBPREFIX/etc/gtk-2.0/gtk.immodules > $pkgetc/gtk-2.0/gtk.immodules
357
358         pango_version=`pkg-config --variable=pango_module_version pango`
359         mkdir -p $pkglib/pango/$pango_version/modules
360         cp $LIBPREFIX/lib/pango/$pango_version/modules/*.so $pkglib/pango/$pango_version/modules/
361
362         gtk_version=`pkg-config --variable=gtk_binary_version gtk+-2.0`
363         mkdir -p $pkglib/gtk-2.0/$gtk_version/{engines,immodules,loaders}
364         cp -r $LIBPREFIX/lib/gtk-2.0/$gtk_version/* $pkglib/gtk-2.0/$gtk_version/
365
366         gdk_pixbuf_version=`pkg-config --variable=gdk_pixbuf_binary_version gdk-pixbuf-2.0`
367         if [ ! -z $gdk_pixbuf_version ]; then
368                 mkdir -p $pkglib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders
369                 #
370                 # As per the above, check whether we have a loaders.cache file
371                 # in $LIBPREFIX/lib/gdk-pixbuf-2.0/$gdk_pixbuf_version, as
372                 # that's where the output of gdk-pixbuf-query-loaders gets
373                 # put if gdk-pixbuf and GTK+ are separated.
374                 #
375                 # The file is ultimately copied to the user's home directory,
376                 # with the pathnames adjusted to refer to the installed package,
377                 # so we always put it in the same location in the installed
378                 # package, regardless of where it lives in the machine on which
379                 # it's built.
380                 #
381                 if [ -e $LIBPREFIX/lib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders.cache ]
382                 then
383                         sed -e "s,$LIBPREFIX,\${CWD},g" $LIBPREFIX/lib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders.cache > $pkgetc/gtk-2.0/gdk-pixbuf.loaders
384                 fi
385                 cp -r $LIBPREFIX/lib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders/* $pkglib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders
386         fi
387 fi # GTK+ / Qt
388
389 # Find out libs we need from Fink, MacPorts, or from a custom install
390 # (i.e. $LIBPREFIX), then loop until no changes.
391 a=1
392 nfiles=0
393 endl=true
394 lib_dep_search_list="
395         $pkglib/*
396         $pkgbin/*-bin
397         "
398 if [ "$ui_toolkit" = "gtk" ] ; then
399         lib_dep_search_list="
400                 $lib_dep_search_list
401                 $pkglib/gtk-2.0/$gtk_version/loaders/*
402                 $pkglib/gtk-2.0/$gtk_version/immodules/*
403                 $pkglib/gtk-2.0/$gtk_version/engines/*.so
404                 $pkglib/pango/$pango_version/modules/*
405                 $pkglib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders/*
406                 "
407 elif [ "$ui_toolkit" = "qt" ] ; then
408         lib_dep_search_list="
409                 $pkgexec/Wireshark
410                 $lib_dep_search_list
411                 "
412 fi
413
414 while $endl; do
415         echo -e "Looking for dependencies. Round" $a
416         libs="`otool -L $lib_dep_search_list 2>/dev/null | fgrep compatibility | cut -d\( -f1 | grep $LIBPREFIX | sort | uniq`"
417         cp -vn $libs "$pkglib"
418         let "a+=1"
419         nnfiles=`ls "$pkglib" | wc -l`
420         if [ $nnfiles = $nfiles ]; then
421                 endl=false
422         else
423                 nfiles=$nnfiles
424         fi
425 done
426
427 # Add extra libraries of necessary
428 for libfile in $EXTRALIBS
429 do
430         cp -f $libfile "$pkglib"
431 done
432 chmod 755 "$pkglib"/*.dylib
433
434 # Strip libraries and executables if requested
435 #----------------------------------------------------------
436 if [ "$strip" = "true" ]; then
437         echo -e "\nStripping debugging symbols...\n"
438         strip -x "$pkglib"/*.dylib
439         strip -ur "$binpath"
440 fi
441
442 # NOTE: we must rpathify *all* files, *including* plugins for GTK+ etc.,
443 #       to keep GTK+ from crashing at startup.
444 #
445 rpathify_file () {
446         # Fix a given executable, library, or plugin to be relocatable
447         if [ ! -d "$1" ]; then
448                 #
449                 # OK, what type of file is this?
450                 #
451                 filetype=`otool -hv "$1" | sed -n '4p' | awk '{print $5}'`
452                 case "$filetype" in
453
454                 EXECUTE|DYLIB|BUNDLE)
455                         #
456                         # Executable, library, or plugin.  (Plugins
457                         # can be either DYLIB or BUNDLE; shared
458                         # libraries are DYLIB.)
459                         #
460                         # For DYLIB and BUNDLE, fix the shared
461                         # library identification.
462                         #
463                         if [[ "$filetype" = "DYLIB" || "$filetype" = "BUNDLE" ]]; then
464                                 echo "Changing shared library identification of $1"
465                                 base=`echo $1 | awk -F/ '{print $NF}'`
466                                 #
467                                 # The library will end up in a directory in
468                                 # the rpath; this is what we should change its
469                                 # ID to.
470                                 #
471                                 to=@rpath/$base
472                                 /usr/bin/install_name_tool -id $to $1
473                         fi
474
475                         #
476                         # Get the list of dynamic libraries on which this
477                         # file depends, and select only the libraries that
478                         # are in $LIBPREFIX, as those are the only ones
479                         # that we'll be shipping in the app bundle; the
480                         # other libraries are system-supplied or supplied
481                         # as part of X11, will be expected to be on the
482                         # system on which the bundle will be installed,
483                         # and should be referred to by their full pathnames.
484                         #
485                         libs="`otool -L $1 | egrep "$LIBPREFIX.* \(compatibility" | cut -d\( -f1`"
486                         for lib in $libs; do
487                                 #
488                                 # Get the file name of the library.
489                                 #
490                                 base=`echo $lib | awk -F/ '{print $NF}'`
491                                 #
492                                 # The library will end up in a directory in
493                                 # the rpath; this is what we should change its
494                                 # file name to.
495                                 #
496                                 to=@rpath/$base
497                                 #
498                                 # Change the reference to that library.
499                                 #
500                                 echo "Changing reference to $lib to $to in $1"
501                                 /usr/bin/install_name_tool -change $lib $to $1
502                         done
503                         ;;
504                 esac
505         fi
506 }
507
508 rpathify_dir () {
509         #
510         # Make sure we *have* that directory
511         #
512         if [ -d "$1" ]; then
513                 (cd "$1"
514                 #
515                 # Make sure we *have* files to fix
516                 #
517                 files=`ls $2 2>/dev/null`
518                 if [ ! -z "$files" ]; then
519                         for file in $files; do
520                                 rpathify_file "$file" "`pwd`"
521                         done
522                 fi
523                 )
524         fi
525 }
526
527 rpathify_files () {
528         #
529         # Fix package deps
530         #
531         rpathify_dir "$pkglib" "*.dylib"
532         if [ "$ui_toolkit" = "gtk" ] ; then
533                 rpathify_dir "$pkglib/gtk-2.0/$gtk_version/loaders" "*.so"
534                 rpathify_dir "$pkglib/gtk-2.0/$gtk_version/engines" "*.so"
535                 rpathify_dir "$pkglib/gtk-2.0/$gtk_version/immodules" "*.so"
536                 rpathify_dir "$pkglib/gtk-2.0/$gtk_version/printbackends" "*.so"
537                 rpathify_dir "$pkglib/gnome-vfs-2.0/modules" "*.so"
538                 rpathify_dir "$pkglib/gdk-pixbuf-2.0/$gtk_version/loaders" "*.so"
539                 rpathify_dir "$pkglib/pango/$pango_version/modules" "*.so"
540         fi
541         rpathify_dir "$pkgbin" "*"
542 }
543
544 PATHLENGTH=`echo $LIBPREFIX | wc -c`
545 if [ "$PATHLENGTH" -ge "6" ]; then
546         # If the LIBPREFIX path is long enough to allow 
547         # path rewriting, then do this.
548         # 6 is the length of @rpath, which replaces LIBPREFIX.
549         rpathify_files
550 else
551         echo "Could not rewrite dylib paths for bundled libraries.  This requires" >&2
552         echo "the support libraries to be installed in a PREFIX of at least 6 characters in length." >&2
553         echo "" >&2
554         echo "The package will still work if the following line is uncommented in" >&2
555         echo "Wireshark.app/Contents/Resources/bin/{various scripts}:" >&2
556         echo '        export DYLD_LIBRARY_PATH="$TOP/lib"' >&2
557         exit 1
558
559 fi
560
561 if [ "$ui_toolkit" = "qt" ] ; then
562         macdeployqt "$package" -verbose=2
563 fi
564
565 exit 0