Added simple perl script to re-write dependencies for Mac OS app bundles
[supertux.git] / tools / darwin / makebundle.pl
1 #!/opt/local/bin/perl
2
3 #
4 # makebundle.pl - copies and makes portable a binary and all its dependencies
5 # Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
6 #
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 #
21
22 use strict;
23 use warnings;
24
25 # Script does some dangerous stuff - make sure a user will double-check everything before running it. 
26 print "This script is highly experimental. Modify it to suit your needs and take care to run it only in controlled environments.\n";
27
28 # This line needs to be removed, the following lines adjusted.
29 exit 1;
30
31 my $OUTPUTDIR='/tmp/SuperTux.app/Contents/MacOS';
32 my $EXECUTABLE='./supertux2';
33
34 my %COPIED;
35 my @TOCOPY;
36 my %PATCHED;
37 my @TOPATCH;
38
39 system('mkdir '.$OUTPUTDIR);
40
41 push (@TOCOPY, $EXECUTABLE);
42
43 # first, copy all direct and indirect dependencies to OUTPUTDIR
44 while (my $EXECUTABLE = pop @TOCOPY) {
45
46         next if $COPIED{$EXECUTABLE};
47         $COPIED{$EXECUTABLE} = 1;
48
49         next unless $EXECUTABLE =~ /^(.*)\/(.*)$/;
50         my $PATH = $1;
51         my $FNAME = $2;
52
53         print("copying ".$EXECUTABLE."\n");
54
55         system('cp '.$EXECUTABLE.' '.$OUTPUTDIR.'/'.$FNAME);
56         system('chmod u+w '.$OUTPUTDIR.'/'.$FNAME);
57
58         # mark the copy as to-be-patched
59         push(@TOPATCH, $OUTPUTDIR.'/'.$FNAME);
60
61         $EXECUTABLE = $OUTPUTDIR.'/'.$FNAME;
62
63         my @LIBS = qx{/usr/bin/otool -L $EXECUTABLE};
64         while ($_ = pop @LIBS) {
65
66                 # parse output of otool
67                 next unless /^\t(.*) \(.*\).*$/;
68                 my $FULLPATH = $1;
69
70                 # skip dependencies on things that are no .dylib
71                 next unless $FULLPATH =~ /\.dylib$/;
72
73                 # skip dependencies that are already dynamic
74                 next if $FULLPATH =~ /^@/;
75
76                 # skip dependencies that don't have an absolute path
77                 next unless $FULLPATH =~ /^(.*)\/(.*)$/;
78                 my $PATH = $1;
79                 my $FNAME = $2;
80
81                 # skip dependencies on anything in /usr/lib
82                 next if $PATH =~ q{^/usr/lib$};
83
84                 # mark dependency as to-be-copied
85                 push(@TOCOPY, $FULLPATH);
86
87         }
88
89 }
90
91 # now patch all binaries we copied
92 while (my $EXECUTABLE = pop @TOPATCH) {
93
94         next if $PATCHED{$EXECUTABLE};
95         $PATCHED{$EXECUTABLE} = 1;
96
97         print "patching ".$EXECUTABLE."\n";
98
99         my @LIBS = qx{/usr/bin/otool -L $EXECUTABLE};
100         while ($_ = pop @LIBS) {
101
102                 # parse output of otool
103                 next unless /^\t(.*) \(.*\).*$/;
104                 my $FULLPATH = $1;
105
106                 # skip dependencies that are not .dylibs
107                 next unless $FULLPATH =~ /\.dylib$/;
108
109                 # skip dependencies that are already dynamic
110                 next if $FULLPATH =~ /^@/;
111
112                 # skip dependencies without absolute paths
113                 next unless $FULLPATH =~ /^(.*)\/(.*)$/;
114                 my $PATH = $1;
115                 my $FNAME = $2;
116
117                 # skip dependencies on stuff in /usr/lib
118                 next if $PATH =~ q{^/usr/lib$};
119
120                 # patch binary to depend on copy in @executable_path instead
121                 system('install_name_tool -change '.$FULLPATH.' @executable_path/'.$FNAME.' '.$EXECUTABLE);
122
123         }
124
125 }
126