Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. import os
  2. import sys
  3.  
  4. VARS = {}
  5. TOPDIR = os.path.abspath(os.path.dirname(__file__))
  6. TEST = False
  7. CLEAN = False
  8. BOOT = False
  9. CORE = ['tokenize','parse','encode','py2bc']
  10. MODULES = []
  11.  
  12. def main():
  13.     chksize()
  14.     if len(sys.argv) < 2:
  15.         print HELP
  16.         return
  17.    
  18.     global TEST,CLEAN,BOOT
  19.     TEST = 'test' in sys.argv
  20.     CLEAN = 'clean' in sys.argv
  21.     BOOT = 'boot' in sys.argv
  22.     CLEAN = CLEAN or BOOT
  23.     TEST = TEST or BOOT
  24.    
  25.     get_libs()
  26.     build_mymain()
  27.    
  28.     cmd = sys.argv[1]
  29.     if cmd == 'linux':
  30.         vars_linux()
  31.         build_gcc()
  32.     elif cmd == 'mingw':
  33.         vars_windows()
  34.         build_gcc()
  35.     elif cmd == 'vs':
  36.         build_vs()
  37.     elif cmd == '64k':
  38.         build_64k()
  39.     elif cmd == 'blob':
  40.         build_blob()
  41.     else:
  42.         print 'invalid command'
  43.  
  44. HELP = """
  45. python setup.py command [options] [modules]
  46.  
  47. Commands:
  48.    linux - build tinypy for linux
  49.    mingw - build tinypy for mingw under windows
  50.    vs - build tinypy using Visual Studio 2005 / 2008
  51.    
  52.    64k - build a 64k version of the tinypy source
  53.    blob - build a single tinypy.c and tinypy.h
  54.    
  55.    build - build CPython module ***
  56.    install - install CPython module ***
  57.    
  58. Options:
  59.    test - run tests during build
  60.    clean - rebuild all .tpc during build
  61.    boot - fully bootstrap and test tinypy
  62.    
  63. Modules:
  64.    math - build math module
  65.    random - build random module *
  66.    pygame - build pygame module **
  67.    marshal - build marshal module ***
  68.    jit - build jit module ***
  69.    re - build re module ***
  70.  
  71. * coming soon!!
  72. ** proof-of-concept included
  73. *** vaporware
  74. """
  75.  
  76. def vars_linux():
  77.     VARS['$RM'] = 'rm -f'
  78.     VARS['$VM'] = './vm'
  79.     VARS['$TINYPY'] = './tinypy'
  80.     VARS['$SYS'] = '-linux'
  81.     VARS['$FLAGS'] = ''
  82.    
  83.     VARS['$WFLAGS'] = '-std=c89 -Wall -Wc++-compat'
  84.     #-Wwrite-strings - i think this is included in -Wc++-compat
  85.    
  86.     if 'pygame' in MODULES:
  87.         VARS['$FLAGS'] += ' `sdl-config --cflags --libs` '
  88.  
  89. def vars_windows():
  90.     VARS['$RM'] = 'del'
  91.     VARS['$VM'] = 'vm'
  92.     VARS['$TINYPY'] = 'tinypy'
  93.     VARS['$FLAGS'] = '-lmingw32'
  94.     VARS['$WFLAGS'] = '-Wwrite-strings -Wall'
  95.     VARS['$SYS'] = '-mingw32'
  96.  
  97.     if 'pygame' in MODULES:
  98.         VARS['$FLAGS'] += ' -Ic:\\mingw\\include\\SDL -lSDLmain -lSDL '
  99.  
  100. def do_cmd(cmd):
  101.     for k,v in VARS.items():
  102.         cmd = cmd.replace(k,v)
  103.     if '$' in cmd:
  104.         print 'vars_error',cmd
  105.         sys.exit(-1)
  106.    
  107.     print cmd
  108.     r = os.system(cmd)
  109.     if r:
  110.         print 'exit_status',r
  111.         sys.exit(r)
  112.        
  113. def do_chdir(dest):
  114.     print 'cd',dest
  115.     os.chdir(dest)
  116.  
  117. def build_bc(opt=False):
  118.     out = []
  119.     for mod in CORE:
  120.         out.append("""unsigned char tp_%s[] = {"""%mod)
  121.         fname = mod+".tpc"
  122.         data = open(fname,'rb').read()
  123.         cols = 16
  124.         for n in xrange(0,len(data),cols):
  125.             out.append(",".join([str(ord(v)) for v in data[n:n+cols]])+',')
  126.         out.append("""};""")
  127.     out.append("")
  128.     f = open('bc.c','wb')
  129.     f.write('\n'.join(out))
  130.     f.close()
  131.    
  132. def open_tinypy(fname,*args):
  133.     return open(os.path.join(TOPDIR,'tinypy',fname),*args)
  134.    
  135. def build_blob():
  136.     mods = CORE[:]
  137.     do_chdir(os.path.join(TOPDIR,'tinypy'))
  138.     for mod in mods: do_cmd('python py2bc.py %s.py %s.tpc'%(mod,mod))
  139.     do_chdir(os.path.join(TOPDIR))
  140.    
  141.     out = []
  142.     out.append("/*")
  143.     out.extend([v.rstrip() for v in open(os.path.join(TOPDIR,'LICENSE.txt'),'r')])
  144.     out.append("*/")
  145.     out.append("")
  146.    
  147.     out.append("#ifndef TINYPY_H")
  148.     out.append("#define TINYPY_H")
  149.     out.extend([v.rstrip() for v in open_tinypy('tp.h','r')])
  150.     for fname in ['list.c','dict.c','misc.c','string.c','builtins.c',
  151.         'gc.c','ops.c','vm.c','tp.c']:
  152.         for line in open_tinypy(fname,'r'):
  153.             line = line.rstrip()
  154.             if not len(line): continue
  155.             if line[0] == '/': continue
  156.             if line[0] == ' ': continue
  157.             if line[0] == '\t': continue
  158.             if line[-1] != '{': continue
  159.             if 'enum' in line: continue
  160.             if '=' in line: continue
  161.             if '#' in line: continue
  162.             line = line.replace('{',';')
  163.            
  164.             # Do not include prototypes already defined earlier, or gcc will
  165.             # warn about doubled prototypes in user code.
  166.             if '(' in line:
  167.                 line2 = line[:line.find('(') + 1]
  168.                 got_already = False
  169.                 for already in out:
  170.                     if already.startswith(line2):
  171.                         got_already = True
  172.                         break
  173.                 if got_already: continue
  174.             out.append(line)
  175.     out.append("#endif")
  176.     out.append('')
  177.     dest = os.path.join(TOPDIR,'build','tinypy.h')
  178.     print 'writing %s'%dest
  179.     f = open(dest,'w')
  180.     f.write('\n'.join(out))
  181.     f.close()
  182.    
  183.     # we leave all the tinypy.h stuff at the top so that
  184.     # if someone wants to include tinypy.c they don't have to have
  185.     # tinypy.h cluttering up their folder
  186.    
  187.     for mod in CORE:
  188.         out.append("""extern unsigned char tp_%s[];"""%mod)
  189.  
  190.     for fname in ['list.c','dict.c','misc.c','string.c','builtins.c',
  191.         'gc.c','ops.c','vm.c','tp.c','bc.c']:
  192.         for line in open_tinypy(fname,'r'):
  193.             line = line.rstrip()
  194.             if line.find('#include "') != -1: continue
  195.             out.append(line)
  196.     out.append('')
  197.     dest = os.path.join(TOPDIR,'build','tinypy.c')
  198.     print 'writing %s'%dest
  199.     f = open(dest,'w')
  200.     f.write('\n'.join(out))
  201.     f.close()
  202.                
  203. def py2bc(cmd,mod):
  204.     src = '%s.py'%mod
  205.     dest = '%s.tpc'%mod
  206.     if CLEAN or not os.path.exists(dest) or os.stat(src).st_mtime > os.stat(dest).st_mtime:
  207.         cmd = cmd.replace('$SRC',src)
  208.         cmd = cmd.replace('$DEST',dest)
  209.         do_cmd(cmd)
  210.     else:
  211.         print '#',dest,'is up to date'
  212.  
  213. def build_gcc():
  214.     mods = CORE[:]
  215.     do_chdir(os.path.join(TOPDIR,'tinypy'))
  216.     if TEST:
  217.         mods.append('tests')
  218.         do_cmd("gcc $WFLAGS -g vmmain.c $FLAGS -lm -o vm")
  219.         do_cmd('python tests.py $SYS')
  220.         for mod in mods:
  221.             py2bc('python py2bc.py $SRC $DEST',mod)
  222.     else:
  223.         for mod in mods:
  224.             py2bc('python py2bc.py $SRC $DEST -nopos',mod)
  225.     if BOOT:
  226.         do_cmd('$VM tests.tpc $SYS')
  227.         for mod in mods: py2bc('$VM py2bc.tpc $SRC $DEST',mod)
  228.         build_bc()
  229.         do_cmd("gcc $WFLAGS -g tpmain.c $FLAGS -lm -o tinypy")
  230.     #second pass - builts optimized binaries and stuff
  231.     if BOOT:
  232.         do_cmd('$TINYPY tests.py $SYS')
  233.         for mod in mods: py2bc('$TINYPY py2bc.py $SRC $DEST -nopos',mod)
  234.     build_bc(True)
  235.     if BOOT:
  236.         do_cmd("gcc $WFLAGS -O2 tpmain.c $FLAGS -lm -o tinypy")
  237.         do_cmd('$TINYPY tests.py $SYS')
  238.         print("# OK - we'll try -O3 for extra speed ...")
  239.         do_cmd("gcc $WFLAGS -O3 tpmain.c $FLAGS -lm -o tinypy")
  240.         do_cmd('$TINYPY tests.py $SYS')
  241.     do_cmd("gcc $WFLAGS -O3 mymain.c $FLAGS -lm -o ../build/tinypy")
  242.     do_chdir('..')
  243.     if TEST:
  244.         test_mods(os.path.join('.','build','tinypy')+' $TESTS')
  245.     print("# OK")
  246.    
  247. def get_libs():
  248.     modules = os.listdir('modules')
  249.     for m in modules[:]:
  250.         if m not in sys.argv: modules.remove(m)
  251.     global MODULES
  252.     MODULES = modules
  253.  
  254. def build_mymain():
  255.     src = os.path.join(TOPDIR,'tinypy','tpmain.c')
  256.     out = open(src,'r').read()
  257.     dest = os.path.join(TOPDIR,'tinypy','mymain.c')
  258.        
  259.     vs = []
  260.     for m in MODULES:
  261.         vs.append('#include "../modules/%s/init.c"'%m)
  262.     out = out.replace('/* INCLUDE */','\n'.join(vs))
  263.    
  264.     vs = []
  265.     for m in MODULES:
  266.         vs.append('%s_init(tp);'%m)
  267.     out = out.replace('/* INIT */','\n'.join(vs))
  268.    
  269.     f = open(dest,'w')
  270.     f.write(out)
  271.     f.close()
  272.     return True
  273.    
  274. def test_mods(cmd):
  275.     for m in MODULES:
  276.         tests = os.path.join('modules',m,'tests.py')
  277.         if not os.path.exists(tests): continue
  278.         cmd = cmd.replace('$TESTS',tests)
  279.         do_cmd(cmd)
  280.  
  281. def build_vs():
  282.     # How to compile on windows with Visual Studio:
  283.     # Call the batch script that sets environement variables for Visual Studio and
  284.     # then run this script.
  285.     # For VS 2005 the script is:
  286.     # "C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat"
  287.     # For VS 2008: "C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
  288.     # Doesn't compile with vc6 (no variadic macros)
  289.     # Note: /MD option causes to dynamically link with msvcrt80.dll. This dramatically
  290.     # reduces size (for vm.exe 159k => 49k). Downside is that msvcrt80.dll must be
  291.     # present on the system (and not all windows machine have it). You can either re-distribute
  292.     # msvcrt80.dll or statically link with C runtime by changing /MD to /MT.
  293.     mods = CORE[:]; mods.append('tests')
  294.     os.chdir(os.path.join(TOPDIR,'tinypy'))
  295.     do_cmd('cl vmmain.c /D "inline=" /Od /Zi /MD /Fdvm.pdb /Fmvm.map /Fevm.exe')
  296.     do_cmd('python tests.py -win')
  297.     for mod in mods: do_cmd('python py2bc.py %s.py %s.tpc'%(mod,mod))
  298.     do_cmd('vm.exe tests.tpc -win')
  299.     for mod in mods: do_cmd('vm.exe py2bc.tpc %s.py %s.tpc'%(mod,mod))
  300.     build_bc()
  301.     do_cmd('cl /Od tpmain.c /D "inline=" /Zi /MD /Fdtinypy.pdb /Fmtinypy.map /Fetinypy.exe')
  302.     #second pass - builts optimized binaries and stuff
  303.     do_cmd('tinypy.exe tests.py -win')
  304.     for mod in mods: do_cmd('tinypy.exe py2bc.py %s.py %s.tpc -nopos'%(mod,mod))
  305.     build_bc(True)
  306.     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')
  307.     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')
  308.     do_cmd("tinypy.exe tests.py -win")
  309.     do_cmd("dir *.exe")
  310.  
  311. def shrink(fname):
  312.     f = open(fname,'r'); lines = f.readlines(); f.close()
  313.     out = []
  314.     fixes = [
  315.     'vm','gc','params','STR',
  316.     'int','float','return','free','delete','init',
  317.     'abs','round','system','pow','div','raise','hash','index','printf','main']
  318.     passing = False
  319.     for line in lines:
  320.         #quit if we've already converted
  321.         if '\t' in line: return ''.join(lines)
  322.        
  323.         #change "    " into "\t" and remove blank lines
  324.         if len(line.strip()) == 0: continue
  325.         line = line.rstrip()
  326.         l1,l2 = len(line),len(line.lstrip())
  327.         line = "\t"*((l1-l2)/4)+line.lstrip()
  328.        
  329.         #remove comments
  330.         if '.c' in fname or '.h' in fname:
  331.             #start block comment
  332.             if line.strip()[:2] == '/*':
  333.                 passing = True;
  334.             #end block comment
  335.             if line.strip()[-2:] == '*/':
  336.                passing = False;
  337.                continue
  338.             #skip lines inside block comments
  339.             if passing:
  340.                 continue
  341.         if '.py' in fname:
  342.             if line.strip()[:1] == '#': continue
  343.        
  344.         #remove the "namespace penalty" from tinypy ...
  345.         for name in fixes:
  346.             line = line.replace('TP_'+name,'t'+name)
  347.             line = line.replace('tp_'+name,'t'+name)
  348.         line = line.replace('TP_','')
  349.         line = line.replace('tp_','')
  350.        
  351.         out.append(line)
  352.     return '\n'.join(out)+'\n'
  353.    
  354. def chksize():
  355.     t1,t2 = 0,0
  356.     for fname in [
  357.         'tokenize.py','parse.py','encode.py','py2bc.py',
  358.         'tp.h','list.c','dict.c','misc.c','string.c','builtins.c',
  359.         'gc.c','ops.c','vm.c','tp.c','tpmain.c',
  360.         ]:
  361.         fname = os.path.join(TOPDIR,'tinypy',fname)
  362.         f = open(fname,'r'); t1 += len(f.read()); f.close()
  363.         txt = shrink(fname)
  364.         t2 += len(txt)
  365.     print "#",t1,t2,t2-65536
  366.     return t2
  367.  
  368. def build_64k():
  369.     for fname in [
  370.         'tokenize.py','parse.py','encode.py','py2bc.py',
  371.         'tp.h','list.c','dict.c','misc.c','string.c','builtins.c',
  372.         'gc.c','ops.c','vm.c','tp.c','tpmain.c',
  373.         ]:
  374.         src = os.path.join(TOPDIR,'tinypy',fname)
  375.         dest = os.path.join(TOPDIR,'build',fname)
  376.         txt = shrink(src)
  377.         f = open(dest,'w')
  378.         f.write(txt)
  379.         f.close()
  380.         print '%s saved to %s'%(src,dest)
  381.  
  382. if __name__ == '__main__':
  383.     main()
  384.