419143e9873431b20d4f827a932194cc7633a72d
[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="$pkgres/bin"
211 # Should pkglib be Contents/Frameworks instead?
212 #pkglib="$pkgres/lib"
213 pkglib="$package/Contents/Frameworks"
214 pkgqtplugin="$package/Contents/PlugIns"
215 pkgplugin="$pkglib/wireshark/plugins"
216 pkgpython="$pkglib/wireshark/python"
217
218 mkdir -p "$pkgexec"
219 mkdir -p "$pkgbin"
220 mkdir -p "$pkgqtplugin"
221 mkdir -p "$pkgplugin"
222 mkdir -p "$pkgpython"
223
224 mkdir -p "$cli_dir"
225
226 if [ "$ui_toolkit" = "qt" ] ; then
227         cp "$binary_path/$wireshark_bin_name" "$pkgexec/Wireshark"
228 else
229 # Build and add the launcher
230 #----------------------------------------------------------
231         (
232                 # Build fails if CC happens to be set (to anything other than CompileC)
233                 unset CC
234
235                 cd "$resdir/ScriptExec"
236                 echo -e "Building launcher...\n"
237                 xcodebuild $XCODEFLAGS clean build
238         )
239         cp "$resdir/$SCRIPTEXECDIR/ScriptExec" "$pkgexec/Wireshark"
240
241 fi
242
243 # Copy all files into the bundle
244 #----------------------------------------------------------
245 echo -e "\nFilling app bundle and utility directory...\n"
246
247 # Wireshark executables
248 cp -v utility-launcher "$cli_dir/$binary"
249 for binary in $binary_list ; do
250         # Copy the binary to its destination
251         dest_path="$pkgbin/$binary-bin"
252         cp -v "$binary_path/$binary" "$dest_path"
253         # TODO Add a "$verbose" variable and command line switch, which sets wether these commands are verbose or not
254
255         ln -sv ./wireshark "$pkgbin/$binary"
256         ln -sv ./wireshark "$cli_dir/$binary"
257 done
258
259 # ChmodBPF
260 mkdir -p "$chmodbpf_dir"
261 cp -v ChmodBPF/* "$chmodbpf_dir"
262 chmod -R g-w "$chmodbpf_dir"
263
264 # The rest of the Wireshark installation (we handled bin above)
265 rsync -av \
266         --exclude bin/ \
267         --exclude lib/wireshark/plugins/ \
268         --exclude lib/wireshark/python/ \
269         "$binary_path/.."/* "$pkgres"
270
271 # Remove the version number from the plugin path
272 find "$binary_path/../lib/wireshark/plugins" -type f \
273         -exec cp -fv "{}" "$pkgplugin/" \;
274
275 # Remove the version number from the python path
276 find "$binary_path/../lib/wireshark/python" -type f \
277         -exec cp -fv "{}" "$pkgpython/" \;
278
279 cp "$plist" "$package/Contents/Info.plist"
280
281 # Icons and the rest of the script framework
282 res_list="
283         Wireshark.icns
284         Wiresharkdoc.icns
285         bin
286         openDoc
287 "
288
289 if [ "$ui_toolkit" = "gtk" ] ; then
290         res_list="
291                 $res_list
292                 etc
293                 script
294                 MenuBar.nib
295                 ProgressWindow.nib
296                 themes
297         "
298 fi
299
300 for rl_entry in $res_list ; do
301         rsync -av "$resdir"/Resources/$rl_entry "$package"/Contents/Resources/
302 done
303
304 # PkgInfo must match bundle type and creator code from Info.plist
305 echo "APPLWshk" > $package/Contents/PkgInfo
306
307 if [ "$ui_toolkit" = "gtk" ] ; then
308
309         # Pull in extra requirements for Pango and GTK
310         pkgetc="$package/Contents/Resources/etc"
311         mkdir -p $pkgetc/pango
312         cp $LIBPREFIX/etc/pango/pangox.aliases $pkgetc/pango/
313         # Need to adjust path and quote in case of spaces in path.
314         sed -e "s,$LIBPREFIX,\"\${CWD},g" -e 's,\.so ,.so" ,g' $LIBPREFIX/etc/pango/pango.modules > $pkgetc/pango/pango.modules
315         cat > $pkgetc/pango/pangorc <<END_PANGO
316 [Pango]
317 ModuleFiles=\${HOME}/.wireshark-etc/pango.modules
318 [PangoX]
319 AliasFiles=\${HOME}/.wireshark-etc/pangox.aliases
320 END_PANGO
321
322         # We use a modified fonts.conf file so only need the dtd
323         mkdir -p $pkgetc/fonts
324         cp $LIBPREFIX/etc/fonts/fonts.dtd $pkgetc/fonts/
325         cp -r $LIBPREFIX/etc/fonts/conf.avail $pkgetc/fonts/
326         cp -r $LIBPREFIX/etc/fonts/conf.d $pkgetc/fonts/
327
328         mkdir -p $pkgetc/gtk-2.0
329         #
330         # In newer versions of GTK+, the gdk-pixbuf library was split off from
331         # GTK+, and the gdk-pixbuf.loaders file moved, so we check for its
332         # existence here.
333         #
334         # The file is ultimately copied to the user's home directory, with
335         # the pathnames adjusted to refer to the installed package, so we
336         # always put it in the same location in the installed package,
337         # regardless of where it lives in the machine on which it's built.
338         #
339         if [ -e $LIBPREFIX/etc/gtk-2.0/gdk-pixbuf.loaders ]
340         then
341                 sed -e "s,$LIBPREFIX,\${CWD},g" $LIBPREFIX/etc/gtk-2.0/gdk-pixbuf.loaders > $pkgetc/gtk-2.0/gdk-pixbuf.loaders
342         fi
343         sed -e "s,$LIBPREFIX,\${CWD},g" $LIBPREFIX/etc/gtk-2.0/gtk.immodules > $pkgetc/gtk-2.0/gtk.immodules
344
345         pango_version=`pkg-config --variable=pango_module_version pango`
346         mkdir -p $pkglib/pango/$pango_version/modules
347         cp $LIBPREFIX/lib/pango/$pango_version/modules/*.so $pkglib/pango/$pango_version/modules/
348
349         gtk_version=`pkg-config --variable=gtk_binary_version gtk+-2.0`
350         mkdir -p $pkglib/gtk-2.0/$gtk_version/{engines,immodules,loaders}
351         cp -r $LIBPREFIX/lib/gtk-2.0/$gtk_version/* $pkglib/gtk-2.0/$gtk_version/
352
353         gdk_pixbuf_version=`pkg-config --variable=gdk_pixbuf_binary_version gdk-pixbuf-2.0`
354         if [ ! -z $gdk_pixbuf_version ]; then
355                 mkdir -p $pkglib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders
356                 #
357                 # As per the above, check whether we have a loaders.cache file
358                 # in $LIBPREFIX/lib/gdk-pixbuf-2.0/$gdk_pixbuf_version, as
359                 # that's where the output of gdk-pixbuf-query-loaders gets
360                 # put if gdk-pixbuf and GTK+ are separated.
361                 #
362                 # The file is ultimately copied to the user's home directory,
363                 # with the pathnames adjusted to refer to the installed package,
364                 # so we always put it in the same location in the installed
365                 # package, regardless of where it lives in the machine on which
366                 # it's built.
367                 #
368                 if [ -e $LIBPREFIX/lib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders.cache ]
369                 then
370                         sed -e "s,$LIBPREFIX,\${CWD},g" $LIBPREFIX/lib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders.cache > $pkgetc/gtk-2.0/gdk-pixbuf.loaders
371                 fi
372                 cp -r $LIBPREFIX/lib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders/* $pkglib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders
373         fi
374 fi # GTK+ / Qt
375
376 # Find out libs we need from Fink, MacPorts, or from a custom install
377 # (i.e. $LIBPREFIX), then loop until no changes.
378 a=1
379 nfiles=0
380 endl=true
381 lib_dep_search_list="
382         $pkglib/*
383         $pkgbin/*-bin
384         "
385 if [ "$ui_toolkit" = "gtk" ] ; then
386         lib_dep_search_list="
387                 $lib_dep_search_list
388                 $pkglib/gtk-2.0/$gtk_version/loaders/*
389                 $pkglib/gtk-2.0/$gtk_version/immodules/*
390                 $pkglib/gtk-2.0/$gtk_version/engines/*.so
391                 $pkglib/pango/$pango_version/modules/*
392                 $pkglib/gdk-pixbuf-2.0/$gdk_pixbuf_version/loaders/*
393                 "
394 elif [ "$ui_toolkit" = "qt" ] ; then
395         lib_dep_search_list="
396                 $pkgexec/Wireshark
397                 $lib_dep_search_list
398                 "
399 fi
400
401 while $endl; do
402         echo -e "Looking for dependencies. Round" $a
403         libs="`otool -L $lib_dep_search_list 2>/dev/null | fgrep compatibility | cut -d\( -f1 | grep $LIBPREFIX | sort | uniq`"
404         cp -vn $libs "$pkglib"
405         let "a+=1"
406         nnfiles=`ls "$pkglib" | wc -l`
407         if [ $nnfiles = $nfiles ]; then
408                 endl=false
409         else
410                 nfiles=$nnfiles
411         fi
412 done
413
414 # Add extra libraries of necessary
415 for libfile in $EXTRALIBS
416 do
417         cp -f $libfile "$pkglib"
418 done
419 chmod 755 "$pkglib"/*.dylib
420
421 # Strip libraries and executables if requested
422 #----------------------------------------------------------
423 if [ "$strip" = "true" ]; then
424         echo -e "\nStripping debugging symbols...\n"
425         strip -x "$pkglib"/*.dylib
426         strip -ur "$binpath"
427 fi
428
429 # NOTE: we must rpathify *all* files, *including* plugins for GTK+ etc.,
430 #       to keep GTK+ from crashing at startup.
431 #
432 rpathify_file () {
433         # Fix a given executable, library, or plugin to be relocatable
434         if [ ! -d "$1" ]; then
435                 #
436                 # OK, what type of file is this?
437                 #
438                 filetype=`otool -hv "$1" | sed -n '4p' | awk '{print $5}'`
439                 case "$filetype" in
440
441                 EXECUTE|DYLIB|BUNDLE)
442                         #
443                         # Executable, library, or plugin.  (Plugins
444                         # can be either DYLIB or BUNDLE; shared
445                         # libraries are DYLIB.)
446                         #
447                         # For DYLIB and BUNDLE, fix the shared
448                         # library identification.
449                         #
450                         if [[ "$filetype" = "DYLIB" || "$filetype" = "BUNDLE" ]]; then
451                                 echo "Changing shared library identification of $1"
452                                 base=`echo $1 | awk -F/ '{print $NF}'`
453                                 #
454                                 # The library will end up in a directory in
455                                 # the rpath; this is what we should change its
456                                 # ID to.
457                                 #
458                                 to=@rpath/$base
459                                 /usr/bin/install_name_tool -id $to $1
460                         fi
461
462                         #
463                         # Get the list of dynamic libraries on which this
464                         # file depends, and select only the libraries that
465                         # are in $LIBPREFIX, as those are the only ones
466                         # that we'll be shipping in the app bundle; the
467                         # other libraries are system-supplied or supplied
468                         # as part of X11, will be expected to be on the
469                         # system on which the bundle will be installed,
470                         # and should be referred to by their full pathnames.
471                         #
472                         libs="`otool -L $1 | egrep "$LIBPREFIX.* \(compatibility" | cut -d\( -f1`"
473                         for lib in $libs; do
474                                 #
475                                 # Get the file name of the library.
476                                 #
477                                 base=`echo $lib | awk -F/ '{print $NF}'`
478                                 #
479                                 # The library will end up in a directory in
480                                 # the rpath; this is what we should change its
481                                 # file name to.
482                                 #
483                                 to=@rpath/$base
484                                 #
485                                 # Change the reference to that library.
486                                 #
487                                 echo "Changing reference to $lib in $1"
488                                 /usr/bin/install_name_tool -change $lib $to $1
489                         done
490                         ;;
491                 esac
492         fi
493 }
494
495 rpathify_dir () {
496         #
497         # Make sure we *have* that directory
498         #
499         if [ -d "$1" ]; then
500                 (cd "$1"
501                 #
502                 # Make sure we *have* files to fix
503                 #
504                 files=`ls $2 2>/dev/null`
505                 if [ ! -z "$files" ]; then
506                         for file in $files; do
507                                 rpathify_file "$file" "`pwd`"
508                         done
509                 fi
510                 )
511         fi
512 }
513
514 rpathify_files () {
515         #
516         # Fix package deps
517         #
518         rpathify_dir "$pkglib" "*.dylib"
519         if [ "$ui_toolkit" = "gtk" ] ; then
520                 rpathify_dir "$pkglib/gtk-2.0/$gtk_version/loaders" "*.so"
521                 rpathify_dir "$pkglib/gtk-2.0/$gtk_version/engines" "*.so"
522                 rpathify_dir "$pkglib/gtk-2.0/$gtk_version/immodules" "*.so"
523                 rpathify_dir "$pkglib/gtk-2.0/$gtk_version/printbackends" "*.so"
524                 rpathify_dir "$pkglib/gnome-vfs-2.0/modules" "*.so"
525                 rpathify_dir "$pkglib/gdk-pixbuf-2.0/$gtk_version/loaders" "*.so"
526                 rpathify_dir "$pkglib/pango/$pango_version/modules" "*.so"
527         fi
528         rpathify_dir "$pkgbin" "*"
529 }
530
531 PATHLENGTH=`echo $LIBPREFIX | wc -c`
532 if [ "$PATHLENGTH" -ge "6" ]; then
533         # If the LIBPREFIX path is long enough to allow 
534         # path rewriting, then do this.
535         # 6 is the length of @rpath, which replaces LIBPREFIX.
536         rpathify_files
537 else
538         echo "Could not rewrite dylib paths for bundled libraries.  This requires" >&2
539         echo "the support libraries to be installed in a PREFIX of at least 6 characters in length." >&2
540         echo "" >&2
541         echo "The package will still work if the following line is uncommented in" >&2
542         echo "Wireshark.app/Contents/Resources/bin/{various scripts}:" >&2
543         echo '        export DYLD_LIBRARY_PATH="$TOP/lib"' >&2
544         exit 1
545
546 fi
547
548 if [ "$ui_toolkit" = "qt" ] ; then
549         macdeployqt "$package" -verbose=2
550 fi
551
552 exit 0