Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1913 jaeger 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()