00001 #!/usr/bin/perl
00002
00003 ### = file
00004 ### osx-packager.pl
00005 ###
00006 ### = revision
00007 ### $Id: osx-packager.pl 25121 2010-06-16 07:52:42Z nigel $
00008 ###
00009 ### = location
00010 ### http://svn.mythtv.org/svn/branches/release-0-21-fixes/mythtv/contrib/OSX/osx-packager.pl
00011 ###
00012 ### = description
00013 ### Tool for automating frontend builds on Mac OS X.
00014 ### Run "osx-packager.pl -man" for full documentation.
00015
00016 use strict;
00017 use Getopt::Long qw(:config auto_abbrev);
00018 use Pod::Usage ();
00019 use Cwd ();
00020
00021 ### Configuration settings (stuff that might change more often)
00022
00023 # We try to auto-locate the Subversion client binaries.
00024 # If they are not in your path, we build them from source
00025 #
00026 our $svn = `which svn`; chomp $svn;
00027
00028 # This script used to always delete the installed include and lib dirs.
00029 # That probably ensures a safe build, but when rebuilding adds minutes to
00030 # the total build time, and prevents us skipping some parts of a full build
00031 #
00032 our $cleanLibs = 1;
00033
00034 # By default, only the frontend is built (i.e. no backend or transcoding)
00035 #
00036 our $backend = 0;
00037 our $jobtools = 0;
00038
00039 # Parallel makes?
00040 #
00041 #$ENV{'DISTCC_HOSTS'} = "localhost 192.168.0.6";
00042 #$ENV{'DISTCC_VERBOSE'} = '1';
00043
00044 # Start with a generic address and let sourceforge
00045 # figure out which mirror is closest to us.
00046 #
00047 our $sourceforge = 'http://downloads.sourceforge.net';
00048
00049 # At the moment, there is mythtv plus these two
00050 our @components = ( 'myththemes', 'mythplugins' );
00051
00052 # The OS X programs that we are likely to be interested in.
00053 our @targetsJT = ( 'MythCommFlag', 'MythJobQueue');
00054 our @targetsBE = ( 'MythBackend', 'MythFillDatabase',
00055 'MythTranscode', 'MythTV-Setup');
00056
00057 # Patches for MythTV source
00058 our %patches = (
00059 'mythtv' => 'Index: libs/libmythui/mythmainwindow.cpp
00060 ===================================================================
00061 --- libs/libmythui/mythmainwindow.cpp (revision 12154)
00062 +++ libs/libmythui/mythmainwindow.cpp (working copy)
00063 @@ -1094,6 +1094,10 @@
00064 {
00065 QKeyEvent *ke = dynamic_cast<QKeyEvent*>(e);
00066
00067 + // Work around weird GCC run-time bug. Only manifest on Mac OS X
00068 + if (!ke)
00069 + ke = (QKeyEvent *)e;
00070 +
00071 if (currentWidget())
00072 {
00073 ke->accept();
00074 '
00075 );
00076
00077 our %depend_order = (
00078 'mythtv'
00079 => [
00080 'faad2',
00081 'freetype',
00082 'lame',
00083 'mysqlclient',
00084 'qt-mt',
00085 ],
00086 'mythplugins'
00087 => [
00088 'tiff',
00089 'exif',
00090 'dvdcss',
00091 # MythMusic needs these:
00092 'libmad',
00093 'taglib',
00094 'libogg',
00095 'vorbis',
00096 'flac',
00097 ],
00098 );
00099
00100 our %depend = (
00101
00102 'svndeps' =>
00103 {
00104 'url'
00105 => 'http://subversion.tigris.org/downloads/subversion-deps-1.4.3.tar.bz2',
00106 'skip'
00107 => 'yes' # Don't actually untarr/configure/make.
00108 },
00109
00110 'svn' =>
00111 {
00112 'url'
00113 => 'http:
00114 'pre-conf'
00115 => 'tar -xjf ../subversion-deps-1.4.3.tar.bz2 -C ..',
00116 'conf'
00117 => [
00118 '--disable-keychain', # Workaround a 10.3 build problem
00119 "MAKEFLAGS=\$parallel_make_flags" # For builds of deps
00120 ],
00121 # For some reason, this dies when the neon sub-make ends
00122 #'parallel-make'
00123 #=> 'yes'
00124 },
00125
00126 'faad2' =>
00127 {
00128 'url' => "$sourceforge/sourceforge/faac/faad2-2.7.tar.gz",
00129 },
00130
00131 'freetype' =>
00132 {
00133 'url' => "$sourceforge/sourceforge/freetype/freetype-2.1.10.tar.gz",
00134 },
00135
00136 'lame' =>
00137 {
00138 'url'
00139 => "$sourceforge/sourceforge/lame/lame-3.96.1.tar.gz",
00140 'conf'
00141 => [
00142 '--disable-frontend',
00143 ],
00144 },
00145
00146 'libmad' =>
00147 {
00148 'url' => "$sourceforge/sourceforge/mad/libmad-0.15.0b.tar.gz"
00149 },
00150
00151 'taglib' =>
00152 {
00153 'url' => 'http://developer.kde.org/~wheeler/files/src/taglib-1.4.tar.gz',
00154 # libtool in taglib has problems with -Z in LDFLAGS
00155 'conf-cmd' => 'LDFLAGS="" ./configure -prefix "$PREFIX"'
00156 },
00157
00158 'libogg' =>
00159 {
00160 'url' => 'http://downloads.xiph.org/releases/ogg/libogg-1.1.2.tar.gz'
00161 },
00162
00163 'vorbis' =>
00164 {
00165 'url' => 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.1.1.tar.gz'
00166 },
00167
00168 'flac' =>
00169 {
00170 'url' => "$sourceforge/sourceforge/flac/flac-1.1.4.tar.gz",
00171 # Workaround Intel problem - Missing _FLAC__lpc_restore_signal_asm_ia32
00172 'conf' => [ '--disable-asm-optimizations' ]
00173 },
00174
00175 'dvdcss'
00176 =>
00177 {
00178 'url'
00179 => 'http://download.videolan.org/pub/videolan/libdvdcss/1.2.9/libdvdcss-1.2.9.tar.bz2'
00180 },
00181
00182 'mysqlclient'
00183 =>
00184 {
00185 'url'
00186 => 'http://mirror.provenscaling.com/mysql/community/source/4.1/mysql-4.1.22.tar.gz',
00187 'conf'
00188 => [
00189 '--without-debug',
00190 '--without-docs',
00191 '--without-man',
00192 '--without-bench',
00193 '--without-server',
00194 '--without-geometry',
00195 '--without-extra-tools',
00196 ],
00197 },
00198
00199 'qt-mt'
00200 =>
00201 {
00202 'url'
00203 => 'http://ftp.iasi.roedu.net/mirrors/ftp.trolltech.com/qt/source/qt-mac-free-3.3.8.tar.gz',
00204 'pre-conf' =>
00205 '/bin/echo \'' . q^
00206 diff -ru qt-mac-free-3.3.8.orig/config.tests/mac/mac_version.test qt-mac-free-3.3.8.new/config.tests/mac/mac_version.test
00207 --- qt-mac-free-3.3.8.orig/config.tests/mac/mac_version.test 2004-04-24 02:40:40.000000000 +1000
00208 +++ qt-mac-free-3.3.8.new/config.tests/mac/mac_version.test 2008-01-01 10:33:55.000000000 +1100
00209 @@ -17,13 +17,17 @@
00210 TSTFILE=mac_version.cpp
00211
00212 rm -f $TSTFILE
00213 -echo "#include <Carbon/Carbon.h>" >$TSTFILE
00214 -echo "#include <stdio.h>" >>$TSTFILE
00215 -echo "int main() {" >>$TSTFILE
00216 -echo " long gestalt_version;" >>$TSTFILE
00217 -echo " fprintf(stdout, \"%d\\\n\", (Gestalt(gestaltSystemVersion, &gestalt_version) == noErr) ? gestalt_version : 0);" >>$TSTFILE
00218 -echo " return 1;" >>$TSTFILE
00219 -echo "}" >>$TSTFILE
00220 +cat << END >$TSTFILE
00221 +#include <Carbon/Carbon.h>
00222 +#include <stdio.h>
00223 +int main() {
00224 + long gestalt_version;
00225 + if (Gestalt(gestaltSystemVersion, &gestalt_version) != noErr)
00226 + gestalt_version=0;
00227 + fprintf(stdout, "0x%x\n", gestalt_version);
00228 + return 1;
00229 +}
00230 +END
00231
00232 COMPILE_ERROR=yes
00233 if [ "$VERBOSE" = "yes" ]; then
00234 diff -ru qt-mac-free-3.3.8.orig/include/qglobal.h qt-mac-free-3.3.8.new/include/qglobal.h
00235 --- qt-mac-free-3.3.8.orig/include/qglobal.h 2007-02-03 01:01:04.000000000 +1100
00236 +++ qt-mac-free-3.3.8.new/include/qglobal.h 2008-01-01 10:47:28.000000000 +1100
00237 @@ -183,7 +183,10 @@
00238 # if !defined(MAC_OS_X_VERSION_10_4)
00239 # define MAC_OS_X_VERSION_10_4 MAC_OS_X_VERSION_10_3 + 1
00240 # endif
00241 -# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4)
00242 +# if !defined(MAC_OS_X_VERSION_10_5)
00243 +# define MAC_OS_X_VERSION_10_5 MAC_OS_X_VERSION_10_4 + 1
00244 +# endif
00245 +# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5)
00246 # error "This version of Mac OS X is unsupported"
00247 # endif
00248 #endif
00249 diff -ru qt-mac-free-3.3.8.orig/src/kernel/qcursor_mac.cpp qt-mac-free-3.3.8.new/src/kernel/qcursor_mac.cpp
00250 --- qt-mac-free-3.3.8.orig/src/kernel/qcursor_mac.cpp 2007-02-03 01:01:16.000000000 +1100
00251 +++ qt-mac-free-3.3.8.new/src/kernel/qcursor_mac.cpp 2008-01-01 10:45:15.000000000 +1100
00252 @@ -177,7 +177,9 @@
00253 #ifdef QMAC_USE_BIG_CURSOR_API
00254 char *big_cursor_name;
00255 #endif
00256 +#ifdef QMAC_NO_FAKECURSOR
00257 CursorImageRec *ci;
00258 +#endif
00259 struct {
00260 QMacAnimateCursor *anim;
00261 ThemeCursor curs;
00262 @@ -258,7 +260,9 @@
00263 if(curs.cp.hcurs && curs.cp.my_cursor)
00264 free(curs.cp.hcurs);
00265 } else if(type == TYPE_CursorImage) {
00266 +#ifdef QMAC_NO_FAKECURSOR
00267 free(curs.ci);
00268 +#endif
00269 #ifdef QMAC_USE_BIG_CURSOR_API
00270 } else if(type == TYPE_BigCursor) {
00271 QDUnregisterNamedPixMapCursur(curs.big_cursor_name);
00272 diff -ru qt-mac-free-3.3.8.orig/src/kernel/qt_mac.h qt-mac-free-3.3.8.new/src/kernel/qt_mac.h
00273 --- qt-mac-free-3.3.8.orig/src/kernel/qt_mac.h 2007-02-03 01:01:13.000000000 +1100
00274 +++ qt-mac-free-3.3.8.new/src/kernel/qt_mac.h 2008-01-01 18:03:04.000000000 +1100
00275 @@ -54,7 +54,7 @@
00276 # define QMAC_DEFAULT_STYLE "QMacStyle" //DefaultStyle
00277 #endif
00278
00279 -#if !defined(Q_WS_MACX) || QT_MACOSX_VERSION < 0x1020 || QT_MACOSX_VERSION >= 0x1030
00280 +#if !defined(Q_WS_MACX) || QT_MACOSX_VERSION < 0x1020 || (QT_MACOSX_VERSION >= 0x1030 && QT_MACOSX_VERSION < 0x1050)
00281 # define QMAC_NO_FAKECURSOR
00282 #endif
00283
00284 diff -ru qt-mac-free-3.3.8.orig/src/tools/qglobal.h qt-mac-free-3.3.8.new/src/tools/qglobal.h
00285 --- qt-mac-free-3.3.8.orig/src/tools/qglobal.h 2007-02-03 01:01:04.000000000 +1100
00286 +++ qt-mac-free-3.3.8.new/src/tools/qglobal.h 2008-01-01 10:47:28.000000000 +1100
00287 @@ -183,7 +183,10 @@
00288 # if !defined(MAC_OS_X_VERSION_10_4)
00289 # define MAC_OS_X_VERSION_10_4 MAC_OS_X_VERSION_10_3 + 1
00290 # endif
00291 -# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4)
00292 +# if !defined(MAC_OS_X_VERSION_10_5)
00293 +# define MAC_OS_X_VERSION_10_5 MAC_OS_X_VERSION_10_4 + 1
00294 +# endif
00295 +# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5)
00296 # error "This version of Mac OS X is unsupported"
00297 # endif
00298 #endif
00299 ^ . '\' | patch -p1',
00300 'conf-cmd'
00301 => 'echo yes | ./configure',
00302 'conf'
00303 => [
00304 '-prefix', '"$PREFIX"',
00305 '-thread',
00306 '-system-zlib',
00307 '-fast',
00308 '-qt-sql-mysql',
00309 '-no-style-cde',
00310 '-no-style-compact',
00311 '-no-style-motif',
00312 '-no-style-motifplus',
00313 '-no-style-platinum',
00314 '-no-style-sgi',
00315 '-no-ipv6',
00316 '-qt-imgfmt-png',
00317 '-qt-imgfmt-jpeg',
00318 '-no-imgfmt-mng',
00319 '-qt-gif',
00320 '-no-tablet',
00321 '-I"$PREFIX/include/mysql"',
00322 '-L"$PREFIX/lib/mysql"',
00323 ],
00324 'post-conf'
00325 => 'echo "QMAKE_LFLAGS_SHLIB += -single_module" >> src/qt.pro',
00326 'make'
00327 => [
00328 'sub-src',
00329 'qmake-install',
00330 'moc-install',
00331 'src-install'
00332 ],
00333 },
00334
00335 'tiff'
00336 =>
00337 {
00338 'url' => 'http:
00339 },
00340
00341 'exif'
00342 =>
00343 {
00344 'url' => "$sourceforge/sourceforge/libexif/libexif-0.6.17.tar.bz2",
00345 'conf' => [ '--disable-docs' ]
00346 }
00347 );
00348
00349
00350 =head1 NAME
00351
00352 osx-packager.pl - build OS X binary packages for MythTV
00353
00354 =head1 SYNOPSIS
00355
00356 osx-packager.pl [options]
00357
00358 Options:
00359 -help print the usage message
00360 -man print full documentation
00361 -verbose print informative messages during the process
00362 -version <str> custom version suffix (defaults to "svnYYYYMMDD")
00363 -noversion don't use any version (for building release versions)
00364 -distclean throw away all intermediate files and exit
00365 -thirdclean do a clean rebuild of third party packages
00366 -thirdskip don't rebuild the third party packages
00367 -mythtvskip don't rebuild/install mythtv
00368 -pluginskip don't rebuild/install mythplugins
00369 -themeskip don't install the extra themes from myththemes
00370 -clean do a clean rebuild of MythTV
00371 -svnbranch <str> build a specified Subversion branch, instead of HEAD
00372 -svnrev <str> build a specified Subversion revision, instead of HEAD
00373 -svntag <str> build a specified release, instead of Subversion HEAD
00374 -nohead don't update to HEAD revision of MythTV before building
00375 -usehdimage perform build inside of a case-sensitive disk image
00376 -leavehdimage leave disk image mounted on exit
00377 -enable-backend build the backend server as well as the frontend
00378 -enable-jobtools build commflag/jobqueue as well as the frontend
00379 -profile build with compile-type=profile
00380 -debug build with compile-type=debug
00381 -plugins <str> comma-separated list of plugins to include
00382 Available plugins:
00383 mythbrowser mythcontrols mythdvd mythflix mythgallery mythgame
00384 mythmusic mythnews mythphone mythvideo mythweather
00385
00386 =head1 DESCRIPTION
00387
00388 This script builds a MythTV frontend and all necessary dependencies, along
00389 with plugins as specified, as a standalone binary package for Mac OS X.
00390
00391 It was designed for building daily CVS (now Subversion) snapshots,
00392 but can also be used to create release builds with the '-svntag' option.
00393
00394 All intermediate files go into an '.osx-packager' directory in the current
00395 working directory. The finished application is named 'MythFrontend.app' and
00396 placed in the current working directory.
00397
00398 =head1 EXAMPLES
00399
00400 Building two snapshots, one with plugins and one without:
00401
00402 osx-packager.pl -clean -plugins mythvideo,mythweather
00403 mv MythFrontend.app MythFrontend-plugins.app
00404 osx-packager.pl -nohead
00405 mv MythFrontend.app MythFrontend-noplugins.app
00406
00407 Building a 0.17 release build:
00408
00409 osx-packager.pl -distclean
00410 osx-packager.pl -svntag release-0-17 -noversion
00411
00412 Building a "fixes" branch:
00413
00414 osx-packager.pl -distclean
00415 osx-packager.pl -svnbranch release-0-18-fixes
00416
00417 =head1 CREDITS
00418
00419 Written by Jeremiah Morris (jm@whpress.com)
00420
00421 Special thanks to Nigel Pearson, Jan Ornstedt, Angel Li, and Andre Pang
00422 for help, code, and advice.
00423
00424 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!
00425
00426 =cut
00427
00428 # Parse options
00429 our (%OPT);
00430 Getopt::Long::GetOptions(\%OPT,
00431 'help|?',
00432 'man',
00433 'verbose',
00434 'version=s',
00435 'noversion',
00436 'distclean',
00437 'thirdclean',
00438 'thirdskip',
00439 'mythtvskip',
00440 'pluginskip',
00441 'themeskip',
00442 'clean',
00443 'svnbranch=s',
00444 'svnrev=s',
00445 'svntag=s',
00446 'nocvs', # This is obsolete, but should stay a while
00447 'nohead',
00448 'usehdimage',
00449 'leavehdimage',
00450 'enable-backend',
00451 'enable-jobtools',
00452 'profile',
00453 'debug',
00454 'plugins=s',
00455 ) or Pod::Usage::pod2usage(2);
00456 Pod::Usage::pod2usage(1) if $OPT{'help'};
00457 Pod::Usage::pod2usage('-verbose' => 2) if $OPT{'man'};
00458
00459 if ( $OPT{'enable-backend'} )
00460 { $backend = 1 }
00461
00462 if ( $OPT{'clean'} )
00463 { $cleanLibs = 1 }
00464
00465 if ( $OPT{'enable-jobtools'} )
00466 { $jobtools = 1 }
00467
00468 # Get version string sorted out
00469 if ($OPT{'svntag'} && !$OPT{'version'})
00470 {
00471 $OPT{'version'} = $OPT{'svntag'};
00472 $OPT{'version'} =~ s/-r *
00473 $OPT{'version'} =~ s/--revision *
00474 }
00475 $OPT{'version'} = '' if $OPT{'noversion'};
00476 unless (defined $OPT{'version'})
00477 {
00478 my @lt = gmtime(time);
00479 $OPT{'version'} = sprintf('svn%04d%02d%02d',
00480 $lt[5] + 1900,
00481 $lt[4] + 1,
00482 $lt[3]);
00483 }
00484
00485 # Fold nocvs to nohead
00486 $OPT{'nohead'} = 1 if $OPT{'nocvs'};
00487
00488 # Build our temp directories
00489 our $SCRIPTDIR = Cwd::abs_path(Cwd::getcwd());
00490 if ($SCRIPTDIR =~ /\s/)
00491 {
00492 &Complain(<<END);
00493 Working directory contains spaces
00494
00495 Error: Your current working path:
00496
00497 $SCRIPTDIR
00498
00499 contains one or more spaces. This will break the compilation process,
00500 so the script cannot continue. Please re-run this script from a different
00501 directory (such as /tmp).
00502
00503 The application produced will run from any directory, the no-spaces
00504 rule is only for the build process itself.
00505
00506 END
00507 die;
00508 }
00509
00510 if ( $OPT{'nohead'} )
00511 {
00512 my $SVNTOP="$SCRIPTDIR/.osx-packager/src/myth-svn/mythtv/.svn";
00513
00514 if ( ! -d $SVNTOP )
00515 { die "No source code to build?" }
00516
00517 if ( ! `grep 0-21-fixes $SVNTOP/entries` )
00518 { die "Source code does not match release-0-21-fixes" }
00519 }
00520 elsif ( ! $OPT{'svnbranch'} )
00521 {
00522 &Complain(<<END);
00523 This script can probably only build branch release-0-21-fixes.
00524 To build SVN HEAD, please try the latest version instead. e.g.
00525 http:
00526 END
00527 die;
00528 }
00529
00530 our $WORKDIR = "$SCRIPTDIR/.osx-packager";
00531 mkdir $WORKDIR;
00532
00533 # Do we need to force a case-sensitive disk image?
00534 if (!$OPT{usehdimage} && !CaseSensitiveFilesystem())
00535 {
00536 Verbose("Forcing -usehdimage due to case-insensitive filesystem");
00537 $OPT{usehdimage} = 1;
00538 }
00539
00540 if ($OPT{usehdimage})
00541 { MountHDImage() }
00542
00543 our $PREFIX = "$WORKDIR/build";
00544 mkdir $PREFIX;
00545
00546 our $SRCDIR = "$WORKDIR/src";
00547 mkdir $SRCDIR;
00548
00549 our $SVNDIR = "$SRCDIR/myth-svn";
00550
00551 # configure mythplugins, and mythtv, etc
00552 our %conf = (
00553 'mythplugins'
00554 => [
00555 '--prefix=' . $PREFIX,
00556 '--enable-opengl',
00557 '--disable-mythbrowser',
00558 '--disable-transcode',
00559 '--enable-mythgallery',
00560 '--enable-exif',
00561 '--enable-new-exif',
00562 '--disable-mythgame',
00563 '--disable-mythphone',
00564 '--disable-mythzoneminder',
00565 ],
00566 'myththemes'
00567 => [
00568 '--prefix=' . $PREFIX,
00569 ],
00570 'mythtv'
00571 => [
00572 '--prefix=' . $PREFIX,
00573 '--runtime-prefix=../Resources',
00574 '--enable-libfaad',
00575 # To "cross compile" something for a lesser Mac:
00576 #'--tune=G3',
00577 #'--disable-altivec',
00578 ],
00579 );
00580
00581 # configure mythplugins, and mythtv, etc
00582 our %makecleanopt = (
00583 'mythplugins'
00584 => [
00585 'distclean',
00586 ],
00587 );
00588
00589 # Source code version.pro needs to call subversion binary
00590 #
00591 use File::Basename;
00592 our $svnpath = dirname $svn;
00593
00594 # Clean the environment
00595 $ENV{'PATH'} = "$PREFIX/bin:/sw/bin:/bin:/usr/bin:$svnpath";
00596 $ENV{'DYLD_LIBRARY_PATH'} = "$PREFIX/lib";
00597 $ENV{'LD_LIBRARY_PATH'} = "/usr/local/lib";
00598 $ENV{'PKG_CONFIG_PATH'} = "$PREFIX/lib/pkgconfig:";
00599 delete $ENV{'CC'};
00600 delete $ENV{'CXX'};
00601 delete $ENV{'CPP'};
00602 delete $ENV{'CXXCPP'};
00603 $ENV{'CFLAGS'} = $ENV{'CXXFLAGS'} = $ENV{'CPPFLAGS'} = "-I$PREFIX/include";
00604 $ENV{'LDFLAGS'} = "-Z -F/System/Library/Frameworks -L/usr/lib -L$PREFIX/lib";
00605 $ENV{'PREFIX'} = $PREFIX;
00606
00607 # set up Qt environment
00608 $ENV{'QTDIR'} = $PREFIX;
00609
00610 # If environment is setup to use distcc, take advantage of it
00611 our $standard_make = '/usr/bin/make';
00612 our $parallel_make = $standard_make;
00613 our $parallel_make_flags = '';
00614
00615 if ( $ENV{'DISTCC_HOSTS'} )
00616 {
00617 my @hosts = split m/\s+/, $ENV{'DISTCC_HOSTS'};
00618 my $numhosts = $#hosts + 1;
00619 &Verbose("Using ", $numhosts * 2, " DistCC jobs on $numhosts build hosts:",
00620 join ', ', @hosts);
00621 $parallel_make_flags = '-j' . $numhosts * 2;
00622 }
00623
00624 # Ditto for multi-cpu setups:
00625 my $cmd = "/usr/bin/hostinfo | grep 'processors\$'";
00626 &Verbose($cmd);
00627 my $cpus = `$cmd`; chomp $cpus;
00628 $cpus =~ s/.*, (\d+) processors$/$1/;
00629 if ( $cpus gt 1 )
00630 {
00631 &Verbose("Using", $cpus+1, "jobs on $cpus parallel CPUs");
00632 ++$cpus;
00633 $parallel_make_flags = "-j$cpus";
00634 }
00635
00636 $parallel_make .= " $parallel_make_flags";
00637
00638 ### Distclean?
00639 if ($OPT{'distclean'})
00640 {
00641 &Syscall([ '/bin/rm', '-f', '$PREFIX/bin/myth*' ]);
00642 &Syscall([ '/bin/rm', '-f', '-r', '$PREFIX/lib/libmyth*' ]);
00643 &Syscall([ '/bin/rm', '-f', '-r', '$PREFIX/lib/mythtv' ]);
00644 &Syscall([ '/bin/rm', '-f', '-r', '$PREFIX/share/mythtv' ]);
00645 &Syscall([ 'find', $SVNDIR, '-name', '*.o', '-delete' ]);
00646 &Syscall([ 'find', $SVNDIR, '-name', '*.a', '-delete' ]);
00647 &Syscall([ 'find', $SVNDIR, '-name', '*.dylib', '-delete' ]);
00648 &Syscall([ 'find', $SVNDIR, '-name', '*.orig', '-delete' ]);
00649 &Syscall([ 'find', $SVNDIR, '-name', '*.rej', '-delete' ]);
00650 exit;
00651 }
00652
00653 ### Check for app present in target location
00654 our $MFE = "$SCRIPTDIR/MythFrontend.app";
00655 if (-d $MFE)
00656 {
00657 &Complain(<<END);
00658 $MFE already exists
00659
00660 Error: a MythFrontend application exists where we were planning
00661 to build one. Please move this application away before running
00662 this script.
00663
00664 END
00665 exit;
00666 }
00667
00668 ### Third party packages
00669 my (@build_depends, %seen_depends);
00670 my @comps = ('mythtv', @components);
00671
00672 # Deal with user-supplied skip arguments
00673 if ( $OPT{'mythtvskip'} )
00674 { @comps = grep(!m/mythtv/, @comps) }
00675 if ( $OPT{'pluginskip'} )
00676 { @comps = grep(!m/mythplugins/, @comps) }
00677 if ( $OPT{'themeskip'} )
00678 { @comps = grep(!m/myththemes/, @comps) }
00679
00680 if ( ! @comps )
00681 {
00682 &Complain("Nothing to build! Too many ...skip arguments?");
00683 exit;
00684 }
00685
00686 &Verbose("Including components:", @comps);
00687
00688 # If no SubVersion in path, and we are checking something out, build SVN:
00689 if ( $svn =~ m/no svn in / && ! $OPT{'nohead'} )
00690 {
00691 $svn = "$PREFIX/bin/svn";
00692 @build_depends = ('svndeps', 'svn');
00693 }
00694
00695 foreach my $comp (@comps)
00696 {
00697 foreach my $dep (@{ $depend_order{$comp} })
00698 {
00699 unless (exists $seen_depends{$dep})
00700 {
00701 push(@build_depends, $dep);
00702 $seen_depends{$dep} = 1;
00703 }
00704 }
00705 }
00706 foreach my $sw (@build_depends)
00707 {
00708 # Get info about this package
00709 my $pkg = $depend{$sw};
00710 my $url = $pkg->{'url'};
00711 my $filename = $url;
00712 $filename =~ s|^.+/([^/]+)$|$1|;
00713 my $dirname = $filename;
00714 $dirname =~ s|\.tar\.gz$||;
00715 $dirname =~ s|\.tar\.bz2$||;
00716
00717 chdir($SRCDIR);
00718
00719 # Download and decompress
00720 unless (-e $filename)
00721 {
00722 &Verbose("Downloading $sw");
00723 unless (&Syscall([ '/usr/bin/curl', '-f', '-L', $url, '>', $filename ],
00724 'munge' => 1))
00725 {
00726 &Syscall([ '/bin/rm', $filename ]) if (-e $filename);
00727 die;
00728 }
00729 }
00730 else
00731 {
00732 &Verbose("Using previously downloaded $sw");
00733 }
00734
00735 if ($pkg->{'skip'})
00736 { next }
00737
00738 if ( -d $dirname )
00739 {
00740 if ( $OPT{'thirdclean'} )
00741 {
00742 &Verbose("Removing previous build of $sw");
00743 &Syscall([ '/bin/rm', '-f', '-r', $dirname ]) or die;
00744 }
00745
00746 if ( $OPT{'thirdskip'} )
00747 {
00748 &Verbose("Using previous build of $sw");
00749 next;
00750 }
00751
00752 &Verbose("Using previously unpacked $sw");
00753 }
00754 else
00755 {
00756 &Verbose("Unpacking $sw");
00757 if ( substr($filename,-3) eq ".gz" )
00758 {
00759 &Syscall([ '/usr/bin/tar', '-xzf', $filename ]) or die;
00760 }
00761 elsif ( substr($filename,-4) eq ".bz2" )
00762 {
00763 &Syscall([ '/usr/bin/tar', '-xjf', $filename ]) or die;
00764 }
00765 else
00766 {
00767 &Complain("Cannot unpack file $filename");
00768 exit;
00769 }
00770 }
00771
00772 # Configure
00773 chdir($dirname);
00774 unless (-e '.osx-config')
00775 {
00776 &Verbose("Configuring $sw");
00777 if ($pkg->{'pre-conf'})
00778 {
00779 &Syscall([ $pkg->{'pre-conf'} ], 'munge' => 1) or die;
00780 }
00781
00782 my (@configure, $munge);
00783
00784 if ($pkg->{'conf-cmd'})
00785 {
00786 push(@configure, $pkg->{'conf-cmd'});
00787 $munge = 1;
00788 }
00789 else
00790 {
00791 push(@configure, './configure',
00792 '--prefix=$PREFIX',
00793 '--disable-static',
00794 '--enable-shared');
00795 }
00796 if ($pkg->{'conf'})
00797 {
00798 push(@configure, @{ $pkg->{'conf'} });
00799 }
00800 &Syscall(\@configure, 'interpolate' => 1, 'munge' => $munge) or die;
00801 if ($pkg->{'post-conf'})
00802 {
00803 &Syscall([ $pkg->{'post-conf'} ], 'munge' => 1) or die;
00804 }
00805 &Syscall([ '/usr/bin/touch', '.osx-config' ]) or die;
00806 }
00807 else
00808 {
00809 &Verbose("Using previously configured $sw");
00810 }
00811
00812 # Build and install
00813 unless (-e '.osx-built')
00814 {
00815 &Verbose("Making $sw");
00816 my (@make);
00817
00818 push(@make, $standard_make);
00819 if ($pkg->{'parallel-make'})
00820 { push(@make, $parallel_make_flags) }
00821
00822 if ($pkg->{'make'})
00823 {
00824 push(@make, @{ $pkg->{'make'} });
00825 }
00826 else
00827 {
00828 push(@make, 'all', 'install');
00829 }
00830 &Syscall(\@make) or die;
00831 &Syscall([ '/usr/bin/touch', '.osx-built' ]) or die;
00832 }
00833 else
00834 {
00835 &Verbose("Using previously built $sw");
00836 }
00837 }
00838
00839
00840 ### build MythTV
00841
00842 # Clean any previously installed libraries
00843 if ( $cleanLibs )
00844 {
00845 if ( $OPT{'mythtvskip'} )
00846 {
00847 &Complain("Cannot skip building mythtv src if also cleaning");
00848 exit;
00849 }
00850 &Verbose("Cleaning previous installs of MythTV");
00851 my @mythlibs = glob "$PREFIX/lib/libmyth*";
00852 if (scalar @mythlibs)
00853 {
00854 &Syscall([ '/bin/rm', @mythlibs ]) or die;
00855 }
00856 foreach my $dir ('include', 'lib', 'share')
00857 {
00858 if (-d "$PREFIX/$dir/mythtv")
00859 {
00860 &Syscall([ '/bin/rm', '-f', '-r', "$PREFIX/$dir/mythtv" ]) or die;
00861 }
00862 }
00863 }
00864
00865 mkdir $SVNDIR;
00866
00867 # Deal with Subversion branches, revisions and tags:
00868 my $svnrepository = 'http://svn.mythtv.org/svn/';
00869 my @svnrevision = ();
00870
00871 if ( $OPT{'svnbranch'} )
00872 {
00873 $svnrepository .= 'branches/' . $OPT{'svnbranch'} . '/';
00874 }
00875 elsif ( $OPT{'svntag'} )
00876 {
00877 $svnrepository .= 'tags/' . $OPT{'svntag'} . '/';
00878 }
00879 elsif ( $OPT{'svnrev'} )
00880 {
00881 $svnrepository .= 'trunk/';
00882
00883 # This arg. could be '1234', '-r 1234', or '--revision 1234'
00884 # If the user just specified a number, add appropriate flag:
00885 if ( $OPT{'svnrev'} =~ m/^\d+$/ )
00886 {
00887 push @svnrevision, '--revision';
00888 }
00889
00890 push @svnrevision, $OPT{'svnrev'};
00891 }
00892 elsif ( ! $OPT{'nohead'} )
00893 {
00894 # Lookup and use the HEAD revision so we are guaranteed consistent source
00895 my $cmd = "$svn log $svnrepository --revision HEAD --xml | grep revision";
00896 &Verbose($cmd);
00897 my $rev = `$cmd`;
00898
00899 if ( $rev =~ m/revision="(\d+)">/ )
00900 {
00901 $svnrepository .= 'trunk/';
00902 @svnrevision = ('--revision', $1);
00903 }
00904 else
00905 {
00906 &Complain("Cannot get head revision - Got '$rev'");
00907 die;
00908 }
00909 }
00910
00911 # Retrieve source
00912 if (! $OPT{'nohead'})
00913 {
00914 # Empty subdirectory 'config' sometimes causes checkout problems
00915 &Syscall(['rm', '-fr', $SVNDIR . '/mythtv/config']);
00916 Verbose("Checking out source code");
00917
00918 if ($#comps == 0)
00919 {
00920 # Single repository needs explicit directory for checkout:
00921 &Syscall([ $svn, 'co', @svnrevision,
00922 "$svnrepository/@comps", "$SVNDIR/@comps"]) or die;
00923 }
00924 else
00925 {
00926 # Multiple repositories are checked out by name under SVNDIR
00927 &Syscall([ $svn, 'co', @svnrevision,
00928 map($svnrepository . $_, @comps), $SVNDIR ]) or die;
00929 }
00930 }
00931 else
00932 {
00933 &Syscall("mkdir -p $SVNDIR/mythtv/config")
00934 }
00935
00936 # Build MythTV and any plugins
00937 foreach my $comp (@comps)
00938 {
00939 my $compdir = "$SVNDIR/$comp/" ;
00940
00941 chdir $compdir;
00942
00943 if ( ! -e "$comp.pro" )
00944 {
00945 &Complain("$compdir/$comp.pro does not exist.",
00946 'You must be building really old source?');
00947 next;
00948 }
00949
00950 if ($OPT{'clean'} && -e 'Makefile')
00951 {
00952 &Verbose("Cleaning $comp");
00953 &Syscall([ $standard_make, 'distclean' ]) or die;
00954 }
00955 else
00956 {
00957 # clean the Makefiles, as process requires PREFIX hacking
00958 &CleanMakefiles();
00959 }
00960
00961 # Apply any nasty mac-specific patches
00962 if ($patches{$comp})
00963 {
00964 &Syscall([ "echo '$patches{$comp}' | patch -p0 --forward" ]);
00965 }
00966
00967 # configure and make
00968 if ( $makecleanopt{$comp} && -e 'Makefile' )
00969 {
00970 my @makecleancom = $standard_make;
00971 push(@makecleancom, @{ $makecleanopt{$comp} }) if $makecleanopt{$comp};
00972 &Syscall([ @makecleancom ]) or die;
00973 }
00974 if (-e 'configure')
00975 {
00976 &Verbose("Configuring $comp");
00977 my @config = './configure';
00978 push(@config, @{ $conf{$comp} }) if $conf{$comp};
00979 if ( $comp eq 'mythtv' && $backend )
00980 {
00981 push @config, '--enable-backend'
00982 }
00983 if ( $OPT{'profile'} )
00984 {
00985 push @config, '--compile-type=profile'
00986 }
00987 if ( $OPT{'debug'} )
00988 {
00989 push @config, '--compile-type=debug'
00990 }
00991 if ( $comp eq 'mythtv' && ! $ENV{'DISTCC_HOSTS'} )
00992 {
00993 push @config, '--disable-distcc'
00994 }
00995 &Syscall([ @config ]) or die;
00996 }
00997 &Verbose("Running qmake for $comp");
00998 my @qmake_opts = (
00999 'QMAKE_LFLAGS+=-Wl,-search_paths_first',
01000 'INCLUDEPATH+="' . $PREFIX . '/include"',
01001 'LIBS+=-L/usr/lib -L"' . $PREFIX . '/lib"'
01002 );
01003 &Syscall([ $PREFIX . '/bin/qmake',
01004 'PREFIX=../Resources',
01005 @qmake_opts,
01006 "$comp.pro" ]) or die;
01007
01008 if ($comp eq 'mythtv')
01009 {
01010 # Remove/add Nigel's frontend building speedup hack
01011 &DoSpeedupHacks('programs/programs.pro', 'mythfrontend mythtv');
01012 }
01013
01014 &Verbose("Making $comp");
01015 &Syscall([ $parallel_make ]) or die;
01016 # install
01017 # This requires a change from the compiled-in relative
01018 # PREFIX to our absolute path of the temp install location.
01019 &CleanMakefiles();
01020 &Verbose("Running qmake for $comp install");
01021 &Syscall([ $PREFIX . '/bin/qmake',
01022 'PREFIX=' . $PREFIX,
01023 @qmake_opts,
01024 "$comp.pro" ]) or die;
01025 &Verbose("Installing $comp");
01026 &Syscall([ $standard_make,
01027 'install' ]) or die;
01028
01029 if ($cleanLibs && $comp eq 'mythtv')
01030 {
01031 # If we cleaned the libs, make install will have recopied them,
01032 # which means any dynamic libraries that the static libraries depend on
01033 # are newer than the table of contents. Hence we need to regenerate it:
01034 my @mythlibs = glob "$PREFIX/lib/libmyth*.a";
01035 if (scalar @mythlibs)
01036 {
01037 &Verbose("Running ranlib on reinstalled static libraries");
01038 foreach my $lib (@mythlibs)
01039 { &Syscall("ranlib $lib") or die }
01040 }
01041 }
01042 }
01043
01044 ### Build version string
01045 our $VERS = `find $PREFIX/lib -name 'libmyth-[0-9].[0-9][0-9].[0-9].dylib'`;
01046 chomp $VERS;
01047 $VERS =~ s/^.*\-(.*)\.dylib$/$1/s;
01048 $VERS .= '.' . $OPT{'version'} if $OPT{'version'};
01049
01050 ### Program which creates bundles:
01051 our @bundler = "$SVNDIR/mythtv/contrib/OSX/osx-bundler.pl";
01052 if ( $OPT{'verbose'} )
01053 { push @bundler, '--verbose' }
01054
01055
01056 ### Framework that has a screwed up link dependency path
01057 my $AVCfw = '/Developer/FireWireSDK*/Examples/' .
01058 'Framework/AVCVideoServices.framework';
01059 my @AVCfw = split / /, `ls -d $AVCfw`;
01060 $AVCfw = pop @AVCfw;
01061 chop $AVCfw;
01062
01063 ### Create each package.
01064 ### Note that this is a bit of a waste of disk space,
01065 ### because there are now multiple copies of each library.
01066 my @targets = ('MythFrontend', 'MythTV');
01067
01068 if ( $jobtools )
01069 { push @targets, @targetsJT }
01070
01071 if ( $backend )
01072 { push @targets, @targetsBE }
01073
01074 foreach my $target ( @targets )
01075 {
01076 my $finalTarget = "$SCRIPTDIR/$target.app";
01077 my $builtTarget = lc $target;
01078
01079 # Get a fresh copy of the binary
01080 &Verbose("Building self-contained $target");
01081 &Syscall([ 'rm', '-fr', $finalTarget ]) or die;
01082 &Syscall([ 'cp', "$SVNDIR/mythtv/programs/$builtTarget/$builtTarget",
01083 "$SCRIPTDIR/$target" ]) or die;
01084
01085 # Convert it to a bundled .app
01086 &Syscall([ @bundler, "$SCRIPTDIR/$target",
01087 "$PREFIX/lib/", "$PREFIX/lib/mysql" ])
01088 or die;
01089
01090 # Remove copy of binary
01091 unlink "$SCRIPTDIR/$target" or die;
01092
01093 if ( $AVCfw )
01094 { &RecursiveCopy($AVCfw, "$finalTarget/Contents/Frameworks") }
01095
01096 if ( $target eq "MythFrontend" or $target =~ m/^MythTV/ )
01097 {
01098 my $res = "$finalTarget/Contents/Resources";
01099 my $libs = "$res/lib";
01100 my $plug = "$libs/mythtv/plugins";
01101
01102 # Install themes, filters, etc.
01103 &Verbose("Installing resources into $target");
01104 mkdir $res; mkdir $libs;
01105 &RecursiveCopy("$PREFIX/lib/mythtv", $libs);
01106 mkdir "$res/share";
01107 &RecursiveCopy("$PREFIX/share/mythtv", "$res/share");
01108
01109 # Correct the library paths for the filters and plugins
01110 foreach my $lib ( glob "$libs/mythtv/*/*" )
01111 { &Syscall([ @bundler, $lib ]) or die }
01112
01113 if ( -e $plug )
01114 {
01115 # Allow Finder's 'Get Info' to manage plugin list:
01116 &Syscall([ 'mv', $plug, "$finalTarget/Contents/Plugins" ]) or die;
01117 &Syscall([ 'ln', '-s', "../../../Plugins", $plug ]) or die;
01118 }
01119
01120 # The icon
01121 &Syscall([ 'cp', "$SVNDIR/mythtv/programs/mythfrontend/mythfrontend.icns",
01122 "$res/application.icns" ]) or die;
01123 &Syscall([ '/Developer/Tools/SetFile', '-a', 'C', $finalTarget ]) or die;
01124 }
01125
01126 if ( $target eq "MythFrontend" )
01127 {
01128 my $mtd = "$PREFIX/bin/mtd";
01129 if ( -e $mtd )
01130 {
01131 &Verbose("Installing $mtd into $target");
01132 &Syscall([ 'cp', $mtd, "$finalTarget/Contents/MacOS" ]) or die;
01133
01134 &Verbose("Updating lib paths of $finalTarget/Contents/MacOS/mtd");
01135 &Syscall([ @bundler, "$finalTarget/Contents/MacOS/mtd" ]) or die;
01136 &AddFakeBinDir($finalTarget);
01137 }
01138 }
01139 }
01140
01141 if ( $backend && grep(m/MythBackend/, @targets) )
01142 {
01143 my $BE = "$SCRIPTDIR/MythBackend.app";
01144
01145 # Copy XML files that UPnP requires:
01146 my $share = "$BE/Contents/Resources/share/mythtv";
01147 &Syscall([ 'mkdir', '-p', $share ]) or die;
01148 &Syscall([ 'cp', glob("$PREFIX/share/mythtv/*.xml"), $share ]) or die;
01149
01150 # The backend gets all the useful binaries it might call:
01151 foreach my $binary ( 'mythjobqueue', 'mythcommflag',
01152 'mythtranscode', 'mythfilldatabase' )
01153 {
01154 my $SRC = "$PREFIX/bin/$binary";
01155 if ( -e $SRC )
01156 {
01157 &Verbose("Installing $SRC into $BE");
01158 &Syscall([ '/bin/cp', $SRC, "$BE/Contents/MacOS" ]) or die;
01159
01160 &Verbose("Updating lib paths of $BE/Contents/MacOS/$binary");
01161 &Syscall([ @bundler, "$BE/Contents/MacOS/$binary" ]) or die;
01162 }
01163 }
01164 &AddFakeBinDir($BE);
01165 }
01166
01167 if ( $jobtools )
01168 {
01169 # JobQueue also gets some binaries it might call:
01170 my $JQ = "$SCRIPTDIR/MythJobQueue.app";
01171 my $DEST = "$JQ/Contents/MacOS";
01172 my $SRC = "$PREFIX/bin/mythcommflag";
01173
01174 &Syscall([ '/bin/cp', $SRC, $DEST ]) or die;
01175 &AddFakeBinDir($JQ);
01176 &Verbose("Updating lib paths of $DEST/mythcommflag");
01177 &Syscall([ @bundler, "$DEST/mythcommflag" ]) or die;
01178
01179 $SRC = "$PREFIX/bin/mythtranscode.app/Contents/MacOS/mythtranscode";
01180 if ( -e $SRC )
01181 {
01182 &Verbose("Installing $SRC into $JQ");
01183 &Syscall([ '/bin/cp', $SRC, $DEST ]) or die;
01184 &Verbose("Updating lib paths of $DEST/mythtranscode");
01185 &Syscall([ @bundler, "$DEST/mythtranscode" ]) or die;
01186 }
01187 }
01188
01189 # Clean tmp files. Most of these are leftovers from configure:
01190 #
01191 &Verbose('Cleaning build tmp directory');
01192 &Syscall([ 'rm', '-fr', $WORKDIR . '/tmp' ]) or die;
01193 &Syscall([ 'mkdir', $WORKDIR . '/tmp' ]) or die;
01194
01195 if ($OPT{usehdimage} && !$OPT{leavehdimage})
01196 {
01197 Verbose("Dismounting case-sensitive build device");
01198 UnmountHDImage();
01199 }
01200
01201 &Verbose("Build complete. Self-contained package is at:\n\n $MFE\n");
01202
01203 ### end script
01204 exit 0;
01205
01206
01207 ######################################
01208 ## RecursiveCopy copies a directory tree, stripping out .svn
01209 ## directories and properly managing static libraries.
01210 ######################################
01211
01212 sub RecursiveCopy($$)
01213 {
01214 my ($src, $dst) = @_;
01215
01216 # First copy absolutely everything
01217 &Syscall([ '/bin/cp', '-pR', "$src", "$dst"]) or die;
01218
01219 # Then strip out any .svn directories
01220 my @files = map { chomp $_; $_ } `find $dst -name .svn`;
01221 if (scalar @files)
01222 {
01223 &Syscall([ '/bin/rm', '-f', '-r', @files ]);
01224 }
01225
01226 # And make sure any static libraries are properly relocated.
01227 my @libs = map { chomp $_; $_ } `find $dst -name "lib*.a"`;
01228 if (scalar @libs)
01229 {
01230 &Syscall([ 'ranlib', '-s', @libs ]);
01231 }
01232 }
01233
01234 ######################################
01235 ## CleanMakefiles removes every generated Makefile
01236 ## from our MythTV build that contains PREFIX.
01237 ## Necessary when we change the
01238 ## PREFIX variable.
01239 ######################################
01240
01241 sub CleanMakefiles
01242 {
01243 &Verbose("Cleaning MythTV makefiles containing PREFIX");
01244 &Syscall([ 'find', '.', '-name', 'Makefile', '-exec',
01245 'egrep', '-q', 'qmake.*PREFIX', '{}', ';', '-delete' ]) or die;
01246 } # end CleanMakefiles
01247
01248
01249 ######################################
01250 ## Syscall wrappers the Perl "system"
01251 ## routine with verbosity and error
01252 ## checking.
01253 ######################################
01254
01255 sub Syscall($%)
01256 {
01257 my ($arglist, %opts) = @_;
01258
01259 unless (ref $arglist)
01260 {
01261 $arglist = [ $arglist ];
01262 }
01263 if ($opts{'interpolate'})
01264 {
01265 my @args;
01266 foreach my $arg (@$arglist)
01267 {
01268 $arg =~ s/\$PREFIX/$PREFIX/ge;
01269 $arg =~ s/\$parallel_make_flags/$parallel_make_flags/ge;
01270 push(@args, $arg);
01271 }
01272 $arglist = \@args;
01273 }
01274 if ($opts{'munge'})
01275 {
01276 $arglist = [ join(' ', @$arglist) ];
01277 }
01278 # clean out any null arguments
01279 $arglist = [ map $_, @$arglist ];
01280 &Verbose(@$arglist);
01281 my $ret = system(@$arglist);
01282 if ($ret)
01283 {
01284 &Complain('Failed system call: "', @$arglist,
01285 '" with error code', $ret >> 8);
01286 }
01287 return ($ret == 0);
01288 } # end Syscall
01289
01290
01291 ######################################
01292 ## Verbose prints messages in verbose
01293 ## mode.
01294 ######################################
01295
01296 sub Verbose
01297 {
01298 print STDERR '[osx-pkg] ' . join(' ', @_) . "\n"
01299 if $OPT{'verbose'};
01300 } # end Verbose
01301
01302
01303 ######################################
01304 ## Complain prints messages in any
01305 ## verbosity mode.
01306 ######################################
01307
01308 sub Complain
01309 {
01310 print STDERR '[osx-pkg] ' . join(' ', @_) . "\n";
01311 } # end Complain
01312
01313
01314 ######################################
01315 ## Manage usehdimage disk image
01316 ######################################
01317
01318 sub MountHDImage
01319 {
01320 if (!HDImageDevice())
01321 {
01322 if (-e "$SCRIPTDIR/.osx-packager.dmg")
01323 {
01324 Verbose("Mounting existing UFS disk image for the build");
01325 }
01326 else
01327 {
01328 Verbose("Creating a case-sensitive (UFS) disk image for the build");
01329 Syscall(['hdiutil', 'create', '-size', '2048m',
01330 "$SCRIPTDIR/.osx-packager.dmg", '-volname',
01331 'MythTvPackagerHDImage', '-fs', 'UFS', '-quiet']) || die;
01332 }
01333
01334 &Syscall(['hdiutil', 'mount',
01335 "$SCRIPTDIR/.osx-packager.dmg",
01336 '-mountpoint', $WORKDIR, '-quiet']) || die;
01337 }
01338
01339 # configure defaults to /tmp and OSX barfs when mv crosses
01340 # filesystems so tell configure to put temp files on the image
01341
01342 $ENV{TMPDIR} = $WORKDIR . "/tmp";
01343 mkdir $ENV{TMPDIR};
01344 }
01345
01346 sub UnmountHDImage
01347 {
01348 my $device = HDImageDevice();
01349 if ($device)
01350 {
01351 &Syscall(['hdiutil', 'detach', $device, '-force']);
01352 }
01353 }
01354
01355 sub HDImageDevice
01356 {
01357 my @dev = split ' ', `/sbin/mount | grep $WORKDIR`;
01358 $dev[0];
01359 }
01360
01361 sub CaseSensitiveFilesystem
01362 {
01363 my $funky = $SCRIPTDIR . "/.osx-packager.FunkyStuff";
01364 my $unfunky = substr($funky, 0, -10) . "FUNKySTuFF";
01365
01366 unlink $funky if -e $funky;
01367 `touch $funky`;
01368 my $sensitivity = ! -e $unfunky;
01369 unlink $funky;
01370
01371 return $sensitivity;
01372 }
01373
01374
01375 ######################################
01376 ## Remove or add Nigel's speedup hacks
01377 ######################################
01378
01379 sub DoSpeedupHacks($$)
01380 {
01381 my ($file, $subdirs) = @_;
01382
01383 &Verbose("Removing Nigel's hacks from file $file");
01384
01385 open(IN, $file) or die;
01386 open(OUT, ">$file.orig") or die;
01387 while ( <IN> )
01388 {
01389 if ( m/^# Nigel/ ) # Skip
01390 { last }
01391 print OUT;
01392 }
01393 if ( ! $backend && ! $jobtools )
01394 {
01395 # Nigel's hack to speedup building
01396 print OUT "# Nigel\'s speedup hack:\n";
01397 print OUT "SUBDIRS = $subdirs\n";
01398 }
01399 close IN; close OUT;
01400 rename("$file.orig", $file);
01401 }
01402
01403 #######################################################
01404 ## Parts of MythTV try to call helper apps like this:
01405 ## gContext->GetInstallPrefix() + "/bin/mythtranscode";
01406 ## which means we need a bin directory.
01407 #######################################################
01408
01409 sub AddFakeBinDir($)
01410 {
01411 my ($target) = @_;
01412
01413 &Syscall("mkdir -p $target/Contents/Resources");
01414 &Syscall(['ln', '-sf', '../MacOS', "$target/Contents/Resources/bin"]);
01415 }
01416
01417 ### end file
01418 1;