diff options
Diffstat (limited to 'acprep')
-rwxr-xr-x | acprep | 1609 |
1 files changed, 1570 insertions, 39 deletions
@@ -1,39 +1,1570 @@ -#!/bin/sh - -touch AUTHORS COPYING - -aclocal -autoheader -if [ "$1" = "--dist" ]; then - automake -a -c -f -i -else - automake -a -c -f -fi -autoconf - -INCDIRS="-I/sw/include -I/usr/include/httpd/xml -I/usr/include/python2.3" -#INCDIRS="$INCDIRS -I/sw/include/libofx" -INCDIRS="$INCDIRS -Wno-long-double" -LIBDIRS="-L/sw/lib -L/usr/lib/python2.3/config" - -if [ "$1" = "--debug" ]; then - ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g" \ - --enable-debug -elif [ "$1" = "--debug-python" ]; then - ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g" \ - --enable-debug --enable-python -elif [ "$1" = "--opt" ]; then - ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \ - CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC" -elif [ "$1" = "--flat-opt" ]; then - ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \ - CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450" -elif [ "$1" = "--safe-opt" ]; then - ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \ - CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC -DDEBUG_LEVEL=1" \ - --enable-python -elif [ "$1" = "--perf" ]; then - ./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g -pg" -fi - -rm AUTHORS COPYING +#!/usr/bin/env python + +# acprep, version 3.0 +# +# This script configures my ledger source tree on my Mac OS/X machine. This +# is not necessary, however, since I keep all the files necessary for building +# checked in to the source tree. Users can just type './configure && make'. +# This script simply sets up the compiler and linker flags for all the various +# build permutations I use for testing and profiling. + +import inspect +import logging +import logging.handlers +import optparse +import os +import re +import shutil +import string +import sys +import time +import tempfile +import datetime + +try: + import hashlib +except: + import md5 + +from os.path import * +from stat import * +from subprocess import Popen, PIPE, call + +LEVELS = {'DEBUG': logging.DEBUG, + 'INFO': logging.INFO, + 'WARNING': logging.WARNING, + 'ERROR': logging.ERROR, + 'CRITICAL': logging.CRITICAL} + + +class CommandLineApp(object): + "Base class for building command line applications." + + force_exit = True # If true, always ends run() with sys.exit() + log_handler = None + darwin_gcc = False + + options = { + 'debug': False, + 'verbose': False, + 'logfile': False, + 'loglevel': False + } + + def __init__(self): + "Initialize CommandLineApp." + # Create the logger + self.log = logging.getLogger(os.path.basename(sys.argv[0])) + ch = logging.StreamHandler() + formatter = logging.Formatter("%(name)s: %(levelname)s: %(message)s") + ch.setFormatter(formatter) + self.log.addHandler(ch) + self.log_handler = ch + + # Setup the options parser + usage = 'usage: %prog [OPTIONS...] [ARGS...]' + op = self.option_parser = optparse.OptionParser(usage = usage, + conflict_handler = 'resolve') + op.add_option('', '--debug', + action='store_true', dest='debug', + default=False, help='show debug messages and pass exceptions') + op.add_option('-v', '--verbose', + action='store_true', dest='verbose', + default=False, help='show informational messages') + op.add_option('-q', '--quiet', + action='store_true', dest='quiet', + default=False, help='do not show log messages on console') + op.add_option('', '--log', metavar='FILE', + type='string', action='store', dest='logfile', + default=False, help='append logging data to FILE') + op.add_option('', '--loglevel', metavar='LEVEL', + type='string', action='store', dest='loglevel', + default=False, help='set log level: DEBUG, INFO, WARNING, ERROR, CRITICAL') + return + + def main(self, *args): + """Main body of your application. + + This is the main portion of the app, and is run after all of the + arguments are processed. Override this method to implment the primary + processing section of your application.""" + pass + + def handleInterrupt(self): + """Called when the program is interrupted via Control-C or SIGINT. + Returns exit code.""" + self.log.error('Canceled by user.') + return 1 + + def handleMainException(self): + "Invoked when there is an error in the main() method." + if not self.options.debug: + self.log.exception('Caught exception') + return 1 + + ## INTERNALS (Subclasses should not need to override these methods) + + def run(self): + """Entry point. + + Process options and execute callback functions as needed. This method + should not need to be overridden, if the main() method is defined.""" + # Process the options supported and given + self.options, main_args = self.option_parser.parse_args() + + if self.options.logfile: + fh = logging.handlers.RotatingFileHandler(self.options.logfile, + maxBytes = (1024 * 1024), + backupCount = 5) + formatter = logging.Formatter("%(asctime)s - %(levelname)s: %(message)s") + fh.setFormatter(formatter) + self.log.addHandler(fh) + + if self.options.quiet: + self.log.removeHandler(self.log_handler) + ch = logging.handlers.SysLogHandler() + formatter = logging.Formatter("%(name)s: %(levelname)s: %(message)s") + ch.setFormatter(formatter) + self.log.addHandler(ch) + self.log_handler = ch + + if self.options.loglevel: + self.log.setLevel(LEVELS[self.options.loglevel]) + elif self.options.debug: + self.log.setLevel(logging.DEBUG) + elif self.options.verbose: + self.log.setLevel(logging.INFO) + + exit_code = 0 + try: + # We could just call main() and catch a TypeError, but that would + # not let us differentiate between application errors and a case + # where the user has not passed us enough arguments. So, we check + # the argument count ourself. + argspec = inspect.getargspec(self.main) + expected_arg_count = len(argspec[0]) - 1 + + if len(main_args) >= expected_arg_count: + exit_code = self.main(*main_args) + else: + self.log.debug('Incorrect argument count (expected %d, got %d)' % + (expected_arg_count, len(main_args))) + self.option_parser.print_help() + exit_code = 1 + + except KeyboardInterrupt: + exit_code = self.handleInterrupt() + + except SystemExit, msg: + exit_code = msg.args[0] + + except Exception: + exit_code = self.handleMainException() + if self.options.debug: + raise + + if self.force_exit: + sys.exit(exit_code) + return exit_code + + +class PrepareBuild(CommandLineApp): + ######################################################################### + # Initialization routines # + ######################################################################### + + def initialize(self): + self.log.debug('Initializing all state variables') + + self.should_clean = False + self.configured = False + self.current_ver = None + #self.current_flavor = 'default' + self.current_flavor = 'debug' + self.products_dir = None + self.build_dir = self.source_dir + self.configure_args = ['--with-included-gettext', '--enable-python'] + self.sys_include_dirs = [] + self.sys_library_dirs = [] + + self.CPPFLAGS = [] + self.CFLAGS = [] + self.CXXFLAGS = [] + self.LDFLAGS = [] + + self.envvars = { + 'PYTHON_HOME': '/usr', + 'PYTHON_VERSION': '2.6', + 'BOOST_SUFFIX': None, + 'BOOST_HOME': '/usr', + 'LEDGER_PRODUCTS': None, + 'CC': 'gcc', + 'CPPFLAGS': '', + 'CFLAGS': '', + 'CXX': 'g++', + 'CXXFLAGS': '', + 'LD': 'g++', + 'LDFLAGS': '' + } + + for varname in self.envvars.keys(): + if os.environ.has_key(varname): + self.envvars[varname] = os.environ[varname] + + if varname.endswith('FLAGS'): + self.__dict__[varname] = string.split(os.environ[varname]) + self.envvars[varname] = '' + + # If ~/Products/ or build/ exists, use them instead of the source tree + # for building + products = self.default_products_directory() + if (exists(products) and isdir(products)) or \ + (exists('build') and isdir('build')): + self.build_dir = None + + def __init__(self): + CommandLineApp.__init__(self) + self.log.setLevel(logging.INFO) + + op = self.option_parser + op.add_option('-j', '--jobs', metavar='N', + type='int', action='store', dest='jobs', + default=1, help='Allow N make jobs at once') + op.add_option('', '--boost', metavar='SUFFIX', + action="callback", type="string", + callback=self.option_boost, + help='Set Boost library suffix (ex: "--boost=-mt")') + op.add_option('', '--force', action="callback", + callback=self.option_force, + help="Perform every action, without checking") + op.add_option('', '--glibcxx-debug', action='store_true', + dest='use_glibcxx_debug', default=False, + help='Define _GLIBCXX_DEBUG=1 during compilation') + op.add_option('', '--help', action="callback", + callback=self.option_help, + help='Show this help text') + op.add_option('', '--local', action="callback", + callback=self.option_local, + help='Build directly within the source tree (default)') + op.add_option('', '--no-pch', action="callback", + callback=self.option_no_pch, + help='Do not use pre-compiled headers') + op.add_option('', '--no-patch', action='store_true', dest='no_patch', + default=False, + help='Do not patch the Makefile for prettier output') + op.add_option('', '--no-git', action='store_true', dest='no_git', + default=False, + help='Do not call out to Git; useful for offline builds') + op.add_option('', '--output', metavar='DIR', action="callback", + callback=self.option_output, + help='Build in the specified directory') + op.add_option('', '--pch', action="callback", + callback=self.option_pch, + help='Enable use of pre-compiled headers') + op.add_option('', '--pic', action="callback", + callback=self.option_pic, + help='Compile with explicit PIC support') + op.add_option('', '--products', metavar='DIR', action="callback", + callback=self.option_products, + help='Collect all build products in this directory') + op.add_option('', '--trees', action="callback", + callback=self.option_trees, + help='Use separate build trees for each flavor') + op.add_option('', '--release', action="callback", + callback=self.option_release, + help='Setup for doing a faster, once-only build') + op.add_option('', '--warn', action="callback", + callback=self.option_warn, + help='Enable full warning flags') + + self.force = False + self.no_pch = False + self.source_dir = os.getcwd() + + self.initialize() + + def main(self, *args): + if args and args[0] in ['default', 'debug', 'opt', 'gcov', 'gprof']: + self.current_flavor = args[0] + args = args[1:] + + if args: + cmd = args[0] + if not PrepareBuild.__dict__.has_key('phase_' + cmd): + cmd = 'config' + else: + args = args[1:] + else: + cmd = 'config' + + self.log.info('Invoking primary phase: ' + cmd) + PrepareBuild.__dict__['phase_' + cmd](self, *args) + + ######################################################################### + # General utility code # + ######################################################################### + + def execute(self, *args): + try: + self.log.debug('Executing command: ' + string.join(args, ' ')) + + retcode = call(args, shell=False) + if retcode < 0: + self.log.error("Child was terminated by signal", -retcode) + sys.exit(1) + elif retcode != 0: + self.log.error("Execution failed: " + string.join(args, ' ')) + sys.exit(1) + except OSError, e: + self.log.error("Execution failed:", e) + sys.exit(1) + + def get_stdout(self, *args): + try: + self.log.debug('Executing command: ' + string.join(args, ' ')) + + proc = Popen(args, shell=False, stdout=PIPE) + stdout = proc.stdout.read() + retcode = proc.wait() + if retcode < 0: + self.log.error("Child was terminated by signal", + -retcode) + sys.exit(1) + elif retcode != 0: + self.log.error("Execution failed: " + string.join(args, ' ')) + sys.exit(1) + return stdout[:-1] + except OSError, e: + self.log.error("Execution failed:", e) + sys.exit(1) + + def isnewer(self, file1, file2): + "Check if file1 is newer than file2." + if not exists(file2): + return True + return os.stat(file1)[ST_MTIME] > os.stat(file2)[ST_MTIME] + + ######################################################################### + # Determine information about the surroundings # + ######################################################################### + + def default_products_directory(self): + if self.envvars['LEDGER_PRODUCTS']: + return self.envvars['LEDGER_PRODUCTS'] + else: + return join(os.environ['HOME'], "Products") + + def products_directory(self): + if not self.products_dir: + products = self.default_products_directory() + + if not exists(products) or not isdir(products): + products = join(self.source_dir, 'build') + + products = join(products, basename(self.source_dir)) + + self.products_dir = products + + return self.products_dir + + def build_directory(self): + if not self.build_dir: + self.build_dir = join(self.products_directory(), + self.current_flavor) + return self.build_dir + + def ensure(self, dirname): + if not exists(dirname): + self.log.info('Making directory: ' + dirname) + os.makedirs(dirname) + elif not isdir(dirname): + self.log.error('Directory is not a directory: ' + dirname) + sys.exit(1) + return dirname + + def git_working_tree(self): + return exists('.git') and isdir('.git') and not self.options.no_git + + def current_version(self): + if not self.current_ver: + if self.git_working_tree(): + #date = self.get_stdout('git', 'log', '--format=%ci', '-1', 'HEAD') + #date = re.sub(" [-+][0-9][0-9][0-9][0-9]$", "", date) + #when = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S") + #self.current_ver = when.strftime("%Y%m%d_%H%M%S") + #commit = self.get_stdout('git', 'log', '--format=%h', 'HEAD^..HEAD') + #self.current_ver += "_" + commit + tag = self.get_stdout('git', 'describe', '--all', '--long') + self.current_ver = re.sub('heads/', '', tag) + else: + self.current_ver = "no-git" + return self.current_ver + + def need_to_prepare_autotools(self): + if self.force: + return 'because it was forced' + elif self.isnewer('acprep', 'configure'): + self.should_clean = True + return 'because acprep is newer than configure' + elif self.isnewer('acprep', 'Makefile.in'): + self.should_clean = True + return 'because acprep is newer than Makefile.in' + elif self.isnewer('configure.ac', 'configure'): + return 'because confgure.ac is newer than configure' + elif self.isnewer('Makefile.am', 'Makefile.in'): + return 'because Makefile.am is newer than Makefile.in' + return False + + def phase_products(self, *args): + self.log.info('Executing phase: products') + print self.products_directory() + + def phase_info(self, *args): + self.log.info('Executing phase: info') + + environ, conf_args = self.configure_environment() + + self.log.info("Current version => " + self.current_version()) + self.log.info("Current flavor => " + self.current_flavor) + self.log.info("Source directory => " + self.source_dir) + self.log.info("Need to run autogen.sh => " + + str(self.need_to_prepare_autotools())) + self.log.info("Products directory => " + self.products_directory()) + self.log.info("Build directory => " + self.build_directory()) + self.log.info("Need to run configure => " + + str(self.need_to_run_configure())) + self.log.info("Use _GLIBCXX_DEBUG => " + + str(self.options.use_glibcxx_debug)) + self.log.info("Use pre-compiled headers => " + + str('--enable-pch' in conf_args)) + + self.log.debug('Configure environment =>') + + keys = environ.keys() + keys.sort() + for key in keys: + if key in ['PATH', 'CC', 'LD', 'CXX'] or \ + key.endswith('FLAGS'): + self.log.debug(' %s=%s' % (key, environ[key])) + + self.log.debug('Configure arguments =>') + + for arg in conf_args + list(args): + self.log.debug(' %s' % arg) + + def phase_sloc(self, *args): + self.log.info('Executing phase: sloc') + self.execute('sloccount', 'src', 'python', 'lisp', 'test') + + ######################################################################### + # Configure source tree using autogen # + ######################################################################### + + def phase_gettext(self, *args): + self.log.info('Executing phase: gettext') + + # configure the template files + assert exists('po') and isdir('po') + if not exists(join('po', 'Makevars')): + assert exists(join('po', 'Makevars.template')) + self.log.info('Moving po/Makevars.template -> po/Makevars') + os.rename(join('po', 'Makevars.template'), + join('po', 'Makevars')) + + POTFILES_in = open('po/POTFILES.in', 'w') + for filename in (f for f in os.listdir(join(self.source_dir, 'src')) + if re.search('\.(cc|h)', f)): + POTFILES_in.write(join('src', filename)) + POTFILES_in.write('\n') + POTFILES_in.close() + + def phase_version(self, *args): + self.log.info('Executing phase: version') + version_m4 = open('version.m4', 'w') + version_m4.write("m4_define([VERSION_NUMBER], [%s])\n" % + self.current_version()) + version_m4.close() + + def phase_autogen(self, *args): + self.log.info('Executing phase: autogen') + + if not exists('autogen.sh') or \ + self.isnewer('tools/autogen.sh', 'autogen.sh'): + shutil.copyfile('tools/autogen.sh', 'autogen.sh') + + self.execute('sh', 'tools/autogen.sh') + + def phase_aclocal(self, *args): + self.log.info('Executing phase: aclocal') + self.execute('aclocal', '-I', 'm4') + + def phase_autoconf(self, *args): + self.log.info('Executing phase: autoconf') + + if not exists('configure.ac') or \ + self.isnewer('tools/configure.ac', 'configure.ac'): + shutil.copyfile('tools/configure.ac', 'configure.ac') + + if not exists('Makefile.am') or \ + self.isnewer('tools/Makefile.am', 'Makefile.am'): + shutil.copyfile('tools/Makefile.am', 'Makefile.am') + + reason = self.need_to_prepare_autotools() + if reason: + self.log.info('autogen.sh must be run ' + reason) + self.phase_version() + self.phase_autogen() + self.phase_gettext() + self.phase_aclocal() + else: + self.log.debug('autogen.sh does not need to be run') + + ######################################################################### + # Update local files with the latest information # + ######################################################################### + + def phase_submodule(self, *args): + self.log.info('Executing phase: submodule') + if self.git_working_tree(): + self.execute('git', 'submodule', 'init') + self.execute('git', 'submodule', 'update') + + def phase_pull(self, *args): + self.log.info('Executing phase: pull') + if self.git_working_tree(): + self.execute('git', 'pull') + self.phase_submodule() + + ######################################################################### + # Automatic installation of build dependencies # + ######################################################################### + + def phase_dependencies(self, *args): + self.log.info('Executing phase: dependencies') + + self.log.info("Installing Ledger's build dependencies ...") + + system = self.get_stdout('uname', '-s') + + if system == 'Darwin': + if exists('/opt/local/bin/port'): + self.log.info('Looks like you are using MacPorts on OS X') + packages = [ + 'sudo', 'port', 'install', '-f', + 'automake', + 'autoconf', + 'libtool', + 'python26', '+universal', + 'libiconv', '+universal', + 'zlib', '+universal', + 'gmp' ,'+universal', + 'mpfr', '+universal', + 'ncurses', '+universal', + 'ncursesw', '+universal', + 'gettext' ,'+universal', + 'libedit' ,'+universal', + 'boost-jam', + 'boost', '+icu+python26+st+universal', + 'cppunit', '+universal', + #'texlive', + #'doxygen', + #'graphviz', + 'texinfo', + 'lcov', + 'sloccount' + ] + self.log.info('Executing: ' + string.join(packages, ' ')) + self.execute(*packages) + elif exists('/sw/bin/fink'): + self.log.info('Looks like you are using Fink on OS X') + self.log.error("I don't know the package names for Fink yet!") + + elif system == 'Linux': + if exists('/etc/issue'): + issue = open('/etc/issue') + if issue.readline().startswith('Ubuntu'): + release = open('/etc/lsb-release') + info = release.read() + release.close() + if re.search('karmic', info): + self.log.info('Looks like you are using APT on Ubuntu Karmic') + packages = [ + 'sudo', 'apt-get', 'install', + 'build-essential', + 'libtool', + 'autoconf', + 'automake', + 'zlib1g-dev', + 'libbz2-dev', + 'python-dev', + 'libgmp3-dev', + 'libmpfr-dev', + 'bjam', + 'gettext', + 'cvs', + 'libboost1.40-dev', + 'libboost-regex1.40-dev', + 'libboost-date-time1.40-dev', + 'libboost-filesystem1.40-dev', + 'libboost-python1.40-dev', + 'libedit-dev', + 'libcppunit-dev', + #'texlive-full', + #'doxygen', + #'graphviz', + 'texinfo', + 'lcov', + 'sloccount' + ] + else: + self.log.info('Looks like you are using APT on Ubuntu Hardy') + packages = [ + 'sudo', 'apt-get', 'install', + 'build-essential', + 'libtool', + 'autoconf', + 'automake', + 'zlib1g-dev', + 'libbz2-dev', + 'python-dev', + 'bjam', + 'cvs', + 'gettext', + 'libgmp3-dev', + 'libmpfr-dev', + 'libboost1.35-dev', + 'libboost-python1.35-dev', + 'libboost-regex1.35-dev', + 'libboost-date-time1.35-dev', + 'libboost-filesystem1.35-dev', + 'libedit-dev', + 'libcppunit-dev', + #'texlive-full', + #'doxygen', + #'graphviz', + 'texinfo', + 'lcov', + 'sloccount' + ] + self.log.info('Executing: ' + string.join(packages, ' ')) + self.execute(*packages) + + if exists('/etc/redhat-release'): + release = open('/etc/redhat-release') + if release.readline().startswith('CentOS'): + self.log.info('Looks like you are using YUM on CentOS') + packages = [ + 'sudo', 'yum', 'install', + 'gcc', + 'gcc-c++', + 'compat-gcc-*', + 'make', + 'libtool', + 'autoconf', + 'automake', + 'zlib-devel', + 'bzip2-devel', + 'python-devel', + 'bboost-devel', + 'gmp-devel', + 'gettext-devel', + #'mpfr-devel' + 'libedit-devel', + 'cppunit-devel', + #'texlive-full', + #'doxygen', + #'graphviz', + 'texinfo', + #'lcov', + #'sloccount' + ] + self.log.info('Executing: ' + string.join(packages, ' ')) + self.execute(*packages) + + def phase_buildlibs(self, *args): + self.log.info('Executing phase: buildlibs') + + try: + os.chdir('lib') + + environ, conf_args = self.configure_environment() + + boost = 'boost_1_41_0' + tarball = boost + '.7z' + + if not exists(boost): + if not exists(tarball): + self.log.info('Downloading Boost source tarball ...') + self.execute('curl', '-L', '-o', tarball, + 'http://downloads.sourceforge.net/boost/' + + boost + '.7z?use_mirror=ufpr') + + if not exists(tarball): + self.log.error('Failed to locate the Boost source tarball') + sys.exit(1) + + fd = open(tarball) + try: + csum = hashlib.md5() + except: + csum = md5.md5() + csum.update(fd.read()) + fd.close() + digest = csum.hexdigest() + + if digest != 'b74ee2f0f46cef601544dd4ac2d7dec4': + self.log.error('Boost source tarball fails to match checksum') + sys.exit(1) + + self.log.info('Extracting Boost source tarball ...') + self.execute('7za', 'x', tarball) + + if not exists(boost): + self.log.error('Failed to locate the Boost sources') + sys.exit(1) + + if not exists('cppunit') and self.git_working_tree(): + self.execute('git', 'clone', 'git://github.com/jwiegley/cppunit.git') + + if not exists('cppunit'): + self.log.error('Failed to locate the CppUnit sources') + sys.exit(1) + + self.execute('make', + 'BOOST_SOURCE=%s' % boost, + 'CC=%s' % environ['CC'], + 'CXX=%s' % environ['CXX'], + 'LD=%s' % environ['LD'], + 'build-all') + finally: + os.chdir(self.source_dir) + + ######################################################################### + # Determine the system's basic configuration # + ######################################################################### + + def locate_boost_in_dir(self, path): + if exists(path) and isdir(path): + entries = os.listdir(path) + entries.sort() + for entry in entries: + if re.search('boost_regex', entry): + self.log.info('Found a Boost library: ' + entry) + + match = re.match('libboost_regex([^.]*)\.(a|so|dylib)', entry) + if match: + suffix = match.group(1) + self.log.info('Found Boost suffix => ' + suffix) + self.envvars['BOOST_HOME'] = dirname(path) + return suffix + else: + self.log.debug('The directory "%s" is not valid, skipping' % + path) + return None + + def inform_boost_location(self, text, suffix): + self.log.info('Boost %s here:' % text) + self.log.info('BOOST_HOME => ' + self.envvars['BOOST_HOME']) + self.log.info('BOOST_SUFFIX => ' + suffix) + + def locate_boost(self): + if self.envvars['BOOST_SUFFIX']: + self.log.info(("Not looking for Boost, since " + + "a suffix of '%s' was given") % + self.envvars['BOOST_SUFFIX']) + else: + suffix = None + for path in ['/usr/local/lib', '/opt/local/lib', + '/sw/lib', '/usr/lib']: + self.log.info('Looking for Boost in %s...' % path) + suffix = self.locate_boost_in_dir(path) + if suffix is not None: + self.inform_boost_location('was found', suffix) + break + if suffix is None: + self.log.error("Boost could not be found.") + self.envvars['BOOST_SUFFIX'] = suffix + return self.envvars['BOOST_SUFFIX'] + + def setup_system_directories(self): + boost_suffix = self.locate_boost() + + # Each of these becomes '-isystem <name>' + for path in ['/usr/local/include', + '%s/include/boost' % + self.envvars['BOOST_HOME'], + '%s/include' % self.envvars['BOOST_HOME'], + '%s/include/python%s' % + (self.envvars['PYTHON_HOME'], + self.envvars['PYTHON_VERSION'].strip()), + '/opt/local/include', + '/sw/include']: + if exists(path) and isdir(path) and \ + path != '/usr/include': + self.log.info('Noticing include directory => ' + path) + self.sys_include_dirs.append(path) + + # Each of these becomes '-L<name>' + for path in ['/usr/local/lib', + '%s/lib' % self.envvars['PYTHON_HOME'], + '%s/lib/python%s/config' + % (self.envvars['PYTHON_HOME'], + self.envvars['PYTHON_VERSION'].strip()), + '/opt/local/lib', + '/sw/lib']: + if exists(path) and isdir(path): + self.log.info('Noticing library directory => ' + path) + self.sys_library_dirs.append(path) + + def setup_for_johnw(self): + if self.current_flavor == 'debug' or self.current_flavor == 'gcov': + if exists('/usr/local/stow/cppunit/include'): + self.sys_include_dirs.insert(0, '/usr/local/stow/cppunit/include') + self.sys_library_dirs.insert(0, '/usr/local/stow/cppunit/lib') + + if exists('/usr/local/stow/icu/include'): + self.sys_include_dirs.insert(0, '/usr/local/stow/icu/include') + self.sys_library_dirs.insert(0, '/usr/local/stow/icu/lib') + + self.CPPFLAGS.append('-D_GLIBCXX_FULLY_DYNAMIC_STRING=1') + self.configure_args.append('--disable-shared') + + self.options.use_glibcxx_debug = True + else: + self.CXXFLAGS.append('-march=nocona') + self.CXXFLAGS.append('-msse3') + + self.configure_args.append('--enable-doxygen') + self.configure_args.append('--enable-python') + + def setup_for_system(self): + self.setup_system_directories() + + system = self.get_stdout('uname', '-s') + + self.log.info('System type is => ' + system) + + # These options are global defaults at the moment + #self.option_warn() + if not self.no_pch: + self.option_pch() + + if system == 'Linux': + arch = self.get_stdout('uname', '-m') + if arch == 'x86_64': + if '--disable-shared' in self.configure_args: + self.configure_args.remove('--disable-shared') + self.configure_args.append('--disable-static') + self.CXXFLAGS.append('-pthread') + + elif system == 'Solaris': + self.CXXFLAGS.append('-pthread') + + elif system == 'Darwin': + if exists('/Users/johnw/Dropbox/Accounts/ledger.dat'): + self.setup_for_johnw() + + self.locate_darwin_libraries() + + if (self.current_flavor == 'opt' or \ + self.current_flavor == 'default') and \ + exists('/usr/bin/g++-4.2'): + self.envvars['CC'] = '/usr/bin/gcc-4.2' + self.envvars['CXX'] = '/usr/bin/g++-4.2' + self.envvars['LD'] = '/usr/bin/g++-4.2' + self.darwin_gcc = True + elif exists('/opt/local/bin/g++-mp-4.4'): + self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.4' + self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.4' + self.envvars['LD'] = '/opt/local/bin/g++-mp-4.4' + elif exists('/opt/local/bin/g++-mp-4.3'): + self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.3' + self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.3' + self.envvars['LD'] = '/opt/local/bin/g++-mp-4.3' + elif exists('/usr/bin/g++-4.2'): + self.envvars['CC'] = '/usr/bin/gcc-4.2' + self.envvars['CXX'] = '/usr/bin/g++-4.2' + self.envvars['LD'] = '/usr/bin/g++-4.2' + self.darwin_gcc = True + else: + # g++ 4.0.1 cannot use PCH headers on OS X 10.5 + self.option_no_pch() + + if '--enable-pch' not in self.configure_args and \ + (exists('/opt/local/bin/ccache') or \ + exists('/usr/local/bin/ccache')): + self.envvars['CC'] = 'ccache ' + self.envvars['CC'] + self.envvars['CXX'] = 'ccache ' + self.envvars['CXX'] + self.envvars['LD'] = 'ccache ' + self.envvars['LD'] + + def setup_flags(self): + for path in self.sys_include_dirs: + self.CPPFLAGS.append('-isystem') + self.CPPFLAGS.append(path) + + self.CXXFLAGS.append('-pipe') + + for path in self.sys_library_dirs: + self.LDFLAGS.append('-L' + path) + + def setup_flavor(self): + self.setup_for_system() + + if not PrepareBuild.__dict__.has_key('setup_flavor_' + + self.current_flavor): + self.log.error('Unknown build flavor "%s"' % self.current_flavor) + sys.exit(1) + + self.log.info('Setting up build flavor => ' + self.current_flavor) + PrepareBuild.__dict__['setup_flavor_' + self.current_flavor](self) + + self.setup_flags() + + def escape_string(self, data): + return re.sub('(["\\\\])', '\\\\\\1', data) + + def finalize_config(self): + self.setup_flavor() + + for var in ('CPPFLAGS', 'CFLAGS', 'CXXFLAGS', 'LDFLAGS'): + value = self.__dict__[var] + if value: + first = not self.envvars[var] + for member in value: + #escaped = self.escape_string(member) + #if member != escaped: + # member = escaped + if first: + first = False + else: + self.envvars[var] += ' ' + self.envvars[var] += member + self.log.debug('Final value of %s: %s' % + (var, self.envvars[var])) + + elif self.envvars.has_key(var): + del self.envvars[var] + + ######################################################################### + # Options that can modify any build flavor # + ######################################################################### + + def option_pch(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --pch') + + self.configure_args.append('--enable-pch') + + self.CXXFLAGS.append('-fpch-deps') + self.CXXFLAGS.append('-Wconversion') + #self.CXXFLAGS.append('-Wold-style-cast') + + system = self.get_stdout('uname', '-s') + + def option_no_pch(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --no-pch') + + self.no_pch = True + + if '--enable-pch' in self.configure_args: + self.configure_args.remove('--enable-pch') + + if '-Wconversion' in self.configure_args: + self.CXXFLAGS.remove('-Wconversion') + #if '-Wold-style-cast' in self.configure_args: + # self.CXXFLAGS.remove('-Wold-style-cast') + + system = self.get_stdout('uname', '-s') + + if system == "Darwin": + self.envvars['CC'] = 'gcc' + self.envvars['CXX'] = 'g++' + self.envvars['LD'] = 'g++' + + def option_force(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --force') + self.force = True + + def option_warn(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --warn') + self.CXXFLAGS.append('-ansi') + self.CXXFLAGS.append('-pedantic') + self.CXXFLAGS.append('-pedantic-errors') + self.CXXFLAGS.append('-Wall') + self.CXXFLAGS.append('-Winvalid-pch') + self.CXXFLAGS.append('-Wextra') + self.CXXFLAGS.append('-Wcast-align') + self.CXXFLAGS.append('-Wcast-qual') + self.CXXFLAGS.append('-Wfloat-equal') + self.CXXFLAGS.append('-Wmissing-field-initializers') + self.CXXFLAGS.append('-Wno-endif-labels') + self.CXXFLAGS.append('-Woverloaded-virtual') + self.CXXFLAGS.append('-Wsign-compare') + self.CXXFLAGS.append('-Wsign-promo') + self.CXXFLAGS.append('-Wstrict-null-sentinel') + self.CXXFLAGS.append('-Wwrite-strings') + self.CXXFLAGS.append('-Wno-old-style-cast') + self.CXXFLAGS.append('-Wno-deprecated') + self.CXXFLAGS.append('-Wno-strict-aliasing') + self.CXXFLAGS.append('-Werror') + + def option_boost(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --boost') + self.envvars['BOOST_SUFFIX'] = value + + def option_pic(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --pic') + self.CXXFLAGS.append('-fPIC') + + def option_output(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --output') + self.build_dir = value + + def option_products(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --products') + self.products_dir = value + + def option_local(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --local') + self.build_dir = self.source_dir + + def option_trees(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --trees') + self.build_dir = None + + def option_release(self, option=None, opt_str=None, value=None, parser=None): + self.log.debug('Saw option --release') + if '--disable-shared' in self.configure_args: + self.configure_args.remove('--disable-shared') + self.configure_args.append('--disable-dependency-tracking') + + def option_help(self, option=None, opt_str=None, value=None, parser=None): + self.phase_help() + + ######################################################################### + # The various build flavors # + ######################################################################### + + def locate_darwin_libraries(self): + if self.current_flavor == 'debug' or self.current_flavor == 'gcov': + self.log.debug('We are using GLIBCXX_DEBUG, so setting up flags') + + if self.options.use_glibcxx_debug: + self.CPPFLAGS.append('-D_GLIBCXX_DEBUG=1') + + if exists('/usr/local/lib/libboost_regex-xgcc44-sd-1_41.a'): + self.envvars['BOOST_HOME'] = '/usr/local' + self.envvars['BOOST_SUFFIX'] = '-xgcc44-sd-1_41' + self.sys_include_dirs.append('/usr/local/include/boost-1_41') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + + elif exists('/usr/local/lib/libboost_regex-xgcc44-d-1_41.a'): + self.envvars['BOOST_HOME'] = '/usr/local' + self.envvars['BOOST_SUFFIX'] = '-xgcc44-d-1_41' + self.sys_include_dirs.append('/usr/local/include/boost-1_41') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + + elif exists('/opt/local/lib/libboost_regex-d.a'): + self.envvars['BOOST_HOME'] = '/opt/local' + self.envvars['BOOST_SUFFIX'] = '-d' + self.sys_include_dirs.append('/opt/local/include/boost') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + + else: + if exists('/opt/local/lib/libboost_regex.a'): + self.envvars['BOOST_HOME'] = '/opt/local' + self.envvars['BOOST_SUFFIX'] = '' + self.sys_include_dirs.append('/opt/local/include/boost') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + + elif exists('/usr/local/lib/libboost_regex-xgcc44-s-1_41.a'): + self.envvars['BOOST_HOME'] = '/usr/local' + self.envvars['BOOST_SUFFIX'] = '-xgcc44-s-1_41' + self.sys_include_dirs.append('/usr/local/include/boost-1_41') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + + elif exists('/usr/local/lib/libboost_regex-xgcc44-1_41.a'): + self.envvars['BOOST_HOME'] = '/usr/local' + self.envvars['BOOST_SUFFIX'] = '-xgcc44-1_41' + self.sys_include_dirs.append('/usr/local/include/boost-1_41') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + + def setup_flavor_default(self): + pass + + def setup_flavor_debug(self): + self.configure_args.append('--enable-debug') + + self.CXXFLAGS.append('-g') + self.LDFLAGS.append('-g') + + def setup_flavor_opt(self): + if self.darwin_gcc: + self.option_no_pch() + if '--disable-shared' in self.configure_args: + self.configure_args.remove('--disable-shared') + self.configure_args.append('--disable-dependency-tracking') + for i in ['-fast']: + self.CXXFLAGS.append(i) + self.CFLAGS.append(i) + self.LDFLAGS.append(i) + for i in ['-arch', 'i386', '-arch', 'x86_64']: + self.CXXFLAGS.append(i) + self.CFLAGS.append(i) + self.LDFLAGS.append(i) + else: + for i in ['-O3', '-fomit-frame-pointer']: + self.CXXFLAGS.append(i) + self.CFLAGS.append(i) + self.LDFLAGS.append(i) + + def setup_flavor_gcov(self): + self.CXXFLAGS.append('-g') + self.CXXFLAGS.append('-fprofile-arcs') + self.CXXFLAGS.append('-ftest-coverage') + self.LDFLAGS.append('-g') + + def setup_flavor_gprof(self): + self.CXXFLAGS.append('-g') + self.CXXFLAGS.append('-pg') + self.LDFLAGS.append('-g') + self.LDFLAGS.append('-pg') + + ######################################################################### + # Prettify the output from automake, by rewriting the Makefile # + ######################################################################### + + def phase_patch(self, *args): + """Alter the Makefile so that it's not nearly so verbose. + + This makes errors and warnings much easier to spot.""" + self.log.info('Executing phase: patch') + + if exists('Makefile'): + self.log.debug('Patching generated Makefile') + Makefile = open('Makefile') + Makefile_new = open('Makefile.new', 'w') + for line in Makefile.readlines(): + line = re.sub('^\t(\$\((LIBTOOL|CXX)\).*?\.(cc|cpp))$', + '\t@echo " " CXX \$@;\\1 > /dev/null', line) + line = re.sub('^\tmv -f', '\t@mv -f', line) + line = re.sub('^\t\$\(am__mv\)', '\t@$(am__mv)', line) + line = re.sub('^\t(\$\((.*?)LINK\).*)', + '\t@echo " LD " \$@;\\1 > /dev/null', line) + Makefile_new.write(line) + Makefile_new.close() + Makefile.close() + + os.remove('Makefile') + os.rename('Makefile.new', 'Makefile') + + stamp = open('.timestamp', 'w') + stamp.write('timestamp') + stamp.close() + + ######################################################################### + # Configure build tree using autoconf # + ######################################################################### + + def configure_environment(self): + self.finalize_config() + + environ = dict(os.environ) + for key, value in self.envvars.items(): + if value: + environ[key] = value + + environ['PATH'] = ('%s/bin:%s' % + (environ['PYTHON_HOME'], environ['PATH'])) + + if self.build_directory() == self.source_dir: + conf_args = ['sh', 'configure'] + else: + conf_args = ['sh', join(self.source_dir, 'configure'), + '--srcdir', self.source_dir] + + for var in ('CC', 'CPPFLAGS', 'CFLAGS', 'CXX', 'CXXFLAGS', + 'LD', 'LDFLAGS'): + if self.envvars.has_key(var) and self.envvars[var] and \ + (var.endswith('FLAGS') or exists(self.envvars[var])): + conf_args.append('%s=%s' % (var, self.envvars[var])) + + if environ.has_key('BOOST_SUFFIX') and environ['BOOST_SUFFIX']: + conf_args.append('--with-boost-suffix=%s' % + environ['BOOST_SUFFIX']) + + return (environ, conf_args + self.configure_args) + + def need_to_run_configure(self): + Makefile = join(self.build_directory(), 'Makefile') + if self.force: + return 'because it was forced' + elif not exists(Makefile): + return 'because Makefile does not exist' + elif self.isnewer(join(self.source_dir, 'configure'), Makefile): + return 'because configure is newer than Makefile' + elif self.isnewer(join(self.source_dir, 'Makefile.in'), Makefile): + return 'because Makefile.in is newer than Makefile' + return False + + def phase_configure(self, *args): + self.log.info('Executing phase: configure') + + self.configured = True + + build_dir = self.ensure(self.build_directory()) + try: + os.chdir(build_dir) + + reason = self.need_to_run_configure() + if reason: + self.log.info('./configure must be run ' + reason) + self.log.debug('Source => ' + self.source_dir) + self.log.debug('Build => ' + build_dir) + + environ, conf_args = self.configure_environment() + for arg in args: + if arg: conf_args.append(arg) + + self.log.debug('configure env => ' + str(environ)) + self.log.debug('configure args => ' + str(conf_args)) + + configure = Popen(conf_args, shell=False, env=environ) + retcode = configure.wait() + if retcode < 0: + self.log.error("Child was terminated by signal", -retcode) + sys.exit(1) + elif retcode != 0: + self.log.error("Execution failed: " + string.join(conf_args, ' ')) + sys.exit(1) + + if not self.options.no_patch: + self.phase_patch() + + # Wipe the pre-compiled header, if there is one + pch = join(self.build_directory(), 'system.hh.gch') + if exists(pch): + os.remove(pch) + else: + if not self.options.no_patch and \ + self.isnewer('Makefile', '.timestamp'): + self.phase_patch() + + self.log.debug('configure does not need to be run') + + finally: + os.chdir(self.source_dir) + + def phase_config(self, *args): + self.log.info('Executing phase: config') + self.phase_submodule() + self.phase_autoconf() + self.phase_configure(*args) + if self.should_clean: + self.phase_clean() + + ######################################################################### + # Builds products from the sources # + ######################################################################### + + def phase_make(self, *args): + self.log.info('Executing phase: make') + + config_args = [] + make_args = [] + + for arg in args: + if arg.startswith('--'): + config_args.append(arg) + else: + make_args.append(arg) + + if self.options.jobs > 1: + make_args.append('-j%d' % self.options.jobs) + + self.log.debug('Configure arguments => ' + str(config_args)) + self.log.debug('Makefile arguments => ' + str(make_args)) + + if not self.configured: + self.phase_config(*config_args) + + build_dir = self.ensure(self.build_directory()) + try: + self.log.debug('Changing directory to ' + build_dir) + os.chdir(build_dir) + + self.execute(*(['make'] + make_args)) + finally: + os.chdir(self.source_dir) + + def phase_update(self, *args): + self.log.info('Executing phase: update') + self.phase_pull() + self.phase_make(*args) + + ######################################################################### + # Build directory cleaning phases # + ######################################################################### + + def phase_clean(self, *args): + self.log.info('Executing phase: clean') + self.phase_make('clean') + + def phase_distclean(self, *args): + self.log.info('Executing phase: distclean') + self.phase_make('distclean') + + def phase_gitclean(self, *args): + self.log.info('Executing phase: gitclean') + if self.git_working_tree(): + self.execute('git', 'clean', '-dfx') + + ######################################################################### + # Packaging phases # + ######################################################################### + + def translate_file(self, path, dest): + dest_file = join(dest, basename(path)) + + self.log.debug("Translating file %s -> %s" % (path, dest_file)) + + if not exists(dest_file): + shutil.copyfile(path, dest_file) + os.chmod(dest_file, 0755) + + for line in self.get_stdout('otool', '-L', dest_file).split('\n'): + match = re.search('/opt/local/lib/(.+?)\.dylib', line) + if not match: + continue + + lib = match.group(0) + base = basename(lib) + + if lib != path: + self.translate_file(lib, dest) + + self.execute('install_name_tool', '-change', lib, + '@loader_path/' + base, dest_file) + + def phase_bindmg(self, *args): + self.log.info('Executing phase: bindmg') + + self.phase_make() + + binary = join(self.build_directory(), 'ledger') + if not exists(binary): + self.log.error('Failed to build Ledger: ' + binary) + sys.exit(1) + + cwd = os.getcwd() + tempdir = tempfile.mkdtemp() + try: + name = 'ledger-%s' % self.current_version() + dest = join(tempdir, name) + + os.makedirs(dest) + self.translate_file(binary, dest) + + self.execute('hdiutil', 'create', '-srcfolder', dest, + '-ov', join(cwd, name + '.dmg')) + finally: + os.chdir(cwd) + shutil.rmtree(tempdir) + + def phase_upload(self, *args): + self.log.info('Executing phase: upload') + + self.phase_bindmg() + + dmg = 'ledger-%s.dmg' % self.current_version() + self.execute('zip', '%s.zip' % dmg, dmg) + dmg = '%s.zip' % dmg + + self.execute('ssh', 'jw', 'rm', '-f', '/srv/ftp/pub/ledger/ledger-*.dmg.zip') + self.execute('scp', dmg, 'jw:/srv/ftp/pub/ledger') + self.execute('ssh', 'jw', + '(cd /srv/ftp/pub/ledger; ln -sf %s ledger-current.dmg.zip)' % + basename(dmg)) + + ######################################################################### + # Other build phases # + ######################################################################### + + def configure_flavor(self, flavor, reset=True): + self.initialize() # reset everything + self.build_dir = None # use the build/ tree + self.current_flavor = flavor + + if reset and exists(self.build_directory()) and \ + isdir(self.build_directory()): + self.option_release() + + self.log.info('=== Wiping build directory %s ===' % + self.build_directory()) + shutil.rmtree(self.build_directory()) + + def phase_distcheck(self, *args): + self.log.info('Executing phase: distcheck') + + self.configure_flavor('default', False) + + environ, conf_args = self.configure_environment() + + configure_args = [] + + skip_next = False + for arg in conf_args[2:]: # skip "sh configure" + if arg == '--srcdir': + skip_next = True + elif skip_next: + skip_next = False + else: + configure_args.append('"' + self.escape_string(arg) + '"') + + make_args = ['DISTCHECK_CONFIGURE_FLAGS=%s' % + string.join(configure_args, ' '), 'distcheck'] + + self.log.debug('make_args for distcheck => ' + str(make_args)) + + self.phase_make(*make_args) + + def phase_rsync(self, *args): + self.log.info('Executing phase: rsync') + + source_copy_dir = join(self.ensure(self.products_directory()), + 'ledger-proof') + + self.execute('rsync', '-a', '--delete', + '--exclude=.git/', '--exclude=b/', + '%s/' % self.source_dir, '%s/' % source_copy_dir) + + self.source_dir = source_copy_dir + + def phase_proof(self, *args): + self.log.info('Executing phase: proof') + + self.log.info('=== Copying source tree ===') + self.phase_rsync() + self.phase_makeall(reset=True, *args) + + self.configure_flavor('opt') + self.log.info('=== Testing opt ===') + self.phase_make('fullcheck') + + self.configure_flavor('gcov') + self.log.info('=== Testing gcov ===') + self.phase_make('check') + + self.configure_flavor('debug') + self.log.info('=== Testing debug ===') + self.phase_make('fullcheck') + + self.configure_flavor('default') + self.log.info('=== Testing default ===') + self.phase_make('fullcheck') + + self.log.info('=== Building final distcheck ===') + self.phase_distcheck() + + def phase_makeall(self, reset=False, *args): + self.log.info('Executing phase: makeall') + + self.configure_flavor('opt', reset) + + system_hh_gch = join(self.source_dir, 'src', 'system.hh.gch') + if exists(system_hh_gch): + os.remove(system_hh_gch) + + self.log.info('=== Building opt ===') + self.phase_make(*args) + + self.configure_flavor('gcov', reset) + + system_hh_gch = join(self.source_dir, 'src', 'system.hh.gch') + if exists(system_hh_gch): + os.remove(system_hh_gch) + + self.log.info('=== Building gcov ===') + self.phase_make(*args) + + system_hh_gch = join(self.source_dir, 'src', 'system.hh.gch') + if exists(system_hh_gch): + os.remove(system_hh_gch) + + self.log.info('=== Building default ===') + self.phase_make(*args) + + self.configure_flavor('debug', reset) + + system_hh_gch = join(self.source_dir, 'src', 'system.hh.gch') + if exists(system_hh_gch): + os.remove(system_hh_gch) + + self.log.info('=== Building debug ===') + self.phase_make(*args) + + self.configure_flavor('default', reset) + + ######################################################################### + # Help # + ######################################################################### + + def phase_help(self, *args): + self.option_parser.print_help() + + print """ +Of the optional ARGS, the first is an optional build FLAVOR, with the default +being 'debug': + + default Regular autoconf settings + debug Debugging and --verify support (default) + opt Full optimizations + gcov Coverage analysis + gprof Code profiling (for OS X, just use: 'shark -i ledger ...') + +Next is the optional build PHASE, with 'config' being the default: + + clean Runs 'make clean' in the build directory + config Configure the environment for building + dependencies Automatically install all necessary build dependencies + distcheck Properly does 'make distcheck', carrying all flags + distclean Runs 'make distclean' in the build directory + gitclean Runs 'git clean -dfx', which *really* cleans things + help Displays this help text + info Show information about the build environment + make Do a make in the build directory + proof Proves Ledger by building and testing every flavor + pull Pulls the latest, and updates local config if need be + update Does it all, updates your environment and re-make's + +There are many other build phases, though most are not of interest to the +typical user: + + aclocal Runs aclocal -I m4 + autoconf Prepare the autoconf subsystem + autogen Runs autogen.sh + configure Runs just ./configure + do_all Runs makeall followed by proof + gettext Initialize gettext support + makeall Build every flavor there is + patch Patches the automake Makefile to be less verbose + products Report the products directory path + rsync Rsync a copy of the source tree into Products + sloc Report total Source Lines Of Code + submodule Updates Git submodules (better to use 'pull') + version Output current HEAD version to version.m4 + +NOTE: If you wish to pass options to configure or make, add "--" followed by +your options. Here are some real-world examples: + + ./acprep + ./acprep opt -- make -j3 + ./acprep -- --enable-doxygen""" + sys.exit(0) + +PrepareBuild().run() |