summaryrefslogtreecommitdiffstats
path: root/make
diff options
context:
space:
mode:
authorkonablend <[email protected]>2009-03-01 17:03:11 +0000
committerkonablend <[email protected]>2009-03-01 17:03:11 +0000
commit4dbce6b69967c1e14092637aa95b6c31855a81fc (patch)
tree516c17095967698eeb419c70ce72dbd2c11bf754 /make
parentc47939541ccec1e5e57753b16b28baed2613f586 (diff)
BuildSystem: conversion from jam-based to make-based system.
KNOWN ISSUES: 1. OSX + Xcode builds do not support parallel builds; attempting to use them may cause unbounded number of jobs. However, disabling via configure --disable-xcode avoids the issue. 2. OSX ppc binary produces binary which has audio-scan problems. 3. OSX ppc64 binary has not been runtime tested. ADDED: 00-BuildUserGuide.txt contrib/*/module.* doc/ make/ libhb/module.* test/module.* macos/module.* gtk/module.* DROPPED: BUILD BuildContribDarwin.sh DownloadMacOsXContribBinaries.sh Jamfile Jamrules MacOsXContribBinariesVersion.txt Makefile Makefile.config jam libhb/Jamefile libhb/Makefile test/BUILDSHARED test/Makefile contrib/Jamfile contrib/Makefile contrib/patch-ffmpeg.patch contrib/patch-x264-idr.patch contrib/patch-x264-linux.patch RENAMED: contrib/*.patch -> contrib/MODULE/[AP]??-*.patch macosx/HandBrake.plist -> macosx/Info.plist MODIFIED: libhb/decavcodec.c Patched to use cleaner include "libavcodec/audioconvert". Second part to support this cleanup is ffmpeg A02-audioconvert.patch . MODIFIED: libhb/hb.c MODIFIED: libhb/hb.h MODIFIED: libhb/muxmkv.c MODIFIED: libhb/muxmp4.c MODIFIED: libhb/update.c Patched to use "project.h" for project metadata. Renamed HB_BUILD -> HB_PROJECT_BUILD. Renamed HB_VERSION -> HB_PROJECT_VERSION. MODIFIED: test/test.c: Patched HandBrakeCLI to support I/O on Mac OS X ZFS filesystems. Reference r1803 as similar patch for HandBrake.app . Unpatched behavior is crash/buserror when using ZFS. MODIFIED: macosx/Growl.framework/ Upgraded 0.7.6 (i386,ppc) -> 1.1.2 (i386,x86_64,ppc,ppc64). New architectures facilitate x86_64 and ppc64 builds. MODIFIED: macosx/HandBrake.xcodeproj/ Bumped compatibilty mode from 2.4 -> 3.1 . Dumped old configurations Deployment, Developer. Added configurations standard, sebug as replacements. Added standard.i386, standard.x86_64, standard.ppc, standard.ppc64 . for explicit architecture build. All configurations settings cleaned up and normalized. Build output directories adjusted to support new build system. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2180 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'make')
-rw-r--r--make/configure.py752
-rw-r--r--make/include/base.defs50
-rw-r--r--make/include/contrib.defs276
-rw-r--r--make/include/function.defs19
-rw-r--r--make/include/gcc.defs146
-rw-r--r--make/include/main.defs75
-rw-r--r--make/include/main.rules39
-rw-r--r--make/include/report.defs53
-rw-r--r--make/include/select.defs12
-rw-r--r--make/include/target.defs14
-rw-r--r--make/include/tool.defs10
-rw-r--r--make/variant/cygwin.defs8
-rw-r--r--make/variant/darwin.defs61
-rw-r--r--make/variant/darwin.rules20
-rw-r--r--make/variant/darwin.x86_64.defs3
-rw-r--r--make/variant/freebsd.defs4
-rw-r--r--make/variant/linux.defs11
17 files changed, 1553 insertions, 0 deletions
diff --git a/make/configure.py b/make/configure.py
new file mode 100644
index 000000000..1aa85bd39
--- /dev/null
+++ b/make/configure.py
@@ -0,0 +1,752 @@
+import fnmatch
+import optparse
+import os
+import platform
+import re
+import subprocess
+import sys
+import time
+
+from optparse import OptionGroup
+from optparse import OptionGroup
+from optparse import OptionParser
+from sys import stderr
+from sys import stdout
+
+###############################################################################
+
+def errf( format, *args ):
+ stderr.write( ('ERROR: ' + format + '\n') % args )
+ sys.exit( 1 )
+
+def outf( format, *args ):
+ stdout.write( (format + '\n') % args )
+
+###############################################################################
+
+## Expand values of iterable object into a decent string representation.
+##
+def expandValues( obj ):
+ buf = ''
+ for v in obj:
+ buf += ', ' + v
+ return '{ ' + buf[2:] + ' }'
+
+###############################################################################
+
+## Find executable by searching path.
+## On success, returns full pathname of executable.
+## On fail, returns None.
+##
+def findExecutable( name ):
+ if len( os.path.split(name)[0] ):
+ return name if os.access( name, os.X_OK ) else None
+
+ if not os.environ.has_key( 'PATH' ) or os.environ[ 'PATH' ] == '':
+ path = os.defpath
+ else:
+ path = os.environ['PATH']
+
+ for dir in path.split( os.pathsep ):
+ f = os.path.join( dir, name )
+ if os.access( f, os.X_OK ):
+ return f
+ return None
+
+###############################################################################
+
+def computeDefaultMakeJobs():
+ ## good for darwin9.6.0 and linux
+ try:
+ n = os.sysconf( 'SC_NPROCESSORS_ONLN' )
+ if n < 1:
+ n = 1
+ return n
+ except:
+ pass
+ ## windows
+ try:
+ n = int( os.environ['NUMBER_OF_PROCESSORS'] )
+ if n < 1:
+ n = 1
+ return n
+ except:
+ pass
+ return 1
+
+###############################################################################
+
+## taken from python2.6 -- we need it
+def relpath(path, start=os.path.curdir):
+ """Return a relative version of a path"""
+
+ if not path:
+ raise ValueError("no path specified")
+
+ start_list = os.path.abspath(start).split(os.sep)
+ path_list = os.path.abspath(path).split(os.sep)
+
+ # Work out how much of the filepath is shared by start and path.
+ i = len(os.path.commonprefix([start_list, path_list]))
+
+ rel_list = [os.pardir] * (len(start_list)-i) + path_list[i:]
+ if not rel_list:
+ return os.path.curdir
+ return os.path.join(*rel_list)
+
+###############################################################################
+
+# compute project dir which should be 2 dirs below this script
+build_dir = os.curdir
+project_dir = os.path.normpath( sys.argv[0] )
+for i in range( 2 ):
+ project_dir = os.path.dirname( project_dir )
+if len( project_dir ) == 0:
+ project_dir = os.curdir
+
+###############################################################################
+
+## model gnu-autotools platform guess
+##
+## native format:
+## (PROC)-(VENDOR)-(SYSTEM)(RELEASE)-(EXTRA)
+##
+## examples:
+## i386-apple-darwin9.6.0 (Mac OS X 10.5.6 Intel)
+## powerpc-apple-darwin9.6.0 (Mac OS X 10.5.6 PPC)
+## i686-pc-cygwin (Cygwin, Microsoft Vista)
+## x86_64-unknown-linux-gnu (Linux, Fedora 10 x86_64)
+##
+class Guess:
+ def __init__( self ):
+ self.proc = 'unknown'
+ self.vendor = 'unknown'
+ self.system = 'unknown'
+ self.release = '0.0.0'
+ self.extra = ''
+
+ p_system = platform.system().lower()
+ p_release = platform.release().lower()
+ p_processor = platform.processor().lower()
+ p_machine = platform.machine().lower()
+
+ if re.match( 'cygwin', p_system ):
+ self.proc = p_machine
+ self.vendor = 'pc'
+ self.system = 'cygwin'
+ self.release = ''
+ self.extra = ''
+ elif re.match( 'darwin', p_system ):
+ self.proc = p_machine
+ self.vendor = 'apple'
+ self.system = p_system
+ self.release = p_release
+ self.extra = ''
+ elif re.match( 'linux', p_system ):
+ self.proc = p_machine
+ self.vendor = 'unknown'
+ self.system = p_system
+ self.release = ''
+ self.extra = 'gnu'
+ else:
+ errf( 'unrecognized host system: %s', p_system )
+
+ def __str__( self ):
+ if len(self.extra):
+ return '%s-%s-%s%s-%s' % (self.proc,self.vendor,self.system,self.release,self.extra)
+ else:
+ return '%s-%s-%s%s' % (self.proc,self.vendor,self.system,self.release)
+
+ def match( self, spec ):
+ return fnmatch.fnmatch( str(self), spec )
+
+###############################################################################
+
+# a tool represents a command-line tool which may be searched for in PATH
+class Tool:
+ def __init__( self, parent, optional, var, *pool ):
+ self.name = pool[0]
+ self.optional = optional
+ self.var = var
+ self.pool = pool
+ self.found = None
+ if parent:
+ parent.register( self )
+
+ def addToConfig( self, config ):
+ config.add( self.var, self.found )
+
+ def addToGroup( self, group ):
+ group.add_option( '', '--' + self.name, help='specify %s location' % (self.name), default=None, metavar='EXE' )
+
+ def locate( self, options ):
+ spec = options.__dict__[self.name]
+ pool = self.pool if not spec else [spec]
+ for p in pool:
+ self.found = findExecutable( p )
+ if self.found:
+ outf( 'located %s: %s', self.name, self.found )
+ return
+ if self.optional:
+ outf( 'missing: %s (optional)', self.name )
+ else:
+ errf( 'unable to locate tool: %s', self.name )
+
+## a select tool picks first found from a list of tools
+class SelectTool( Tool ):
+ def __init__( self, parent, var, name, *pool ):
+ self.var = var
+ self.name = name
+ self.pool = pool
+ self.found = None
+
+ self.poolMap = {}
+ for p in self.pool:
+ self.poolMap[p.name] = p
+ if parent:
+ parent.register( self )
+
+ def addToConfig( self, config ):
+ config.add( self.var, self.found )
+
+ def addToGroup( self, group ):
+ group.add_option( '', '--' + self.name, help='select %s mode: %s' % (self.name,expandValues(self.poolMap)),
+ default=self.name, metavar='MODE' )
+
+ def locate( self, options ):
+ spec = options.__dict__[self.name]
+ if spec in self.poolMap:
+ self.found = spec
+ return
+ for p in self.pool:
+ if p.found:
+ self.found = p.name
+ outf( 'selected %s: %s', self.name, self.found )
+ return
+ errf( 'require at least one location of: %s', expandValues( self.poolMap ))
+
+###############################################################################
+
+class ToolSet:
+ def __init__( self ):
+ self.items = []
+ Tool( self, False, 'AR.exe', 'ar' )
+ Tool( self, False, 'CP.exe', 'cp' )
+ Tool( self, True, 'CURL.exe', 'curl' )
+ Tool( self, False, 'GCC.gcc', 'gcc', 'gcc-4' )
+ Tool( self, False, 'M4.exe', 'm4' )
+ Tool( self, False, 'MKDIR.exe', 'mkdir' )
+ Tool( self, False, 'PATCH.exe', 'patch' )
+ Tool( self, False, 'RM.exe', 'rm' )
+ Tool( self, False, 'TAR.exe', 'tar' )
+ Tool( self, True, 'WGET.exe', 'wget' )
+
+ SelectTool( self, 'FETCH.select', 'fetch', self.wget, self.curl )
+
+ def register( self, item ):
+ self.__dict__[item.name] = item
+ self.items.append( item )
+
+###############################################################################
+
+class OptionMode( list ):
+ def __init__( self, default, *items ):
+ super( OptionMode, self ).__init__( items )
+ self.default = items[default]
+ self.mode = self.default
+
+ def __str__( self ):
+ return ' '.join( self ).replace( self.mode, '*'+self.mode )
+
+ def addToGroup( self, group, option, name ):
+ group.add_option( '', option, help='select %s mode: %s' % (name,self), default=self.mode, metavar='MODE' )
+
+ def setFromOption( self, name, mode ):
+ if mode not in self:
+ errf( 'invalid %s mode: %s', name, mode )
+ self.mode = mode
+
+###############################################################################
+
+## create singletons
+guessHost = Guess()
+guessBuild = Guess()
+
+makeTool = Tool( None, False, 'CONF.make', 'gmake', 'make' )
+tools = ToolSet()
+
+debugMode = OptionMode( 0, 'none', 'min', 'std', 'max' )
+optimizeMode = OptionMode( 1, 'none', 'speed', 'size' )
+
+## populate platform-specific architecture modes
+if guessHost.match( 'i386-*-darwin8.*' ):
+ archMode = OptionMode( 0, 'i386', 'ppc' )
+elif guessHost.match( 'powerpc-*-darwin8.*' ):
+ archMode = OptionMode( 1, 'i386', 'ppc' )
+elif guessHost.match( 'i386-*-darwin9.*' ):
+ archMode = OptionMode( 0, 'i386', 'x86_64', 'ppc', 'ppc64' )
+elif guessHost.match( 'powerpc-*-darwin9.*' ):
+ archMode = OptionMode( 2, 'i386', 'x86_64', 'ppc', 'ppc64' )
+else:
+ archMode = OptionMode( 0, guessHost.proc )
+
+## create parser
+parser = OptionParser( 'Usage: %prog' )
+
+group = OptionGroup( parser, 'Feature Options' )
+group.add_option( '', '--disable-xcode', default=False, action='store_true',
+ help='disable Xcode (Darwin only)' )
+group.add_option( '', '--disable-gtk', default=False, action='store_true',
+ help='disable GTK GUI (Linux only)' )
+parser.add_option_group( group )
+
+## add launch options
+group = OptionGroup( parser, 'Launch Options' )
+group.add_option( '', '--launch', default=False, action='store_true',
+ help='launch build, capture log and wait for completion' )
+group.add_option( '', '--launch-jobs', default=1, action='store', metavar='N',
+ help='allow N jobs at once; 0 to match CPU count (1)' )
+group.add_option( '', '--launch-args', default=None, action='store', metavar='ARGS',
+ help='specify additional ARGS for launch command' )
+group.add_option( '', '--launch-dir', default='build', action='store', metavar='DIR',
+ help='specify scratch DIR to use for build (build)' )
+group.add_option( '', '--launch-force', default=False, action='store_true',
+ help='force use of scratch directory even if exists' )
+group.add_option( '', '--launch-log', default='log.txt', action='store', metavar='FILE',
+ help='specify log FILE (log.txt)' )
+group.add_option( '', '--launch-quiet', default=False, action='store_true',
+ help='do not echo build output' )
+parser.add_option_group( group )
+
+## add compile options
+group = OptionGroup( parser, 'Compiler Options' )
+debugMode.addToGroup( group, '--debug', 'debug' )
+optimizeMode.addToGroup( group, '--optimize', 'optimize' )
+archMode.addToGroup( group, '--arch', 'architecutre' )
+parser.add_option_group( group )
+
+## add tool options
+group = OptionGroup( parser, 'Tool Options' )
+makeTool.addToGroup( group )
+for tool in tools.items:
+ tool.addToGroup( group )
+parser.add_option_group( group )
+
+(options, args) = parser.parse_args()
+
+## recompute values when launch mode
+if options.launch:
+ options.launch_jobs = int(options.launch_jobs)
+ build_dir = options.launch_dir
+ if os.path.isabs( build_dir ):
+ project_dir = os.getcwd()
+ else:
+ project_dir = os.path.normpath( relpath( project_dir, build_dir ))
+ if options.launch_jobs == 0:
+ options.launch_jobs = computeDefaultMakeJobs()
+ if options.launch_jobs < 1:
+ options.launch_jobs = 1
+ elif options.launch_jobs > 8:
+ options.launch_jobs = 8
+
+## make sure configure does not run in source root
+if os.path.abspath( project_dir ) == os.path.abspath( build_dir ):
+ errf( 'scratch (build) directory must not be the same as source root' )
+
+## validate modes
+debugMode.setFromOption( 'debug', options.debug )
+optimizeMode.setFromOption( 'optimize', options.optimize )
+archMode.setFromOption( 'architecture', options.arch )
+
+## update guessBuild as per architecture mode
+if guessHost.match( '*-*-darwin*' ):
+ if archMode.mode == 'i386':
+ guessBuild.proc = 'i386'
+ elif archMode.mode == 'x86_64':
+ guessBuild.proc = 'x86_64'
+ elif archMode.mode == 'ppc':
+ guessBuild.proc = 'powerpc'
+ elif archMode.mode == 'ppc64':
+ guessBuild.proc = 'powerpc64'
+else:
+ guessBuild.proc = archMode.mode
+guessBuild.cross = 0 if archMode.default == archMode.mode else 1
+
+# locate tools
+makeTool.locate( options )
+for tool in tools.items:
+ tool.locate( options )
+
+###############################################################################
+
+## Repository object.
+## Holds information gleaned from subversion working dir.
+##
+## Builds are classed into one of the following types:
+##
+## release
+## must be built from official svn with '/tags/' in the url
+## developer
+## must be built from official svn but is not a release
+## unofficial
+## all other builds
+##
+class Repository:
+ def __init__( self ):
+ self.url = 'svn://nowhere.com/project/unknown'
+ self.root = 'svn://nowhere.com/project'
+ self.branch = 'unknown'
+ self.uuid = '00000000-0000-0000-0000-000000000000';
+ self.rev = 0
+ self.date = '0000-00-00 00:00:00 -0000'
+ self.wcversion = 'exported'
+ self.official = 0
+ self.type = 'unofficial'
+
+ # parse output: svnversion PROJECT_DIR
+ cmd = 'svnversion ' + project_dir
+ print 'running: %s' % (cmd)
+ try:
+ p = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
+ p.wait();
+ if p.returncode == 0:
+ self.wcversion = p.stdout.readline().rstrip()
+ except:
+ pass
+
+ # parse output: svn info PROJECT_DIR
+ cmd = 'svn info ' + project_dir
+ print 'running: %s' % (cmd)
+ try:
+ p = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
+ p.wait();
+ if p.returncode == 0:
+ for line in p.stdout:
+ (name,value) = re.match( '([^:]+):\\s+(.+)', line.rstrip() ).groups()
+ if name == 'URL':
+ self.url = value
+ elif name == 'Repository Root':
+ self.root = value
+ elif name == 'Repository UUID':
+ self.uuid = value
+ elif name == 'Revision':
+ self.rev = int( value )
+ elif name == 'Last Changed Date':
+ # strip chars in parens
+ if value.find( ' (' ):
+ self.date = value[0:value.find(' (')]
+ else:
+ self.date = value
+ except:
+ pass
+
+ i = self.url.rfind( '/' )
+ if i != -1 and i < len(self.url)-1:
+ self.branch = self.url[i+1:]
+
+ # official UUID behavior
+ if self.uuid == 'b64f7644-9d1e-0410-96f1-a4d463321fa5':
+ self.official = 1
+ m = re.match( '([^:]+)://([^/]+)/(.+)', self.url )
+ if m and re.match( 'tags/', m.group( 3 )):
+ self.type = 'release'
+ else:
+ self.type = 'developer'
+
+###############################################################################
+
+## Project object.
+## Contains manually updated version numbers consistent with HB releases
+## and other project metadata.
+##
+class Project:
+ def __init__( self ):
+ self.name = 'HandBrake'
+ self.name_lower = self.name.lower()
+ self.name_upper = self.name.upper()
+ self.acro_lower = 'hb'
+ self.acro_upper = 'HB'
+ self.url_website = 'http://handbrake.fr'
+ self.url_community = 'http://forum.handbrake.fr'
+ self.url_irc = 'irc://irc.freenode.net/handbrake'
+
+ self.vmajor = 0
+ self.vminor = 9
+ self.vpoint = 3
+
+ self.version = '%d.%d.%d' % (self.vmajor,self.vminor,self.vpoint)
+ appcastfmt = 'http://handbrake.fr/appcast%s.xml'
+
+ if repo.type == 'release':
+ self.version_formal = '%s Release' % (self.version)
+ self.url_appcast = appcastfmt % ('')
+ elif repo.type == 'developer':
+ self.version_formal = '%s Developer ' % (self.version)
+ self.url_appcast = appcastfmt % ('_unstable')
+ else:
+ self.version_formal = '%s Unnofficial ' % (self.version)
+ self.url_appcast = appcastfmt % ('_unofficial')
+
+ self.title = '%s %s' % (self.name,self.version)
+ self.build = time.strftime('%Y%m%d') + '01'
+
+###############################################################################
+
+## Config object used to output gnu-make or gnu-m4 output.
+##
+## Use add() to add NAME/VALUE pairs suitable for both make/m4.
+## Use addBlank() to add a linefeed for both make/m4.
+## Use addMake() to add a make-specific line.
+## Use addM4() to add a m4-specific line.
+##
+class Config:
+ def __init__( self ):
+ self._items = []
+
+ def add( self, name, value ):
+ self._items.append( (name,value) )
+
+ def addBlank( self ):
+ self._items.append( None )
+
+ def addComment( self, format, *args ):
+ self.addMake( '## ' + format % args )
+ self.addM4( 'dnl ' + format % args )
+
+ def addMake( self, line ):
+ self._items.append( ('?make',line) )
+
+ def addM4( self, line ):
+ self._items.append( ('?m4',line) )
+
+ def output( self, file, type ):
+ namelen = 0
+ for item in self._items:
+ if item == None or item[0].find( '?' ) == 0:
+ continue
+ if len(item[0]) > namelen:
+ namelen = len(item[0])
+ for item in self._items:
+ if item == None:
+ if type == 'm4':
+ file.write( 'dnl\n' )
+ else:
+ file.write( '\n' )
+ continue
+ if item[0].find( '?' ) == 0:
+ if item[0].find( type, 1 ) == 1:
+ file.write( '%s\n' % (item[1]) )
+ continue
+
+ if type == 'm4':
+ self._outputM4( file, namelen, item[0], item[1] )
+ else:
+ self._outputMake( file, namelen, item[0], item[1] )
+
+ def _outputMake( self, file, namelen, name, value ):
+ file.write( '%-*s = %s\n' % (namelen, name, value ))
+
+ def _outputM4( self, file, namelen, name, value ):
+ namelen += 7
+ name = '<<__%s>>,' % name.replace( '.', '_' )
+ file.write( 'define(%-*s <<%s>>)dnl\n' % (namelen, name, value ))
+
+###############################################################################
+
+## create configure line, stripping arg --launch, quoting others
+configure = []
+for arg in sys.argv[1:]:
+ #if arg.find( '--launch' ) == 0:
+ # continue
+ if arg == '--launch':
+ continue
+ configure.append( '"%s"' % (arg.replace('"', '\\"')) )
+
+## create singletones
+repo = Repository()
+project = Project()
+config = Config()
+
+config.addComment( 'generated by configure on %s', time.strftime( '%c' ))
+
+config.addBlank()
+config.add( 'CONF.args', ' '.join( configure ))
+
+config.addBlank()
+config.add( 'HB.title', project.title )
+config.add( 'HB.name', project.name )
+config.add( 'HB.name.lower', project.name_lower )
+config.add( 'HB.name.upper', project.name_upper )
+config.add( 'HB.acro.lower', project.acro_lower )
+config.add( 'HB.acro.upper', project.acro_upper )
+
+config.add( 'HB.url.website', project.url_website )
+config.add( 'HB.url.community', project.url_community )
+config.add( 'HB.url.irc', project.url_irc )
+config.add( 'HB.url.appcast', project.url_appcast )
+
+config.add( 'HB.version.major', project.vmajor )
+config.add( 'HB.version.minor', project.vminor )
+config.add( 'HB.version.point', project.vpoint )
+config.add( 'HB.version', project.version )
+config.add( 'HB.version.formal', project.version_formal )
+config.add( 'HB.version.hex', '%04x%02x%02x%02x%06x' % (project.vmajor,project.vminor,project.vpoint,0,repo.rev) )
+
+config.add( 'HB.build', project.build )
+
+config.add( 'HB.repo.url', repo.url )
+config.add( 'HB.repo.root', repo.root )
+config.add( 'HB.repo.branch', repo.branch )
+config.add( 'HB.repo.uuid', repo.uuid )
+config.add( 'HB.repo.rev', repo.rev )
+config.add( 'HB.repo.date', repo.date )
+config.add( 'HB.repo.wcversion', repo.wcversion )
+config.add( 'HB.repo.official', repo.official )
+config.add( 'HB.repo.type', repo.type )
+
+config.addBlank()
+config.add( 'HOST.spec', guessHost )
+config.add( 'HOST.proc', guessHost.proc )
+config.add( 'HOST.vendor', guessHost.vendor )
+config.add( 'HOST.system', guessHost.system )
+config.add( 'HOST.release', guessHost.release )
+config.add( 'HOST.extra', guessHost.extra )
+
+config.addBlank()
+config.add( 'BUILD.spec', guessBuild )
+config.add( 'BUILD.proc', guessBuild.proc )
+config.add( 'BUILD.vendor', guessBuild.vendor )
+config.add( 'BUILD.system', guessBuild.system )
+config.add( 'BUILD.release', guessBuild.release )
+config.add( 'BUILD.extra', guessBuild.extra )
+config.add( 'BUILD.cross', guessBuild.cross )
+config.add( 'BUILD.date', time.strftime('%c') )
+config.add( 'BUILD.arch', archMode.mode )
+
+config.addBlank()
+config.add( 'BUILD/', os.curdir + os.sep )
+config.add( 'PROJECT/', project_dir + os.sep )
+
+config.addBlank()
+config.add( 'FEATURE.xcode', 0 if options.disable_xcode else 1 )
+config.add( 'FEATURE.gtk', 0 if options.disable_gtk else 1 )
+
+config.addMake( '' )
+config.addMake( '## include main definitions' )
+config.addMake( 'include $(PROJECT/)make/include/main.defs' )
+
+config.addBlank()
+for tool in tools.items:
+ tool.addToConfig( config )
+
+config.addBlank()
+config.add( 'GCC.archs', archMode.mode if guessBuild.cross else '' )
+config.add( 'GCC.g', options.debug )
+config.add( 'GCC.O', options.optimize )
+
+config.addMake( '' )
+config.addMake( '## include (optional) customization file' )
+config.addMake( '-include $(BUID/)GNUmakefile.custom' )
+
+config.addMake( '' )
+config.addMake( '## include main rules' )
+config.addMake( 'include $(PROJECT/)make/include/main.rules' )
+
+###############################################################################
+
+# generate make or m4 file
+def generate( type ):
+ if type == 'make':
+ fname = 'GNUmakefile'
+ elif type == 'm4':
+ fname = os.path.join( 'project', project.name_lower + '.m4' )
+ else:
+ raise ValueError, 'unknown file type: ' + type
+
+ ftmp = fname + '.tmp'
+
+ pdir = os.path.dirname( fname )
+ if pdir:
+ if not os.path.exists( pdir ):
+ os.makedirs( pdir )
+
+ try:
+ try:
+ outf( 'generating %s', fname )
+ file = open( ftmp, 'w' )
+ config.output( file, type )
+ finally:
+ try:
+ file.close()
+ except:
+ pass
+ except Exception, x:
+ try:
+ os.remove( ftmp )
+ except Exception, x:
+ pass
+ errf( 'failed writing to %s\n%s', ftmp, x )
+
+ try:
+ os.rename( ftmp, fname )
+ except Exception, x:
+ errf( 'failed writing to %s\n%s', fname, x )
+
+###############################################################################
+
+if not options.launch:
+ generate( 'make' )
+ generate( 'm4' )
+ sys.exit( 0 )
+
+###############################################################################
+
+if os.path.exists( options.launch_dir ):
+ if not options.launch_force:
+ errf( 'scratch directory already exists: %s', options.launch_dir )
+else:
+ outf( 'creating %s', options.launch_dir )
+ os.makedirs( options.launch_dir )
+
+outf( 'chdir %s', options.launch_dir )
+os.chdir( options.launch_dir )
+generate( 'make' )
+generate( 'm4' )
+
+outf( 'opening %s', options.launch_log )
+try:
+ log = open( options.launch_log, 'w' )
+except Exception, x:
+ errf( 'open failure: %s', x )
+
+cmd = '%s -j%d' % (makeTool.found,options.launch_jobs)
+if options.launch_args:
+ cmd += ' ' + options.launch_args
+
+## record begin
+timeBegin = time.time()
+s = '###\n### TIME: %s\n### launch: %s\n###\n' % (time.asctime(),cmd)
+stdout.write( s ); stdout.flush()
+log.write( s ); log.flush()
+
+## launch/pipe
+try:
+ pipe = subprocess.Popen( cmd, shell=True, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
+except Exception, x:
+ errf( 'launch failure: %s', x )
+for line in pipe.stdout:
+ if not options.launch_quiet:
+ stdout.write( line ); stdout.flush()
+ log.write( line ); log.flush()
+pipe.wait()
+
+## record end
+timeEnd = time.time()
+elapsed = timeEnd - timeBegin
+result = '%s (exit code %d)' % ('success' if pipe.returncode == 0 else 'failed',pipe.returncode)
+s = '###\n### TIME: %s\n### finished: %.2f seconds\n### %s\n###\n' % (time.asctime(),elapsed,result)
+stdout.write( s ); stdout.flush()
+log.write( s ); log.flush()
+
+log.close()
+sys.exit( 0 )
diff --git a/make/include/base.defs b/make/include/base.defs
new file mode 100644
index 000000000..3b4e666f3
--- /dev/null
+++ b/make/include/base.defs
@@ -0,0 +1,50 @@
+## Define module metadata.
+## It is mandatory for every module to use this template.
+##
+## $(1) module name (uppercase)
+## $(2) module name (lowercase)
+## $(3) list of prerequisite modules (uppercase)
+##
+define import.MODULE.defs
+ ## indicates module is defined; useful for conditionals
+ $(1).enabled = 1
+
+ ## module name (lowercase)
+ $(1).name = $(2)
+
+ ## list of prerequisite modules (uppercase)
+ $(1).prerequisites = $(3)
+
+ ## add to global list of modules
+ MODULES.NAMES += $(1)
+ MODULES.names += $(2)
+endef
+
+##
+## $(1) module name (uppercase)
+##
+define import.MODULE.rules
+$($(1).name).report:
+ @$(MAKE) report.true REPORT=module REPORT.module=$(1)
+
+## aggregate
+report.modules:: $($(1).name).report
+
+endef
+
+.PHONY: report.main report.gcc report.modules
+
+report.modules::
+
+.PHONY: report.main
+report.main:
+ @$(MAKE) report.true REPORT=main
+
+.PHONY: report.gcc
+report.gcc:
+ @$(MAKE) report.true REPORT=gcc
+
+## needed for nested make (which drives each report)
+.PHONY: report.true
+report.true:
+ @true
diff --git a/make/include/contrib.defs b/make/include/contrib.defs
new file mode 100644
index 000000000..772258c37
--- /dev/null
+++ b/make/include/contrib.defs
@@ -0,0 +1,276 @@
+CONTRIB.build/ = $(BUILD/)contrib/
+CONTRIB.download/ = $(PROJECT/)download/
+CONTRIB.host = $(if $(filter 1,$(BUILD.cross)),$(BUILD.spec))
+
+###############################################################################
+
+##
+## $(1) = module name (uppercase)
+##
+define import.CONTRIB.defs
+ ##
+ ## import gcc/g++ support mainly so we can force contrib choice of
+ ## gcc executable, and debug/optimization flags.
+ ##
+ $$(eval $$(call import.GCC,$(1)))
+
+ ##
+ ## common values useful across targets
+ ##
+ $(1).src/ = $$(PROJECT/)contrib/$($(1).name)/
+ $(1).build/ = $$(CONTRIB.build/)$($(1).name)/
+ $(1).deps = $$(foreach n,$($(1).prerequisites),$$($$n.INSTALL.target))
+
+ ##
+ ## target: fetch
+ ##
+ $(1).FETCH.tar = $$(CONTRIB.download/)$$(notdir $$($(1).FETCH.url))
+ $(1).FETCH.url = FETCH_IS_UNDEFINED
+ $(1).FETCH.target = $$($(1).FETCH.tar)
+ define $(1).FETCH
+ $$(call FETCH,$$@,$$($(1).FETCH.url))
+ endef
+
+ ##
+ ## target: extract
+ ##
+ $(1).EXTRACT.tarbase = $$(patsubst %.tar.gz,%,$$(notdir $$($(1).FETCH.url)))
+ $(1).EXTRACT.target/ = $$($(1).build/)$$($(1).EXTRACT.tarbase)/
+ define $(1).EXTRACT
+ $$(TAR.exe) xfC $$($(1).FETCH.tar) $$($(1).build/)
+ endef
+
+ ##
+ ## target: patch
+ ##
+ $(1).PATCH.srcs = $$(wildcard \
+ $$($(1).src/)A??-*.patch \
+ $$($(1).src/)P??-$$(BUILD.system)*.patch )
+
+ # extra line feed is required
+ define $(1).PATCH.item
+ $$(PATCH.exe) -t -p1 -d $$(1) < $$(2)
+
+ endef
+
+ $(1).PATCH.target = $$($(1).build/).stamp.patch
+ define $(1).PATCH
+ $$(foreach p,$$($(1).PATCH.srcs),$$(call $(1).PATCH.item,$$($(1).EXTRACT.target/),$$(p)))
+ endef
+
+ ##
+ ## target: configure
+ ##
+ $(1).CONFIGURE.sete = set -e;
+ $(1).CONFIGURE.dir = $$($(1).EXTRACT.target/)
+ $(1).CONFIGURE.bootstrap =
+ $(1).CONFIGURE.exe = ./configure
+ $(1).CONFIGURE.host = $$(CONTRIB.host)
+ $(1).CONFIGURE.prefix = $$(call fn.ABSOLUTE,$$(CONTRIB.build/))
+ $(1).CONFIGURE.deps = --disable-dependency-tracking
+ $(1).CONFIGURE.shared = --disable-shared
+ $(1).CONFIGURE.static = --enable-static
+ $(1).CONFIGURE.extra =
+
+ $(1).CONFIGURE.args.dir = cd $$(1);
+ $(1).CONFIGURE.args.host = --host=$$(1)
+ $(1).CONFIGURE.args.prefix = --prefix=$$(1)
+
+ $(1).CONFIGURE.args = !sete @dir !bootstrap !env !exe @host @prefix !deps !shared !static !extra
+
+ $(1).CONFIGURE.env.CC = CC=$$($(1).GCC.gcc)
+ $(1).CONFIGURE.env.CFLAGS = CFLAGS="$$(call fn.ARGS,$(1).GCC,*archs)"
+ $(1).CONFIGURE.env.CXX = CXX=$$($(1).GCC.gxx)
+ $(1).CONFIGURE.env.CXXFLAGS = CXXFLAGS="$$(call fn.ARGS,$(1).GCC,*archs)"
+ $(1).CONFIGURE.env.CPPFLAGS = CPPFLAGS="$$(call fn.ARGS,$(1).GCC,*archs)"
+ $(1).CONFIGURE.env.LDFLAGS = LDFLAGS="$$(call fn.ARGS,$(1).GCC,*archs)"
+
+ $(1).CONFIGURE.env.args = !CC !CFLAGS !CXX !CXXFLAGS !CPPFLAGS !LDFLAGS
+ $(1).CONFIGURE.env = $$(call fn.ARGS,$(1).CONFIGURE.env,$$($(1).CONFIGURE.env.args))
+
+ $(1).CONFIGURE.target = $$($(1).build/).stamp.configure
+ define $(1).CONFIGURE
+ $$(call fn.ARGS,$(1).CONFIGURE,$$($(1).CONFIGURE.args))
+ endef
+
+ ##
+ ## target: build
+ ##
+ $(1).BUILD.make = $$(MAKE)
+ $(1).BUILD.dir = $$($(1).EXTRACT.target/)
+ $(1).BUILD.extra =
+ $(1).BUILD.ntargets =
+
+ $(1).BUILD.args = !make @dir !extra !ntargets
+ $(1).BUILD.args.dir = -C $$(1)
+
+ $(1).BUILD.target = $$($(1).build/).stamp.build
+ define $(1).BUILD
+ $$(call fn.ARGS,$(1).BUILD,$$($(1).BUILD.args))
+ endef
+
+ ##
+ ## target: install
+ ##
+
+ $(1).INSTALL.make = $$(MAKE)
+ $(1).INSTALL.dir = $$($(1).EXTRACT.target/)
+ $(1).INSTALL.extra =
+ $(1).INSTALL.ntargets =
+
+ $(1).INSTALL.args = !make @dir !extra !ntargets
+ $(1).INSTALL.args.dir = -C $$(1) install
+
+ $(1).INSTALL.target = $$($(1).build/).stamp.install
+ define $(1).INSTALL
+ $$(call fn.ARGS,$(1).INSTALL,$$($(1).INSTALL.args))
+ endef
+
+ ##
+ ## target: uninstall
+ ##
+ $(1).UNINSTALL.make = $$(MAKE)
+ $(1).UNINSTALL.dir = $$($(1).EXTRACT.target/)
+ $(1).UNINSTALL.extra =
+ $(1).UNINSTALL.ntargets = uninstall
+
+ $(1).UNINSTALL.args = !make @dir !extra !ntargets
+ $(1).UNINSTALL.args.dir = -C $$(1)
+
+ define $(1).UNINSTALL
+ $$(call fn.ARGS,$(1).UNINSTALL,$$($(1).UNINSTALL.args))
+ endef
+
+ ##
+ ## target: clean
+ ##
+ $(1).CLEAN.make = $$(MAKE)
+ $(1).CLEAN.dir = $$($(1).EXTRACT.target/)
+ $(1).CLEAN.extra =
+ $(1).CLEAN.ntargets = clean
+
+ $(1).CLEAN.args = !make @dir !extra !ntargets
+ $(1).CLEAN.args.dir = -C $$(1)
+
+ define $(1).CLEAN
+ $$(call fn.ARGS,$(1).CLEAN,$$($(1).CLEAN.args))
+ endef
+
+ ## other values used to aid prerequisite dirs and cleanup
+ ##
+ $(1).out += $$($(1).build/)
+ $(1).out += $$($(1).FETCH.target)
+ $(1).out += $$($(1).PATCH.target)
+ $(1).out += $$($(1).CONFIGURE.target)
+ $(1).out += $$($(1).ALL.target)
+ $(1).out += $$($(1).INSTALL.target)
+
+ BUILD.out += $$($(1).out)
+endef
+
+###############################################################################
+
+##
+## $(1) = module name
+##
+define import.CONTRIB.rules
+
+##
+## target: fetch
+##
+$($(1).name).fetch: $$($(1).FETCH.target)
+
+$$($(1).FETCH.target): | $$(dir $$($(1).FETCH.target))
+ $$($(1).FETCH)
+
+##
+## target: extract
+## must touch dir after extraction because old timestamp is restored via tar.
+##
+$($(1).name).extract: | $$($(1).EXTRACT.target/)
+
+$$($(1).EXTRACT.target/): | $$(dir $$($(1).build/))
+$$($(1).EXTRACT.target/): $$($(1).FETCH.target)
+ $$($(1).EXTRACT)
+ $$(TOUCH.exe) $$@
+
+##
+## target: patch
+##
+$($(1).name).patch: $$($(1).PATCH.target)
+
+$$($(1).PATCH.target): | $$(dir $$($(1).PATCH.target))
+$$($(1).PATCH.target): | $$($(1).EXTRACT.target/)
+ $$($(1).PATCH)
+ $$(TOUCH.exe) $$@
+
+##
+## target: configure
+##
+$($(1).name).configure: $$($(1).CONFIGURE.target)
+
+$$($(1).CONFIGURE.target): | $$(dir $$($(1).CONFIGURE.target))
+$$($(1).CONFIGURE.target): $$($(1).deps)
+$$($(1).CONFIGURE.target): $$($(1).PATCH.target)
+ $$($(1).CONFIGURE)
+ $$(TOUCH.exe) $$@
+
+##
+## target: build
+##
+$($(1).name).build: $$($(1).BUILD.target)
+
+$$($(1).BUILD.target): | $$(dir $$($(1).BUILD.target))
+$$($(1).BUILD.target): $$($(1).CONFIGURE.target)
+ +$$($(1).BUILD)
+ $$(TOUCH.exe) $$@
+
+##
+## target: install
+##
+$($(1).name).install: $$($(1).INSTALL.target)
+
+$$($(1).INSTALL.target): | $$(dir $$($(1).INSTALL.target))
+$$($(1).INSTALL.target): $$($(1).BUILD.target)
+ $$($(1).INSTALL)
+ $$(TOUCH.exe) $$@
+
+##
+## target: uninstall
+##
+$($(1).name).uninstall:
+ -$$($(1).UNINSTALL)
+ $$(RM.exe) -f $$($(1).INSTALL.target)
+
+##
+## target: clean
+##
+$($(1).name).clean:
+ -$$($(1).CLEAN)
+ $$(RM.exe) -f $$($(1).BUILD.target)
+
+##
+## target: xclean
+##
+$($(1).name).xclean: $($(1).name).uninstall
+ $$(RM.exe) -fr $$($(1).build/)
+
+##
+## alias: module name is same as build
+##
+$($(1).name): $($(1).name).build
+
+##
+## participate with global convenience targets
+##
+contrib.fetch: $($(1).name).fetch
+contrib.extract: $($(1).name).extract
+contrib.patch: $($(1).name).patch
+contrib.configure: $($(1).name).configure
+contrib.build: $($(1).name).build
+contrib.install: $($(1).name).install
+contrib.uninstall: $($(1).name).uninstall
+contrib.clean: $($(1).name).clean
+contrib.xclean: $($(1).name).xclean
+
+endef
diff --git a/make/include/function.defs b/make/include/function.defs
new file mode 100644
index 000000000..5bf5aaa89
--- /dev/null
+++ b/make/include/function.defs
@@ -0,0 +1,19 @@
+fn.ERROR1 = ERROR: $(1)
+fn.ERROR2 = ERROR: $(1): $(2)
+
+fn.HEADER = @echo "$(1): $(2)"
+fn.DIVIDER = @echo "======================================================================"
+
+fn.ABSOLUTE = $(if $(filter /%,$(1)),$(1),$(subst /./,/,$(CURDIR)/$(1)))
+
+fn.ARGS = $(strip $(foreach a,$(2), \
+ $($(1).$(patsubst !%,%,$(filter !%,$(a)))) \
+ $(foreach x,$(patsubst ?%,%,$(filter ?%,$(a))),$(if $(filter 1,$($(1).$(x))),$($(1).args.$(x)))) \
+ $(foreach x,$(patsubst .%,%,$(filter .%,$(a))),$($(1).args.$(x).$($(1).$(x)))) \
+ $(foreach x,$(patsubst @%,%,$(filter @%,$(a))),$(if $($(1).$(x)),$(call $(1).args.$(x),$($(1).$(x))))) \
+ $(foreach x,$(patsubst *%,%,$(filter *%,$(a))),$(foreach i,$($(1).$(x)),$(call $(1).args.$(x),$(i)))) \
+ ))
+
+fn.VARS = $(foreach v,$($(1).vars),$(v)="$($(1).vars.$(v))")
+
+fn.TARGET = $(TARGET.$(2).prefix)$(1)$(TARGET.$(2).suffix)$(TARGET.$(2).ext)
diff --git a/make/include/gcc.defs b/make/include/gcc.defs
new file mode 100644
index 000000000..4ed746392
--- /dev/null
+++ b/make/include/gcc.defs
@@ -0,0 +1,146 @@
+GCC.gcc = gcc
+GCC.gxx = $(dir $(GCC.gcc))$(subst gcc,g++,$(notdir $(GCC.gcc)))
+
+GCC.strip = $$(if $$(filter none,$$(GCC.g)),1)
+GCC.dylib = 1
+GCC.pipe = 1
+GCC.ML = 1
+GCC.H = 0
+GCC.W = all
+GCC.archs =
+GCC.vis = 0
+GCC.pic = 0
+GCC.g = none
+GCC.O = none
+GCC.D =
+GCC.I =
+GCC.muldefs = 0
+GCC.start = 0
+GCC.a =
+GCC.F =
+GCC.f =
+GCC.L =
+GCC.l =
+GCC.end = 0
+
+GCC.args.pipe = -pipe
+GCC.args.strip = -Wl,-S
+GCC.args.dylib = -dynamiclib
+GCC.args.ML = -fmessage-length=0
+GCC.args.H = -H
+GCC.args.W = -W$(1)
+GCC.args.archs = -arch $(1)
+GCC.args.vis = -fvisibility=hidden
+GCC.args.pic = -fPIC
+GCC.args.g.none = -g0
+GCC.args.g.min = -gdwarf-2 -g1
+GCC.args.g.std = -gdwarf-2
+GCC.args.g.max = -gdwarf-2 -g3
+GCC.args.O.none = -O0
+GCC.args.O.size = -Os
+GCC.args.O.speed = -O3
+GCC.args.D = -D$(1)
+GCC.args.I = -I$(1)
+GCC.args.muldefs = -Wl,--allow-multiple-definition
+GCC.args.start = -Wl,--start-group
+GCC.args.F = -F$(1)
+GCC.args.f = -framework $(1)
+GCC.args.L = -L$(1)
+GCC.args.l = -l$(1)
+GCC.args.end = -Wl,--end-group
+
+###############################################################################
+
+define import.GCC
+ $(1).GCC.gcc = $$(GCC.gcc)
+ $(1).GCC.gxx = $$(dir $$($(1).GCC.gcc))$$(subst gcc,g++,$$(notdir $$($(1).GCC.gcc)))
+
+ $(1).GCC.pipe = $$(GCC.pipe)
+ $(1).GCC.strip = $$(if $$(filter none,$$($(1).GCC.g)),1)
+ $(1).GCC.dylib = $$(GCC.dylib)
+ $(1).GCC.ML = $$(GCC.ML)
+ $(1).GCC.H = $$(GCC.H)
+ $(1).GCC.W = $$(GCC.W)
+ $(1).GCC.archs = $$(GCC.archs)
+ $(1).GCC.vis = $$(GCC.vis)
+ $(1).GCC.pic = $$(GCC.pic)
+ $(1).GCC.g = $$(GCC.g)
+ $(1).GCC.O = $$(GCC.O)
+ $(1).GCC.D = $$(GCC.D)
+ $(1).GCC.I = $$(GCC.I)
+ $(1).GCC.muldefs = $$(GCC.muldefs)
+ $(1).GCC.start = $$(GCC.start)
+ $(1).GCC.a = $$(GCC.a)
+ $(1).GCC.F = $$(GCC.F)
+ $(1).GCC.f = $$(GCC.f)
+ $(1).GCC.L = $$(GCC.L)
+ $(1).GCC.l = $$(GCC.l)
+ $(1).GCC.end = $$(GCC.end)
+
+ $(1).GCC.args.pipe = $$(GCC.args.pipe)
+ $(1).GCC.args.strip = $$(GCC.args.strip)
+ $(1).GCC.args.dylib = $$(GCC.args.dylib)
+ $(1).GCC.args.ML = $$(GCC.args.ML)
+ $(1).GCC.args.H = $$(GCC.args.H)
+ $(1).GCC.args.W = $$(GCC.args.W)
+ $(1).GCC.args.archs = $$(GCC.args.archs)
+ $(1).GCC.args.vis = $$(GCC.args.vis)
+ $(1).GCC.args.pic = $$(GCC.args.pic)
+ $(1).GCC.args.g.none = $$(GCC.args.g.none)
+ $(1).GCC.args.g.min = $$(GCC.args.g.min)
+ $(1).GCC.args.g.std = $$(GCC.args.g.std)
+ $(1).GCC.args.g.max = $$(GCC.args.g.max )
+ $(1).GCC.args.O.none = $$(GCC.args.O.none)
+ $(1).GCC.args.O.size = $$(GCC.args.O.size)
+ $(1).GCC.args.O.speed = $$(GCC.args.O.speed)
+ $(1).GCC.args.D = $$(GCC.args.D)
+ $(1).GCC.args.I = $$(GCC.args.I)
+ $(1).GCC.args.muldefs = $$(GCC.args.muldefs)
+ $(1).GCC.args.start = $$(GCC.args.start)
+ $(1).GCC.args.F = $$(GCC.args.F)
+ $(1).GCC.args.f = $$(GCC.args.f)
+ $(1).GCC.args.L = $$(GCC.args.L)
+ $(1).GCC.args.l = $$(GCC.args.l)
+ $(1).GCC.args.end = $$(GCC.args.end)
+
+ ###########################################################################
+
+ $(1).GCC.c = -c $$(4)
+ $(1).GCC.o = -o $$(3)
+
+ # FUNCTION: C precompiled headers
+ $(1).GCC.H_O.args = !gcc ?pipe ?ML ?H *W *archs ?vis ?pic .g .O *D *I !c !o
+ $(1).GCC.H_O = $$(call fn.ARGS,$(1).GCC,$$($(1).GCC.H_O.args),$$(1),$$(2))
+
+ # FUNCTION: C compile source
+ $(1).GCC.C_O.args = !gcc ?pipe ?ML ?H *W *archs ?vis ?pic .g .O *D *I !c !o
+ $(1).GCC.C_O = $$(call fn.ARGS,$(1).GCC,$$($(1).GCC.C_O.args),$$(1),$$(2))
+
+ # FUNCTION: C++ precompile headers
+ $(1).GCC.HPP_O.args = !gxx ?pipe ?ML ?H *W *archs ?vis ?pic .g .O *D *I !c !o
+ $(1).GCC.HPP_O = $$(call fn.ARGS,$(1).GCC,$$($(1).GCC.HPP_O.args),$$(1),$$(2))
+
+ # FUNCTION: C++ compile source
+ $(1).GCC.CPP_O.args = !gxx ?pipe ?ML ?H *W *archs ?vis ?pic .g .O *D *I !c !o
+ $(1).GCC.CPP_O = $$(call fn.ARGS,$(1).GCC,$$($(1).GCC.CPP_O.args),$$(1),$$(2))
+
+ ###########################################################################
+
+ $(1).GCC.i = $$(4)
+
+ # FUNCTION: C link dynamic-lib
+ $(1).GCC.DYLIB.args = !gcc ?pipe ?strip ?dylib ?ML *W *archs ?vis ?pic .g .O *D *I !o ?muldefs ?start !i *F *f *L *l *i !a ?end
+ $(1).GCC.DYLIB = $$(call fn.ARGS,$(1).GCC,$$($(1).GCC.DYLIB.args),$$(1),$$(2))
+
+ # FUNCTION: C link executable
+ $(1).GCC.EXE.args = !gcc ?pipe ?strip ?ML *W *archs ?vis ?pic .g .O *D *I !o ?muldefs ?start !i *F *f *L *l *i !a ?end
+ $(1).GCC.EXE = $$(call fn.ARGS,$(1).GCC,$$($(1).GCC.EXE.args),$$(1),$$(2))
+
+ # FUNCTION: C++ link dynamic-lib
+ $(1).GCC.DYLIB++.args = !gxx ?pipe ?strip ?dylib ?ML *W *archs ?vis ?pic .g .O *D *I !o ?muldefs ?start !i *F *f *L *l *i !a ?end
+ $(1).GCC.DYLIB++ = $$(call fn.ARGS,$(1).GCC,$$($(1).GCC.DYLIB++.args),$$(1),$$(2))
+
+ # FUNCTION: C++ link executable
+ $(1).GCC.EXE++.args = !gxx ?pipe ?strip ?ML *W *archs ?vis ?pic .g .O *D *I !o ?muldefs ?start !i *F *f *L *l *i !a ?end
+ $(1).GCC.EXE++ = $$(call fn.ARGS,$(1).GCC,$$($(1).GCC.EXE++.args),$$(1),$$(2))
+endef
diff --git a/make/include/main.defs b/make/include/main.defs
new file mode 100644
index 000000000..c40e2b62a
--- /dev/null
+++ b/make/include/main.defs
@@ -0,0 +1,75 @@
+.DELETE_ON_ERROR:
+.SUFFIXES:
+
+.PHONY: build
+build:
+
+###############################################################################
+
+include $(PROJECT/)make/include/base.defs
+include $(PROJECT/)make/include/contrib.defs
+include $(PROJECT/)make/include/function.defs
+include $(PROJECT/)make/include/gcc.defs
+include $(PROJECT/)make/include/select.defs
+include $(PROJECT/)make/include/target.defs
+include $(PROJECT/)make/include/tool.defs
+
+###############################################################################
+
+MODULES += contrib/a52dec
+
+ifneq (,$(filter $(BUILD.system),cygwin))
+ MODULES += contrib/bzip2
+endif
+
+MODULES += contrib/faac
+MODULES += contrib/faad2
+MODULES += contrib/ffmpeg
+MODULES += contrib/lame
+MODULES += contrib/libdca
+MODULES += contrib/libdvdread
+MODULES += contrib/libmkv
+MODULES += contrib/libmp4v2
+MODULES += contrib/libogg
+MODULES += contrib/libsamplerate
+MODULES += contrib/libtheora
+MODULES += contrib/libvorbis
+MODULES += contrib/mpeg2dec
+MODULES += contrib/x264
+MODULES += contrib/xvidcore
+
+ifneq (,$(filter $(BUILD.system),cygwin))
+ MODULES += contrib/zlib
+endif
+
+## these must come after contrib since some contrib modules are optional
+MODULES += libhb
+
+###############################################################################
+
+## test module is replaced with macosx when Darwin+Xcode
+ifneq (,$(filter $(BUILD.system),darwin))
+ ifeq (1,$(FEATURE.xcode))
+ MODULES += macosx
+ else
+ MODULES += test
+ endif
+else
+ MODULES += test
+endif
+
+ifneq (,$(filter $(BUILD.system),linux))
+ ifeq (1,$(FEATURE.gtk))
+ MODULES += gtk
+ endif
+endif
+
+###############################################################################
+
+MODULES += doc
+
+###############################################################################
+
+include $(MODULES:%=$(PROJECT/)%/module.defs)
+include $(PROJECT/)make/variant/$(HOST.system).defs
+-include $(PROJECT/)make/variant/$(HOST.system).$(BUILD.proc).defs
diff --git a/make/include/main.rules b/make/include/main.rules
new file mode 100644
index 000000000..f46d22398
--- /dev/null
+++ b/make/include/main.rules
@@ -0,0 +1,39 @@
+## only included using special report targets
+ifneq (,$(REPORT))
+ include $(PROJECT/)make/include/report.defs
+endif
+
+###############################################################################
+
+.PHONY: clean xclean doc report
+
+clean:
+xclean: contrib.xclean clean
+doc:
+report:: report.main report.modules
+
+## legacy
+mrproper: xclean
+
+###############################################################################
+
+include $(MODULES:%=$(PROJECT/)%/module.rules)
+include $(PROJECT/)make/variant/$(HOST.system).rules
+-include $(PROJECT/)make/variant/$(HOST.system).$(BUILD.proc).rules
+
+###############################################################################
+
+## target which causes re-configure if project-root is svn update'd
+$(BUILD/)GNUmakefile: $(wildcard $(PROJECT/).svn/entries)
+ $(PROJECT/)configure $(CONF.args)
+
+## target useful to force reconfigure; only helpful for build-system development
+.PHONY: reconfigure
+reconfigure:
+ $(PROJECT/)configure $(CONF.args)
+
+###############################################################################
+
+## target to build all dependency dirs
+$(sort $(dir $(BUILD.out))):
+ $(MKDIR.exe) -p $@
diff --git a/make/include/report.defs b/make/include/report.defs
new file mode 100644
index 000000000..6ff71dc99
--- /dev/null
+++ b/make/include/report.defs
@@ -0,0 +1,53 @@
+## function: print a var's name, definition and expanded value
+##
+## $(1) = name of variable
+##
+define fn.PRINTVAR
+
+$(1)
+ ORIGIN = $(origin $(1))
+ FLAVOR = $(flavor $(1))
+ DEFINITION = $(value $(1))
+ EXPANDED = $($(1))
+endef
+
+## report: module
+##
+## REPORT.module = module name (uppercase)
+##
+ifeq (module,$(REPORT))
+$(info ###############################################################################)
+$(info ##)
+$(info ## MODULE: $(REPORT.module))
+$(info ##)
+$(info ###############################################################################)
+$(info $(foreach v,$(sort $(filter $(REPORT.module).%,$(.VARIABLES))),$(call fn.PRINTVAR,$v)))
+$(info )
+endif
+
+## report: main
+##
+ifeq (main,$(REPORT))
+$(info ###############################################################################)
+$(info ##)
+$(info ## MAIN)
+$(info ##)
+$(info ###############################################################################)
+$(info $(foreach v,$(sort $(filter HB.%,$(.VARIABLES))),$(call fn.PRINTVAR,$v)))
+$(info $(foreach v,$(sort $(filter HOST.%,$(.VARIABLES))),$(call fn.PRINTVAR,$v)))
+$(info $(foreach v,$(sort $(filter BUILD.%,$(.VARIABLES))),$(call fn.PRINTVAR,$v)))
+$(info $(foreach v,$(sort $(filter CONTRIB.%,$(.VARIABLES))),$(call fn.PRINTVAR,$v)))
+$(info )
+endif
+
+## report: gcc
+##
+ifeq (gcc,$(REPORT))
+$(info ###############################################################################)
+$(info ##)
+$(info ## GCC)
+$(info ##)
+$(info ###############################################################################)
+$(info $(foreach v,$(sort $(filter GCC.%,$(.VARIABLES))),$(call fn.PRINTVAR,$v)))
+$(info )
+endif
diff --git a/make/include/select.defs b/make/include/select.defs
new file mode 100644
index 000000000..32a652523
--- /dev/null
+++ b/make/include/select.defs
@@ -0,0 +1,12 @@
+##
+## fetch a file from the web via well-known anonymous protocols such as HTTP.
+##
+## $(1) = output filename
+## $(2) = URL
+##
+FETCH = $(FETCH.$(FETCH.select))
+
+FETCH.select = MISSING
+FETCH.MISSING = $(error one of the following tools is required: wget, curl)
+FETCH.curl = $(CURL.exe) -q -L -o $(1) $(2)
+FETCH.wget = $(WGET.exe) -O $(1) $(2)
diff --git a/make/include/target.defs b/make/include/target.defs
new file mode 100644
index 000000000..64bdde434
--- /dev/null
+++ b/make/include/target.defs
@@ -0,0 +1,14 @@
+TARGET.dylib.prefix = lib
+TARGET.dylib.suffix =
+TARGET.dylib.ext = .dylib
+TARGET.dylib = $(TARGET.dylib.prefix)$(1)$(TARGET.dylib.suffix)$(TARGET.dylib.ext)
+
+TARGET.archive.prefix = lib
+TARGET.archive.suffix =
+TARGET.archive.ext = .a
+TARGET.archive = $(TARGET.archive.prefix)$(1)$(TARGET.archive.suffix)$(TARGET.archive.ext)
+
+TARGET.exe.prefix =
+TARGET.exe.suffix =
+TARGET.exe.ext =
+TARGET.exe = $(TARGET.exe.prefix)$(1)$(TARGET.exe.suffix)$(TARGET.exe.ext)
diff --git a/make/include/tool.defs b/make/include/tool.defs
new file mode 100644
index 000000000..0ccccd728
--- /dev/null
+++ b/make/include/tool.defs
@@ -0,0 +1,10 @@
+AR.exe = ar
+CP.exe = cp
+CURL.exe = curl
+M4.exe = m4
+MKDIR.exe = mkdir
+PATCH.exe = patch
+RM.exe = rm
+TAR.exe = tar
+TOUCH.exe = touch
+WGET.exe = wget
diff --git a/make/variant/cygwin.defs b/make/variant/cygwin.defs
new file mode 100644
index 000000000..bab73c6ca
--- /dev/null
+++ b/make/variant/cygwin.defs
@@ -0,0 +1,8 @@
+GCC.muldefs = 1
+GCC.start = 1
+GCC.end = 1
+
+GCC.args.g.none = -g0
+GCC.args.g.min = -g1
+GCC.args.g.default = -g2
+GCC.args.g.max = -g3
diff --git a/make/variant/darwin.defs b/make/variant/darwin.defs
new file mode 100644
index 000000000..6f8f6729d
--- /dev/null
+++ b/make/variant/darwin.defs
@@ -0,0 +1,61 @@
+## UB build support
+##
+## PROCEDURE:
+##
+## 1. Perform a build (let us call it arch-X).
+## 2. cd into arch-X's build/ driectory.
+## 3. Launch builds of the remaining architectures.
+## We compute $(UB.archs.other) to be the remaining archs to build.
+## The entire list is defined $(UB.archs) .
+## 4. Combine other architectures into arch-X's binaries.
+##
+## EXAMPLE: serial method, archs: i386,x86_64,ppc,ppc64
+##
+## ./configure --launch
+## cd build/
+## make ub.build.serial
+## make ub.combine
+##
+## EXAMPLE: parallel method, archs: i386,x86_64,ppc,ppc64
+##
+## ./configure --launch
+## cd build/
+## make ub.build.parallel
+## make ub.combine
+##
+## EXAMPLE: serial, archs: i386,x86_64 (assuming i386 is native)
+##
+## ./configure --launch
+## cd build/
+## make ub.build.parallel UB.archs="i386 x86_64"
+## make ub.combine UB.archs="i386 x86_64"
+##
+UB.archs = i386 x86_64 ppc ppc64
+UB.archs.other = $(filter-out $(BUILD.arch),$(UB.archs))
+UB.builds = $(wildcard $(foreach n,$(UB.archs.other),$(PROJECT/)build.$n))
+
+UB.BUILD = $(PROJECT/)configure --launch --launch-dir=ub.$(1) --arch=$(1)
+
+## linefeed is important
+define UB.BUILD.item
+ $(call UB.BUILD,$(1))
+
+endef
+
+define UB.BUILD.SERIAL
+ $(foreach n,$(UB.archs.other),$(call UB.BUILD.item,$n))
+endef
+
+define UB.BUILD.PARALLEL
+ $(call UB.BUILD,$(1)) 2>&1 > ub.$(1).log
+endef
+
+define UB.COMBINE
+ $(RM.exe) -fr ub.combine
+ $(MKDIR.exe) -p ub.combine
+ $(CP.exe) -R HandBrake.app ub.combine/.
+ lipo $(1) $(foreach n,$(UB.archs.other),ub.$n/$(1)) -create -output ub.combine/$(1)
+ @echo ""
+ @sync; lipo -info ub.combine/$(1)
+ @du -sh ub.combine/$(1)
+endef
diff --git a/make/variant/darwin.rules b/make/variant/darwin.rules
new file mode 100644
index 000000000..c4f4f97a4
--- /dev/null
+++ b/make/variant/darwin.rules
@@ -0,0 +1,20 @@
+.PHONY: ub.build ub.combine ub.clean
+
+ub.build.serial:
+ @$(UB.BUILD.SERIAL)
+
+ub.build.parallel:
+ @set -e; \
+ for arch in $(UB.archs.other); do \
+ $(call UB.BUILD.PARALLEL,$$arch) & \
+ children="$$children $$!"; \
+ echo "pid $$!: $(call UB.BUILD.PARALLEL,$$arch)"; \
+ done; \
+ echo "waiting for background jobs to complete:$$children"; \
+ wait
+
+ub.combine:
+ $(call UB.COMBINE,HandBrake.app/Contents/MacOS/HandBrake)
+
+ub.clean:
+ $(RM.EXE) -fr $(foreach n,$(UB.archs.other),ub.$n)
diff --git a/make/variant/darwin.x86_64.defs b/make/variant/darwin.x86_64.defs
new file mode 100644
index 000000000..c6e856476
--- /dev/null
+++ b/make/variant/darwin.x86_64.defs
@@ -0,0 +1,3 @@
+## can enable asm if we replace .rept pseudo op with standard pre-processor macros
+## since darwin's as doesn't support them. for now just disable.
+LIBTHEORA.CONFIGURE.extra += --disable-asm
diff --git a/make/variant/freebsd.defs b/make/variant/freebsd.defs
new file mode 100644
index 000000000..c58706ba1
--- /dev/null
+++ b/make/variant/freebsd.defs
@@ -0,0 +1,4 @@
+TARGET.dylib.ext = .so
+
+GCC.args.dylib = -shared
+GCC.args.pic = 1
diff --git a/make/variant/linux.defs b/make/variant/linux.defs
new file mode 100644
index 000000000..f0babe87c
--- /dev/null
+++ b/make/variant/linux.defs
@@ -0,0 +1,11 @@
+TARGET.dylib.ext = .so
+
+GCC.start = 1
+GCC.end = 1
+GCC.args.dylib = -shared
+GCC.args.pic = 1
+
+GCC.args.g.none = -g0
+GCC.args.g.min = -g1
+GCC.args.g.default = -g2
+GCC.args.g.max = -g3