#!/usr/bin/python -B

# Build cross toolchain for AmigaOS 4.x / PowerPC target.

from fnmatch import fnmatch
from logging import info
from os import environ
import argparse
import logging
import platform
import sys

URLS = \
  ['git://github.com/FrodeSolheim/python-lhafile',
   'ftp://ftp.gnu.org/gnu/gmp/gmp-5.1.3.tar.bz2',
   'ftp://ftp.gnu.org/gnu/mpc/mpc-1.0.3.tar.gz',
   'ftp://ftp.gnu.org/gnu/mpfr/mpfr-3.1.3.tar.bz2',
   'ftp://ftp.gnu.org/gnu/texinfo/texinfo-4.12.tar.gz',
   'http://isl.gforge.inria.fr/isl-0.12.2.tar.bz2',
   'http://www.bastoul.net/cloog/pages/download/cloog-0.18.4.tar.gz',
   'ftp://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz',
   ('http://hyperion-entertainment.biz/index.php/downloads' +
    '?view=download&amp;format=raw&amp;file=69', 'SDK_53.24.lha'),
   ('svn://svn.code.sf.net/p/adtools/code/trunk/binutils', 'binutils-2.18'),
   ('svn://svn.code.sf.net/p/adtools/code/trunk/gcc', 'gcc-4.2.4'),
   ('svn://svn.code.sf.net/p/adtools/code/branches/binutils/2.23.2',
    'binutils-2.23.2'),
   ('svn://svn.code.sf.net/p/adtools/code/branches/gcc/4.9.x', 'gcc-4.9.1')]


from common import * # NOQA


def update_autotools(dst):
  remove(path.join(dst, 'config.guess'), path.join(dst, 'config.sub'))
  copy('{sources}/{automake}/lib/config.guess', path.join(dst, 'config.guess'))
  copy('{sources}/{automake}/lib/config.sub', path.join(dst, 'config.sub'))


@recipe('{sdk}-prepare')
def prepare_sdk():
  info('preparing {sdk}')

  target = path.join('{target}', 'ppc-amigaos/SDK')

  unpack('{sdk}', work_dir='{archives}', top_dir='SDK_Install', dst_dir='SDK')
  unpack('SDK/base', top_dir='Include', dst_dir=path.join(target, 'include'))
  unpack('SDK/clib2', top_dir='clib2', dst_dir=path.join(target, 'clib2'))
  unpack('SDK/newlib', top_dir='newlib', dst_dir=path.join(target, 'newlib'))


def build():
  for var in environ.keys():
    if var not in ['_', 'LOGNAME', 'HOME', 'SHELL', 'TMPDIR', 'PWD']:
      del environ[var]

  environ['PATH'] = '/usr/bin:/bin'
  environ['LANG'] = 'C'
  environ['TERM'] = 'xterm'

  if platform.system() == 'Darwin':
    CC, CXX = 'clang', 'clang++'
  else:
    CC, CXX = 'gcc', 'g++'

  environ['CC'] = find_executable(CC)
  environ['CXX'] = find_executable(CXX)

  find_executable('patch')
  find_executable('bison')
  find_executable('flex')
  find_executable('make')
  find_executable('svn')

  environ['PATH'] = ":".join([path.join('{target}', 'bin'),
                              path.join('{host}', 'bin'),
                              environ['PATH']])

  add_site_dir('{host}')

  with cwd('{archives}'):
    for url in URLS:
      if type(url) == tuple:
        url, name = url[0], url[1]
      else:
        name = path.basename(url)
      fetch(name, url)

  unpack('{automake}')

  py_ver = 'python%d.%d' % (sys.version_info.major, sys.version_info.minor)
  require_header([path.join(py_ver, 'Python.h')],
                 lang='c', errmsg='python-dev package missing')
  unpack('python-lha', work_dir='{build}')
  python_setup('python-lha')

  unpack('{texinfo}')
  update_autotools('{sources}/{texinfo}/build-aux')
  configure('{texinfo}', '--prefix={host}')
  make('{texinfo}')
  make('{texinfo}', 'install')

  unpack('{gmp}')
  update_autotools('{sources}/{gmp}')
  configure('{gmp}',
            '--disable-shared',
            '--prefix={host}')
  make('{gmp}')
  make('{gmp}', 'install')

  unpack('{mpfr}')
  update_autotools('{sources}/{mpfr}')
  configure('{mpfr}',
            '--disable-shared',
            '--prefix={host}',
            '--with-gmp={host}')
  make('{mpfr}')
  make('{mpfr}', 'install')

  unpack('{mpc}')
  update_autotools('{sources}/{mpc}')
  configure('{mpc}',
            '--disable-shared',
            '--prefix={host}',
            '--with-gmp={host}',
            '--with-mpfr={host}')
  make('{mpc}')
  make('{mpc}', 'install')

  unpack('{isl}')
  update_autotools('{sources}/{isl}')
  configure('{isl}',
            '--disable-shared',
            '--prefix={host}',
            '--with-gmp-prefix={host}')
  make('{isl}')
  make('{isl}', 'install')

  unpack('{cloog}')
  update_autotools('{sources}/{cloog}')
  configure('{cloog}',
            '--disable-shared',
            '--prefix={host}',
            '--with-isl=system',
            '--with-gmp-prefix={host}',
            '--with-isl-prefix={host}')
  make('{cloog}')
  make('{cloog}', 'install')

  with env(CFLAGS='-Wno-error'):
    update_autotools('{archives}/{binutils}')
    configure('{binutils}',
              '--prefix={target}',
              '--target=ppc-amigaos',
              from_dir='{archives}/{binutils}')
    make('{binutils}')
    make('{binutils}', 'install')

  prepare_sdk()

  gcc_env = {}
  if cmpver('eq', '{gcc_ver}', '4.2.4'):
    gcc_env.update(CFLAGS='-std=gnu89',
                   CC=find_executable(CC) + ' -m32',
                   CXX=find_executable(CXX) + ' -m32')

  update_autotools('{archives}/{gcc}')
  with env(**gcc_env):
    configure('{gcc}',
              '--prefix={target}',
              '--target=ppc-amigaos',
              '--with-bugurl="http://sf.net/p/adtools"',
              '--with-gmp={host}',
              '--with-mpfr={host}',
              '--with-isl={host}',
              '--with-cloog={host}',
              '--enable-languages=c,c++',
              '--enable-haifa',
              '--enable-sjlj-exceptions',
              '--disable-libstdcxx-pch',
              '--disable-tls',
              from_dir='{archives}/{gcc}')
  make('{gcc}')
  make('{gcc}', 'install')


