Ticket #9400: osx-packager_WCT_git.pl

File osx-packager_WCT_git.pl, 41.8 KB (added by Craig Treleaven <ctreleaven@…>, 13 years ago)
Line 
1#!/opt/local/bin/perl
2#WCT was /usr/bin/perl
3
4### = file
5### osx-packager.pl
6###
7### = revision
8### $Id$
9###
10### = location
11# XXX Fix Me XXX
12### http://svn.mythtv.org/svn/trunk/packaging/OSX/build/osx-packager.pl
13###
14### = description
15### Tool for automating frontend builds on Mac OS X.
16### Run "osx-packager.pl -man" for full documentation.
17
18use strict;
19use Getopt::Long qw(:config auto_abbrev);
20use Pod::Usage ();
21use Cwd ();
22
23### Configuration settings (stuff that might change more often)
24
25# We try to auto-locate the Subversion client binaries.
26# If they are not in your path, we build them from source
27#
28# XXX Fix Me XXX
29our $git = `which git`; chomp $git;
30#our $svn = `which svn`; chomp $svn;
31
32# This script used to always delete the installed include and lib dirs.
33# That probably ensures a safe build, but when rebuilding adds minutes to
34# the total build time, and prevents us skipping some parts of a full build
35#
36our $cleanLibs = 1;
37
38# By default, only the frontend is built (i.e. no backend or transcoding)
39#
40our $backend = 0;
41our $jobtools = 0;
42our $feplus = 0;
43
44# Parallel makes?
45#
46#$ENV{'DISTCC_HOSTS'}   = "localhost 192.168.0.6";
47#$ENV{'DISTCC_VERBOSE'} = '1';
48
49# Start with a generic address and let sourceforge
50# figure out which mirror is closest to us.
51#
52our $sourceforge = 'http://downloads.sourceforge.net';
53
54# At the moment, there is mythtv plus these two
55our @components = ( 'myththemes', 'mythplugins' );
56
57# The OS X programs that we are likely to be interested in.
58our @targets   = ( 'MythFrontend' );
59our @targetTW  = ( 'MythAVTest',  'MythWelcome');   # WCT-make Test & Welcome options
60our @targetsJT = ( 'MythCommFlag', 'MythJobQueue');
61our @targetsBE = ( 'MythBackend',  'MythFillDatabase', 'MythTV-Setup');
62
63
64# Patches for MythTV source
65our %patches = ();
66
67our %depend_order = (
68  'mythtv'
69  =>  [
70        'dvdcss',
71        'freetype',
72        'lame',
73        'mysqlclient',
74        #'dbus',
75        'qt-4.6',
76      ],
77  'mythplugins'
78  =>  [
79        'exif',
80# MythMusic needs these:
81        'taglib',
82        'libogg',
83        'vorbis',
84        'flac',
85      ],
86);
87
88our %depend = (
89
90  'freetype' =>
91  {
92    'url' => "$sourceforge/sourceforge/freetype/freetype-2.1.10.tar.gz",
93  },
94
95  'lame' =>
96  {
97    'url'
98    =>  "$sourceforge/sourceforge/lame/lame-3.96.1.tar.gz",
99    'conf'
100    =>  [
101          '--disable-frontend',
102        ],
103  },
104
105  'libmad' =>
106  {
107    'url' => "$sourceforge/sourceforge/mad/libmad-0.15.0b.tar.gz"
108  },
109
110  'taglib' =>
111  {
112    'url' => 'http://developer.kde.org/~wheeler/files/src/taglib-1.5.tar.gz',
113  },
114
115  'libogg' =>
116  {
117    'url' => 'http://downloads.xiph.org/releases/ogg/libogg-1.1.2.tar.gz'
118  },
119
120  'vorbis' =>
121  {
122    'url' => 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.1.1.tar.gz'
123  },
124
125  'flac' =>
126  {
127    'url' => "$sourceforge/sourceforge/flac/flac-1.1.4.tar.gz",
128    # Workaround Intel problem - Missing _FLAC__lpc_restore_signal_asm_ia32
129    'conf' => [ '--disable-asm-optimizations' ]
130  },
131
132  'dvdcss' =>
133  {
134    'url'
135    =>  'http://download.videolan.org/pub/videolan/libdvdcss/1.2.9/libdvdcss-1.2.9.tar.bz2'
136  },
137
138  'mysqlclient' =>
139  {
140    'url'
141    => 'http://mysql.he.net/Downloads/MySQL-5.0/mysql-5.0.89.tar.gz',
142    'conf'
143    =>  [
144          '--without-debug',
145          '--without-docs',
146          '--without-man',
147          '--without-bench',
148          '--without-server',
149          '--without-geometry',
150          '--without-extra-tools',
151        ],
152  },
153
154  'dbus' =>
155  {
156    'url' => 'http://dbus.freedesktop.org/releases/dbus/dbus-1.0.3.tar.gz',
157    'post-make' => 'mv $PREFIX/lib/dbus-1.0/include/dbus/dbus-arch-deps.h '.
158                     ' $PREFIX/include/dbus-1.0/dbus ; '.
159                   'rm -fr $PREFIX/lib/dbus-1.0 ; '.
160                   'cd $PREFIX/bin ; '.
161                   'echo "#!/bin/sh
162if [ \"\$2\" = dbus-1 ]; then
163  case \"\$1\" in
164    \"--version\") echo 1.0.3  ;;
165    \"--cflags\")  echo -I$PREFIX/include/dbus-1.0 ;;
166    \"--libs\")    echo \"-L$PREFIX/lib -ldbus-1\" ;;
167  esac
168fi
169exit 0"   > pkg-config ; '.
170                   'chmod 755 pkg-config'
171  },
172
173  'qt-4.6'
174  =>
175  {
176    'url'
177    => 'http://get.qt.nokia.com/qt/source/qt-everywhere-opensource-src-4.6.0.tar.gz',
178    'conf-cmd'
179    =>  'echo yes | MAKEFLAGS=$parallel_make_flags ./configure',
180    'conf'
181    =>  [
182          '-opensource',
183          '-prefix', '"$PREFIX"',
184          '-release',
185          '-fast',
186          '-no-accessibility',
187          '-no-stl',
188          # When MythTV all ported:  '-no-qt3support',
189
190          # When MySQL 5.1 is used, its plugin.h file clashes with Qt's.
191          # To work around that, replace these three lines:
192          '-I"$PREFIX/include/mysql"',
193          '-L"$PREFIX/lib/mysql"',
194          '-qt-sql-mysql',
195          # with:
196          # '-qt-sql-mysql -mysql_config "$PREFIX/bin/mysql_config"',
197
198          '-no-sql-sqlite',
199          '-no-sql-odbc',
200          '-system-zlib',
201          '-no-libtiff',
202          '-no-libmng',
203          '-nomake examples -nomake demos',
204          '-no-nis',
205          '-no-cups',
206          '-no-qdbus',
207          #'-dbus-linked',
208          '-no-framework',
209          '-no-multimedia',
210          '-no-phonon',
211          '-no-svg',
212          '-no-javascript-jit',
213          '-no-scripttools',
214       ],
215    'make'
216    =>  [
217          'sub-plugins-install_subtargets-ordered',
218          'install_qmake',
219          'install_mkspecs',
220        ],
221    # Using configure -release saves a lot of space and time,
222    # but by default, debug builds of mythtv try to link against
223    # debug libraries of Qt. This works around that:
224    'post-make' => 'cd $PREFIX/lib ; '.
225                   'ln -sf libQt3Support.dylib libQt3Support_debug.dylib ; '.
226                   'ln -sf libQtSql.dylib      libQtSql_debug.dylib      ; '.
227                   'ln -sf libQtXml.dylib      libQtXml_debug.dylib      ; '.
228                   'ln -sf libQtOpenGL.dylib   libQtOpenGL_debug.dylib   ; '.
229                   'ln -sf libQtGui.dylib      libQtGui_debug.dylib      ; '.
230                   'ln -sf libQtNetwork.dylib  libQtNetwork_debug.dylib  ; '.
231                   'ln -sf libQtCore.dylib     libQtCore_debug.dylib     ; '.
232                   'ln -sf libQtWebKit.dylib   libQtWebKit_debug.dylib   ; '.
233                   'rm -f $PREFIX/bin/pkg-config ; '.
234                   '',
235    'parallel-make' => 'yes'
236  },
237
238  'exif' =>
239  {
240    'url'  => "$sourceforge/sourceforge/libexif/libexif-0.6.17.tar.bz2",
241    'conf' => [ '--disable-docs' ]
242  }
243);
244
245
246=head1 NAME
247
248osx-packager.pl - build OS X binary packages for MythTV
249
250=head1 SYNOPSIS
251
252 osx-packager.pl [options]
253
254 Options:
255   -help            print the usage message
256   -man             print full documentation
257   -verbose         print informative messages during the process
258   -version <str>   custom version suffix (defaults to "svnYYYYMMDD")
259   -noversion       don't use any version (for building release versions)
260   -distclean       throw away all intermediate files and exit
261   -thirdclean      do a clean rebuild of third party packages
262   -thirdskip       don't rebuild the third party packages
263   -mythtvskip      don't rebuild/install mythtv
264   -pluginskip      don't rebuild/install mythplugins
265   -themeskip       don't install the extra themes from myththemes
266   -clean           do a clean rebuild of MythTV
267# XXX Fix Me XXX
268   -svnbranch <str> build a specified Subversion branch,   instead of HEAD
269   -svnrev <str>    build a specified Subversion revision, instead of HEAD
270   -svntag <str>    build a specified release, instead of Subversion HEAD
271   -nohead          don't update to HEAD revision of MythTV before building
272   -usehdimage      perform build inside of a case-sensitive disk image
273   -leavehdimage    leave disk image mounted on exit
274   -enable-feplus   build MythAVTest and MythWelcome as well as the frontend
275   -enable-backend  build the backend server as well as the frontend
276   -enable-jobtools build commflag/jobqueue  as well as the frontend
277   -profile         build with compile-type=profile
278   -debug           build with compile-type=debug
279   -m32             build for a 32-bit environment
280   -plugins <str>   comma-separated list of plugins to include
281   -srcdir  <path>  build using (fresh copy of) provided root mythtv directory
282# XXX Fix Me XXX
283   -force           do not check for SVN validity
284   -noclean         use with -nohead, do not re-run configure nor clean
285
286=head1 DESCRIPTION
287
288This script builds a MythTV frontend and all necessary dependencies, along
289with plugins as specified, as a standalone binary package for Mac OS X.
290
291It was designed for building daily snapshots,
292but can also be used to create release builds.
293
294All intermediate files go into an '.osx-packager' directory in the current
295working directory. The finished application is named 'MythFrontend.app' and
296placed in the current working directory.
297
298=head1 EXAMPLES
299
300Building two snapshots, one with plugins and one without:
301
302  osx-packager.pl -clean -plugins mythvideo,mythweather
303  mv MythFrontend.app MythFrontend-plugins.app
304  osx-packager.pl -nohead
305  mv MythFrontend.app MythFrontend-noplugins.app
306
307Building a "fixes" branch:
308
309  osx-packager.pl -distclean
310  osx-packager.pl -svnbranch release-0-22-fixes
311
312Note that this script will not build old branches.
313Please try the branched version instead. e.g.
314http://svn.mythtv.org/svn/branches/release-0-23-fixes/mythtv/contrib/OSX/osx-packager.pl
315
316=head1 CREDITS
317
318Written by Jeremiah Morris (jm@whpress.com)
319
320Special thanks to Nigel Pearson, Jan Ornstedt, Angel Li, and Andre Pang
321for help, code, and advice.
322
323Small 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!
324Mods for move to github, Craig Treleaven December 2010.
325
326=cut
327
328# Parse options
329our (%OPT);
330Getopt::Long::GetOptions(\%OPT,
331                         'help|?',
332                         'man',
333                         'verbose',
334                         'version=s',
335                         'noversion',
336                         'distclean',
337                         'thirdclean',
338                         'thirdskip',
339                         'mythtvskip',
340                         'pluginskip',
341                         'themeskip',
342                         'clean',
343                         'svnbranch=s',
344                         'svnrev=s',
345                         'svntag=s',
346                         'nohead',
347                         'usehdimage',
348                         'leavehdimage',
349                         'enable-feplus',
350                         'enable-backend',
351                         'enable-jobtools',
352                         'profile',
353                         'debug',
354                         'm32',
355                         'plugins=s',
356                         'srcdir=s',
357                         'force',
358                         'noclean',
359                        ) or Pod::Usage::pod2usage(2);
360Pod::Usage::pod2usage(1) if $OPT{'help'};
361Pod::Usage::pod2usage('-verbose' => 2) if $OPT{'man'};
362
363if ( $OPT{'enable-backend'} )
364{   $backend = 1  }
365
366if ( $OPT{'clean'} )
367{   $cleanLibs = 1  }
368
369if ( $OPT{'enable-jobtools'} )
370{   $jobtools = 1  }
371
372if ( $OPT{'enable-feplus'} )    # add MythAVTest and MythWelcome
373{   $feplus = 1  }
374
375# Get version string sorted out
376if ( $OPT{'svntag'} && !$OPT{'version'} )
377{
378    $OPT{'version'} = $OPT{'svntag'};
379    $OPT{'version'} =~ s/-r *//;
380    $OPT{'version'} =~ s/--revision *//;
381}
382$OPT{'version'} = '' if $OPT{'noversion'};
383unless (defined $OPT{'version'})
384{
385    my @lt = gmtime(time);
386    $OPT{'version'} = sprintf('git%04d%02d%02d',
387                              $lt[5] + 1900, $lt[4] + 1, $lt[3]);
388}
389
390if ( $OPT{'srcdir'} )
391{
392    $OPT{'nohead'} = 1;
393    $OPT{'svnbranch'} = 0;
394}
395
396# Build our temp directories
397our $SCRIPTDIR = Cwd::abs_path(Cwd::getcwd());
398if ( $SCRIPTDIR =~ /\s/ )
399{
400    &Complain(<<END);
401Working directory contains spaces
402
403Error: Your current working path:
404
405   $SCRIPTDIR
406
407contains one or more spaces. This will break the compilation process,
408so the script cannot continue. Please re-run this script from a different
409directory (such as /tmp).
410
411The application produced will run from any directory, the no-spaces
412rule is only for the build process itself.
413
414END
415    die;
416}
417
418if ( $OPT{'nohead'} && ! $OPT{'force'} )
419{
420    my $SVNTOP="$SCRIPTDIR/.osx-packager/src/myth-svn/mythtv/.svn";
421
422    if ( ! -d $SVNTOP )
423    {   die "No source code to build?"   }
424
425    if ( ! `grep svn/trunk/mythtv $SVNTOP/entries` )
426    {   die "Source code does not match SVN trunk"   }
427}
428#
429# Trunk building has diverged from 0.23-fixes. After 0.24-fixes, disable this:
430#
431#elsif ( $OPT{'svnbranch'} )
432#{
433#    &Complain(<<END);
434#This version of this script can not build old branches.
435#Please try the branched version instead. e.g.
436# XXX Fix Me XXX
437#http://svn.mythtv.org/svn/branches/release-0-23-fixes/packaging/OSX/build/osx-packager.pl
438#END
439#    die;
440#}
441
442if ( $OPT{'svnbranch'} && $OPT{'svnbranch'} lt "release-0-24-fixes" )
443{
444    &Complain(<<END);
445This version of this script can not build old branches.
446Please try the branched version instead. e.g.
447# XXX Fix Me XXX
448http://svn.mythtv.org/svn/branches/release-0-21-fixes/mythtv/contrib/OSX/osx-packager.pl
449END
450    die;
451}
452
453#
454# Same tests for fixes copy of this script:
455#
456if ( 0 )
457{
458if ( $OPT{'nohead'} && ! $OPT{'force'} )
459{
460    my $SVNTOP="$SCRIPTDIR/.osx-packager/src/myth-svn/mythtv/.svn";
461
462    if ( ! -d $SVNTOP )
463    {   die "No source code to build?"   }
464
465    if ( ! `grep 0-22-fixes $SVNTOP/entries` )
466    {   die "Source code does not match release-0-22-fixes"   }
467}
468elsif ( ! $OPT{'svnbranch'} && ! $OPT{'force'} )
469{
470    &Complain(<<END);
471This script can only build branch release-0-22-fixes.
472To build SVN HEAD, please try the latest version instead. e.g.
473http://svn.mythtv.org/svn/trunk/packaging/OSX/build/osx-packager.pl
474END
475    die;
476}
477}
478
479our $WORKDIR = "$SCRIPTDIR/.osx-packager";
480mkdir $WORKDIR;
481
482# Do we need to force a case-sensitive disk image?
483if (0 &&       # No. MythTV source doesn't require it at the moment.
484    !$OPT{usehdimage} && !CaseSensitiveFilesystem())
485{
486    Verbose("Forcing -usehdimage due to case-insensitive filesystem");
487    $OPT{usehdimage} = 1;
488}
489
490if ($OPT{usehdimage})
491{   MountHDImage()   }
492
493our $PREFIX = "$WORKDIR/build";
494mkdir $PREFIX;
495
496our $SRCDIR = "$WORKDIR/src";
497mkdir $SRCDIR;
498
499#our $SVNDIR = "$SRCDIR/myth-svn";
500our $MYTHSRCDIR = "$SRCDIR/mythtv";
501
502our @pluginConf;
503if ( $OPT{plugins} )
504{
505    @pluginConf = split /,/, $OPT{plugins};
506    @pluginConf = grep(s/^/--enable-/, @pluginConf);
507    unshift @pluginConf, '--disable-all';
508}
509else
510{
511    @pluginConf = (
512        '--enable-opengl',
513        '--enable-mythgallery',
514        '--enable-exif',
515        '--enable-new-exif',
516    );
517}
518
519
520# configure mythplugins, and mythtv, etc
521our %conf = (
522  'mythplugins'
523  =>  [
524        '--prefix=' . $PREFIX,
525#        '--extra-cflags=-I/opt/local/include',
526#        '--extra-ldflags=-L/opt/local/lib',
527        @pluginConf
528      ],
529  'myththemes'
530  =>  [
531        '--prefix=' . $PREFIX,
532      ],
533  'mythtv'
534  =>  [
535        '--prefix=' . $PREFIX,
536        '--runprefix=../Resources',
537#        '--extra-cflags=-I/opt/local/include',
538#        '--extra-ldflags=-L/opt/local/lib',
539
540        # To "cross compile" something for a lesser Mac:
541        #'--tune=G3',
542        #'--disable-altivec',
543
544        # Currently needed for Mac OS 10.6 builds?
545        #WCT'--disable-mmx', '--enable-disable-mmx-for-debugging',
546      ],
547);
548
549# configure mythplugins, and mythtv, etc
550our %makecleanopt = (
551  'mythplugins'
552  =>  [
553        'distclean',
554      ],
555);
556
557# Source code version.pro needs to call subversion binary
558#
559
560use File::Basename;
561
562our $gitpath = dirname $git;
563our $MYTHBRANCH = 'fixes/0.24';    # assume master is the default
564
565# Clean the environment
566$ENV{'PATH'} = "$PREFIX/bin:/bin:/usr/bin:/usr/sbin:/usr/local/bin:$gitpath";
567$ENV{'PKG_CONFIG_PATH'} = "$PREFIX/lib/pkgconfig:";
568#$ENV{'PATH'} = "$PREFIX/bin:/opt/local/bin:/bin:/usr/bin:/usr/sbin:$gitpath";
569#$ENV{'PKG_CONFIG_PATH'} = "$PREFIX/lib/pkgconfig:/opt/local/bin:";
570delete $ENV{'CC'};
571delete $ENV{'CXX'};
572delete $ENV{'CPP'};
573delete $ENV{'CXXCPP'};
574$ENV{'CFLAGS'} = $ENV{'CXXFLAGS'} = $ENV{'CPPFLAGS'} = "-I$PREFIX/include";
575$ENV{'LDFLAGS'} = "-F/System/Library/Frameworks -L/usr/lib -L$PREFIX/lib";
576#$ENV{'CFLAGS'} = $ENV{'CXXFLAGS'} = $ENV{'CPPFLAGS'} = "-I$PREFIX/include -I/opt/local/include";
577#$ENV{'LDFLAGS'} = "-F/System/Library/Frameworks -L/usr/lib -L$PREFIX/lib -L/opt/local/lib";
578$ENV{'PREFIX'} = $PREFIX;
579
580# set up Qt environment
581$ENV{'QTDIR'} = $PREFIX;
582
583# If environment is setup to use distcc, take advantage of it
584our $standard_make = '/usr/bin/make';
585our $parallel_make = $standard_make;
586our $parallel_make_flags = '';
587
588if ( $ENV{'DISTCC_HOSTS'} )
589{
590    my @hosts = split m/\s+/, $ENV{'DISTCC_HOSTS'};
591    my $numhosts = $#hosts + 1;
592    &Verbose("Using ", $numhosts * 2, " DistCC jobs on $numhosts build hosts:",
593             join ', ', @hosts);
594    $parallel_make_flags = '-j' . $numhosts * 2;
595}
596
597# Ditto for multi-cpu setups:
598my $cmd = "/usr/bin/hostinfo | grep 'processors\$'";
599&Verbose($cmd);
600my $cpus = `$cmd`; chomp $cpus;
601$cpus =~ s/.*, (\d+) processors$/$1/;
602if ( $cpus gt 1 )
603{
604    &Verbose("Using", $cpus+1, "jobs on $cpus parallel CPUs");
605    ++$cpus;
606    $parallel_make_flags = "-j$cpus";
607}
608
609$parallel_make .= " $parallel_make_flags";
610
611# Auto-disable mixed 64/32bit:
612if ( `sysctl -n hw.cpu64bit_capable` eq "1\n" )
613{
614    &Verbose('OS is 64bit. Disabling 64bit for this build...');
615    $OPT{'m32'} = 1;
616}
617
618# We set 32-bit mode via environment variables.
619# The messier alternative would be to tweak all the configure arguments.
620if ( $OPT{'m32'} )
621{
622    &Verbose('Forcing 32-bit mode');
623    $ENV{'CFLAGS'}    .= ' -m32';
624    $ENV{'CPPFLAGS'}  .= ' -m32';
625    $ENV{'CXXFLAGS'}  .= ' -m32';
626    $ENV{'ECXXFLAGS'} .= ' -m32';  # MythTV configure
627    $ENV{'LDFLAGS'}   .= ' -m32';
628}
629
630### Distclean?
631if ( $OPT{'distclean'} )
632{
633    &Syscall([ '/bin/rm', '-f',       '$PREFIX/bin/myth*'    ]);
634    &Syscall([ '/bin/rm', '-f', '-r', '$PREFIX/lib/libmyth*' ]);
635    &Syscall([ '/bin/rm', '-f', '-r', '$PREFIX/lib/mythtv'   ]);
636    &Syscall([ '/bin/rm', '-f', '-r', '$PREFIX/share/mythtv' ]);
637    &Syscall([ 'find', $MYTHSRCDIR, '-name', '*.o',     '-delete' ]);
638    &Syscall([ 'find', $MYTHSRCDIR, '-name', '*.a',     '-delete' ]);
639    &Syscall([ 'find', $MYTHSRCDIR, '-name', '*.dylib', '-delete' ]);
640    &Syscall([ 'find', $MYTHSRCDIR, '-name', '*.orig',  '-delete' ]);
641    &Syscall([ 'find', $MYTHSRCDIR, '-name', '*.rej',   '-delete' ]);
642    exit;
643}
644
645### Check for app present in target location
646our $MFE = "$SCRIPTDIR/MythFrontend.app";
647if ( -d $MFE )
648{
649    &Complain(<<END);
650$MFE already exists
651
652Error: a MythFrontend application exists where we were planning
653to build one. Please move this application away before running
654this script.
655
656END
657    exit;
658}
659
660### Third party packages
661my ( @build_depends, %seen_depends );
662my @comps = ( 'mythtv', @components, 'packaging' );
663
664# Deal with user-supplied skip arguments
665if ( $OPT{'mythtvskip'} )
666{   @comps = grep(!m/mythtv/,      @comps)   }
667if ( $OPT{'pluginskip'} )
668{   @comps = grep(!m/mythplugins/, @comps)   }
669if ( $OPT{'themeskip'} )
670{   @comps = grep(!m/myththemes/,  @comps)   }
671
672if ( ! @comps )
673{
674    &Complain("Nothing to build! Too many ...skip arguments?");
675    exit;
676}
677
678&Verbose("Including components:", @comps);
679
680foreach my $comp (@comps)
681{
682    foreach my $dep (@{ $depend_order{$comp} })
683    {
684        unless (exists $seen_depends{$dep})
685        {
686            push(@build_depends, $dep);
687            $seen_depends{$dep} = 1;
688        }
689    }
690}
691foreach my $sw ( @build_depends )
692{
693    # Get info about this package
694    my $pkg = $depend{$sw};
695    my $url = $pkg->{'url'};
696    my $filename = $url;
697    $filename =~ s|^.+/([^/]+)$|$1|;
698    my $dirname = $filename;
699    $dirname =~ s|\.tar\.gz$||;
700    $dirname =~ s|\.tar\.bz2$||;
701
702    chdir($SRCDIR);
703
704    # Download and decompress
705    unless ( -e $filename )
706    {
707        &Verbose("Downloading $sw");
708        unless (&Syscall([ '/usr/bin/curl', '-f', '-L', $url, '>', $filename ],
709                         'munge' => 1))
710        {
711            &Syscall([ '/bin/rm', $filename ]) if (-e $filename);
712            die;
713        }
714    }
715    else
716    {   &Verbose("Using previously downloaded $sw")   }
717
718    if ( $pkg->{'skip'} )
719    {   next   }
720
721    if ( -d $dirname )
722    {
723        if ( $OPT{'thirdclean'} )
724        {
725            &Verbose("Removing previous build of $sw");
726            &Syscall([ '/bin/rm', '-f', '-r', $dirname ]) or die;
727        }
728
729        if ( $OPT{'thirdskip'} )
730        {
731            &Verbose("Using previous build of $sw");
732            next;
733        }
734
735        &Verbose("Using previously unpacked $sw");
736    }
737    else
738    {
739        &Verbose("Unpacking $sw");
740        if ( substr($filename,-3) eq ".gz" )
741        {   &Syscall([ '/usr/bin/tar', '-xzf', $filename ]) or die   }
742        elsif ( substr($filename,-4) eq ".bz2" )
743        {   &Syscall([ '/usr/bin/tar', '-xjf', $filename ]) or die   }
744        else
745        {
746            &Complain("Cannot unpack file $filename");
747            exit;
748        }
749    }
750
751    # Configure
752    chdir($dirname);
753    unless (-e '.osx-config')
754    {
755        &Verbose("Configuring $sw");
756        if ( $pkg->{'pre-conf'} )
757        {   &Syscall([ $pkg->{'pre-conf'} ], 'munge' => 1) or die   }
758
759        my (@configure, $munge);
760
761        if ( $pkg->{'conf-cmd'} )
762        {
763            push(@configure, $pkg->{'conf-cmd'});
764            $munge = 1;
765        }
766        else
767        {
768            push(@configure, './configure',
769                       '--prefix=$PREFIX',
770                       '--disable-static',
771                       '--enable-shared');
772        }
773        if ( $pkg->{'conf'} )
774        {
775            push(@configure, @{ $pkg->{'conf'} });
776        }
777        &Syscall(\@configure, 'interpolate' => 1, 'munge' => $munge) or die;
778        if ( $pkg->{'post-conf'} )
779        {
780            &Syscall([ $pkg->{'post-conf'} ], 'munge' => 1) or die;
781        }
782        &Syscall([ '/usr/bin/touch', '.osx-config' ]) or die;
783    }
784    else
785    {   &Verbose("Using previously configured $sw")   }
786
787    # Build and install
788    unless (-e '.osx-built')
789    {
790        &Verbose("Making $sw");
791        my (@make);
792
793        push(@make, $standard_make);
794        if ( $pkg->{'parallel-make'} && $parallel_make_flags )
795        {   push(@make, $parallel_make_flags)   }
796
797        if ( $pkg->{'make'} )
798        {   push(@make, @{ $pkg->{'make'} })   }
799        else
800        {   push(@make, 'all', 'install')   }
801
802        &Syscall(\@make) or die;
803        if ( $pkg->{'post-make'} )
804        {
805            &Syscall([ $pkg->{'post-make'} ], 'munge' => 1) or die;
806        }
807        &Syscall([ '/usr/bin/touch', '.osx-built' ]) or die;
808    }
809    else
810    {
811        &Verbose("Using previously built $sw");
812    }
813}
814
815
816### build MythTV
817
818# Clean any previously installed libraries
819if ( $cleanLibs )
820{
821    if ( $OPT{'mythtvskip'} )
822    {
823        &Complain("Cannot skip building mythtv src if also cleaning");
824        exit;
825    }
826    &Verbose("Cleaning previous installs of MythTV");
827    my @mythlibs = glob "$PREFIX/lib/libmyth*";
828    if ( scalar @mythlibs )
829    {
830        &Syscall([ '/bin/rm', @mythlibs ]) or die;
831    }
832    foreach my $dir ('include', 'lib', 'share')
833    {
834        if ( -d "$PREFIX/$dir/mythtv" )
835        {
836            &Syscall([ '/bin/rm', '-f', '-r', "$PREFIX/$dir/mythtv" ]) or die;
837        }
838    }
839}
840
841# mkdir $SVNDIR;                # Not necessary, Git creates
842
843#
844# Work out Subversion branches, revisions and tags.
845# Note these vars are unused if nohead or srcdir set!
846#
847my $svnrepository = 'http://svn.mythtv.org/svn/';
848my @svnrevision   = ();
849
850if ( $OPT{'svnbranch'} )
851{
852    $svnrepository .= 'branches/' . $OPT{'svnbranch'} . '/';
853}
854elsif ( $OPT{'svntag'} )
855{
856    $svnrepository .= 'tags/' . $OPT{'svntag'} . '/';
857}
858elsif ( $OPT{'svnrev'} )
859{
860    $svnrepository .= 'trunk/';
861
862    # This arg. could be '1234', '-r 1234', or '--revision 1234'
863    # If the user just specified a number, add appropriate flag:
864    if ( $OPT{'svnrev'} =~ m/^\d+$/ )
865    {
866        push @svnrevision, '--revision';
867    }
868
869    push @svnrevision, $OPT{'svnrev'};
870}
871#elsif ( ! $OPT{'nohead'} )
872#{
873#    # Lookup and use the HEAD revision so we are guaranteed consistent source
874#    my $cmd = "$svn log $svnrepository --revision HEAD --xml | grep revision";
875#    &Verbose($cmd);
876#    my $rev = `$cmd`;
877#
878#    if ( $rev =~ m/revision="(\d+)">/ )
879#    {
880#        $svnrepository .= 'trunk/';
881#        @svnrevision = ('--revision', $1);
882#    }
883#    else
884#    {
885#        &Complain("Cannot get head revision - Got '$rev'");
886#        die;
887#    }
888#}
889
890# Retrieve source
891if ( $OPT{'srcdir'} )
892{
893    chdir($SCRIPTDIR);
894    &Syscall(['rm', '-fr', $MYTHSRCDIR]);
895    &Syscall(['mkdir', '-p', $MYTHSRCDIR]);
896    foreach my $dir ('mythtv', 'mythplugins',
897                     'myththemes', 'themes', 'packaging')
898    {
899        &Syscall(['cp', '-pR', "$OPT{'srcdir'}/$dir", "$MYTHSRCDIR/$dir"]);
900    }
901    &Syscall("mkdir -p $MYTHSRCDIR/mythtv/config")
902}
903elsif ( ! $OPT{'nohead'} )
904######################################################################
905#  Get the code via Git
906# only do 'git clone' if mythtv directory does not exist.
907# always do 'git checkout' to make sure we have the right branch.
908# then 'git pull' to get up to date.
909######################################################################
910{
911    chdir($SCRIPTDIR);
912    &Syscall(['rm', '-fr', $MYTHSRCDIR . '/mythtv/config']);
913    if ( ! -e $MYTHSRCDIR )
914    {
915     &Syscall([ $git, 'clone', 'git://github.com/MythTV/mythtv.git',
916                      $MYTHSRCDIR ]) or die;
917    }
918    if ( ! -e "$MYTHSRCDIR/packaging" )
919    {
920     &Syscall([ $git, 'clone', 'git://github.com/MythTV/packaging.git',
921                      $MYTHSRCDIR . '/packaging' ]) or die;
922    }
923   
924    chdir($MYTHSRCDIR);
925    &Syscall([ $git, 'checkout', $MYTHBRANCH]) or die;
926    &Syscall([ $git, 'pull']) or die;
927    chdir("$MYTHSRCDIR/packaging");
928    &Syscall([ $git, 'checkout', $MYTHBRANCH]) or die;
929    &Syscall([ $git, 'pull']) or die;
930}
931else
932{   &Syscall("mkdir -p $MYTHSRCDIR/mythtv/config")   }
933
934# Make a convenience (non-hidden) directory for editing src code:
935system("ln -sf $MYTHSRCDIR $SCRIPTDIR/src");
936
937# Build MythTV and any plugins
938foreach my $comp (@comps)
939{
940    my $compdir = "$MYTHSRCDIR/$comp/" ;
941
942    chdir $compdir;
943
944    if ( ! -e "$comp.pro" and ! -e 'Makefile' and ! -e 'configure' )
945    {
946        &Complain("Nothing to configure/make in $compdir");
947        next;
948    }
949
950    if ( $OPT{'clean'} && -e 'Makefile' )
951    {
952        &Verbose("Cleaning $comp");
953        &Syscall([ $standard_make, 'distclean' ]) or die;
954    }
955    #else
956    #{
957    #    # clean the Makefiles, as process requires PREFIX hacking
958    #    &CleanMakefiles();
959    #}
960
961    # Apply any nasty mac-specific patches
962    if ( $patches{$comp} )
963    {
964        &Syscall([ "echo '$patches{$comp}' | patch -p0 --forward" ]);
965    }
966
967    # configure and make
968    if ( $makecleanopt{$comp} && -e 'Makefile' && ! $OPT{'noclean'} )
969    {
970        my @makecleancom = $standard_make;
971        push(@makecleancom, @{ $makecleanopt{$comp} }) if $makecleanopt{$comp};
972        &Syscall([ @makecleancom ]) or die;
973    }
974    if ( -e 'configure' && ! $OPT{'noclean'} )
975    {
976        &Verbose("Configuring $comp");
977        my @config = './configure';
978        push(@config, @{ $conf{$comp} }) if $conf{$comp};
979        if ( $comp eq 'mythtv' && $backend )
980        {
981            push @config, '--enable-backend'
982        }
983        if ( $OPT{'profile'} )
984        {
985            push @config, '--compile-type=profile'
986        }
987        if ( $OPT{'debug'} )
988        {
989            push @config, '--compile-type=debug'
990        }
991        if ( $comp eq 'mythtv' && ! $ENV{'DISTCC_HOSTS'} )
992        {
993            push @config, '--disable-distcc'
994        }
995        &Syscall([ @config ]) or die;
996    }
997    if ( -e "$comp.pro" )
998    {
999        &Verbose("Running qmake for $comp");
1000        my @qmake_opts = (
1001            'QMAKE_LFLAGS+=-Wl,-search_paths_first',
1002            'INCLUDEPATH+="' . $PREFIX . '/include"',
1003            'LIBS+=-L/usr/lib -L"' . $PREFIX . '/lib"'
1004            );
1005        &Syscall([ $PREFIX . '/bin/qmake',
1006                   'PREFIX=../Resources',
1007                   @qmake_opts,
1008                   "$comp.pro" ]) or die;
1009    }
1010    if ( $comp eq 'mythtv' )
1011    {
1012        # Remove/add Nigel's frontend building speedup hack
1013        &DoSpeedupHacks('programs/programs.pro', 'mythfrontend mythavtest');
1014    }
1015
1016    &Verbose("Making $comp");
1017    &Syscall([ $parallel_make ]) or die;
1018#    # install
1019#    # This requires a change from the compiled-in relative
1020#    # PREFIX to our absolute path of the temp install location.
1021#    &CleanMakefiles();
1022#    &Verbose("Running qmake for $comp install");
1023#    &Syscall([ $PREFIX . '/bin/qmake',
1024#               'PREFIX=' . $PREFIX,
1025#               @qmake_opts,
1026#               "$comp.pro" ]) or die;
1027    &Verbose("Installing $comp");
1028    &Syscall([ $standard_make,
1029               'install' ]) or die;
1030
1031    if ( $cleanLibs && $comp eq 'mythtv' )
1032    {
1033        # If we cleaned the libs, make install will have recopied them,
1034        # which means any dynamic libraries that the static libraries depend on
1035        # are newer than the table of contents. Hence we need to regenerate it:
1036        my @mythlibs = glob "$PREFIX/lib/libmyth*.a";
1037        if ( scalar @mythlibs )
1038        {
1039            &Verbose("Running ranlib on reinstalled static libraries");
1040            foreach my $lib (@mythlibs)
1041            {   &Syscall("ranlib $lib") or die }
1042        }
1043    }
1044}
1045
1046### Build version string
1047our $VERS = `find $PREFIX/lib -name 'libmyth-[0-9].[0-9][0-9].[0-9].dylib'`;
1048chomp $VERS;
1049$VERS =~ s/^.*\-(.*)\.dylib$/$1/s;
1050$VERS .= '.' . $OPT{'version'} if $OPT{'version'};
1051
1052### Program which creates bundles:
1053our @bundler = "$MYTHSRCDIR/packaging/OSX/build/osx-bundler.pl";
1054if ( $OPT{'verbose'} )
1055{   push @bundler, '--verbose'   }
1056
1057
1058### Framework that has a screwed up link dependency path
1059my $AVCfw = '/Developer/FireWireSDK*/Examples/' .
1060            'Framework/AVCVideoServices.framework';
1061my @AVCfw = split / /, `ls -d $AVCfw`;
1062$AVCfw = pop @AVCfw;
1063chop $AVCfw;
1064
1065### Create each package.
1066### Note that this is a bit of a waste of disk space,
1067### because there are now multiple copies of each library.
1068
1069if ( $jobtools )
1070{   push @targets, @targetsJT   }
1071
1072if ( $feplus )
1073{   push @targets, @targetTW   }
1074
1075if ( $backend )
1076{   push @targets, @targetsBE   }
1077
1078foreach my $target ( @targets )
1079{
1080    my $finalTarget = "$SCRIPTDIR/$target.app";
1081    my $builtTarget = lc $target;
1082
1083    # Get a fresh copy of the binary
1084    &Verbose("Building self-contained $target");
1085    &Syscall([ 'rm', '-fr', $finalTarget ]) or die;
1086    &Syscall([ 'cp',  "$MYTHSRCDIR/mythtv/programs/$builtTarget/$builtTarget",
1087                      "$SCRIPTDIR/$target" ]) or die;
1088
1089    # Convert it to a bundled .app
1090    &Syscall([ @bundler, "$SCRIPTDIR/$target",
1091               "$PREFIX/lib/", "$PREFIX/lib/mysql" ]) or die;
1092
1093    # Remove copy of binary
1094    unlink "$SCRIPTDIR/$target" or die;
1095
1096    if ( $AVCfw )
1097    {   &RecursiveCopy($AVCfw, "$finalTarget/Contents/Frameworks")   }
1098
1099    # Themes are required by all GUI apps. The filters and plugins are not
1100    # used by mythtv-setup or mythwelcome, but for simplicity, do them all.
1101    if ( $target eq "MythAVTest" or $target eq "MythFrontend" or
1102         $target eq "MythWelcome" or $target =~ m/^MythTV-/ )
1103    {
1104        my $res  = "$finalTarget/Contents/Resources";
1105        my $libs = "$res/lib";
1106        my $plug = "$libs/mythtv/plugins";
1107
1108        # Install themes, filters, etc.
1109        &Verbose("Installing resources into $target");
1110        mkdir $res; mkdir $libs;
1111        &RecursiveCopy("$PREFIX/lib/mythtv", $libs);
1112        mkdir "$res/share";
1113        &RecursiveCopy("$PREFIX/share/mythtv", "$res/share");
1114
1115        # Correct the library paths for the filters and plugins
1116        foreach my $lib ( glob "$libs/mythtv/*/*" )
1117        {   &Syscall([ @bundler, $lib, "$PREFIX/lib/" ]) or die   }
1118
1119        if ( -e $plug )
1120        {
1121            # Allow Finder's 'Get Info' to manage plugin list:
1122            &Syscall([ 'mv', $plug, "$finalTarget/Contents/Plugins" ]) or die;
1123            &Syscall([ 'ln', '-s', "../../../Plugins", $plug ]) or die;
1124        }
1125
1126        # The icon
1127        &Syscall([ 'cp',
1128                   "$MYTHSRCDIR/mythtv/programs/mythfrontend/mythfrontend.icns",
1129                   "$res/application.icns" ]) or die;
1130        &Syscall([ '/Developer/Tools/SetFile', '-a', 'C', $finalTarget ])
1131            or die;
1132    }
1133
1134    if ( $target eq "MythFrontend" )
1135    {
1136        foreach my $extra ( 'ignyte', 'mythpreviewgen', 'mtd' )
1137        {
1138            if ( -e "$PREFIX/bin/$extra" )
1139            {
1140                &Verbose("Installing $extra into $target");
1141                &Syscall([ 'cp', "$PREFIX/bin/$extra",
1142                           "$finalTarget/Contents/MacOS" ]) or die;
1143
1144                &Verbose('Updating lib paths of',
1145                         "$finalTarget/Contents/MacOS/$extra");
1146                &Syscall([ @bundler, "$finalTarget/Contents/MacOS/$extra" ])
1147                    or die;
1148                &AddFakeBinDir($finalTarget);
1149            }
1150        }
1151
1152        # Allow playback of region encoded DVDs
1153        mkdir("$finalTarget/Contents/Plugins");
1154        &Syscall([ 'cp', "$PREFIX/lib/libdvdcss.2.dylib",
1155                         "$finalTarget/Contents/Plugins" ]) or die;
1156
1157        # Allow opening of GIFs and JPEGs:
1158        mkdir("$finalTarget/Contents/MacOS/imageformats");
1159        foreach my $plugin ( 'libqgif.dylib', 'libqjpeg.dylib' )
1160        {
1161            my $pluginSrc = "$PREFIX/plugins/imageformats/$plugin";
1162            if ( -e $pluginSrc )
1163            {
1164                &Syscall([ 'cp', $pluginSrc,
1165                           "$finalTarget/Contents/MacOS/imageformats" ])
1166                    or die;
1167                &Syscall([ @bundler,
1168                           "$finalTarget/Contents/MacOS/imageformats/$plugin" ])
1169                    or die;
1170            }
1171        }
1172    }
1173
1174    if ( $target eq "MythWelcome" )
1175    {
1176        &Verbose("Installing mythfrontend into $target");
1177        &Syscall([ 'cp', "$PREFIX/bin/mythfrontend",
1178                         "$finalTarget/Contents/MacOS" ]) or die;
1179        &Syscall([ @bundler, "$finalTarget/Contents/MacOS/mythfrontend" ])
1180            or die;
1181        &AddFakeBinDir($finalTarget);
1182
1183        # For some unknown reason, mythfrontend looks here for support files:
1184        &Syscall([ 'ln', '-s', "../Resources/share",   # themes
1185                               "../Resources/lib",     # filters/plugins
1186                   "$finalTarget/Contents/MacOS" ]) or die;
1187    }
1188
1189    # Run 'rebase' on all the frameworks:
1190    my @libs = glob "$finalTarget/Contents/Frameworks/*";
1191    @libs = grep(s,(.*/)(\w+).framework$,$1$2.framework/Versions/A/$2, , @libs); # WCT mod
1192    # @libs = grep(s,(.*/)(\w+).framework$,$1$2.framework/$2, , @libs);
1193    # and all the filters/plugins:
1194    push(@libs, glob "$finalTarget/Contents/Resources/lib/mythtv/*/*");
1195    if ( $OPT{'verbose'} )
1196    {   &Syscall([ 'rebase', '-v', @libs ]) or die   }
1197    else
1198    {   &Syscall([ 'rebase', @libs ]) or die   }
1199}
1200
1201if ( $backend && grep(m/MythBackend/, @targets) )
1202{
1203    my $BE = "$SCRIPTDIR/MythBackend.app";
1204
1205    # Copy XML files that UPnP requires:
1206    my $share = "$BE/Contents/Resources/share/mythtv";
1207    &Syscall([ 'mkdir', '-p', $share ]) or die;
1208    &Syscall([ 'cp', glob("$PREFIX/share/mythtv/*.xml"), $share ]) or die;
1209
1210    # The backend gets all the useful binaries it might call:
1211    foreach my $binary ( 'mythjobqueue', 'mythcommflag',
1212                         'mythtranscode', 'mythfilldatabase' )
1213    {
1214        my $SRC  = "$PREFIX/bin/$binary";
1215        if ( -e $SRC )
1216        {
1217            &Verbose("Installing $SRC into $BE");
1218            &Syscall([ '/bin/cp', $SRC, "$BE/Contents/MacOS" ]) or die;
1219
1220            &Verbose("Updating lib paths of $BE/Contents/MacOS/$binary");
1221            &Syscall([ @bundler, "$BE/Contents/MacOS/$binary" ]) or die;
1222        }
1223    }
1224    &AddFakeBinDir($BE);
1225}
1226
1227if ( $jobtools )
1228{
1229    # JobQueue also gets some binaries it might call:
1230    my $JQ   = "$SCRIPTDIR/MythJobQueue.app";
1231    my $DEST = "$JQ/Contents/MacOS";
1232    my $SRC  = "$PREFIX/bin/mythcommflag";
1233
1234    &Syscall([ '/bin/cp', $SRC, $DEST ]) or die;
1235    &AddFakeBinDir($JQ);
1236    &Verbose("Updating lib paths of $DEST/mythcommflag");
1237    &Syscall([ @bundler, "$DEST/mythcommflag" ]) or die;
1238
1239    $SRC  = "$PREFIX/bin/mythtranscode.app/Contents/MacOS/mythtranscode";
1240    if ( -e $SRC )
1241    {
1242        &Verbose("Installing $SRC into $JQ");
1243        &Syscall([ '/bin/cp', $SRC, $DEST ]) or die;
1244        &Verbose("Updating lib paths of $DEST/mythtranscode");
1245        &Syscall([ @bundler, "$DEST/mythtranscode" ]) or die;
1246    }
1247}
1248
1249# Clean tmp files. Most of these are leftovers from configure:
1250#
1251&Verbose('Cleaning build tmp directory');
1252&Syscall([ 'rm', '-fr', $WORKDIR . '/tmp' ]) or die;
1253&Syscall([ 'mkdir',     $WORKDIR . '/tmp' ]) or die;
1254
1255if ($OPT{usehdimage} && !$OPT{leavehdimage} )
1256{
1257    Verbose("Dismounting case-sensitive build device");
1258    UnmountHDImage();
1259}
1260
1261&Verbose("Build complete. Self-contained package is at:\n\n    $MFE\n");
1262
1263### end script
1264exit 0;
1265
1266
1267######################################
1268## RecursiveCopy copies a directory tree, stripping out .svn
1269## directories and properly managing static libraries.
1270######################################
1271
1272sub RecursiveCopy($$)
1273{
1274    my ($src, $dst) = @_;
1275
1276    # First copy absolutely everything
1277    &Syscall([ '/bin/cp', '-pR', "$src", "$dst"]) or die;
1278
1279    # Then strip out any .svn directories
1280    my @files = map { chomp $_; $_ } `find $dst -name .svn`;
1281    if ( scalar @files )
1282    {
1283        &Syscall([ '/bin/rm', '-f', '-r', @files ]);
1284    }
1285
1286    # And make sure any static libraries are properly relocated.
1287    my @libs = map { chomp $_; $_ } `find $dst -name "lib*.a"`;
1288    if ( scalar @libs )
1289    {
1290        &Syscall([ 'ranlib', '-s', @libs ]);
1291    }
1292}
1293
1294######################################
1295## CleanMakefiles removes every generated Makefile
1296## from our MythTV build that contains PREFIX.
1297## Necessary when we change the
1298## PREFIX variable.
1299######################################
1300
1301sub CleanMakefiles
1302{
1303    &Verbose("Cleaning MythTV makefiles containing PREFIX");
1304    &Syscall([ 'find', '.', '-name', 'Makefile', '-exec',
1305               'egrep', '-q', 'qmake.*PREFIX', '{}', ';', '-delete' ]) or die;
1306} # end CleanMakefiles
1307
1308
1309######################################
1310## Syscall wrappers the Perl "system"
1311## routine with verbosity and error
1312## checking.
1313######################################
1314
1315sub Syscall($%)
1316{
1317    my ($arglist, %opts) = @_;
1318
1319    unless (ref $arglist)
1320    {
1321        $arglist = [ $arglist ];
1322    }
1323    if ( $opts{'interpolate'} )
1324    {
1325        my @args;
1326        foreach my $arg (@$arglist)
1327        {
1328            $arg =~ s/\$PREFIX/$PREFIX/ge;
1329            $arg =~ s/\$parallel_make_flags/$parallel_make_flags/ge;
1330            push(@args, $arg);
1331        }
1332        $arglist = \@args;
1333    }
1334    if ( $opts{'munge'} )
1335    {
1336        $arglist = [ join(' ', @$arglist) ];
1337    }
1338    # clean out any null arguments
1339    $arglist = [ map $_, @$arglist ];
1340    &Verbose(@$arglist);
1341    my $ret = system(@$arglist);
1342    if ( $ret )
1343    {
1344        &Complain('Failed system call: "', @$arglist,
1345                  '" with error code', $ret >> 8);
1346    }
1347    return ($ret == 0);
1348} # end Syscall
1349
1350
1351######################################
1352## Verbose prints messages in verbose
1353## mode.
1354######################################
1355
1356sub Verbose
1357{
1358    print STDERR '[osx-pkg] ' . join(' ', @_) . "\n"
1359        if $OPT{'verbose'};
1360} # end Verbose
1361
1362
1363######################################
1364## Complain prints messages in any
1365## verbosity mode.
1366######################################
1367
1368sub Complain
1369{
1370    print STDERR '[osx-pkg] ' . join(' ', @_) . "\n";
1371} # end Complain
1372
1373
1374######################################
1375## Manage usehdimage disk image
1376######################################
1377
1378sub MountHDImage
1379{
1380    if ( ! HDImageDevice() )
1381    {
1382        if ( -e "$SCRIPTDIR/.osx-packager.dmg" )
1383        {
1384            Verbose("Mounting existing UFS disk image for the build");
1385        }
1386        else
1387        {
1388            Verbose("Creating a case-sensitive (UFS) disk image for the build");
1389            Syscall(['hdiutil', 'create', '-size', '2048m',
1390                     "$SCRIPTDIR/.osx-packager.dmg", '-volname',
1391                     'MythTvPackagerHDImage', '-fs', 'UFS', '-quiet']) || die;
1392        }
1393
1394        &Syscall(['hdiutil', 'mount',
1395                  "$SCRIPTDIR/.osx-packager.dmg",
1396                  '-mountpoint', $WORKDIR, '-quiet']) || die;
1397    }
1398
1399    # configure defaults to /tmp and OSX barfs when mv crosses
1400    # filesystems so tell configure to put temp files on the image
1401
1402    $ENV{TMPDIR} = $WORKDIR . "/tmp";
1403    mkdir $ENV{TMPDIR};
1404}
1405
1406sub UnmountHDImage
1407{
1408    my $device = HDImageDevice();
1409    if ( $device )
1410    {
1411        &Syscall(['hdiutil', 'detach', $device, '-force']);
1412    }
1413}
1414
1415sub HDImageDevice
1416{
1417    my @dev = split ' ', `/sbin/mount | grep $WORKDIR`;
1418    $dev[0];
1419}
1420
1421sub CaseSensitiveFilesystem
1422{
1423    my $funky = $SCRIPTDIR . "/.osx-packager.FunkyStuff";
1424    my $unfunky = substr($funky, 0, -10) . "FUNKySTuFF";
1425
1426    unlink $funky if -e $funky;
1427    `touch $funky`;
1428    my $sensitivity = ! -e $unfunky;
1429    unlink $funky;
1430
1431    return $sensitivity;
1432}
1433
1434
1435######################################
1436## Remove or add Nigel's speedup hacks
1437######################################
1438
1439sub DoSpeedupHacks($$)
1440{
1441    my ($file, $subdirs) = @_;
1442
1443    &Verbose("Removing Nigel's hacks from file $file");
1444
1445    open(IN,  $file)         or die;
1446    open(OUT, ">$file.orig") or die;
1447    while ( <IN> )
1448    {
1449        if ( m/^# Nigel/ )  # Skip
1450        {  last  }
1451        print OUT;
1452    }
1453    if ( ! $backend && ! $jobtools )
1454    {
1455        # Nigel's hack to speedup building
1456        print OUT "# Nigel\'s speedup hack:\n";
1457        print OUT "SUBDIRS = $subdirs\n";
1458    }
1459    close IN; close OUT;
1460    rename("$file.orig", $file);
1461}
1462
1463#######################################################
1464## Parts of MythTV try to call helper apps like this:
1465## gContext->GetInstallPrefix() + "/bin/mythtranscode";
1466## which means we need a bin directory.
1467#######################################################
1468
1469sub AddFakeBinDir($)
1470{
1471    my ($target) = @_;
1472
1473    &Syscall("mkdir -p $target/Contents/Resources");
1474    &Syscall(['ln', '-sf', '../MacOS', "$target/Contents/Resources/bin"]);
1475}
1476
1477### end file
14781;