mirror of
https://github.com/KolibriOS/kolibrios.git
synced 2024-12-04 22:32:05 +03:00
384 lines
12 KiB
Python
384 lines
12 KiB
Python
|
import os
|
||
|
import sys
|
||
|
|
||
|
VARS = {}
|
||
|
TOPDIR = os.path.abspath(os.path.dirname(__file__))
|
||
|
TEST = False
|
||
|
CLEAN = False
|
||
|
BOOT = False
|
||
|
CORE = ['tokenize','parse','encode','py2bc']
|
||
|
MODULES = []
|
||
|
|
||
|
def main():
|
||
|
chksize()
|
||
|
if len(sys.argv) < 2:
|
||
|
print HELP
|
||
|
return
|
||
|
|
||
|
global TEST,CLEAN,BOOT
|
||
|
TEST = 'test' in sys.argv
|
||
|
CLEAN = 'clean' in sys.argv
|
||
|
BOOT = 'boot' in sys.argv
|
||
|
CLEAN = CLEAN or BOOT
|
||
|
TEST = TEST or BOOT
|
||
|
|
||
|
get_libs()
|
||
|
build_mymain()
|
||
|
|
||
|
cmd = sys.argv[1]
|
||
|
if cmd == 'linux':
|
||
|
vars_linux()
|
||
|
build_gcc()
|
||
|
elif cmd == 'mingw':
|
||
|
vars_windows()
|
||
|
build_gcc()
|
||
|
elif cmd == 'vs':
|
||
|
build_vs()
|
||
|
elif cmd == '64k':
|
||
|
build_64k()
|
||
|
elif cmd == 'blob':
|
||
|
build_blob()
|
||
|
else:
|
||
|
print 'invalid command'
|
||
|
|
||
|
HELP = """
|
||
|
python setup.py command [options] [modules]
|
||
|
|
||
|
Commands:
|
||
|
linux - build tinypy for linux
|
||
|
mingw - build tinypy for mingw under windows
|
||
|
vs - build tinypy using Visual Studio 2005 / 2008
|
||
|
|
||
|
64k - build a 64k version of the tinypy source
|
||
|
blob - build a single tinypy.c and tinypy.h
|
||
|
|
||
|
build - build CPython module ***
|
||
|
install - install CPython module ***
|
||
|
|
||
|
Options:
|
||
|
test - run tests during build
|
||
|
clean - rebuild all .tpc during build
|
||
|
boot - fully bootstrap and test tinypy
|
||
|
|
||
|
Modules:
|
||
|
math - build math module
|
||
|
random - build random module *
|
||
|
pygame - build pygame module **
|
||
|
marshal - build marshal module ***
|
||
|
jit - build jit module ***
|
||
|
re - build re module ***
|
||
|
|
||
|
* coming soon!!
|
||
|
** proof-of-concept included
|
||
|
*** vaporware
|
||
|
"""
|
||
|
|
||
|
def vars_linux():
|
||
|
VARS['$RM'] = 'rm -f'
|
||
|
VARS['$VM'] = './vm'
|
||
|
VARS['$TINYPY'] = './tinypy'
|
||
|
VARS['$SYS'] = '-linux'
|
||
|
VARS['$FLAGS'] = ''
|
||
|
|
||
|
VARS['$WFLAGS'] = '-std=c89 -Wall -Wc++-compat'
|
||
|
#-Wwrite-strings - i think this is included in -Wc++-compat
|
||
|
|
||
|
if 'pygame' in MODULES:
|
||
|
VARS['$FLAGS'] += ' `sdl-config --cflags --libs` '
|
||
|
|
||
|
def vars_windows():
|
||
|
VARS['$RM'] = 'del'
|
||
|
VARS['$VM'] = 'vm'
|
||
|
VARS['$TINYPY'] = 'tinypy'
|
||
|
VARS['$FLAGS'] = '-lmingw32'
|
||
|
VARS['$WFLAGS'] = '-Wwrite-strings -Wall'
|
||
|
VARS['$SYS'] = '-mingw32'
|
||
|
|
||
|
if 'pygame' in MODULES:
|
||
|
VARS['$FLAGS'] += ' -Ic:\\mingw\\include\\SDL -lSDLmain -lSDL '
|
||
|
|
||
|
def do_cmd(cmd):
|
||
|
for k,v in VARS.items():
|
||
|
cmd = cmd.replace(k,v)
|
||
|
if '$' in cmd:
|
||
|
print 'vars_error',cmd
|
||
|
sys.exit(-1)
|
||
|
|
||
|
print cmd
|
||
|
r = os.system(cmd)
|
||
|
if r:
|
||
|
print 'exit_status',r
|
||
|
sys.exit(r)
|
||
|
|
||
|
def do_chdir(dest):
|
||
|
print 'cd',dest
|
||
|
os.chdir(dest)
|
||
|
|
||
|
def build_bc(opt=False):
|
||
|
out = []
|
||
|
for mod in CORE:
|
||
|
out.append("""unsigned char tp_%s[] = {"""%mod)
|
||
|
fname = mod+".tpc"
|
||
|
data = open(fname,'rb').read()
|
||
|
cols = 16
|
||
|
for n in xrange(0,len(data),cols):
|
||
|
out.append(",".join([str(ord(v)) for v in data[n:n+cols]])+',')
|
||
|
out.append("""};""")
|
||
|
out.append("")
|
||
|
f = open('bc.c','wb')
|
||
|
f.write('\n'.join(out))
|
||
|
f.close()
|
||
|
|
||
|
def open_tinypy(fname,*args):
|
||
|
return open(os.path.join(TOPDIR,'tinypy',fname),*args)
|
||
|
|
||
|
def build_blob():
|
||
|
mods = CORE[:]
|
||
|
do_chdir(os.path.join(TOPDIR,'tinypy'))
|
||
|
for mod in mods: do_cmd('python py2bc.py %s.py %s.tpc'%(mod,mod))
|
||
|
do_chdir(os.path.join(TOPDIR))
|
||
|
|
||
|
out = []
|
||
|
out.append("/*")
|
||
|
out.extend([v.rstrip() for v in open(os.path.join(TOPDIR,'LICENSE.txt'),'r')])
|
||
|
out.append("*/")
|
||
|
out.append("")
|
||
|
|
||
|
out.append("#ifndef TINYPY_H")
|
||
|
out.append("#define TINYPY_H")
|
||
|
out.extend([v.rstrip() for v in open_tinypy('tp.h','r')])
|
||
|
for fname in ['list.c','dict.c','misc.c','string.c','builtins.c',
|
||
|
'gc.c','ops.c','vm.c','tp.c']:
|
||
|
for line in open_tinypy(fname,'r'):
|
||
|
line = line.rstrip()
|
||
|
if not len(line): continue
|
||
|
if line[0] == '/': continue
|
||
|
if line[0] == ' ': continue
|
||
|
if line[0] == '\t': continue
|
||
|
if line[-1] != '{': continue
|
||
|
if 'enum' in line: continue
|
||
|
if '=' in line: continue
|
||
|
if '#' in line: continue
|
||
|
line = line.replace('{',';')
|
||
|
|
||
|
# Do not include prototypes already defined earlier, or gcc will
|
||
|
# warn about doubled prototypes in user code.
|
||
|
if '(' in line:
|
||
|
line2 = line[:line.find('(') + 1]
|
||
|
got_already = False
|
||
|
for already in out:
|
||
|
if already.startswith(line2):
|
||
|
got_already = True
|
||
|
break
|
||
|
if got_already: continue
|
||
|
out.append(line)
|
||
|
out.append("#endif")
|
||
|
out.append('')
|
||
|
dest = os.path.join(TOPDIR,'build','tinypy.h')
|
||
|
print 'writing %s'%dest
|
||
|
f = open(dest,'w')
|
||
|
f.write('\n'.join(out))
|
||
|
f.close()
|
||
|
|
||
|
# we leave all the tinypy.h stuff at the top so that
|
||
|
# if someone wants to include tinypy.c they don't have to have
|
||
|
# tinypy.h cluttering up their folder
|
||
|
|
||
|
for mod in CORE:
|
||
|
out.append("""extern unsigned char tp_%s[];"""%mod)
|
||
|
|
||
|
for fname in ['list.c','dict.c','misc.c','string.c','builtins.c',
|
||
|
'gc.c','ops.c','vm.c','tp.c','bc.c']:
|
||
|
for line in open_tinypy(fname,'r'):
|
||
|
line = line.rstrip()
|
||
|
if line.find('#include "') != -1: continue
|
||
|
out.append(line)
|
||
|
out.append('')
|
||
|
dest = os.path.join(TOPDIR,'build','tinypy.c')
|
||
|
print 'writing %s'%dest
|
||
|
f = open(dest,'w')
|
||
|
f.write('\n'.join(out))
|
||
|
f.close()
|
||
|
|
||
|
def py2bc(cmd,mod):
|
||
|
src = '%s.py'%mod
|
||
|
dest = '%s.tpc'%mod
|
||
|
if CLEAN or not os.path.exists(dest) or os.stat(src).st_mtime > os.stat(dest).st_mtime:
|
||
|
cmd = cmd.replace('$SRC',src)
|
||
|
cmd = cmd.replace('$DEST',dest)
|
||
|
do_cmd(cmd)
|
||
|
else:
|
||
|
print '#',dest,'is up to date'
|
||
|
|
||
|
def build_gcc():
|
||
|
mods = CORE[:]
|
||
|
do_chdir(os.path.join(TOPDIR,'tinypy'))
|
||
|
if TEST:
|
||
|
mods.append('tests')
|
||
|
do_cmd("gcc $WFLAGS -g vmmain.c $FLAGS -lm -o vm")
|
||
|
do_cmd('python tests.py $SYS')
|
||
|
for mod in mods:
|
||
|
py2bc('python py2bc.py $SRC $DEST',mod)
|
||
|
else:
|
||
|
for mod in mods:
|
||
|
py2bc('python py2bc.py $SRC $DEST -nopos',mod)
|
||
|
if BOOT:
|
||
|
do_cmd('$VM tests.tpc $SYS')
|
||
|
for mod in mods: py2bc('$VM py2bc.tpc $SRC $DEST',mod)
|
||
|
build_bc()
|
||
|
do_cmd("gcc $WFLAGS -g tpmain.c $FLAGS -lm -o tinypy")
|
||
|
#second pass - builts optimized binaries and stuff
|
||
|
if BOOT:
|
||
|
do_cmd('$TINYPY tests.py $SYS')
|
||
|
for mod in mods: py2bc('$TINYPY py2bc.py $SRC $DEST -nopos',mod)
|
||
|
build_bc(True)
|
||
|
if BOOT:
|
||
|
do_cmd("gcc $WFLAGS -O2 tpmain.c $FLAGS -lm -o tinypy")
|
||
|
do_cmd('$TINYPY tests.py $SYS')
|
||
|
print("# OK - we'll try -O3 for extra speed ...")
|
||
|
do_cmd("gcc $WFLAGS -O3 tpmain.c $FLAGS -lm -o tinypy")
|
||
|
do_cmd('$TINYPY tests.py $SYS')
|
||
|
do_cmd("gcc $WFLAGS -O3 mymain.c $FLAGS -lm -o ../build/tinypy")
|
||
|
do_chdir('..')
|
||
|
if TEST:
|
||
|
test_mods(os.path.join('.','build','tinypy')+' $TESTS')
|
||
|
print("# OK")
|
||
|
|
||
|
def get_libs():
|
||
|
modules = os.listdir('modules')
|
||
|
for m in modules[:]:
|
||
|
if m not in sys.argv: modules.remove(m)
|
||
|
global MODULES
|
||
|
MODULES = modules
|
||
|
|
||
|
def build_mymain():
|
||
|
src = os.path.join(TOPDIR,'tinypy','tpmain.c')
|
||
|
out = open(src,'r').read()
|
||
|
dest = os.path.join(TOPDIR,'tinypy','mymain.c')
|
||
|
|
||
|
vs = []
|
||
|
for m in MODULES:
|
||
|
vs.append('#include "../modules/%s/init.c"'%m)
|
||
|
out = out.replace('/* INCLUDE */','\n'.join(vs))
|
||
|
|
||
|
vs = []
|
||
|
for m in MODULES:
|
||
|
vs.append('%s_init(tp);'%m)
|
||
|
out = out.replace('/* INIT */','\n'.join(vs))
|
||
|
|
||
|
f = open(dest,'w')
|
||
|
f.write(out)
|
||
|
f.close()
|
||
|
return True
|
||
|
|
||
|
def test_mods(cmd):
|
||
|
for m in MODULES:
|
||
|
tests = os.path.join('modules',m,'tests.py')
|
||
|
if not os.path.exists(tests): continue
|
||
|
cmd = cmd.replace('$TESTS',tests)
|
||
|
do_cmd(cmd)
|
||
|
|
||
|
def build_vs():
|
||
|
# How to compile on windows with Visual Studio:
|
||
|
# Call the batch script that sets environement variables for Visual Studio and
|
||
|
# then run this script.
|
||
|
# For VS 2005 the script is:
|
||
|
# "C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat"
|
||
|
# For VS 2008: "C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
|
||
|
# Doesn't compile with vc6 (no variadic macros)
|
||
|
# Note: /MD option causes to dynamically link with msvcrt80.dll. This dramatically
|
||
|
# reduces size (for vm.exe 159k => 49k). Downside is that msvcrt80.dll must be
|
||
|
# present on the system (and not all windows machine have it). You can either re-distribute
|
||
|
# msvcrt80.dll or statically link with C runtime by changing /MD to /MT.
|
||
|
mods = CORE[:]; mods.append('tests')
|
||
|
os.chdir(os.path.join(TOPDIR,'tinypy'))
|
||
|
do_cmd('cl vmmain.c /D "inline=" /Od /Zi /MD /Fdvm.pdb /Fmvm.map /Fevm.exe')
|
||
|
do_cmd('python tests.py -win')
|
||
|
for mod in mods: do_cmd('python py2bc.py %s.py %s.tpc'%(mod,mod))
|
||
|
do_cmd('vm.exe tests.tpc -win')
|
||
|
for mod in mods: do_cmd('vm.exe py2bc.tpc %s.py %s.tpc'%(mod,mod))
|
||
|
build_bc()
|
||
|
do_cmd('cl /Od tpmain.c /D "inline=" /Zi /MD /Fdtinypy.pdb /Fmtinypy.map /Fetinypy.exe')
|
||
|
#second pass - builts optimized binaries and stuff
|
||
|
do_cmd('tinypy.exe tests.py -win')
|
||
|
for mod in mods: do_cmd('tinypy.exe py2bc.py %s.py %s.tpc -nopos'%(mod,mod))
|
||
|
build_bc(True)
|
||
|
do_cmd('cl /Os vmmain.c /D "inline=__inline" /D "NDEBUG" /Gy /GL /Zi /MD /Fdvm.pdb /Fmvm.map /Fevm.exe /link /opt:ref /opt:icf')
|
||
|
do_cmd('cl /Os tpmain.c /D "inline=__inline" /D "NDEBUG" /Gy /GL /Zi /MD /Fdtinypy.pdb /Fmtinypy.map /Fetinypy.exe /link /opt:ref,icf /OPT:NOWIN98')
|
||
|
do_cmd("tinypy.exe tests.py -win")
|
||
|
do_cmd("dir *.exe")
|
||
|
|
||
|
def shrink(fname):
|
||
|
f = open(fname,'r'); lines = f.readlines(); f.close()
|
||
|
out = []
|
||
|
fixes = [
|
||
|
'vm','gc','params','STR',
|
||
|
'int','float','return','free','delete','init',
|
||
|
'abs','round','system','pow','div','raise','hash','index','printf','main']
|
||
|
passing = False
|
||
|
for line in lines:
|
||
|
#quit if we've already converted
|
||
|
if '\t' in line: return ''.join(lines)
|
||
|
|
||
|
#change " " into "\t" and remove blank lines
|
||
|
if len(line.strip()) == 0: continue
|
||
|
line = line.rstrip()
|
||
|
l1,l2 = len(line),len(line.lstrip())
|
||
|
line = "\t"*((l1-l2)/4)+line.lstrip()
|
||
|
|
||
|
#remove comments
|
||
|
if '.c' in fname or '.h' in fname:
|
||
|
#start block comment
|
||
|
if line.strip()[:2] == '/*':
|
||
|
passing = True;
|
||
|
#end block comment
|
||
|
if line.strip()[-2:] == '*/':
|
||
|
passing = False;
|
||
|
continue
|
||
|
#skip lines inside block comments
|
||
|
if passing:
|
||
|
continue
|
||
|
if '.py' in fname:
|
||
|
if line.strip()[:1] == '#': continue
|
||
|
|
||
|
#remove the "namespace penalty" from tinypy ...
|
||
|
for name in fixes:
|
||
|
line = line.replace('TP_'+name,'t'+name)
|
||
|
line = line.replace('tp_'+name,'t'+name)
|
||
|
line = line.replace('TP_','')
|
||
|
line = line.replace('tp_','')
|
||
|
|
||
|
out.append(line)
|
||
|
return '\n'.join(out)+'\n'
|
||
|
|
||
|
def chksize():
|
||
|
t1,t2 = 0,0
|
||
|
for fname in [
|
||
|
'tokenize.py','parse.py','encode.py','py2bc.py',
|
||
|
'tp.h','list.c','dict.c','misc.c','string.c','builtins.c',
|
||
|
'gc.c','ops.c','vm.c','tp.c','tpmain.c',
|
||
|
]:
|
||
|
fname = os.path.join(TOPDIR,'tinypy',fname)
|
||
|
f = open(fname,'r'); t1 += len(f.read()); f.close()
|
||
|
txt = shrink(fname)
|
||
|
t2 += len(txt)
|
||
|
print "#",t1,t2,t2-65536
|
||
|
return t2
|
||
|
|
||
|
def build_64k():
|
||
|
for fname in [
|
||
|
'tokenize.py','parse.py','encode.py','py2bc.py',
|
||
|
'tp.h','list.c','dict.c','misc.c','string.c','builtins.c',
|
||
|
'gc.c','ops.c','vm.c','tp.c','tpmain.c',
|
||
|
]:
|
||
|
src = os.path.join(TOPDIR,'tinypy',fname)
|
||
|
dest = os.path.join(TOPDIR,'build',fname)
|
||
|
txt = shrink(src)
|
||
|
f = open(dest,'w')
|
||
|
f.write(txt)
|
||
|
f.close()
|
||
|
print '%s saved to %s'%(src,dest)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|