def clean():
  rmtree('{stamps}')
  rmtree('{sources}')
  rmtree('{host}')
  rmtree('{build}')
  rmtree('{tmpdir}')


if __name__ == "__main__":
  logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')

  if not sys.version_info[:2] == (2, 7):
    panic('I need Python 2.7 to run!')

  if not any(fnmatch(platform.system(), pat)
             for pat in ['Darwin', 'Linux', 'CYGWIN_NT*', 'MSYS_NT*']):
    panic('Build on %s not supported!', platform.system())

  if platform.machine() not in ['i686', 'x86_64']:
    panic('Build on %s architecture not supported!', platform.machine())

  parser = argparse.ArgumentParser(description='Build cross toolchain.')
  parser.add_argument('action',
                      choices=['build', 'clean'],
                      default='build', help='perform action')
  parser.add_argument('args', metavar='ARGS', type=str, nargs='*',
                      help='action arguments')
  parser.add_argument('--binutils', choices=['2.18', '2.23.2'], default='2.18',
                      help='desired binutils version')
  parser.add_argument('--gcc', choices=['4.2.4', '4.9.1'], default='4.2.4',
                      help='desired gcc version')
  parser.add_argument('--prefix', type=str, default=None,
                      help='installation directory')
  args = parser.parse_args()

  setvar(top=path.abspath(path.dirname(sys.argv[0])),
         binutils_ver=args.binutils,
         gcc_ver=args.gcc)

  setvar(gmp='gmp-5.1.3',
         mpfr='mpfr-3.1.3',
         mpc='mpc-1.0.3',
         isl='isl-0.12.2',
         cloog='cloog-0.18.4',
         texinfo='texinfo-4.12',
         automake='automake-1.15',
         binutils='binutils-{binutils_ver}',
         sdk='SDK_53.24',
         gcc='gcc-{gcc_ver}',
         patches=path.join('{top}', 'patches'),
         stamps=path.join('{top}', '.build-ppc', 'stamps'),
         build=path.join('{top}', '.build-ppc', 'build'),
         sources=path.join('{top}', '.build-ppc', 'sources'),
         host=path.join('{top}', '.build-ppc', 'host'),
         tmpdir=path.join('{top}', '.build-ppc', 'tmpdir'),
         target=path.join('{top}', 'ppc-amigaos'),
         archives=path.join('{top}', '.build-ppc', 'archives'),
         submodules=path.join('{top}', 'submodules'))

  if args.prefix is not None:
    setvar(target=args.prefix)

  if not path.exists('{target}'):
    mkdir('{target}')

  action = args.action.replace('-', '_')
  globals()[action].__call__(*args.args)
