1 ###############################################################################
3 ## This script is coded for minimum version of Python 2.4 .
4 ## Pyhthon3 is incompatible.
8 ###############################################################################
19 from optparse import OptionGroup
20 from optparse import OptionGroup
21 from optparse import OptionParser
22 from sys import stderr
23 from sys import stdout
25 class AbortError( Exception ):
26 def __init__( self, format, *args ):
27 self.value = format % args
31 ###############################################################################
33 ## Main configure object.
35 ## dir = containing this configure script
36 ## cwd = current working dir at time of script launch
38 class Configure( object ):
43 def __init__( self, verbose ):
45 self._log_verbose = []
48 self.verbose = verbose
49 self.dir = os.path.dirname( sys.argv[0] )
50 self.cwd = os.getcwd()
54 ## compute src dir which is 2 dirs up from this script
55 self.src_dir = os.path.normpath( sys.argv[0] )
57 self.src_dir = os.path.dirname( self.src_dir )
58 if len( self.src_dir ) == 0:
59 self.src_dir = os.curdir
61 def _final_dir( self, chdir, dir ):
62 dir = os.path.normpath( dir )
63 if not os.path.isabs( dir ):
64 if os.path.isabs( chdir ):
65 dir = os.path.normpath( os.path.abspath(dir ))
67 dir = os.path.normpath( self.relpath( dir, chdir ))
71 def errln( self, format, *args ):
73 if re.match( '^.*[!?:;.]$', s ):
74 stderr.write( 'ERROR: %s configure stop.\n' % (s) )
76 stderr.write( 'ERROR: %s; configure stop.\n' % (s) )
79 def infof( self, format, *args ):
81 self._log_verbose.append( line )
82 if cfg.verbose >= Configure.OUT_INFO:
83 self._log_info.append( line )
85 def verbosef( self, format, *args ):
87 self._log_verbose.append( line )
88 if cfg.verbose >= Configure.OUT_VERBOSE:
91 ## doc is ready to be populated
92 def doc_ready( self ):
93 ## compute final paths as they are after chdir into build
94 self.build_final = os.curdir
95 self.src_final = self._final_dir( self.build_dir, self.src_dir )
96 self.prefix_final = self._final_dir( self.build_dir, self.prefix_dir )
98 cfg.infof( 'compute: makevar SRC/ = %s\n', self.src_final )
99 cfg.infof( 'compute: makevar BUILD/ = %s\n', self.build_final )
100 cfg.infof( 'compute: makevar PREFIX/ = %s\n', self.prefix_final )
102 ## xcode does a chdir so we need appropriate values
103 macosx = os.path.join( self.src_dir, 'macosx' )
104 self.xcode_x_src = self._final_dir( macosx, self.src_dir )
105 self.xcode_x_build = self._final_dir( macosx, self.build_dir )
106 self.xcode_x_prefix = self._final_dir( macosx, self.prefix_dir )
108 ## perform chdir and enable log recording
110 if os.path.abspath( self.build_dir ) == os.path.abspath( self.src_dir ):
111 cfg.errln( 'build (scratch) directory must not be the same as top-level source root!' )
113 if self.build_dir != os.curdir:
114 if os.path.exists( self.build_dir ):
115 if not options.force:
116 self.errln( 'build directory already exists: %s (use --force to overwrite)', self.build_dir )
118 self.mkdirs( self.build_dir )
119 self.infof( 'chdir: %s\n', self.build_dir )
120 os.chdir( self.build_dir )
125 def mkdirs( self, dir ):
126 if len(dir) and not os.path.exists( dir ):
127 self.infof( 'mkdir: %s\n', dir )
130 def open( self, *args ):
131 dir = os.path.dirname( args[0] )
132 if len(args) > 1 and args[1].find('w') != -1:
134 m = re.match( '^(.*)\.tmp$', args[0] )
136 self.infof( 'write: %s\n', m.group(1) )
138 self.infof( 'write: %s\n', args[0] )
143 cfg.errln( 'open failure: %s', x )
145 def record_log( self ):
149 self.verbose = Configure.OUT_QUIET
150 file = cfg.open( 'log/config.info.txt', 'w' )
151 for line in self._log_info:
154 file = cfg.open( 'log/config.verbose.txt', 'w' )
155 for line in self._log_verbose:
159 ## Find executable by searching path.
160 ## On success, returns full pathname of executable.
161 ## On fail, returns None.
162 def findExecutable( self, name ):
163 if len( os.path.split(name)[0] ):
164 if os.access( name, os.X_OK ):
168 if not os.environ.has_key( 'PATH' ) or os.environ[ 'PATH' ] == '':
171 path = os.environ['PATH']
173 for dir in path.split( os.pathsep ):
174 f = os.path.join( dir, name )
175 if os.access( f, os.X_OK ):
179 ## taken from python2.6 -- we need it
180 def relpath( self, path, start=os.curdir ):
181 """Return a relative version of a path"""
184 raise ValueError("no path specified")
186 start_list = os.path.abspath(start).split(os.sep)
187 path_list = os.path.abspath(path).split(os.sep)
189 # Work out how much of the filepath is shared by start and path.
190 i = len(os.path.commonprefix([start_list, path_list]))
192 rel_list = [os.pardir] * (len(start_list)-i) + path_list[i:]
195 return os.path.join(*rel_list)
197 ## update with parsed cli options
198 def update_cli( self, options ):
199 self.src_dir = os.path.normpath( options.src )
200 self.build_dir = os.path.normpath( options.build )
201 self.prefix_dir = os.path.normpath( options.prefix )
203 ## special case if src == build: add build subdir
204 if os.path.abspath( self.src_dir ) == os.path.abspath( self.build_dir ):
205 self.build_dir = os.path.join( self.build_dir, 'build' )
207 ###############################################################################
211 ## pretext = text which immediately follows 'probe:' output prefix
212 ## abort = if true configure will exit on probe fail
213 ## head = if true probe session is stripped of all but first line
214 ## session = output from command, including stderr
215 ## fail = true if probe failed
217 class Action( object ):
220 def __init__( self, category, pretext='unknown', abort=False, head=False ):
221 if self not in Action.actions:
222 Action.actions.append( self )
224 self.category = category
225 self.pretext = pretext
230 self.run_done = False
232 self.msg_fail = 'fail'
233 self.msg_pass = 'pass'
236 def _actionBegin( self ):
237 cfg.infof( '%s: %s...', self.category, self.pretext )
239 def _actionEnd( self ):
241 cfg.infof( '(%s) %s\n', self.msg_fail, self.msg_end )
243 self._dumpSession( cfg.infof )
244 cfg.errln( 'unable to continue' )
245 self._dumpSession( cfg.verbosef )
247 cfg.infof( '(%s) %s\n', self.msg_pass, self.msg_end )
248 self._dumpSession( cfg.verbosef )
250 def _dumpSession( self, printf ):
251 if self.session and len(self.session):
252 for line in self.session:
253 printf( ' : %s\n', line )
255 printf( ' : <NO-OUTPUT>\n' )
257 def _parseSession( self ):
270 ###############################################################################
272 ## base probe: anything which runs in shell.
274 ## pretext = text which immediately follows 'probe:' output prefix
275 ## command = full command and arguments to pipe
276 ## abort = if true configure will exit on probe fail
277 ## head = if true probe session is stripped of all but first line
278 ## session = output from command, including stderr
279 ## fail = true if probe failed
281 class ShellProbe( Action ):
282 def __init__( self, pretext, command, abort=False, head=False ):
283 super( ShellProbe, self ).__init__( 'probe', pretext, abort, head )
284 self.command = command
287 ## pipe and redirect stderr to stdout; effects communicate result
288 pipe = subprocess.Popen( self.command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
290 ## read data into memory buffers, only first element (stdout) data is used
291 data = pipe.communicate()
292 self.fail = pipe.returncode != 0
295 self.session = data[0].splitlines()
300 self.msg_end = 'code %d' % (pipe.returncode)
302 def _dumpSession( self, printf ):
303 printf( ' + %s\n', self.command )
304 super( ShellProbe, self )._dumpSession( printf )
306 ###############################################################################
308 ## GNU host tuple probe: determine canonical platform type
310 ## example results from various platforms:
312 ## i386-apple-darwin9.6.0 (Mac OS X 10.5.6 Intel)
313 ## powerpc-apple-darwin9.6.0 (Mac OS X 10.5.6 PPC)
314 ## i686-pc-cygwin (Cygwin, Microsoft Vista)
315 ## x86_64-unknown-linux-gnu (Linux, Fedora 10 x86_64)
317 class HostTupleProbe( ShellProbe, list ):
318 GNU_TUPLE_RX = '([^-]+)-([^-]+)-([^0-9-]+)([^-]*)-?([^-]*)'
320 def __init__( self ):
321 super( HostTupleProbe, self ).__init__( 'host tuple', '%s/config.guess' % (cfg.dir), abort=True, head=True )
323 def _parseSession( self ):
324 if len(self.session):
325 self.spec = self.session[0]
329 ## grok GNU host tuples
330 m = re.match( HostTupleProbe.GNU_TUPLE_RX, self.spec )
333 self.msg_end = 'invalid host tuple: %s' % (self.spec)
336 self.msg_end = self.spec
338 ## assign tuple from regex
342 self.machine = self[0]
343 self.vendor = self[1]
344 self.system = self[2]
345 self.release = self[3]
348 ## nice formal name for 'system'
349 self.systemf = platform.system()
351 if self.match( '*-*-cygwin*' ):
352 self.systemf = self[2][0].upper() + self[2][1:]
354 ## glob-match against spec
355 def match( self, spec ):
356 return fnmatch.fnmatch( self.spec, spec )
358 ###############################################################################
360 class BuildAction( Action, list ):
361 def __init__( self ):
362 super( BuildAction, self ).__init__( 'compute', 'build tuple', abort=True )
365 self.spec = arch.mode[arch.mode.mode]
367 ## grok GNU host tuples
368 m = re.match( HostTupleProbe.GNU_TUPLE_RX, self.spec )
370 self.msg_end = 'invalid host tuple: %s' % (self.spec)
373 self.msg_end = self.spec
375 ## assign tuple from regex
379 self.machine = self[0]
380 self.vendor = self[1]
381 self.system = self[2]
382 self.release = self[3]
384 self.systemf = host.systemf
388 ###############################################################################
390 ## platform conditional string; if specs do not match host:
392 ## - str value is blank
393 ## - evaluates to False
395 class IfHost( object ):
396 def __init__( self, value, *specs ):
399 if host.match( spec ):
403 def __nonzero__( self ):
404 return len(self.value) != 0
409 ###############################################################################
411 ## platform conditional value; loops through list of tuples comparing
412 ## to first host match and sets value accordingly; the first value is
415 class ForHost( object ):
416 def __init__( self, default, *tuples ):
419 if host.match( tuple[1] ):
420 self.value = tuple[0]
426 ###############################################################################
428 class ArchAction( Action ):
429 def __init__( self ):
430 super( ArchAction, self ).__init__( 'compute', 'available architectures', abort=True )
431 self.mode = SelectMode( 'architecture', (host.machine,host.spec) )
436 ## some match on system should be made here; otherwise we signal a warning.
437 if host.match( '*-*-cygwin*' ):
439 elif host.match( '*-*-darwin*' ):
440 self.mode['i386'] = 'i386-apple-darwin%s' % (host.release)
441 self.mode['x86_64'] = 'x86_64-apple-darwin%s' % (host.release)
442 self.mode['ppc'] = 'powerpc-apple-darwin%s' % (host.release)
443 self.mode['ppc64'] = 'powerpc64-apple-darwin%s' % (host.release)
444 elif host.match( '*-*-linux*' ):
447 self.msg_pass = 'WARNING'
449 self.msg_end = self.mode.toString()
451 ## glob-match against spec
452 def match( self, spec ):
453 return fnmatch.fnmatch( self.spec, spec )
455 ###############################################################################
457 class CoreProbe( Action ):
458 def __init__( self ):
459 super( CoreProbe, self ).__init__( 'probe', 'number of CPU cores' )
464 ## good for darwin9.6.0 and linux
466 self.count = os.sysconf( 'SC_NPROCESSORS_ONLN' )
476 self.count = int( os.environ['NUMBER_OF_PROCESSORS'] )
486 elif self.count > 32:
490 if options.launch_jobs == 0:
491 self.jobs = core.count
493 self.jobs = options.launch_jobs
495 self.jobs = core.count
497 self.msg_end = str(self.count)
499 ###############################################################################
501 class SelectMode( dict ):
502 def __init__( self, descr, *modes, **kwargs ):
503 super( SelectMode, self ).__init__( modes )
506 self.default = kwargs.get('default',modes[0][0])
507 self.mode = self.default
509 def cli_add_option( self, parser, option ):
510 parser.add_option( '', option, default=self.mode, metavar='MODE',
511 help='select %s mode: %s' % (self.descr,self.toString()),
512 action='callback', callback=self.cli_callback, type='str' )
514 def cli_callback( self, option, opt_str, value, parser, *args, **kwargs ):
515 if value not in self:
516 raise optparse.OptionValueError( 'invalid %s mode: %s (choose from %s)'
517 % (self.descr,value,self.toString( True )) )
520 def toString( self, nodefault=False ):
526 value = ' '.join( keys )
528 value = '%s [%s]' % (' '.join( keys ), self.mode )
531 ###############################################################################
533 ## Repository object.
534 ## Holds information gleaned from subversion working dir.
536 ## Builds are classed into one of the following types:
539 ## must be built from official svn with '/tags/' in the url
541 ## must be built from official svn but is not a release
545 class RepoProbe( ShellProbe ):
546 def __init__( self ):
547 super( RepoProbe, self ).__init__( 'svn info', 'svn info %s' % (cfg.src_dir) )
549 self.url = 'svn://nowhere.com/project/unknown'
550 self.root = 'svn://nowhere.com/project'
551 self.branch = 'unknown'
552 self.uuid = '00000000-0000-0000-0000-000000000000';
554 self.date = '0000-00-00 00:00:00 -0000'
556 self.type = 'unofficial'
558 def _parseSession( self ):
559 for line in self.session:
561 m = re.match( '([^:]+):\\s+(.+)', line )
565 (name,value) = m.groups()
568 elif name == 'Repository Root':
570 elif name == 'Repository UUID':
572 elif name == 'Revision':
573 self.rev = int( value )
574 elif name == 'Last Changed Date':
575 # strip chars in parens
576 if value.find( ' (' ):
577 self.date = value[0:value.find(' (')]
582 i = self.url.rfind( '/' )
583 if i != -1 and i < len(self.url)-1:
584 self.branch = self.url[i+1:]
586 # type-classification via repository UUID
587 if self.uuid == 'b64f7644-9d1e-0410-96f1-a4d463321fa5':
589 m = re.match( '([^:]+)://([^/]+)/(.+)', self.url )
590 if m and re.match( 'tags/', m.group( 3 )):
591 self.type = 'release'
593 self.type = 'developer'
595 self.msg_end = self.url
597 ###############################################################################
601 ## Contains manually updated version numbers consistent with HB releases
602 ## and other project metadata.
604 class Project( Action ):
605 def __init__( self ):
606 super( Project, self ).__init__( 'compute', 'project data' )
608 self.name = 'HandBrake'
609 self.acro_lower = 'hb'
610 self.acro_upper = 'HB'
611 self.url_website = 'http://handbrake.fr'
612 self.url_community = 'http://forum.handbrake.fr'
613 self.url_irc = 'irc://irc.freenode.net/handbrake'
615 self.name_lower = self.name.lower()
616 self.name_upper = self.name.upper()
623 appcastfmt = 'http://handbrake.fr/appcast%s.xml'
625 if repo.type == 'release':
626 self.version = '%d.%d.%d' % (self.vmajor,self.vminor,self.vpoint)
627 self.url_appcast = appcastfmt % ('')
628 self.build = time.strftime('%Y%m%d') + '00'
629 self.title = '%s %s (%s)' % (self.name,self.version,self.build)
630 elif repo.type == 'developer':
631 self.version = 'svn%d' % (repo.rev)
632 self.url_appcast = appcastfmt % ('_unstable')
633 self.build = time.strftime('%Y%m%d') + '01'
634 self.title = '%s svn%d (%s)' % (self.name,repo.rev,self.build)
636 self.version = 'svn%d' % (repo.rev)
637 self.url_appcast = appcastfmt % ('_unofficial')
638 self.build = time.strftime('%Y%m%d') + '99'
639 self.title = 'Unofficial svn%d (%s)' % (repo.rev,self.build)
641 self.msg_end = '%s (%s)' % (self.name,repo.type)
644 ###############################################################################
646 class ToolProbe( Action ):
649 def __init__( self, var, *names, **kwargs ):
650 super( ToolProbe, self ).__init__( 'find', abort=kwargs.get('abort',True) )
651 if not self in ToolProbe.tools:
652 ToolProbe.tools.append( self )
658 self.names.append( str(name) )
659 self.name = self.names[0]
660 self.pretext = self.name
661 self.pathname = self.names[0]
665 for i,name in enumerate(self.names):
666 self.session.append( 'name[%d] = %s' % (i,name) )
667 for name in self.names:
668 f = cfg.findExecutable( name )
675 self.msg_end = 'not found'
677 def cli_add_option( self, parser ):
678 parser.add_option( '', '--'+self.name, metavar='PROG',
679 help='[%s]' % (self.pathname),
680 action='callback', callback=self.cli_callback, type='str' )
682 def cli_callback( self, option, opt_str, value, parser, *args, **kwargs ):
683 self.__init__( self.var, value, **self.kwargs )
686 def doc_add( self, doc ):
687 doc.add( self.var, self.pathname )
689 ###############################################################################
691 class SelectTool( Action ):
694 def __init__( self, var, name, *pool, **kwargs ):
695 super( SelectTool, self ).__init__( 'select', abort=kwargs.get('abort',True) )
697 if not self in SelectTool.selects:
698 SelectTool.selects.append( self )
706 for i,(name,tool) in enumerate(self.pool):
707 self.session.append( 'tool[%d] = %s (%s)' % (i,name,tool.pathname) )
708 for (name,tool) in self.pool:
712 self.msg_end = '%s (%s)' % (name,tool.pathname)
715 self.msg_end = 'not found'
717 def cli_add_option( self, parser ):
718 parser.add_option( '', '--'+self.name, metavar='MODE',
719 help='select %s mode: %s' % (self.name,self.toString()),
720 action='callback', callback=self.cli_callback, type='str' )
722 def cli_callback( self, option, opt_str, value, parser, *args, **kwargs ):
724 for (name,tool) in self.pool:
727 self.__init__( self.var, self.name, [name,tool], **kwargs )
731 raise optparse.OptionValueError( 'invalid %s mode: %s (choose from %s)'
732 % (self.name,value,self.toString( True )) )
734 def doc_add( self, doc ):
735 doc.add( self.var, self.selected )
737 def toString( self, nodefault=False ):
738 if len(self.pool) == 1:
739 value = self.pool[0][0]
742 for key,value in self.pool:
747 value = '%s [%s]' % (s[1:], self.selected )
750 ###############################################################################
752 ## config object used to output gnu-make or gnu-m4 output.
754 ## - add() to add NAME/VALUE pairs suitable for both make/m4.
755 ## - addBlank() to add a linefeed for both make/m4.
756 ## - addMake() to add a make-specific line.
757 ## - addM4() to add a m4-specific line.
759 class ConfigDocument:
760 def __init__( self ):
763 def _outputMake( self, file, namelen, name, value ):
764 file.write( '%-*s = %s\n' % (namelen, name, value ))
766 def _outputM4( self, file, namelen, name, value ):
768 name = '<<__%s>>,' % name.replace( '.', '_' )
769 file.write( 'define(%-*s <<%s>>)dnl\n' % (namelen, name, value ))
771 def add( self, name, value ):
772 self._elements.append( (name,value) )
774 def addBlank( self ):
775 self._elements.append( None )
777 def addComment( self, format, *args ):
778 self.addMake( '## ' + format % args )
779 self.addM4( 'dnl ' + format % args )
781 def addMake( self, line ):
782 self._elements.append( ('?make',line) )
784 def addM4( self, line ):
785 self._elements.append( ('?m4',line) )
787 def output( self, file, type ):
789 for item in self._elements:
790 if item == None or item[0].find( '?' ) == 0:
792 if len(item[0]) > namelen:
793 namelen = len(item[0])
794 for item in self._elements:
797 file.write( 'dnl\n' )
801 if item[0].find( '?' ) == 0:
802 if item[0].find( type, 1 ) == 1:
803 file.write( '%s\n' % (item[1]) )
807 self._outputM4( file, namelen, item[0], item[1] )
809 self._outputMake( file, namelen, item[0], item[1] )
811 def write( self, type ):
813 fname = 'GNUmakefile'
815 fname = os.path.join( 'project', project.name_lower + '.m4' )
817 raise ValueError, 'unknown file type: ' + type
819 ftmp = fname + '.tmp'
822 file = cfg.open( ftmp, 'w' )
823 self.output( file, type )
834 cfg.errln( 'failed writing to %s\n%s', ftmp, x )
837 os.rename( ftmp, fname )
839 cfg.errln( 'failed writing to %s\n%s', fname, x )
841 ###############################################################################
846 cli = OptionParser( 'usage: %prog [OPTIONS...] [TARGETS...]' )
849 cli.description += 'Configure %s build system.' % (project.name)
851 ## add hidden options
852 cli.add_option( '', '--conf-method', default='terminal', action='store', help=optparse.SUPPRESS_HELP )
853 cli.add_option( '', '--force', default=False, action='store_true', help='overwrite existing build config' )
854 cli.add_option( '', '--verbose', default=False, action='store_true', help='increase verbosity' )
856 ## add install options
857 grp = OptionGroup( cli, 'Directory Locations' )
858 grp.add_option( '', '--src', default=cfg.src_dir, action='store', metavar='DIR',
859 help='specify top-level source dir [%s]' % (cfg.src_dir) )
860 grp.add_option( '', '--build', default=cfg.build_dir, action='store', metavar='DIR',
861 help='specify build scratch/output dir [%s]' % (cfg.build_dir) )
862 grp.add_option( '', '--prefix', default=cfg.prefix_dir, action='store', metavar='DIR',
863 help='specify install dir for products [%s]' % (cfg.prefix_dir) )
864 cli.add_option_group( grp )
866 ## add feature options
867 grp = OptionGroup( cli, 'Feature Options' )
868 h = ForHost( optparse.SUPPRESS_HELP, ['disable Xcode (Darwin only)','*-*-darwin*'] ).value
869 grp.add_option( '', '--disable-xcode', default=False, action='store_true', help=h )
870 h = ForHost( optparse.SUPPRESS_HELP, ['disable GTK GUI (Linux only)','*-*-linux*'] ).value
871 grp.add_option( '', '--disable-gtk', default=False, action='store_true', help=h )
872 cli.add_option_group( grp )
874 ## add launch options
875 grp = OptionGroup( cli, 'Launch Options' )
876 grp.add_option( '', '--launch', default=False, action='store_true',
877 help='launch build, capture log and wait for completion' )
878 grp.add_option( '', '--launch-jobs', default=1, action='store', metavar='N', type='int',
879 help='allow N jobs at once; 0 to match CPU count [1]' )
880 grp.add_option( '', '--launch-args', default=None, action='store', metavar='ARGS',
881 help='specify additional ARGS for launch command' )
882 grp.add_option( '', '--launch-quiet', default=False, action='store_true',
883 help='do not echo build output' )
884 cli.add_option_group( grp )
886 ## add compile options
887 grp = OptionGroup( cli, 'Compiler Options' )
888 debugMode.cli_add_option( grp, '--debug' )
889 optimizeMode.cli_add_option( grp, '--optimize' )
890 arch.mode.cli_add_option( grp, '--arch' )
891 cli.add_option_group( grp )
893 ## add tool locations
894 grp = OptionGroup( cli, 'Tool Basenames and Locations' )
895 for tool in ToolProbe.tools:
896 tool.cli_add_option( grp )
897 cli.add_option_group( grp )
900 grp = OptionGroup( cli, 'Tool Options' )
901 for select in SelectTool.selects:
902 select.cli_add_option( grp )
903 cli.add_option_group( grp )
906 ###############################################################################
908 ## launcher - used for QuickStart method; launch; build and capture log.
911 def __init__( self, targets ):
913 self._file = cfg.open( 'log/build.txt', 'w' )
915 cmd = '%s -j%d' % (Tools.gmake.pathname,core.jobs)
916 if options.launch_args:
917 cmd += ' ' + options.launch_args
919 cmd += ' ' + ' '.join(targets)
922 timeBegin = time.time()
923 self.infof( 'time begin: %s\n', time.asctime() )
924 self.infof( 'launch: %s\n', cmd )
925 if options.launch_quiet:
926 stdout.write( 'building to %s ...\n' % (os.path.abspath( cfg.build_final )))
928 stdout.write( '%s\n' % ('-' * 79) )
932 pipe = subprocess.Popen( cmd, shell=True, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
934 cfg.errln( 'launch failure: %s', x )
935 for line in pipe.stdout:
936 self.echof( '%s', line )
940 timeEnd = time.time()
941 elapsed = timeEnd - timeBegin
944 result = 'FAILURE (code %d)' % pipe.returncode
948 ## present duration in decent format
950 hours = int(seconds / 3600)
951 seconds -= hours * 3600
952 minutes = int(seconds / 60)
953 seconds -= minutes * 60
959 segs.append( '%d hour' % hours )
961 segs.append( '%d hours' % hours )
963 if len(segs) or minutes == 1:
964 segs.append( '%d minute' % minutes )
965 elif len(segs) or minutes > 1:
966 segs.append( '%d minutes' % minutes )
969 segs.append( '%d second' % seconds )
971 segs.append( '%d seconds' % seconds )
973 if not options.launch_quiet:
974 stdout.write( '%s\n' % ('-' * 79) )
975 self.infof( 'time end: %s\n', time.asctime() )
976 self.infof( 'duration: %s (%.2fs)\n', ', '.join(segs), elapsed )
977 self.infof( 'result: %s\n', result )
982 def echof( self, format, *args ):
984 self._file.write( line )
985 if not options.launch_quiet:
986 stdout.write( ' : %s' % line )
989 def infof( self, format, *args ):
991 self._file.write( line )
992 cfg.infof( '%s', line )
994 ###############################################################################
999 ## we need to pre-check argv for -h or --help or --verbose to deal with
1000 ## initializing Configure correctly.
1001 verbose = Configure.OUT_INFO
1002 for arg in sys.argv:
1003 if arg == '-h' or arg == '--help':
1004 verbose = Configure.OUT_QUIET
1006 if arg == '--verbose':
1007 verbose = Configure.OUT_VERBOSE
1009 ## create main objects; actions/probes run() is delayed.
1010 ## if any actions must be run earlier (eg: for configure --help purposes)
1011 ## then run() must be invoked earlier. subequent run() invocations
1013 cfg = Configure( verbose )
1014 host = HostTupleProbe(); host.run()
1016 cfg.prefix_dir = ForHost( '/usr/local', ['/Applications','*-*-darwin*'] ).value
1018 build = BuildAction()
1019 arch = ArchAction(); arch.run()
1021 ## create remaining main objects
1026 ## create tools in a scope
1028 ar = ToolProbe( 'AR.exe', 'ar' )
1029 cp = ToolProbe( 'CP.exe', 'cp' )
1030 curl = ToolProbe( 'CURL.exe', 'curl', abort=False )
1031 gcc = ToolProbe( 'GCC.gcc', 'gcc', IfHost('gcc-4','*-*-cygwin*') )
1033 if host.match( '*-*-darwin*' ):
1034 gmake = ToolProbe( 'GMAKE.exe', 'make', 'gmake' )
1036 gmake = ToolProbe( 'GMAKE.exe', 'gmake', 'make' )
1038 m4 = ToolProbe( 'M4.exe', 'm4' )
1039 mkdir = ToolProbe( 'MKDIR.exe', 'mkdir' )
1040 patch = ToolProbe( 'PATCH.exe', 'gpatch', 'patch' )
1041 rm = ToolProbe( 'RM.exe', 'rm' )
1042 tar = ToolProbe( 'TAR.exe', 'gtar', 'tar' )
1043 wget = ToolProbe( 'WGET.exe', 'wget', abort=False )
1045 xcodebuild = ToolProbe( 'XCODEBUILD.exe', 'xcodebuild', abort=False )
1046 lipo = ToolProbe( 'LIPO.exe', 'lipo', abort=False )
1048 fetch = SelectTool( 'FETCH.select', 'fetch', ['wget',wget], ['curl',curl] )
1051 for tool in ToolProbe.tools:
1053 for select in SelectTool.selects:
1056 debugMode = SelectMode( 'debug', ('none','none'), ('min','min'), ('std','std'), ('max','max') )
1057 optimizeMode = SelectMode( 'optimize', ('none','none'), ('speed','speed'), ('size','size'), default='speed' )
1059 ## create CLI and parse
1061 (options,args) = cli.parse_args()
1063 ## update cfg with cli directory locations
1064 cfg.update_cli( options )
1066 ## prepare list of targets and NAME=VALUE args to pass to make
1069 rx_exports = re.compile( '([^=]+)=(.*)' )
1071 m = rx_exports.match( arg )
1073 exports.append( m.groups() )
1075 targets.append( arg )
1077 ## run delayed actions
1078 for action in Action.actions:
1081 ## cfg hook before doc prep
1084 ## create document object
1085 doc = ConfigDocument()
1086 doc.addComment( 'generated by configure on %s', time.strftime( '%c' ))
1088 ## add configure line for reconfigure purposes
1091 for arg in sys.argv[1:]:
1092 if arg == '--launch':
1095 doc.add( 'CONF.args', ' '.join( args ))
1098 doc.add( 'HB.title', project.title )
1099 doc.add( 'HB.name', project.name )
1100 doc.add( 'HB.name.lower', project.name_lower )
1101 doc.add( 'HB.name.upper', project.name_upper )
1102 doc.add( 'HB.acro.lower', project.acro_lower )
1103 doc.add( 'HB.acro.upper', project.acro_upper )
1105 doc.add( 'HB.url.website', project.url_website )
1106 doc.add( 'HB.url.community', project.url_community )
1107 doc.add( 'HB.url.irc', project.url_irc )
1108 doc.add( 'HB.url.appcast', project.url_appcast )
1110 doc.add( 'HB.version.major', project.vmajor )
1111 doc.add( 'HB.version.minor', project.vminor )
1112 doc.add( 'HB.version.point', project.vpoint )
1113 doc.add( 'HB.version', project.version )
1114 doc.add( 'HB.version.hex', '%04x%02x%02x%08x' % (project.vmajor,project.vminor,project.vpoint,repo.rev) )
1116 doc.add( 'HB.build', project.build )
1118 doc.add( 'HB.repo.url', repo.url )
1119 doc.add( 'HB.repo.root', repo.root )
1120 doc.add( 'HB.repo.branch', repo.branch )
1121 doc.add( 'HB.repo.uuid', repo.uuid )
1122 doc.add( 'HB.repo.rev', repo.rev )
1123 doc.add( 'HB.repo.date', repo.date )
1124 doc.add( 'HB.repo.official', repo.official )
1125 doc.add( 'HB.repo.type', repo.type )
1128 doc.add( 'HOST.spec', host.spec )
1129 doc.add( 'HOST.machine', host.machine )
1130 doc.add( 'HOST.vendor', host.vendor )
1131 doc.add( 'HOST.system', host.system )
1132 doc.add( 'HOST.systemf', host.systemf )
1133 doc.add( 'HOST.release', host.release )
1134 doc.add( 'HOST.extra', host.extra )
1135 doc.add( 'HOST.title', '%s %s' % (host.systemf,arch.mode.default) )
1136 doc.add( 'HOST.ncpu', core.count )
1139 doc.add( 'BUILD.spec', build.spec )
1140 doc.add( 'BUILD.machine', build.machine )
1141 doc.add( 'BUILD.vendor', build.vendor )
1142 doc.add( 'BUILD.system', build.system )
1143 doc.add( 'BUILD.systemf', build.systemf )
1144 doc.add( 'BUILD.release', build.release )
1145 doc.add( 'BUILD.extra', build.extra )
1146 doc.add( 'BUILD.title', '%s %s' % (build.systemf,arch.mode.mode) )
1147 doc.add( 'BUILD.ncpu', core.count )
1148 doc.add( 'BUILD.jobs', core.jobs )
1150 doc.add( 'BUILD.cross', int(arch.mode.mode != arch.mode.default) )
1151 doc.add( 'BUILD.method', 'terminal' )
1152 doc.add( 'BUILD.date', time.strftime('%c') )
1153 doc.add( 'BUILD.arch', arch.mode.mode )
1156 doc.add( 'CONF.method', options.conf_method )
1159 doc.add( 'SRC', cfg.src_final )
1160 doc.add( 'SRC/', cfg.src_final + os.sep )
1161 doc.add( 'BUILD', cfg.build_final )
1162 doc.add( 'BUILD/', cfg.build_final + os.sep )
1163 doc.add( 'PREFIX', cfg.prefix_final )
1164 doc.add( 'PREFIX/', cfg.prefix_final + os.sep )
1167 doc.add( 'FEATURE.xcode', int( not (Tools.xcodebuild.fail or options.disable_xcode) ))
1168 doc.add( 'FEATURE.gtk', int( not options.disable_gtk ))
1170 if not Tools.xcodebuild.fail and not options.disable_xcode:
1172 doc.add( 'XCODE.external.src', cfg.xcode_x_src )
1173 doc.add( 'XCODE.external.build', cfg.xcode_x_build )
1174 doc.add( 'XCODE.external.prefix', cfg.xcode_x_prefix )
1177 doc.addMake( '## include definitions' )
1178 doc.addMake( 'include $(SRC/)make/include/main.defs' )
1181 for tool in ToolProbe.tools:
1185 for select in SelectTool.selects:
1186 select.doc_add( doc )
1189 if arch.mode.mode != arch.mode.default:
1190 doc.add( 'GCC.archs', arch.mode.mode )
1192 doc.add( 'GCC.archs', '' )
1193 doc.add( 'GCC.g', debugMode.mode )
1194 doc.add( 'GCC.O', optimizeMode.mode )
1196 ## add exports to make
1199 doc.addComment( 'overrides via VARIABLE=VALUE on command-line' )
1201 doc.add( nv[0], nv[1] )
1204 doc.addMake( '## include custom definitions' )
1205 doc.addMake( '-include $(SRC/)custom.defs' )
1206 doc.addMake( '-include $(BUILD/)GNUmakefile.custom.defs' )
1209 doc.addMake( '## include rules' )
1210 doc.addMake( 'include $(SRC/)make/include/main.rules' )
1211 doc.addMake( '-include $(SRC/)custom.rules' )
1212 doc.addMake( '-include $(BUILD/)GNUmakefile.custom.rules' )
1225 if os.path.normpath( cfg.build_dir ) == os.curdir:
1230 stdout.write( '%s\n' % ('-' * 79) )
1232 stdout.write( 'Build is finished!\n' )
1234 stdout.write( 'You may now examine the output.\n' )
1236 stdout.write( 'You may now cd into %s and examine the output.\n' % (cfg.build_dir) )
1238 stdout.write( 'Build is configured!\n' )
1240 stdout.write( 'You may now run make (%s).\n' % (Tools.gmake.pathname) )
1242 stdout.write( 'You may now cd into %s and run make (%s).\n' % (cfg.build_dir,Tools.gmake.pathname) )
1244 except AbortError, x:
1245 stderr.write( 'ERROR: %s\n' % (x) )