1 | #!/usr/bin/perl |
---|
2 | |
---|
3 | ### osx-packager.pl $Id$ |
---|
4 | ### Tool for automating frontend builds on Mac OS X. |
---|
5 | ### Run "osx-packager.pl -man" for full documentation. |
---|
6 | |
---|
7 | use strict; |
---|
8 | use Getopt::Long qw(:config auto_abbrev); |
---|
9 | use Pod::Usage (); |
---|
10 | use Cwd (); |
---|
11 | |
---|
12 | |
---|
13 | open(SVNVER, '>./ftp/revision.txt'); |
---|
14 | |
---|
15 | |
---|
16 | ### Configuration settings (stuff that might change more often) |
---|
17 | |
---|
18 | # We try to auto-locate the Subversion client binaries. |
---|
19 | # If they are not in your path, you should use the second line. |
---|
20 | # |
---|
21 | our $svn = '/usr/local/bin/svn'; |
---|
22 | #our $svn = '/Volumes/Users/nigel/bin/svn'; |
---|
23 | |
---|
24 | # This script used to always delete the installed include and lib dirs. |
---|
25 | # That probably ensures a safe build, but when rebuilding adds minutes to |
---|
26 | # the total build time, and prevents us skipping some parts of a full build |
---|
27 | # |
---|
28 | our $cleanLibs = 1; |
---|
29 | |
---|
30 | # By default, only the frontend is built (i.e. no backend or transcoding) |
---|
31 | # |
---|
32 | our $backend = 0; |
---|
33 | our $jobtools = 0; |
---|
34 | |
---|
35 | # Parallel makes? |
---|
36 | # |
---|
37 | #$ENV{'DISTCC_HOSTS'} = "localhost 192.168.0.6"; |
---|
38 | #$ENV{'DISTCC_VERBOSE'} = '1'; |
---|
39 | |
---|
40 | # For faster downloads, change this to a local mirror. |
---|
41 | # |
---|
42 | our $sourceforge = 'http://umn.dl.sourceforge.net'; |
---|
43 | |
---|
44 | # At the moment, there is mythtv plus these two |
---|
45 | our @components = ( 'myththemes', 'mythplugins' ); |
---|
46 | |
---|
47 | # The OS X programs that we are likely to be interested in. |
---|
48 | our @targetsJT = ( 'MythCommFlag', 'MythJobQueue'); |
---|
49 | our @targetsBE = ( 'MythBackend', 'MythFillDatabase', |
---|
50 | 'MythTranscode', 'MythTV-Setup'); |
---|
51 | |
---|
52 | # Patches for MythTV source |
---|
53 | our %patches = ( |
---|
54 | ); |
---|
55 | |
---|
56 | our %depend_order = ( |
---|
57 | 'mythtv' |
---|
58 | => [ |
---|
59 | 'freetype', |
---|
60 | 'lame', |
---|
61 | 'mysqlclient', |
---|
62 | 'qt-mt', |
---|
63 | # Not needed since SVN -r8965. Kept here for 0.19 builds |
---|
64 | #'dvdnav' |
---|
65 | ], |
---|
66 | 'mythplugins' |
---|
67 | => [ |
---|
68 | 'tiff', |
---|
69 | 'exif', |
---|
70 | 'dvdcss', |
---|
71 | # MythDVD used to use this to build mtd. |
---|
72 | # Not needed since SVN -r8965. Kept here for 0.19 builds |
---|
73 | # 'dvdread', |
---|
74 | # MythMusic needs these seven things: |
---|
75 | # 'libmad', |
---|
76 | # 'libid3tag', |
---|
77 | # 'libogg', |
---|
78 | # 'vorbis', |
---|
79 | # 'flac', |
---|
80 | # These CD ones don't compile on OS X. I doubt that they ever will. |
---|
81 | # MythMusic probably needs to have native OS X code to assess CDs |
---|
82 | # 'cddaparanoia', |
---|
83 | # 'cdaudio' |
---|
84 | ], |
---|
85 | ); |
---|
86 | |
---|
87 | our %depend = ( |
---|
88 | |
---|
89 | 'freetype' |
---|
90 | => |
---|
91 | { |
---|
92 | 'url' |
---|
93 | => "$sourceforge/sourceforge/freetype/freetype-2.1.10.tar.gz", |
---|
94 | }, |
---|
95 | |
---|
96 | # SVN head doesn't need this, but 0.19-fixes and earlier do |
---|
97 | 'dvdnav' => |
---|
98 | { |
---|
99 | 'url' => "$sourceforge/sourceforge/dvd/libdvdnav-0.1.10.tar.gz", |
---|
100 | }, |
---|
101 | |
---|
102 | 'lame' |
---|
103 | => |
---|
104 | { |
---|
105 | 'url' |
---|
106 | => "$sourceforge/sourceforge/lame/lame-3.96.1.tar.gz", |
---|
107 | 'conf' |
---|
108 | => [ |
---|
109 | '--disable-frontend', |
---|
110 | ], |
---|
111 | }, |
---|
112 | |
---|
113 | 'cdaudio' => |
---|
114 | { |
---|
115 | 'url' => "$sourceforge/sourceforge/libcdaudio/libcdaudio-0.99.12.tar.gz" |
---|
116 | }, |
---|
117 | |
---|
118 | 'libmad' => |
---|
119 | { |
---|
120 | 'url' => 'ftp://ftp.mars.org/pub/mpeg/libmad-0.15.0b.tar.gz' |
---|
121 | }, |
---|
122 | |
---|
123 | 'libid3tag' => |
---|
124 | { |
---|
125 | 'url' => 'ftp://ftp.mars.org/pub/mpeg/libid3tag-0.15.0b.tar.gz' |
---|
126 | }, |
---|
127 | |
---|
128 | 'cddaparanoia' => |
---|
129 | { |
---|
130 | 'url' => 'http://www.buserror.net/cdparanoia/cdparanoia-osx-5.tar.gz', |
---|
131 | }, |
---|
132 | |
---|
133 | 'libogg' => |
---|
134 | { |
---|
135 | 'url' => 'http://downloads.xiph.org/releases/ogg/libogg-1.1.2.tar.gz' |
---|
136 | }, |
---|
137 | |
---|
138 | 'vorbis' => |
---|
139 | { |
---|
140 | 'url' => 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.1.1.tar.gz' |
---|
141 | }, |
---|
142 | |
---|
143 | 'flac' => |
---|
144 | { |
---|
145 | 'url' => "$sourceforge/sourceforge/flac/flac-1.1.2.tar.gz" |
---|
146 | }, |
---|
147 | |
---|
148 | 'dvdcss' |
---|
149 | => |
---|
150 | { |
---|
151 | 'url' |
---|
152 | => 'ftp://ftp.fu-berlin.de/unix/linux/mirrors/gentoo/distfiles/libdvdcss-1.2.8.tar.bz2', |
---|
153 | }, |
---|
154 | |
---|
155 | 'dvdread' |
---|
156 | => |
---|
157 | { |
---|
158 | 'url' |
---|
159 | => 'http://www.dtek.chalmers.se/groups/dvd/dist/libdvdread-0.9.4.tar.gz', |
---|
160 | 'conf' |
---|
161 | => [ |
---|
162 | '--with-libdvdcss', |
---|
163 | ], |
---|
164 | }, |
---|
165 | |
---|
166 | |
---|
167 | 'mysqlclient' |
---|
168 | => |
---|
169 | { |
---|
170 | 'url' |
---|
171 | => 'http://mirrors.dedipower.com/www.mysql.com/Downloads/MySQL-4.1/mysql-4.1.21.tar.gz', |
---|
172 | 'conf' |
---|
173 | => [ |
---|
174 | '--without-debug', |
---|
175 | '--without-docs', |
---|
176 | '--without-man', |
---|
177 | '--without-bench', |
---|
178 | '--without-server', |
---|
179 | '--without-geometry', |
---|
180 | '--without-extra-tools', |
---|
181 | ], |
---|
182 | }, |
---|
183 | |
---|
184 | 'qt-mt' |
---|
185 | => |
---|
186 | # { |
---|
187 | # 'url' |
---|
188 | # => 'http://ftp.iasi.roedu.net/mirrors/ftp.trolltech.com/qt/sources/qt-mac-opensource-src-4.0.1.tar.gz', |
---|
189 | # 'conf-cmd' |
---|
190 | # => 'echo yes | ./configure', |
---|
191 | # 'conf' |
---|
192 | # => [ |
---|
193 | # '-prefix', '"$PREFIX"', |
---|
194 | # '-system-zlib', |
---|
195 | # '-fast', |
---|
196 | # '-qt-sql-mysql', |
---|
197 | # '-qt-libpng', |
---|
198 | # '-qt-libjpeg', |
---|
199 | # '-qt-gif', |
---|
200 | # '-platform macx-g++', |
---|
201 | # '-no-tablet', |
---|
202 | # '-I"$PREFIX/include/mysql"', |
---|
203 | # '-L"$PREFIX/lib/mysql"', |
---|
204 | # ], |
---|
205 | # 'post-conf' |
---|
206 | # => 'echo "QMAKE_LFLAGS_SHLIB += -single_module" >> src/qt.pro', |
---|
207 | # 'make' |
---|
208 | # => [ |
---|
209 | # 'sub-src' |
---|
210 | # ], |
---|
211 | # }, |
---|
212 | { |
---|
213 | 'url' |
---|
214 | => 'http://ftp.iasi.roedu.net/mirrors/ftp.trolltech.com/qt/source/qt-mac-free-3.3.6.tar.gz', |
---|
215 | 'conf-cmd' |
---|
216 | => 'echo yes | ./configure', |
---|
217 | 'conf' |
---|
218 | => [ |
---|
219 | '-prefix', '"$PREFIX"', |
---|
220 | '-thread', |
---|
221 | '-system-zlib', |
---|
222 | '-fast', |
---|
223 | '-qt-sql-mysql', |
---|
224 | '-no-style-cde', |
---|
225 | '-no-style-compact', |
---|
226 | '-no-style-motif', |
---|
227 | '-no-style-motifplus', |
---|
228 | '-no-style-platinum', |
---|
229 | '-no-style-sgi', |
---|
230 | '-no-ipv6', |
---|
231 | '-qt-imgfmt-png', |
---|
232 | '-qt-imgfmt-jpeg', |
---|
233 | '-no-imgfmt-mng', |
---|
234 | '-qt-gif', |
---|
235 | '-no-tablet', |
---|
236 | '-I"$PREFIX/include/mysql"', |
---|
237 | '-L"$PREFIX/lib/mysql"', |
---|
238 | ], |
---|
239 | 'post-conf' |
---|
240 | => 'echo "QMAKE_LFLAGS_SHLIB += -single_module" >> src/qt.pro', |
---|
241 | 'make' |
---|
242 | => [ |
---|
243 | 'sub-src', |
---|
244 | 'qmake-install', |
---|
245 | 'moc-install' |
---|
246 | ], |
---|
247 | }, |
---|
248 | |
---|
249 | 'tiff' |
---|
250 | => |
---|
251 | { |
---|
252 | 'url' => 'http://dl.maptools.org/dl/libtiff/tiff-3.8.2.tar.gz' |
---|
253 | }, |
---|
254 | |
---|
255 | 'exif' |
---|
256 | => |
---|
257 | { |
---|
258 | 'url' => "$sourceforge/sourceforge/libexif/libexif-0.6.13.tar.bz2", |
---|
259 | 'conf' => [ '--disable-nls' ], |
---|
260 | 'post-conf' => 'echo "install-apidocs: |
---|
261 | install-apidocs-internals: |
---|
262 | " >> doc/Makefile.in' |
---|
263 | } |
---|
264 | ); |
---|
265 | |
---|
266 | |
---|
267 | =head1 NAME |
---|
268 | |
---|
269 | osx-packager.pl - build OS X binary packages for MythTV |
---|
270 | |
---|
271 | =head1 SYNOPSIS |
---|
272 | |
---|
273 | osx-packager.pl [options] |
---|
274 | |
---|
275 | Options: |
---|
276 | -help print the usage message |
---|
277 | -man print full documentation |
---|
278 | -verbose print informative messages during the process |
---|
279 | -version <str> custom version suffix (defaults to "svnYYYYMMDD") |
---|
280 | -noversion don't use any version (for building release versions) |
---|
281 | -distclean throw away all intermediate files and exit |
---|
282 | -thirdclean do a clean rebuild of third party packages |
---|
283 | -thirdskip don't rebuild the third party packages |
---|
284 | -mythtvskip don't rebuild/install mythtv |
---|
285 | -pluginskip don't rebuild/install mythplugins |
---|
286 | -themeskip don't install the extra themes from myththemes |
---|
287 | -clean do a clean rebuild of MythTV |
---|
288 | -svnbranch <str> build a specified Subversion branch, instead of HEAD |
---|
289 | -svnrev <str> build a specified Subversion revision, instead of HEAD |
---|
290 | -svntag <str> build a specified release, instead of Subversion HEAD |
---|
291 | -nohead don't update to HEAD revision of MythTV before building |
---|
292 | -usehdimage perform build inside of a case-sensitive disk image |
---|
293 | -enable-backend build the backend server as well as the frontend |
---|
294 | -enable-jobtools build commflag/jobqueue as well as the frontend |
---|
295 | -plugins <str> comma-separated list of plugins to include |
---|
296 | Available plugins: |
---|
297 | mythbrowser mythcontrols mythdvd mythflix mythgallery mythgame |
---|
298 | mythmusic mythnews mythphone mythvideo mythweather |
---|
299 | |
---|
300 | =head1 DESCRIPTION |
---|
301 | |
---|
302 | This script builds a MythTV frontend and all necessary dependencies, along |
---|
303 | with plugins as specified, as a standalone binary package for Mac OS X. |
---|
304 | |
---|
305 | It was designed for building daily CVS (now Subversion) snapshots, |
---|
306 | but can also be used to create release builds with the '-svntag' option. |
---|
307 | |
---|
308 | All intermediate files go into an '.osx-packager' directory in the current |
---|
309 | working directory. The finished application is named 'MythFrontend.app' and |
---|
310 | placed in the current working directory. |
---|
311 | |
---|
312 | =head1 EXAMPLES |
---|
313 | |
---|
314 | Building two snapshots, one with plugins and one without: |
---|
315 | |
---|
316 | osx-packager.pl -clean -plugins mythvideo,mythweather |
---|
317 | mv MythFrontend.app MythFrontend-plugins.app |
---|
318 | osx-packager.pl -nohead |
---|
319 | mv MythFrontend.app MythFrontend-noplugins.app |
---|
320 | |
---|
321 | Building a 0.17 release build: |
---|
322 | |
---|
323 | osx-packager.pl -distclean |
---|
324 | osx-packager.pl -svntag release-0-17 -noversion |
---|
325 | |
---|
326 | Building a "fixes" branch: |
---|
327 | |
---|
328 | osx-packager.pl -distclean |
---|
329 | osx-packager.pl -svnbranch release-0-18-fixes |
---|
330 | |
---|
331 | =head1 CREDITS |
---|
332 | |
---|
333 | Written by Jeremiah Morris (jm@whpress.com) |
---|
334 | |
---|
335 | Special thanks to Nigel Pearson, Jan Ornstedt, Angel Li, and Andre Pang |
---|
336 | for help, code, and advice. |
---|
337 | |
---|
338 | Small modifications made by Bas Hulsken (bhulsken@hotmail.com) to allow building current svn, and allow lirc (if installed properly on before running script). The modifications are crappy, and should probably be revised by someone who can actually code in perl. However it works for the moment, and I wanted to share with other mac frontend experimenters! |
---|
339 | |
---|
340 | =cut |
---|
341 | |
---|
342 | # Parse options |
---|
343 | our (%OPT); |
---|
344 | Getopt::Long::GetOptions(\%OPT, |
---|
345 | 'help|?', |
---|
346 | 'man', |
---|
347 | 'verbose', |
---|
348 | 'version=s', |
---|
349 | 'noversion', |
---|
350 | 'distclean', |
---|
351 | 'thirdclean', |
---|
352 | 'thirdskip', |
---|
353 | 'mythtvskip', |
---|
354 | 'pluginskip', |
---|
355 | 'themeskip', |
---|
356 | 'clean', |
---|
357 | 'svnbranch=s', |
---|
358 | 'svnrev=s', |
---|
359 | 'svntag=s', |
---|
360 | 'nocvs', # This is obsolete, but should stay a while |
---|
361 | 'nohead', |
---|
362 | 'usehdimage', |
---|
363 | 'enable-backend', |
---|
364 | 'enable-jobtools', |
---|
365 | 'plugins=s', |
---|
366 | ) or Pod::Usage::pod2usage(2); |
---|
367 | Pod::Usage::pod2usage(1) if $OPT{'help'}; |
---|
368 | Pod::Usage::pod2usage('-verbose' => 2) if $OPT{'man'}; |
---|
369 | |
---|
370 | if ( $OPT{'enable-backend'} ) |
---|
371 | { $backend = 1 } |
---|
372 | |
---|
373 | if ( $OPT{'clean'} ) |
---|
374 | { $cleanLibs = 1 } |
---|
375 | |
---|
376 | if ( $OPT{'enable-jobtools'} ) |
---|
377 | { $jobtools = 1 } |
---|
378 | |
---|
379 | # Get version string sorted out |
---|
380 | if ($OPT{'svntag'} && !$OPT{'version'}) |
---|
381 | { |
---|
382 | $OPT{'version'} = $OPT{'svntag'}; |
---|
383 | $OPT{'version'} =~ s/-r *//; |
---|
384 | $OPT{'version'} =~ s/--revision *//; |
---|
385 | } |
---|
386 | $OPT{'version'} = '' if $OPT{'noversion'}; |
---|
387 | unless (defined $OPT{'version'}) |
---|
388 | { |
---|
389 | my @lt = gmtime(time); |
---|
390 | $OPT{'version'} = sprintf('svn%04d%02d%02d', |
---|
391 | $lt[5] + 1900, |
---|
392 | $lt[4] + 1, |
---|
393 | $lt[3]); |
---|
394 | } |
---|
395 | |
---|
396 | # Fold nocvs to nohead |
---|
397 | $OPT{'nohead'} = 1 if $OPT{'nocvs'}; |
---|
398 | |
---|
399 | # Build our temp directories |
---|
400 | our $SCRIPTDIR = Cwd::abs_path(Cwd::getcwd()); |
---|
401 | if ($SCRIPTDIR =~ /\s/) |
---|
402 | { |
---|
403 | &Complain(<<END); |
---|
404 | Working directory contains spaces |
---|
405 | |
---|
406 | Error: Your current working path: |
---|
407 | |
---|
408 | $SCRIPTDIR |
---|
409 | |
---|
410 | contains one or more spaces. This will break the compilation process, |
---|
411 | so the script cannot continue. Please re-run this script from a different |
---|
412 | directory (such as /tmp). |
---|
413 | |
---|
414 | The application produced will run from any directory, the no-spaces |
---|
415 | rule is only for the build process itself. |
---|
416 | |
---|
417 | END |
---|
418 | die; |
---|
419 | } |
---|
420 | |
---|
421 | our $WORKDIR = "$SCRIPTDIR/.osx-packager"; |
---|
422 | mkdir $WORKDIR; |
---|
423 | |
---|
424 | # Do we need to force a case-sensitive disk image? |
---|
425 | if (!$OPT{usehdimage} && !CaseSensitiveFilesystem()) |
---|
426 | { |
---|
427 | Verbose("Forcing -usehdimage due to case-insensitive filesystem"); |
---|
428 | $OPT{usehdimage} = 1; |
---|
429 | } |
---|
430 | |
---|
431 | if ($OPT{usehdimage}) |
---|
432 | { |
---|
433 | Verbose("Creating a case-sensitive device for the build"); |
---|
434 | MountHDImage(); |
---|
435 | } |
---|
436 | |
---|
437 | our $PREFIX = "$WORKDIR/build"; |
---|
438 | mkdir $PREFIX; |
---|
439 | |
---|
440 | our $SRCDIR = "$WORKDIR/src"; |
---|
441 | mkdir $SRCDIR; |
---|
442 | |
---|
443 | # configure mythplugins, and mythtv, etc |
---|
444 | our %conf = ( |
---|
445 | 'mythplugins' |
---|
446 | => [ |
---|
447 | '--prefix=' . $PREFIX, |
---|
448 | '--enable-opengl', |
---|
449 | '--disable-mythbrowser', |
---|
450 | '--enable-mythdvd', |
---|
451 | '--enable-vcd', |
---|
452 | '--disable-transcode', |
---|
453 | '--enable-mythgallery', |
---|
454 | '--enable-exif', |
---|
455 | '--enable-new-exif', |
---|
456 | '--disable-mythgame', |
---|
457 | '--disable-mythmusic', |
---|
458 | '--enable-mythnews', |
---|
459 | '--disable-mythphone', |
---|
460 | '--enable-mythweather', |
---|
461 | '--disable-mytharchive', |
---|
462 | ], |
---|
463 | 'myththemes' |
---|
464 | => [ |
---|
465 | '--prefix=' . $PREFIX, |
---|
466 | ], |
---|
467 | 'mythtv' |
---|
468 | => [ |
---|
469 | '--disable-distcc', |
---|
470 | '--disable-firewire', |
---|
471 | '--enable-mmx', |
---|
472 | '--arch=pentium-m', |
---|
473 | '--enable-memalign-hack', |
---|
474 | # '--enable-mac-accel', |
---|
475 | '--extra-cxxflags=-msse -msse2 -msse3', |
---|
476 | '--prefix=' . $PREFIX, |
---|
477 | ], |
---|
478 | |
---|
479 | ); |
---|
480 | |
---|
481 | # configure mythplugins, and mythtv, etc |
---|
482 | our %makecleanopt = ( |
---|
483 | 'mythplugins' |
---|
484 | => [ |
---|
485 | 'distclean', |
---|
486 | ], |
---|
487 | ); |
---|
488 | |
---|
489 | # Source code version.pro needs to call subversion binary |
---|
490 | # |
---|
491 | use File::Basename; |
---|
492 | our $svnpath = dirname $svn; |
---|
493 | |
---|
494 | # Clean the environment |
---|
495 | $ENV{'PATH'} = "$PREFIX/bin:/sw/bin:/bin:/usr/bin:$svnpath"; |
---|
496 | $ENV{'DYLD_LIBRARY_PATH'} = "$PREFIX/lib"; |
---|
497 | $ENV{'LD_LIBRARY_PATH'} = "/usr/local/lib"; |
---|
498 | $ENV{'PKG_CONFIG_PATH'} = "$PREFIX/lib/pkgconfig:"; |
---|
499 | delete $ENV{'CC'}; |
---|
500 | delete $ENV{'CXX'}; |
---|
501 | delete $ENV{'CPP'}; |
---|
502 | delete $ENV{'CXXCPP'}; |
---|
503 | $ENV{'CFLAGS'} = $ENV{'CXXFLAGS'} = $ENV{'CPPFLAGS'} = "-I$PREFIX/include"; |
---|
504 | $ENV{'LDFLAGS'} = "-Z -F/System/Library/Frameworks -L/usr/lib -L$PREFIX/lib"; |
---|
505 | $ENV{'PREFIX'} = $PREFIX; |
---|
506 | |
---|
507 | # set up Qt environment |
---|
508 | my $qt_vers = $depend{'qt-mt'}{'url'}; |
---|
509 | $qt_vers =~ s|^.*/([^/]+)\.tar\.gz$|$1|; |
---|
510 | $ENV{'QTDIR'} = "$SRCDIR/$qt_vers"; |
---|
511 | |
---|
512 | # If environment is setup to use distcc, take advantage of it |
---|
513 | our $standard_make = '/usr/bin/make'; |
---|
514 | our $parallel_make = $standard_make; |
---|
515 | |
---|
516 | if ( $ENV{'DISTCC_HOSTS'} ) |
---|
517 | { |
---|
518 | my @hosts = split m/\s+/, $ENV{'DISTCC_HOSTS'}; |
---|
519 | my $numhosts = $#hosts + 1; |
---|
520 | &Verbose("Using $numhosts build hosts:", join ', ', @hosts); |
---|
521 | $parallel_make .= ' -j' . $numhosts * 2; |
---|
522 | } |
---|
523 | |
---|
524 | |
---|
525 | ### Distclean? |
---|
526 | if ($OPT{'distclean'}) |
---|
527 | { |
---|
528 | &Syscall([ '/bin/rm', '-f', '-r', $PREFIX ]); |
---|
529 | &Syscall([ '/bin/rm', '-f', '-r', $SRCDIR ]); |
---|
530 | exit; |
---|
531 | } |
---|
532 | |
---|
533 | ### Check for app present in target location |
---|
534 | our $MFE = "$SCRIPTDIR/MythFrontend.app"; |
---|
535 | if (-d $MFE) |
---|
536 | { |
---|
537 | &Complain(<<END); |
---|
538 | $MFE already exists |
---|
539 | |
---|
540 | Error: a MythFrontend application exists where we were planning |
---|
541 | to build one. Please move this application away before running |
---|
542 | this script. |
---|
543 | |
---|
544 | END |
---|
545 | exit; |
---|
546 | } |
---|
547 | |
---|
548 | ### Third party packages |
---|
549 | my (@build_depends, %seen_depends); |
---|
550 | my @comps = ('mythtv', @components); |
---|
551 | &Verbose("Including components:", @comps); |
---|
552 | |
---|
553 | foreach my $comp (@comps) |
---|
554 | { |
---|
555 | foreach my $dep (@{ $depend_order{$comp} }) |
---|
556 | { |
---|
557 | unless (exists $seen_depends{$dep}) |
---|
558 | { |
---|
559 | push(@build_depends, $dep); |
---|
560 | $seen_depends{$dep} = 1; |
---|
561 | } |
---|
562 | } |
---|
563 | } |
---|
564 | foreach my $sw (@build_depends) |
---|
565 | { |
---|
566 | # Get info about this package |
---|
567 | my $pkg = $depend{$sw}; |
---|
568 | my $url = $pkg->{'url'}; |
---|
569 | my $filename = $url; |
---|
570 | $filename =~ s|^.+/([^/]+)$|$1|; |
---|
571 | my $dirname = $filename; |
---|
572 | $dirname =~ s|\.tar\.gz$||; |
---|
573 | $dirname =~ s|\.tar\.bz2$||; |
---|
574 | |
---|
575 | chdir($SRCDIR); |
---|
576 | |
---|
577 | # Download and decompress |
---|
578 | unless (-e $filename) |
---|
579 | { |
---|
580 | &Verbose("Downloading $sw"); |
---|
581 | unless (&Syscall([ '/usr/bin/curl', $url, '>', $filename ], |
---|
582 | 'munge' => 1)) |
---|
583 | { |
---|
584 | &Syscall([ '/bin/rm', $filename ]) if (-e $filename); |
---|
585 | die; |
---|
586 | } |
---|
587 | } |
---|
588 | else |
---|
589 | { |
---|
590 | &Verbose("Using previously downloaded $sw"); |
---|
591 | } |
---|
592 | |
---|
593 | if ( -d $dirname ) |
---|
594 | { |
---|
595 | if ( $OPT{'thirdclean'} ) |
---|
596 | { |
---|
597 | &Verbose("Removing previous build of $sw"); |
---|
598 | &Syscall([ '/bin/rm', '-f', '-r', $dirname ]) or die; |
---|
599 | } |
---|
600 | |
---|
601 | if ( $OPT{'thirdskip'} ) |
---|
602 | { |
---|
603 | &Verbose("Using previous build of $sw"); |
---|
604 | next; |
---|
605 | } |
---|
606 | |
---|
607 | &Verbose("Using previously unpacked $sw"); |
---|
608 | } |
---|
609 | else |
---|
610 | { |
---|
611 | &Verbose("Unpacking $sw"); |
---|
612 | if ( substr($filename,-3) eq ".gz" ) |
---|
613 | { |
---|
614 | &Syscall([ '/usr/bin/tar', '-xzf', $filename ]) or die; |
---|
615 | } |
---|
616 | elsif ( substr($filename,-4) eq ".bz2" ) |
---|
617 | { |
---|
618 | &Syscall([ '/usr/bin/tar', '-xjf', $filename ]) or die; |
---|
619 | } |
---|
620 | } |
---|
621 | |
---|
622 | # Configure |
---|
623 | chdir($dirname); |
---|
624 | unless (-e '.osx-config') |
---|
625 | { |
---|
626 | &Verbose("Configuring $sw"); |
---|
627 | my (@configure, $munge); |
---|
628 | |
---|
629 | if ($pkg->{'conf-cmd'}) |
---|
630 | { |
---|
631 | push(@configure, $pkg->{'conf-cmd'}); |
---|
632 | $munge = 1; |
---|
633 | } |
---|
634 | else |
---|
635 | { |
---|
636 | push(@configure, './configure', |
---|
637 | '--prefix=$PREFIX', |
---|
638 | '--disable-static', |
---|
639 | '--enable-shared'); |
---|
640 | } |
---|
641 | if ($pkg->{'conf'}) |
---|
642 | { |
---|
643 | push(@configure, @{ $pkg->{'conf'} }); |
---|
644 | } |
---|
645 | &Syscall(\@configure, 'interpolate' => 1, 'munge' => $munge) or die; |
---|
646 | if ($pkg->{'post-conf'}) |
---|
647 | { |
---|
648 | &Syscall([ $pkg->{'post-conf'} ], 'munge' => 1) or die; |
---|
649 | } |
---|
650 | &Syscall([ '/usr/bin/touch', '.osx-config' ]) or die; |
---|
651 | } |
---|
652 | else |
---|
653 | { |
---|
654 | &Verbose("Using previously configured $sw"); |
---|
655 | } |
---|
656 | |
---|
657 | # Build and install |
---|
658 | unless (-e '.osx-built') |
---|
659 | { |
---|
660 | &Verbose("Making $sw"); |
---|
661 | my (@make); |
---|
662 | |
---|
663 | push(@make, $standard_make); |
---|
664 | if ($pkg->{'make'}) |
---|
665 | { |
---|
666 | push(@make, @{ $pkg->{'make'} }); |
---|
667 | } |
---|
668 | else |
---|
669 | { |
---|
670 | push(@make, 'all', 'install'); |
---|
671 | } |
---|
672 | &Syscall(\@make) or die; |
---|
673 | &Syscall([ '/usr/bin/touch', '.osx-built' ]) or die; |
---|
674 | } |
---|
675 | else |
---|
676 | { |
---|
677 | &Verbose("Using previously built $sw"); |
---|
678 | } |
---|
679 | } |
---|
680 | |
---|
681 | |
---|
682 | ### build MythTV |
---|
683 | |
---|
684 | # Clean any previously installed libraries |
---|
685 | if ( $cleanLibs ) |
---|
686 | { |
---|
687 | if ( $OPT{'mythtvskip'} ) |
---|
688 | { |
---|
689 | &Complain("Cannot skip building mythtv src if also cleaning"); |
---|
690 | exit; |
---|
691 | } |
---|
692 | &Verbose("Cleaning previous installs of MythTV"); |
---|
693 | my @mythlibs = glob "$PREFIX/lib/libmyth*"; |
---|
694 | if (scalar @mythlibs) |
---|
695 | { |
---|
696 | &Syscall([ '/bin/rm', @mythlibs ]) or die; |
---|
697 | } |
---|
698 | foreach my $dir ('include', 'lib', 'share') |
---|
699 | { |
---|
700 | if (-d "$PREFIX/$dir/mythtv") |
---|
701 | { |
---|
702 | &Syscall([ '/bin/rm', '-f', '-r', "$PREFIX/$dir/mythtv" ]) or die; |
---|
703 | } |
---|
704 | } |
---|
705 | } |
---|
706 | |
---|
707 | my $svndir = "$SRCDIR/myth-svn"; |
---|
708 | mkdir $svndir; |
---|
709 | |
---|
710 | # Deal with Subversion branches, revisions and tags: |
---|
711 | my $svnrepository = 'http://svn.mythtv.org/svn/'; |
---|
712 | my @svnrevision = (); |
---|
713 | |
---|
714 | if ( $OPT{'svnbranch'} ) |
---|
715 | { |
---|
716 | $svnrepository .= 'branches/' . $OPT{'svnbranch'} . '/'; |
---|
717 | } |
---|
718 | elsif ( $OPT{'svntag'} ) |
---|
719 | { |
---|
720 | $svnrepository .= 'tags/' . $OPT{'svntag'} . '/'; |
---|
721 | } |
---|
722 | elsif ( $OPT{'svnrev'} ) |
---|
723 | { |
---|
724 | $svnrepository .= 'trunk/'; |
---|
725 | |
---|
726 | # This arg. could be '1234', '-r 1234', or '--revision 1234' |
---|
727 | # If the user just specified a number, add appropriate flag: |
---|
728 | if ( $OPT{'svnrev'} =~ m/^\d+$/ ) |
---|
729 | { |
---|
730 | push @svnrevision, '--revision'; |
---|
731 | } |
---|
732 | |
---|
733 | push @svnrevision, $OPT{'svnrev'}; |
---|
734 | } |
---|
735 | elsif ( ! $OPT{'nohead'} ) |
---|
736 | { |
---|
737 | # Lookup and use the HEAD revision so we are guaranteed consistent source |
---|
738 | my $cmd = "$svn log $svnrepository --revision HEAD --xml | grep revision"; |
---|
739 | &Verbose($cmd); |
---|
740 | my $rev = `$cmd`; |
---|
741 | $rev =~ s/[^[:digit:]]//gs; |
---|
742 | |
---|
743 | #spit out the revision number |
---|
744 | print SVNVER $rev; |
---|
745 | |
---|
746 | $svnrepository .= 'trunk/'; |
---|
747 | @svnrevision = ('--revision', $rev); |
---|
748 | } |
---|
749 | |
---|
750 | # Retrieve source |
---|
751 | if (! $OPT{'nohead'}) |
---|
752 | { |
---|
753 | # Empty subdirectory 'config' sometimes causes checkout problems |
---|
754 | &Syscall(['rm', '-fr', $svndir . '/mythtv/config']); |
---|
755 | Verbose("Checking out source code"); |
---|
756 | &Syscall([ $svn, 'co', @svnrevision, |
---|
757 | map($svnrepository . $_, @comps), $svndir ]) or die; |
---|
758 | } |
---|
759 | else |
---|
760 | { |
---|
761 | &Syscall("mkdir -p $svndir/mythtv/config") |
---|
762 | } |
---|
763 | |
---|
764 | # Deal with user-supplied skip arguments |
---|
765 | if ( $OPT{'mythtvskip'} ) |
---|
766 | { @comps = grep(!m/mythtv/, @comps) } |
---|
767 | if ( $OPT{'pluginskip'} ) |
---|
768 | { @comps = grep(!m/mythplugins/, @comps) } |
---|
769 | if ( $OPT{'themeskip'} ) |
---|
770 | { @comps = grep(!m/myththemes/, @comps) } |
---|
771 | |
---|
772 | if ( ! @comps ) |
---|
773 | { |
---|
774 | &Complain("Nothing to build! Too many ...skip arguments?"); |
---|
775 | exit; |
---|
776 | } |
---|
777 | |
---|
778 | # Build MythTV and any plugins |
---|
779 | foreach my $comp (@comps) |
---|
780 | { |
---|
781 | my $compdir = "$svndir/$comp/" ; |
---|
782 | |
---|
783 | chdir $compdir; |
---|
784 | |
---|
785 | if ( ! -e "$comp.pro" ) |
---|
786 | { |
---|
787 | &Complain("$compdir/$comp.pro does not exist.", |
---|
788 | 'You must be building really old source?'); |
---|
789 | next; |
---|
790 | } |
---|
791 | |
---|
792 | if ($comp eq 'mythtv') |
---|
793 | { |
---|
794 | # MythTV has an empty subdirectory 'config' that causes problems for me: |
---|
795 | &Syscall('touch config/config.pro'); |
---|
796 | } |
---|
797 | |
---|
798 | if ($OPT{'clean'} && -e 'Makefile') |
---|
799 | { |
---|
800 | &Verbose("Cleaning $comp"); |
---|
801 | &Syscall([ $standard_make, 'distclean' ]) or die; |
---|
802 | } |
---|
803 | else |
---|
804 | { |
---|
805 | # clean the Makefiles, as process requires PREFIX hacking |
---|
806 | &CleanMakefiles(); |
---|
807 | } |
---|
808 | |
---|
809 | # Apply any nasty mac-specific patches |
---|
810 | if ($patches{$comp}) |
---|
811 | { |
---|
812 | &Syscall([ "echo '$patches{$comp}' | patch -p0 --forward" ]); |
---|
813 | } |
---|
814 | |
---|
815 | # configure and make |
---|
816 | if ( $makecleanopt{$comp} && -e 'Makefile' ) |
---|
817 | { |
---|
818 | my @makecleancom= $standard_make; |
---|
819 | push(@makecleancom, @{ $makecleanopt{$comp} }) if $makecleanopt{$comp}; |
---|
820 | &Syscall([ @makecleancom ]) or die; |
---|
821 | } |
---|
822 | if (-e 'configure') |
---|
823 | { |
---|
824 | &Verbose("Configuring $comp"); |
---|
825 | my @config = './configure'; |
---|
826 | push(@config, @{ $conf{$comp} }) if $conf{$comp}; |
---|
827 | if ( $comp eq 'mythtv' && $backend ) |
---|
828 | { |
---|
829 | push @config, '--enable-backend' |
---|
830 | } |
---|
831 | if ( $comp eq 'mythtv' && ! $ENV{'DISTCC_HOSTS'} ) |
---|
832 | { |
---|
833 | push @config, '--disable-distcc' |
---|
834 | } |
---|
835 | &Syscall([ @config ]) or die; |
---|
836 | } |
---|
837 | &Verbose("Running qmake for $comp"); |
---|
838 | my @qmake_opts = ( |
---|
839 | 'QMAKE_LFLAGS+=-Wl,-search_paths_first', |
---|
840 | 'INCLUDEPATH+="' . $PREFIX . '/include"', |
---|
841 | 'LIBS+=-L/usr/lib -L"' . $PREFIX . '/lib"' |
---|
842 | ); |
---|
843 | &Syscall([ $PREFIX . '/bin/qmake', |
---|
844 | 'PREFIX=../Resources', |
---|
845 | @qmake_opts, |
---|
846 | "$comp.pro" ]) or die; |
---|
847 | |
---|
848 | if ($comp eq 'mythtv') |
---|
849 | { |
---|
850 | # Remove/add Nigel's frontend building speedup hack |
---|
851 | &DoSpeedupHacks('programs/programs.pro', 'mythfrontend mythtv'); |
---|
852 | } |
---|
853 | |
---|
854 | &Verbose("Making $comp"); |
---|
855 | &Syscall([ $parallel_make ]) or die; |
---|
856 | # install |
---|
857 | # This requires a change from the compiled-in relative |
---|
858 | # PREFIX to our absolute path of the temp install location. |
---|
859 | &CleanMakefiles(); |
---|
860 | &Verbose("Running qmake for $comp install"); |
---|
861 | &Syscall([ $PREFIX . '/bin/qmake', |
---|
862 | 'PREFIX=' . $PREFIX, |
---|
863 | @qmake_opts, |
---|
864 | "$comp.pro" ]) or die; |
---|
865 | &Verbose("Installing $comp"); |
---|
866 | &Syscall([ $standard_make, |
---|
867 | 'install' ]) or die; |
---|
868 | |
---|
869 | if ($cleanLibs && $comp eq 'mythtv') |
---|
870 | { |
---|
871 | # If we cleaned the libs, make install will have recopied them, |
---|
872 | # which means any dynamic libraries that the static libraries depend on |
---|
873 | # are newer than the table of contents. Hence we need to regenerate it: |
---|
874 | my @mythlibs = glob "$PREFIX/lib/libmyth*.a"; |
---|
875 | if (scalar @mythlibs) |
---|
876 | { |
---|
877 | &Verbose("Running ranlib on reinstalled static libraries"); |
---|
878 | foreach my $lib (@mythlibs) |
---|
879 | { &Syscall("ranlib $lib") or die } |
---|
880 | } |
---|
881 | } |
---|
882 | } |
---|
883 | |
---|
884 | ### Build version string |
---|
885 | our $VERS = `find $PREFIX/lib -name 'libmyth-[0-9].[0-9][0-9].[0-9].dylib'`; |
---|
886 | chomp $VERS; |
---|
887 | $VERS =~ s/^.*\-(.*)\.dylib$/$1/s; |
---|
888 | $VERS .= '.' . $OPT{'version'} if $OPT{'version'}; |
---|
889 | |
---|
890 | ### Create each package. |
---|
891 | ### Note that this is a bit of a waste of disk space, |
---|
892 | ### because there are now multiple copies of each library. |
---|
893 | my @targets = ('MythFrontend', 'MythTV'); |
---|
894 | |
---|
895 | if ( $jobtools ) |
---|
896 | { push @targets, @targetsJT } |
---|
897 | |
---|
898 | if ( $backend ) |
---|
899 | { push @targets, @targetsBE } |
---|
900 | |
---|
901 | foreach my $target ( @targets ) |
---|
902 | { |
---|
903 | my $finalTarget = "$SCRIPTDIR/$target.app"; |
---|
904 | my $builtTarget = $target; |
---|
905 | $builtTarget =~ tr/[A-Z]/[a-z]/; |
---|
906 | |
---|
907 | # Get a fresh copy of the app |
---|
908 | &Verbose("Building self-contained $target"); |
---|
909 | &Syscall([ 'rm', '-fr', $finalTarget ]) or die; |
---|
910 | &RecursiveCopy("$PREFIX/bin/$builtTarget.app", $finalTarget); |
---|
911 | |
---|
912 | # write a custom Info.plist |
---|
913 | &GeneratePlist($target, $builtTarget, $finalTarget, $VERS); |
---|
914 | |
---|
915 | # Make frameworks from Myth libraries |
---|
916 | &Verbose("Installing frameworks into $target"); |
---|
917 | &PackagedExecutable($finalTarget, $builtTarget); |
---|
918 | |
---|
919 | if ( $target eq "MythFrontend" or $target =~ m/^MythTV/ ) |
---|
920 | { |
---|
921 | # Install themes, filters, etc. |
---|
922 | &Verbose("Installing resources into $target"); |
---|
923 | mkdir "$finalTarget/Contents/Resources"; |
---|
924 | mkdir "$finalTarget/Contents/Resources/lib"; |
---|
925 | &RecursiveCopy("$PREFIX/lib/mythtv", |
---|
926 | "$finalTarget/Contents/Resources/lib"); |
---|
927 | mkdir "$finalTarget/Contents/Resources/share"; |
---|
928 | &RecursiveCopy("$PREFIX/share/mythtv", |
---|
929 | "$finalTarget/Contents/Resources/share"); |
---|
930 | } |
---|
931 | |
---|
932 | if ( $target eq "MythFrontend" ) |
---|
933 | { |
---|
934 | my $mtd = "$svndir/mythplugins/mythdvd/mtd/mtd.app/Contents/MacOS/mtd"; |
---|
935 | if ( -e $mtd ) |
---|
936 | { |
---|
937 | &Verbose("Installing $mtd into $target"); |
---|
938 | &Syscall([ 'cp', $mtd, "$finalTarget/Contents/MacOS" ]) or die; |
---|
939 | &AddFakeBinDir($finalTarget); |
---|
940 | } |
---|
941 | } |
---|
942 | } |
---|
943 | |
---|
944 | if ( $backend ) |
---|
945 | { |
---|
946 | my $BE = "$SCRIPTDIR/MythBackend.app"; |
---|
947 | |
---|
948 | # The backend gets all the useful binaries it might call: |
---|
949 | foreach my $binary ( 'mythjobqueue', 'mythcommflag', 'mythtranscode' ) |
---|
950 | { |
---|
951 | my $SRC = "$PREFIX/bin/$binary.app/Contents/MacOS/$binary"; |
---|
952 | if ( -e $SRC ) |
---|
953 | { |
---|
954 | &Syscall([ '/bin/cp', $SRC, "$BE/Contents/MacOS" ]) or die; |
---|
955 | &PackagedExecutable($BE, $binary); |
---|
956 | &AddFakeBinDir($BE); |
---|
957 | } |
---|
958 | } |
---|
959 | } |
---|
960 | |
---|
961 | if ( $jobtools ) |
---|
962 | { |
---|
963 | # JobQueue also gets some binaries it might call: |
---|
964 | my $JQ = "$SCRIPTDIR/MythJobQueue.app"; |
---|
965 | my $DEST = "$JQ/Contents/MacOS"; |
---|
966 | my $SRC = "$PREFIX/bin/mythcommflag.app/Contents/MacOS/mythcommflag"; |
---|
967 | |
---|
968 | &Syscall([ '/bin/cp', $SRC, $DEST ]) or die; |
---|
969 | &PackagedExecutable($JQ, 'mythcommflag'); |
---|
970 | |
---|
971 | $SRC = "$PREFIX/bin/mythtranscode.app/Contents/MacOS/mythtranscode"; |
---|
972 | if ( -e $SRC ) |
---|
973 | { |
---|
974 | &Syscall([ '/bin/cp', $SRC, $DEST ]) or die; |
---|
975 | &PackagedExecutable($JQ, 'mythtranscode'); |
---|
976 | &AddFakeBinDir($JQ); |
---|
977 | } |
---|
978 | } |
---|
979 | |
---|
980 | if ($OPT{usehdimage}) |
---|
981 | { |
---|
982 | Verbose("Dismounting case-sensitive build device"); |
---|
983 | UnmountHDImage(); |
---|
984 | } |
---|
985 | |
---|
986 | &Verbose("Build complete. Self-contained package is at:\n\n $MFE\n"); |
---|
987 | |
---|
988 | |
---|
989 | ### end script |
---|
990 | exit 0; |
---|
991 | |
---|
992 | |
---|
993 | ###################################### |
---|
994 | ## RecursiveCopy copies a directory tree, stripping out .svn |
---|
995 | ## directories and properly managing static libraries. |
---|
996 | ###################################### |
---|
997 | |
---|
998 | sub RecursiveCopy |
---|
999 | { |
---|
1000 | my ($src, $dst) = @_; |
---|
1001 | |
---|
1002 | # First copy absolutely everything |
---|
1003 | &Syscall([ '/bin/cp', '-R', "$src", "$dst"]) or die; |
---|
1004 | |
---|
1005 | # Then strip out any .svn directories |
---|
1006 | my @files = map { chomp $_; $_ } `find $dst -name .svn`; |
---|
1007 | if (scalar @files) |
---|
1008 | { |
---|
1009 | &Syscall([ '/bin/rm', '-f', '-r', @files ]); |
---|
1010 | } |
---|
1011 | |
---|
1012 | # And make sure any static libraries are properly relocated. |
---|
1013 | my @libs = map { chomp $_; $_ } `find $dst -name "lib*.a"`; |
---|
1014 | if (scalar @libs) |
---|
1015 | { |
---|
1016 | &Syscall([ 'ranlib', '-s', @libs ]); |
---|
1017 | } |
---|
1018 | } |
---|
1019 | |
---|
1020 | ###################################### |
---|
1021 | ## Given an application package $finalTarget and an executable |
---|
1022 | ## $builtTarget that has been copied into it, PackagedExecutable |
---|
1023 | ## makes sure the package contains all the library dependencies as |
---|
1024 | ## frameworks and that all the paths internal to the executable have |
---|
1025 | ## been adjusted appropriately. |
---|
1026 | ###################################### |
---|
1027 | |
---|
1028 | sub PackagedExecutable($$) |
---|
1029 | { |
---|
1030 | my ($finalTarget, $builtTarget) = @_; |
---|
1031 | |
---|
1032 | my $fw_dir = "$finalTarget/Contents/Frameworks"; |
---|
1033 | mkdir $fw_dir; |
---|
1034 | |
---|
1035 | my $dephash |
---|
1036 | = &ProcessDependencies("$finalTarget/Contents/MacOS/$builtTarget", |
---|
1037 | glob "$PREFIX/lib/mythtv/*/*.dylib"); |
---|
1038 | my @deps = values %$dephash; |
---|
1039 | while (scalar @deps) |
---|
1040 | { |
---|
1041 | my $dep = shift @deps; |
---|
1042 | |
---|
1043 | my $file = &MakeFramework(&FindLibraryFile($dep), $fw_dir); |
---|
1044 | if ( $file ) |
---|
1045 | { |
---|
1046 | my $newhash = &ProcessDependencies($file); |
---|
1047 | foreach my $base (keys %$newhash) |
---|
1048 | { |
---|
1049 | next if exists $dephash->{$base}; |
---|
1050 | $dephash->{$base} = $newhash->{$base}; |
---|
1051 | push(@deps, $newhash->{$base}); |
---|
1052 | } |
---|
1053 | } |
---|
1054 | } |
---|
1055 | } |
---|
1056 | |
---|
1057 | |
---|
1058 | ###################################### |
---|
1059 | ## MakeFramework copies a dylib into a |
---|
1060 | ## framework bundle. |
---|
1061 | ###################################### |
---|
1062 | |
---|
1063 | sub MakeFramework |
---|
1064 | { |
---|
1065 | my ($dylib, $dest) = @_; |
---|
1066 | |
---|
1067 | my ($base, $vers) = &BaseVers($dylib); |
---|
1068 | $vers .= '.' . $OPT{'version'} if ($OPT{'version'} && $base =~ /myth/); |
---|
1069 | my $fw_dir = $dest . '/' . $base . '.framework'; |
---|
1070 | |
---|
1071 | return '' if ( -e $fw_dir ); |
---|
1072 | |
---|
1073 | &Verbose("Building $base framework"); |
---|
1074 | |
---|
1075 | &Syscall([ '/bin/mkdir', |
---|
1076 | '-p', |
---|
1077 | "$fw_dir/Versions/A/Resources" ]) or die; |
---|
1078 | &Syscall([ '/bin/cp', |
---|
1079 | $dylib, |
---|
1080 | "$fw_dir/Versions/A/$base" ]) or die; |
---|
1081 | |
---|
1082 | &Syscall([ '/usr/bin/install_name_tool', |
---|
1083 | '-id', |
---|
1084 | $base, |
---|
1085 | "$fw_dir/Versions/A/$base" ]) or die; |
---|
1086 | |
---|
1087 | symlink('A', "$fw_dir/Versions/Current") or die; |
---|
1088 | symlink('Versions/Current/Resources', "$fw_dir/Resources") or die; |
---|
1089 | symlink("Versions/A/$base", "$fw_dir/$base") or die; |
---|
1090 | |
---|
1091 | &Verbose("Writing Info.plist for $base framework"); |
---|
1092 | my $plist; |
---|
1093 | unless (open($plist, '>' . "$fw_dir/Versions/A/Resources/Info.plist")) |
---|
1094 | { |
---|
1095 | &Complain("Failed to open $base framework's plist for writing"); |
---|
1096 | die; |
---|
1097 | } |
---|
1098 | print $plist <<END; |
---|
1099 | <?xml version="1.0" encoding="UTF-8"?> |
---|
1100 | <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
---|
1101 | <plist version="1.0"> |
---|
1102 | <dict> |
---|
1103 | <key>CFBundleName</key> |
---|
1104 | <string>$base</string> |
---|
1105 | <key>CFBundleIdentifier</key> |
---|
1106 | <string>org.mythtv.macx.$base</string> |
---|
1107 | <key>CFBundleVersion</key> |
---|
1108 | <string>$vers</string> |
---|
1109 | <key>CFBundleSignature</key> |
---|
1110 | <string>Myth</string> |
---|
1111 | <key>CFBundlePackageType</key> |
---|
1112 | <string>FMWK</string> |
---|
1113 | <key>NSHumanReadableCopyright</key> |
---|
1114 | <string>Packaged for the MythTV project, www.mythtv.org</string> |
---|
1115 | <key>CFBundleGetInfoString</key> |
---|
1116 | <string>lib$base-$vers.dylib, packaged for the MythTV project, www.mythtv.org</string> |
---|
1117 | </dict> |
---|
1118 | </plist> |
---|
1119 | END |
---|
1120 | close($plist); |
---|
1121 | |
---|
1122 | return "$fw_dir/Versions/A/$base"; |
---|
1123 | } # end MakeFramework |
---|
1124 | |
---|
1125 | |
---|
1126 | ###################################### |
---|
1127 | ## GeneratePlist . |
---|
1128 | ###################################### |
---|
1129 | |
---|
1130 | sub GeneratePlist |
---|
1131 | { |
---|
1132 | my ($name, $binary, $path, $vers) = @_; |
---|
1133 | |
---|
1134 | &Verbose("Writing Info.plist for $name"); |
---|
1135 | my $plist; |
---|
1136 | $path .= '/Contents/Info.plist'; |
---|
1137 | unless (open($plist, ">$path")) |
---|
1138 | { |
---|
1139 | &Complain("Could not open $path for writing"); |
---|
1140 | die; |
---|
1141 | } |
---|
1142 | print $plist <<END; |
---|
1143 | <?xml version="1.0" encoding="UTF-8"?> |
---|
1144 | <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
---|
1145 | <plist version="1.0"> |
---|
1146 | <dict> |
---|
1147 | <key>CFBundleExecutable</key> |
---|
1148 | <string>$binary</string> |
---|
1149 | <key>CFBundleIconFile</key> |
---|
1150 | <string>application.icns</string> |
---|
1151 | <key>CFBundleIdentifier</key> |
---|
1152 | <string>org.mythtv.macx.$binary</string> |
---|
1153 | <key>CFBundleInfoDictionaryVersion</key> |
---|
1154 | <string>6.0</string> |
---|
1155 | <key>CFBundlePackageType</key> |
---|
1156 | <string>APPL</string> |
---|
1157 | <key>CFBundleShortVersionString</key> |
---|
1158 | <string>$vers</string> |
---|
1159 | <key>CFBundleSignature</key> |
---|
1160 | <string>Myth</string> |
---|
1161 | <key>CFBundleVersion</key> |
---|
1162 | <string>$vers</string> |
---|
1163 | <key>NSAppleScriptEnabled</key> |
---|
1164 | <string>NO</string> |
---|
1165 | <key>CFBundleGetInfoString</key> |
---|
1166 | <string>$vers, MythTV project, www.mythtv.org</string> |
---|
1167 | <key>CFBundleName</key> |
---|
1168 | <string>$name</string> |
---|
1169 | <key>NSHumanReadableCopyright</key> |
---|
1170 | <string>MythTV project, www.mythtv.org</string> |
---|
1171 | </dict> |
---|
1172 | </plist> |
---|
1173 | END |
---|
1174 | close($plist); |
---|
1175 | |
---|
1176 | $path =~ s/Info\.plist$/PkgInfo/; |
---|
1177 | unless (open($plist, ">$path")) |
---|
1178 | { |
---|
1179 | &Complain("Could not open $path for writing"); |
---|
1180 | die; |
---|
1181 | } |
---|
1182 | print $plist <<END; |
---|
1183 | APPLMyth |
---|
1184 | END |
---|
1185 | close($plist); |
---|
1186 | } |
---|
1187 | |
---|
1188 | ###################################### |
---|
1189 | ## FindLibraryFile locates a dylib. |
---|
1190 | ###################################### |
---|
1191 | |
---|
1192 | sub FindLibraryFile |
---|
1193 | { |
---|
1194 | my ($dylib) = @_; |
---|
1195 | |
---|
1196 | return Cwd::abs_path($dylib) if (-e $dylib); |
---|
1197 | return Cwd::abs_path("$PREFIX/lib/$dylib") if (-e "$PREFIX/lib/$dylib"); |
---|
1198 | return Cwd::abs_path("$ENV{'QTDIR'}/lib/$dylib") if (-e "$ENV{'QTDIR'}/lib/$dylib"); |
---|
1199 | my @sublibs = glob("$PREFIX/lib/*/$dylib"); |
---|
1200 | return Cwd::abs_path($sublibs[0]) if (scalar @sublibs); |
---|
1201 | &Complain("Could not find $dylib"); |
---|
1202 | die; |
---|
1203 | } # end FindLibraryFile |
---|
1204 | |
---|
1205 | |
---|
1206 | ###################################### |
---|
1207 | ## ProcessDependencies catalogs and |
---|
1208 | ## rewrites dependencies that will be |
---|
1209 | ## packaged into our app bundle. |
---|
1210 | ###################################### |
---|
1211 | |
---|
1212 | sub ProcessDependencies |
---|
1213 | { |
---|
1214 | my (%depfiles); |
---|
1215 | |
---|
1216 | foreach my $file (@_) |
---|
1217 | { |
---|
1218 | &Verbose("Processing shared library dependencies for $file"); |
---|
1219 | my ($filebase) = &BaseVers($file); |
---|
1220 | |
---|
1221 | my $cmd = "otool -L $file"; |
---|
1222 | &Verbose($cmd); |
---|
1223 | my @deps = `$cmd`; |
---|
1224 | shift @deps; # first line just repeats filename |
---|
1225 | &Verbose("Dependencies for $file = @deps"); |
---|
1226 | foreach my $dep (@deps) |
---|
1227 | { |
---|
1228 | chomp $dep; |
---|
1229 | |
---|
1230 | # otool returns lines like: |
---|
1231 | # libblah-7.dylib (compatibility version 7, current version 7) |
---|
1232 | # but we only want the file part |
---|
1233 | $dep =~ s/\s+(.*) \(.*\)$/$1/; |
---|
1234 | |
---|
1235 | # Paths like /usr/lib/libstdc++ contain quantifiers that must be escaped |
---|
1236 | $dep =~ s/([+*?])/\\$1/; |
---|
1237 | |
---|
1238 | # otool sometimes lists the framework as depending on itself |
---|
1239 | next if ($file =~ m,/Versions/A/$dep,); |
---|
1240 | |
---|
1241 | # Any dependency which is already package relative can be ignored |
---|
1242 | next if $dep =~ m/\@executable_path/; |
---|
1243 | |
---|
1244 | # skip system library locations |
---|
1245 | next if ($dep =~ m|^/System| || |
---|
1246 | $dep =~ m|^/usr/lib|); |
---|
1247 | |
---|
1248 | my ($base) = &BaseVers($dep); |
---|
1249 | $depfiles{$base} = $dep; |
---|
1250 | |
---|
1251 | # Change references while we're here |
---|
1252 | &Syscall([ '/usr/bin/install_name_tool', |
---|
1253 | '-change', |
---|
1254 | $dep, |
---|
1255 | "\@executable_path/../Frameworks/$base.framework/$base", |
---|
1256 | $file ]) or die; |
---|
1257 | } |
---|
1258 | } |
---|
1259 | return \%depfiles; |
---|
1260 | } # end ProcessDependencies |
---|
1261 | |
---|
1262 | |
---|
1263 | ###################################### |
---|
1264 | ## BaseVers splits up a dylib file |
---|
1265 | ## name for framework naming. |
---|
1266 | ###################################### |
---|
1267 | |
---|
1268 | sub BaseVers |
---|
1269 | { |
---|
1270 | my ($filename) = @_; |
---|
1271 | |
---|
1272 | if ($filename =~ m|^(?:.*/)?lib(.*)\-(\d.*)\.dylib$|) |
---|
1273 | { |
---|
1274 | return ($1, $2); |
---|
1275 | } |
---|
1276 | elsif ($filename =~ m|^(?:.*/)?lib(.*?)\.(\d.*)\.dylib$|) |
---|
1277 | { |
---|
1278 | return ($1, $2); |
---|
1279 | } |
---|
1280 | elsif ($filename =~ m|^(?:.*/)?lib(.*?)\.dylib$|) |
---|
1281 | { |
---|
1282 | return ($1, undef); |
---|
1283 | } |
---|
1284 | |
---|
1285 | &Verbose("Not a library file: $filename"); |
---|
1286 | return $filename; |
---|
1287 | } # end BaseVers |
---|
1288 | |
---|
1289 | |
---|
1290 | ###################################### |
---|
1291 | ## CleanMakefiles removes every |
---|
1292 | ## Makefile from our MythTV build. |
---|
1293 | ## Necessary when we change the |
---|
1294 | ## PREFIX variable. |
---|
1295 | ###################################### |
---|
1296 | |
---|
1297 | sub CleanMakefiles |
---|
1298 | { |
---|
1299 | &Verbose("Cleaning MythTV makefiles"); |
---|
1300 | my @files = map { chomp $_; $_ } `find . -name Makefile`; |
---|
1301 | if (scalar @files) |
---|
1302 | { |
---|
1303 | &Syscall([ '/bin/rm', @files ]) or die; |
---|
1304 | } |
---|
1305 | } # end CleanMakefiles |
---|
1306 | |
---|
1307 | |
---|
1308 | ###################################### |
---|
1309 | ## Syscall wrappers the Perl "system" |
---|
1310 | ## routine with verbosity and error |
---|
1311 | ## checking. |
---|
1312 | ###################################### |
---|
1313 | |
---|
1314 | sub Syscall |
---|
1315 | { |
---|
1316 | my ($arglist, %opts) = @_; |
---|
1317 | |
---|
1318 | unless (ref $arglist) |
---|
1319 | { |
---|
1320 | $arglist = [ $arglist ]; |
---|
1321 | } |
---|
1322 | if ($opts{'interpolate'}) |
---|
1323 | { |
---|
1324 | my @args; |
---|
1325 | foreach my $arg (@$arglist) |
---|
1326 | { |
---|
1327 | $arg =~ s/\$PREFIX/$PREFIX/ge; |
---|
1328 | push(@args, $arg); |
---|
1329 | } |
---|
1330 | $arglist = \@args; |
---|
1331 | } |
---|
1332 | if ($opts{'munge'}) |
---|
1333 | { |
---|
1334 | $arglist = [ join(' ', @$arglist) ]; |
---|
1335 | } |
---|
1336 | # clean out any null arguments |
---|
1337 | $arglist = [ map $_, @$arglist ]; |
---|
1338 | &Verbose(@$arglist); |
---|
1339 | my $ret = system(@$arglist); |
---|
1340 | if ($ret) |
---|
1341 | { |
---|
1342 | &Complain('Failed system call: "', @$arglist, |
---|
1343 | '" with error code', $ret >> 8); |
---|
1344 | } |
---|
1345 | return ($ret == 0); |
---|
1346 | } # end Syscall |
---|
1347 | |
---|
1348 | |
---|
1349 | ###################################### |
---|
1350 | ## Verbose prints messages in verbose |
---|
1351 | ## mode. |
---|
1352 | ###################################### |
---|
1353 | |
---|
1354 | sub Verbose |
---|
1355 | { |
---|
1356 | print STDERR '[osx-pkg] ' . join(' ', @_) . "\n" |
---|
1357 | if $OPT{'verbose'}; |
---|
1358 | } # end Verbose |
---|
1359 | |
---|
1360 | |
---|
1361 | ###################################### |
---|
1362 | ## Complain prints messages in any |
---|
1363 | ## verbosity mode. |
---|
1364 | ###################################### |
---|
1365 | |
---|
1366 | sub Complain |
---|
1367 | { |
---|
1368 | print STDERR '[osx-pkg] ' . join(' ', @_) . "\n"; |
---|
1369 | } # end Complain |
---|
1370 | |
---|
1371 | |
---|
1372 | ###################################### |
---|
1373 | ## Manage usehdimage disk image |
---|
1374 | ###################################### |
---|
1375 | |
---|
1376 | sub MountHDImage |
---|
1377 | { |
---|
1378 | if (!HDImageDevice()) |
---|
1379 | { |
---|
1380 | if (! -e "$SCRIPTDIR/.osx-packager.dmg") |
---|
1381 | { |
---|
1382 | Syscall(['hdiutil', 'create', '-size', '1300m', |
---|
1383 | "$SCRIPTDIR/.osx-packager.dmg", '-volname', |
---|
1384 | 'MythTvPackagerHDImage', '-fs', 'UFS', '-quiet']); |
---|
1385 | } |
---|
1386 | |
---|
1387 | Syscall(['hdiutil', 'mount', "$SCRIPTDIR/.osx-packager.dmg", |
---|
1388 | '-mountpoint', $WORKDIR, '-quiet']); |
---|
1389 | } |
---|
1390 | |
---|
1391 | # configure defaults to /tmp and OSX barfs when mv crosses |
---|
1392 | # filesystems so tell configure to put temp files on the image |
---|
1393 | |
---|
1394 | $ENV{TMPDIR} = $WORKDIR . "/tmp"; |
---|
1395 | mkdir $ENV{TMPDIR}; |
---|
1396 | } |
---|
1397 | |
---|
1398 | sub UnmountHDImage |
---|
1399 | { |
---|
1400 | my $device = HDImageDevice(); |
---|
1401 | if ($device) |
---|
1402 | { |
---|
1403 | &Syscall(['hdiutil', 'detach', $device, '-force']); |
---|
1404 | } |
---|
1405 | } |
---|
1406 | |
---|
1407 | sub HDImageDevice |
---|
1408 | { |
---|
1409 | my @dev = split ' ', `/sbin/mount | grep $WORKDIR`; |
---|
1410 | $dev[0]; |
---|
1411 | } |
---|
1412 | |
---|
1413 | sub CaseSensitiveFilesystem |
---|
1414 | { |
---|
1415 | my $funky = $SCRIPTDIR . "/.osx-packager.FunkyStuff"; |
---|
1416 | my $unfunky = substr($funky, 0, -10) . "FUNKySTuFF"; |
---|
1417 | |
---|
1418 | unlink $funky if -e $funky; |
---|
1419 | `touch $funky`; |
---|
1420 | my $sensitivity = ! -e $unfunky; |
---|
1421 | unlink $funky; |
---|
1422 | |
---|
1423 | return $sensitivity; |
---|
1424 | } |
---|
1425 | |
---|
1426 | |
---|
1427 | ###################################### |
---|
1428 | ## Remove or add Nigel's speedup hacks |
---|
1429 | ###################################### |
---|
1430 | |
---|
1431 | sub DoSpeedupHacks($$) |
---|
1432 | { |
---|
1433 | my ($file, $subdirs) = @_; |
---|
1434 | |
---|
1435 | &Verbose("Removing Nigel's hacks from file $file"); |
---|
1436 | |
---|
1437 | open(IN, $file) or die; |
---|
1438 | open(OUT, ">$file.orig") or die; |
---|
1439 | while ( <IN> ) |
---|
1440 | { |
---|
1441 | if ( m/^# Nigel/ ) # Skip |
---|
1442 | { last } |
---|
1443 | print OUT; |
---|
1444 | } |
---|
1445 | if ( ! $backend && ! $jobtools ) |
---|
1446 | { |
---|
1447 | # Nigel's hack to speedup building |
---|
1448 | print OUT "# Nigel\'s speedup hack:\n"; |
---|
1449 | print OUT "SUBDIRS = $subdirs\n"; |
---|
1450 | } |
---|
1451 | close IN; close OUT; |
---|
1452 | rename("$file.orig", $file); |
---|
1453 | } |
---|
1454 | |
---|
1455 | ####################################################### |
---|
1456 | ## Parts of MythTV try to call helper apps like this: |
---|
1457 | ## gContext->GetInstallPrefix() + "/bin/mythtranscode"; |
---|
1458 | ## which means we need a bin directory. |
---|
1459 | ####################################################### |
---|
1460 | |
---|
1461 | sub AddFakeBinDir($) |
---|
1462 | { |
---|
1463 | my ($target) = @_; |
---|
1464 | |
---|
1465 | &Syscall(['ln', '-sf', '../MacOS', "$target/Contents/Resources/bin"]); |
---|
1466 | } |
---|
1467 | |
---|
1468 | ### end file |
---|
1469 | 1; |
---|