1
0
mirror of https://github.com/cahirwpz/amigaos-cross-toolchain synced 2025-11-20 09:02:49 +00:00
Files
amigaos-cross-toolchain/toolchain-m68k
2016-05-19 00:07:12 +02:00

675 lines
21 KiB
Python
Executable File

#!/usr/bin/python -B
# Build cross toolchain for AmigaOS <= 3.9 / M68k target.
from fnmatch import fnmatch
from logging import info
from os import environ
import argparse
import logging
import platform
import re
import string
import sys
URLS = \
['git://github.com/FrodeSolheim/python-lhafile',
'ftp://ftp.gnu.org/gnu/m4/m4-1.4.17.tar.gz',
'ftp://ftp.gnu.org/gnu/gawk/gawk-3.1.8.tar.gz',
'ftp://ftp.gnu.org/gnu/autoconf/autoconf-2.13.tar.gz',
'ftp://ftp.gnu.org/gnu/bison/bison-1.35.tar.gz',
'ftp://ftp.gnu.org/gnu/texinfo/texinfo-4.12.tar.gz',
('git://github.com/cahirwpz/amigaos-binutils-2.9.1', 'binutils-2.9.1'),
('git://github.com/cahirwpz/amigaos-gcc-2.95.3', 'gcc-2.95.3'),
('http://downloads.sourceforge.net/project/flex/flex/2.5.4.a/flex-2.5.4a.tar.gz',
'flex-2.5.4.tar.gz'),
'git://github.com/adtools/clib2',
'git://github.com/cahirwpz/libnix',
'git://github.com/cahirwpz/fd2sfd',
'git://github.com/adtools/sfdc',
'git://github.com/cahirwpz/libdebug',
('http://www.haage-partner.de/download/AmigaOS/NDK39.lha', 'NDK_3.9.lha'),
('ftp://ftp.exotica.org.uk/mirrors/geekgadgets/amiga/m68k/snapshots/' +
'990529/bin/libamiga-bin.tgz', 'libamiga.tar.gz'),
('ftp://ftp.exotica.org.uk/mirrors/geekgadgets/amiga/m68k/snapshots/' +
'990529/src/libm-5.4-src.tgz', 'libm-5.4.tar.gz'),
('http://sourceforge.net/projects/amiga/files/ixemul.library/48.2/' +
'ixemul-src.lha/download', 'ixemul-48.2.lha'),
'http://sun.hasenbraten.de/vasm/release/vasm.tar.gz',
'http://sun.hasenbraten.de/vlink/release/vlink.tar.gz',
'http://www.ibaug.de/vbcc/vbcc.tar.gz',
'http://aminet.net/dev/asm/ira.lha',
('http://mail.pb-owl.de/~frank/vbcc/current/vbcc_target_m68k-amigaos.lha',
'vclib.lha')]
MULTILIB = [('', []),
('libb', ['-fbaserel', '-DSMALL_DATA']),
('libm020', ['-m68020']),
('libb/libm020', ['-fbaserel', '-DSMALL_DATA', '-m68020']),
('libm020/libm881', ['-m68020', '-m68881']),
('libb/libm020/libm881',
['-fbaserel', '-DSMALL_DATA', '-m68020', '-m68881']),
('libb32/libm020', ['-fbaserel32', '-DSMALL_DATA', '-m68020'])]
from common import * # NOQA
@recipe('target-prepare')
def prepare_target():
info('preparing target')
with cwd('{target}'):
mkdir('bin', 'doc', 'etc', 'lib', 'm68k-amigaos', 'os-include',
'os-include/lvo', 'os-lib', 'os-lib/fd', 'os-lib/sfd',
'vbcc-include', 'vbcc-lib')
@recipe('{NDK}-install')
def install_ndk():
info('installing ndk')
copytree('{sources}/{NDK}/Include/include_h', '{target}/os-include')
copytree('{sources}/{NDK}/Include/include_i', '{target}/os-include')
copytree('{sources}/{NDK}/Include/fd', '{target}/os-lib/fd')
copytree('{sources}/{NDK}/Include/sfd', '{target}/os-lib/sfd')
copytree('{sources}/{NDK}/Include/linker_libs', '{target}/os-lib',
exclude=['README'])
copytree('{sources}/{NDK}/Documentation/Autodocs', '{target}/doc')
for name in find('{target}/os-lib/sfd', include=['*.sfd']):
base = path.basename(name).split('_')[0]
execute('sfdc', '--target=m68k-amigaos', '--mode=proto',
'--output={target}/os-include/proto/' + base + '.h', name)
execute('sfdc', '--target=m68k-amigaos', '--mode=macros',
'--output={target}/os-include/inline/' + base + '.h', name)
execute('sfdc', '--target=m68k-amigaos', '--mode=lvo',
'--output={target}/os-include/lvo/' + base + '_lib.i', name)
@recipe('headers-install')
def headers_install():
info('installing ixemul header files')
copytree('{sources}/{ixemul}/include', '{target}/m68k-amigaos/libnix/include')
@recipe('tools-install')
def install_tools():
info('installing extra tools')
copy('{build}/ira/ira', '{target}/bin')
@recipe('libamiga-install')
def install_libamiga():
info('installing libamiga')
copytree('{sources}/libamiga/lib', '{target}/m68k-amigaos/libnix/lib')
@recipe('clib2-install')
def install_clib2():
info('installing clib2')
with cwd('{target}/m68k-amigaos/clib2'):
copytree('{build}/clib2/lib', 'lib')
copytree('{build}/clib2/include', 'include')
@recipe('vbcc-build')
def build_vbcc():
copytree('{sources}/vbcc', '{build}/vbcc')
mkdir('{build}/vbcc/bin')
config = textfile(
'y', 'y', 'signed char',
'y', 'unsigned char',
'n', 'y', 'signed short',
'n', 'y', 'unsigned short',
'n', 'y', 'signed int',
'n', 'y', 'unsigned int',
'n', 'y', 'signed long long',
'n', 'y', 'unsigned long long',
'n', 'y', 'float',
'n', 'y', 'double')
make('vbcc', TARGET='m68k', ETCDIR='\\"{target}/etc/\\"', CONFIG=config)
remove(config)
@recipe('vlink-build')
def build_vlink():
mkdir('{build}/vlink/objects')
make('vlink')
@recipe('vbcc-install')
def install_vbcc_toolchain():
info('installing vasm')
copy('{build}/vasm/vasmm68k_mot', '{target}/bin')
copy('{build}/vasm/vobjdump', '{target}/bin')
vasm = textfile(
'#!/bin/sh',
'',
'vasmm68k_mot -I{target}/os-include "$@"')
chmod(vasm, 0755)
move(vasm, '{target}/bin/vasm')
info('installing vlink')
copy('{build}/vlink/vlink', '{target}/bin')
info('installing vbcc')
copy('{build}/vbcc/bin/vbccm68k', '{target}/bin')
copy('{build}/vbcc/bin/vc', '{target}/bin')
copy('{build}/vbcc/bin/vprof', '{target}/bin')
info('installing vbcc_target_m68k-amigaos')
copytree('{sources}/vclib/targets/m68k-amigaos/include',
'{target}/vbcc-include')
copytree('{sources}/vclib/targets/m68k-amigaos/lib',
'{target}/vbcc-lib')
config = textfile(
('-cc={target}/bin/vbccm68k -hunkdebug %s -o= %s %s -O=%ld' +
' -quiet -I{target}/vbcc-include -I{target}/os-include'),
('-ccv={target}/bin/vbccm68k -hunkdebug %s -o= %s %s -O=%ld' +
' -I{target}/vbcc-include -I{target}/os-include'),
('-as={target}/bin/vasmm68k_mot -Fhunk -phxass -opt-fconst -nowarn=62' +
' -quiet -I{target}/os-include %s -o %s'),
('-asv={target}/bin/vasmm68k_mot -Fhunk -phxass -opt-fconst -nowarn=62' +
' -I{target}/os-include %s -o %s'),
'-rm=rm %s',
'-rmv=rm -v %s',
('-ld={target}/bin/vlink -bamigahunk -x -Bstatic -Cvbcc -nostdlib' +
' {target}/vbcc-lib/startup.o %s %s' +
' -L{target}/vbcc-lib -L{target}/vbcc-include -lvc -o %s'),
('-l2={target}/bin/vlink -bamigahunk -x -Bstatic -Cvbcc -nostdlib' +
' %s %s -L{target}/vbcc-lib -L{target}/vbcc-include -o %s'),
('-ldv={target}/bin/vlink -bamigahunk -t -x -Bstatic -Cvbcc -nostdlib' +
' {target}/vbcc-lib/startup.o %s %s' +
' -L{target}/vbcc-lib -L{target}/vbcc-include -lvc -o %s'),
('-l2v={target}/bin/vlink -bamigahunk -t -x -Bstatic -Cvbcc -nostdlib' +
' %s %s -L{target}/vbcc-lib -L{target}/vbcc-include -o %s'),
'-ldnodb=-s -Rshort',
'-ul=-l%s',
'-cf=-F%s',
'-ml=500')
move(config, '{target}/etc/vc.config')
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'
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)
add_site_dir('{host}')
"""
Make sure we always choose known compiler (from the distro) and not one in
user's path that could shadow the original one.
"""
if platform.system() == 'Darwin':
CC, CXX = 'clang', 'clang++'
else:
CC, CXX = 'gcc', 'g++'
CC = find_executable(CC)
CXX = find_executable(CXX)
"""
On 64-bit architecture GNU Assembler crashes writing out an object, due to
(probably) miscalculated structure sizes. There could be some other bugs
lurking there in 64-bit mode, but I have little incentive chasing them.
Just compile everything in 32-bit mode and forget about the issues.
"""
ARCH = '-m32' if platform.machine() == 'x86_64' else ''
environ['CC'] = CC + ' ' + ARCH
environ['CXX'] = CXX + ' ' + ARCH
environ['PATH'] = ':'.join([path.join('{target}', 'bin'),
path.join('{host}', 'bin'),
environ['PATH']])
setvar(cc=environ['CC'], cxx=environ['CXX'])
"""
When we have a working compiler in our path, we shoule also check if the
required programs, headers and libraries are present.
"""
find_executable('perl')
find_executable('gperf')
find_executable('patch')
find_executable('make')
find_executable('git')
find_executable('yacc')
require_header('ncurses.h', 'c', 'libncurses-dev package missing')
py_ver = 'python%d.%d' % (sys.version_info.major, sys.version_info.minor)
with env(CC=CC, CXX=CXX):
require_header(path.join(py_ver, 'Python.h'), 'c',
'python-dev package missing')
unpack('python-lha', work_dir='{build}')
python_setup('python-lha')
unpack('{m4}')
configure('{m4}', '--prefix={host}')
make('{m4}')
make('{m4}', 'install')
unpack('{gawk}')
configure('{gawk}', '--prefix={host}')
make('{gawk}')
make('{gawk}', 'install')
unpack('{flex}')
configure('{flex}', '--prefix={host}')
make('{flex}')
make('{flex}', 'install')
unpack('{bison}')
configure('{bison}', '--prefix={host}')
make('{bison}')
make('{bison}', 'install')
unpack('{texinfo}')
configure('{texinfo}', '--prefix={host}')
make('{texinfo}')
make('{texinfo}', 'install')
unpack('{autoconf}')
configure('{autoconf}', '--prefix={host}')
make('{autoconf}')
make('{autoconf}', 'install')
prepare_target()
unpack('vasm', work_dir='{build}')
make('vasm', CPU='m68k', SYNTAX='mot')
unpack('vlink', work_dir='{build}')
build_vlink()
unpack('vbcc')
patch('vbcc')
build_vbcc()
unpack('vclib', top_dir='vbcc_target_m68k-amigaos')
install_vbcc_toolchain()
unpack('fd2sfd')
patch('fd2sfd')
configure('fd2sfd', '--prefix={target}', copy_source=True)
make('fd2sfd')
make('fd2sfd', 'install')
unpack('sfdc')
patch('sfdc')
configure('sfdc', '--prefix={target}', copy_source=True)
make('sfdc')
make('sfdc', 'install')
unpack('{NDK}')
patch('{NDK}')
install_ndk()
"""
Older gcc compilers (i.e. 2.95.3 and 3.4.6) and binutils have to be tricked
into thinking that they're being compiled on Linux IA-32 machine. Theirs
config.guess script knows nothing about x86-64 or darwin.
"""
unpack('{binutils}')
with env(CC=environ['CC'] + ' -std=gnu11',
CXX=environ['CXX'] + ' -std=gnu++11',
CFLAGS='-g -O2 -Wall',
CXXFLAGS='-g -O2 -Wall'):
configure('{binutils}',
'--prefix={target}',
'--host=i686-linux-gnu',
'--target=m68k-amigaos')
make('{binutils}')
make('{binutils}', 'install')
unpack('{ixemul}', top_dir='ixemul')
patch('{ixemul}')
unpack('{gcc}')
with env(CC=environ['CC'] + ' -std=gnu11',
CXX=environ['CXX'] + ' -std=gnu++11',
CFLAGS='-g -O2 -Wall',
CXXFLAGS='-g -O2 -Wall'):
configure('{gcc}',
'--prefix={target}',
'--host=i686-linux-gnu',
'--build=i686-linux-gnu',
'--target=m68k-amigaos',
'--enable-languages=c,c++',
'--enable-version-specific-runtime-libs',
'--with-headers={sources}/{ixemul}/include')
touch('{sources}/{gcc}/gcc/c-parse.in')
make('{gcc}', 'all-gcc',
MAKEINFO='makeinfo', CFLAGS_FOR_TARGET='-noixemul')
make('{gcc}', 'install-gcc',
MAKEINFO='makeinfo', CFLAGS_FOR_TARGET='-noixemul')
headers_install()
unpack('libamiga', top_dir='.')
install_libamiga()
unpack('libnix')
configure('libnix',
'--prefix={target}/m68k-amigaos/libnix',
'--host=i686-linux-gnu',
'--target=m68k-amigaos')
make('libnix',
CC='m68k-amigaos-gcc',
CPP='m68k-amigaos-gcc -E',
AR='m68k-amigaos-ar',
AS='m68k-amigaos-as',
RANLIB='m68k-amigaos-ranlib',
LD='m68k-amigaos-ld')
make('libnix', 'install')
copy('{sources}/libnix/sources/headers/stabs.h',
'{target}/m68k-amigaos/libnix/include')
unpack('{libm}', top_dir='contrib/libm')
with env(CC='m68k-amigaos-gcc -noixemul',
AR='m68k-amigaos-ar',
RANLIB='m68k-amigaos-ranlib'):
configure('{libm}',
'--prefix={target}/m68k-amigaos/libnix',
'--host=i686-linux-gnu',
'--target=m68k-amigaos')
make('{libm}')
make('{libm}', 'install')
unpack('{libdebug}')
with env(CC='m68k-amigaos-gcc -noixemul',
AR='m68k-amigaos-ar',
RANLIB='m68k-amigaos-ranlib'):
configure('{libdebug}',
'--prefix={target}/m68k-amigaos/libnix',
'--host=m68k-amigaos')
make('{libdebug}')
make('{libdebug}', 'install')
unpack('clib2', work_dir='{build}', top_dir='library')
make('clib2', makefile='GNUmakefile.68k')
install_clib2()
make('{gcc}', MAKEINFO='makeinfo', CFLAGS_FOR_TARGET='-noixemul')
make('{gcc}', 'install', MAKEINFO='makeinfo', CFLAGS_FOR_TARGET='-noixemul')
unpack('ira', top_dir='.', work_dir='{build}')
patch('ira', work_dir='{build}')
make('ira')
install_tools()
def clean():
rmtree('{stamps}')
rmtree('{sources}')
rmtree('{host}')
rmtree('{build}')
rmtree('{tmpdir}')
def read_sdk(filename):
phase = 'info'
info = {}
files = []
for line in open(filename):
line = line.strip()
if phase == 'info':
if line == '':
phase = 'files'
else:
fields = [field.strip() for field in line.split(':', 1)]
info[string.lower(fields[0])] = fields[1]
elif phase == 'files':
if ':' in line:
fields = [field.strip() for field in re.split('[: ]+', line)]
files.append(tuple(fields))
elif '=' in line:
fields = [field.strip() for field in line.split('=')]
files.append(tuple(['file'] + fields))
else:
files.append(('file', line))
return (info, files)
def list_sdk():
print 'Available SDKs:'
for filename in find('{top}/sdk', include='*.sdk'):
info, _ = read_sdk(filename)
name = path.splitext(path.basename(filename))[0]
print ' - %s %s : %s' % (name, info['version'], info['short'])
def add_stubs(src):
obj = re.sub(r'\.c$', r'.o', src)
for libdir, cflags in MULTILIB:
lib = path.join('{target}/m68k-amigaos/libnix/lib',
libdir, 'libnix/libstubs.a')
info('stubs: "%s" -> "%s"', obj, lib)
cflags = list(cflags) + ['-noixemul', '-c', '-o', obj, src]
execute('m68k-amigaos-gcc', '-Wall', '-O3', '-fomit-frame-pointer', *cflags)
execute('m68k-amigaos-ar', 'rs', lib, obj)
remove(obj)
def add_lib(src, libname):
obj = re.sub(r'\.a$', r'.o', libname)
for libdir, cflags in MULTILIB:
lib = path.join('{target}/m68k-amigaos/libnix/lib', libdir, libname)
info('lib: "%s" -> "%s"', obj, lib)
cflags = list(cflags) + ['-noixemul', '-c', '-o', obj, src]
execute('m68k-amigaos-gcc', '-Wall', '-O3', '-fomit-frame-pointer', *cflags)
execute('m68k-amigaos-ar', 'rcs', lib, obj)
remove(obj)
@recipe('install-sdk', 1)
def process_sdk(sdk, dirname, files):
with cwd(path.join('{sources}', dirname)):
for f in files:
kind = f[0]
if kind == 'fd2sfd':
fd, protos = f[1:]
sfd = path.splitext(path.basename(fd))[0]
if not fd.endswith('_lib.fd'):
sfd = sfd + '_lib.sfd'
else:
sfd = sfd + '.sfd'
info('fd2sfd: "%s" "%s" -> "%s"', fd, protos, sfd)
execute('fd2sfd', '-o', sfd, fd, protos)
copy(sfd, path.join('{target}/os-lib/sfd', sfd))
elif kind == 'sfdc':
source = f[1]
basename = re.sub(r'_lib.sfd$', r'', path.basename(source))
proto = path.join('{target}/os-include/proto', basename + '.h')
inline = path.join('{target}/os-include/inline', basename + '.h')
lvo = path.join('{target}/os-include/lvo', basename + '.i')
info('sfdc: "%s" -> "%s"', source, proto)
execute('sfdc', '--quiet', '--target=m68k-amigaos', '--mode=proto',
'--output=' + proto, source)
info('sfdc: "%s" -> "%s"', source, inline)
execute('sfdc', '--quiet', '--target=m68k-amigaos', '--mode=macros',
'--output=' + inline, source)
info('sfdc: "%s" -> "%s"', source, lvo)
execute('sfdc', '--quiet', '--target=m68k-amigaos', '--mode=lvo',
'--output=' + lvo, source)
elif kind == 'stubs':
filename = f[1]
c_file = re.sub(r'_lib\.sfd$', r'.c', path.basename(filename))
info('stubs: "%s" -> "%s"', filename, c_file)
execute('sfdc', '--quiet', '--target=m68k-amigaos', '--mode=autoopen',
'--output=' + c_file, filename)
add_stubs(c_file)
elif kind == 'lib':
filename = f[1]
c_file = re.sub(r'_lib.sfd$', r'.c', path.basename(filename))
lib_file = 'lib' + sdk + '.a'
info('lib: %s -> %s', filename, c_file)
execute('sfdc', '--quiet', '--target=m68k-amigaos', '--mode=stubs',
'--output=' + c_file, filename)
add_lib(c_file, lib_file)
elif kind == 'file':
source = f[1]
try:
name = f[2]
except:
name = path.basename(f[1])
if any(name.endswith(ext) for ext in ['.doc', '.html', '.pdf', '.ps']):
mkdir('{target}/doc')
copy(source, path.join('{target}/doc', name))
elif name.endswith('.guide'):
mkdir('{target}/guide')
copy(source, path.join('{target}/guide', name))
elif any(name.endswith(ext) for ext in ['.h', '.i']):
lastdir = path.basename(path.dirname(f[1]))
mkdir(path.join('{target}/os-include', lastdir))
copy(source, path.join('{target}/os-include', lastdir, name))
elif name.endswith('.fd'):
mkdir('{target}/os-lib/fd')
copy(source, path.join('{target}/os-lib/fd', name))
elif name.endswith('.sfd'):
mkdir('{target}/os-lib/sfd')
copy(source, path.join('{target}/os-lib/sfd', name))
def install_sdk(*names):
environ['PATH'] = ":".join([path.join('{target}', 'bin'),
path.join('{host}', 'bin'),
environ['PATH']])
add_site_dir('{host}')
for name in names:
filename = path.join('{top}/sdk', name + '.sdk')
if not path.exists(filename):
panic('No SDK description file for "%s".', name)
desc, files = read_sdk(filename)
with cwd('{archives}'):
fetch(path.basename(desc['url']), desc['url'])
basename = path.splitext(path.basename(desc['url']))[0]
unpack(basename, top_dir='.')
process_sdk(name, basename, files)
def test():
install_sdk('mmu', 'mui')
environ['PATH'] = ":".join([path.join('{target}', 'bin'),
environ['PATH']])
with cwd(path.join('{top}', 'examples')):
execute('make', 'clean')
execute('make')
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 (platform.system() in ['Darwin', 'Linux'] or
fnmatch(platform.system(), 'CYGWIN*')):
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', 'list-sdk', 'install-sdk', 'clean',
'test'],
default='build', help='perform action')
parser.add_argument('args', metavar='ARGS', type=str, nargs='*',
help='action arguments')
parser.add_argument('--binutils', choices=['2.9.1'], default='2.9.1',
help='desired binutils version')
parser.add_argument('--gcc', choices=['2.95.3'], default='2.95.3',
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(m4='m4-1.4.17',
gawk='gawk-3.1.8',
flex='flex-2.5.4',
bison='bison-1.35',
autoconf='autoconf-2.13',
texinfo='texinfo-4.12',
NDK='NDK_3.9',
ixemul='ixemul-48.2',
libm='libm-5.4',
libdebug='libdebug',
binutils='binutils-{binutils_ver}',
gcc='gcc-{gcc_ver}',
gpp='g++-{gcc_ver}',
patches=path.join('{top}', 'patches'),
stamps=path.join('{top}', '.build-m68k', 'stamps'),
build=path.join('{top}', '.build-m68k', 'build'),
sources=path.join('{top}', '.build-m68k', 'sources'),
host=path.join('{top}', '.build-m68k', 'host'),
tmpdir=path.join('{top}', '.build-m68k', 'tmp'),
target=path.join('{top}', 'm68k-amigaos'),
archives=path.join('{top}', '.build-m68k', 'archives'))
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)