Merging r39998 through r40043 from trunk into soc-2011-tomato
[blender.git] / build_files / scons / tools / Blender.py
1 #!/usr/bin/env python
2
3 """
4 tools.BlenderEnvironment
5
6 This environment builds on SCons.Script.SConscript.SConsEnvironment
7
8 * library repository
9 * custom printout
10 * wrapper functions
11
12 TODO: clean up and sanitise code - crosscheck with btools and SConstruct
13 to kill any code duplication
14
15 """
16
17 import os
18 import os.path
19 import string
20 import glob
21 import time
22 import sys
23 import tarfile
24 import shutil
25 import cStringIO
26 import platform
27
28 from SCons.Script.SConscript import SConsEnvironment
29 import SCons.Action
30 import SCons.Util
31 import SCons.Builder
32 import SCons.Tool
33 import bcolors
34 bc = bcolors.bcolors()
35 import btools
36 VERSION = btools.VERSION
37
38 Split = SCons.Util.Split
39 Action = SCons.Action.Action
40 Builder = SCons.Builder.Builder
41 GetBuildPath = SConsEnvironment.GetBuildPath
42
43 # a few globals
44 root_build_dir = ''
45 doc_build_dir = ''
46 quickie = None # Anything else than None if BF_QUICK has been passed
47 quicklist = [] # The list of libraries/programs to compile during a quickie
48 program_list = [] # A list holding Nodes to final binaries, used to create installs
49 arguments = None
50 targets = None
51 resources = []
52
53 #some internals
54 blenderdeps = [] # don't manipulate this one outside this module!
55
56 ##### LIB STUFF ##########
57
58 possible_types = ['core'] # can be set in ie. SConstruct
59 libs = {}
60 vcp = []
61
62 def getresources():
63     return resources
64
65 def init_lib_dict():
66     for pt in possible_types:
67         libs[pt] = {}
68
69 # helper func for add_lib_to_dict
70 def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
71     if not libname in dict[libtype]:
72         done = None
73         while not done:
74             if dict[libtype].has_key(priority):
75                 priority = priority + 1
76             else:
77                 done = True
78         dict[libtype][priority] = libname
79
80 # libtype and priority can both be lists, for defining lib in multiple places
81 def add_lib_to_dict(env, dict = None, libtype = None, libname = None, priority = 100):
82     if not dict or not libtype or not libname:
83         print "Passed wrong arg"
84         env.Exit()
85
86     if type(libtype) is str and type(priority) is int:
87         internal_lib_to_dict(dict, libtype, libname, priority)
88     elif type(libtype) is list and type(priority) is list:
89         if len(libtype)==len(priority):
90             for lt, p in zip(libtype, priority):
91                 internal_lib_to_dict(dict, lt, libname, p)
92         else:
93             print "libtype and priority lists are unequal in length"
94             env.Exit()
95     else:
96         print "Wrong type combinations for libtype and priority. Only str and int or list and list"
97         env.Exit()
98
99 def create_blender_liblist(lenv = None, libtype = None):
100     if not lenv or not libtype:
101         print "missing arg"
102
103     lst = []
104     if libtype in possible_types:
105         curlib = libs[libtype]
106         sortlist = curlib.keys()
107         sortlist.sort()
108         for sk in sortlist:
109             v = curlib[sk]
110             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
111                 target = os.path.abspath(os.getcwd() + os.sep + root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
112             else:
113                 target = os.path.abspath(root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
114             lst.append(target)
115
116     return lst
117
118 ## TODO: static linking
119 def setup_staticlibs(lenv):
120     statlibs = [
121         #here libs for static linking
122     ]
123
124     libincs = []
125
126     if lenv['WITH_BF_FFMPEG']:
127         libincs += Split(lenv['BF_FFMPEG_LIBPATH'])
128
129     libincs.extend([
130         lenv['BF_OPENGL_LIBPATH'],
131         lenv['BF_JPEG_LIBPATH'],
132         lenv['BF_ZLIB_LIBPATH'],
133         lenv['BF_PNG_LIBPATH'],
134         lenv['BF_LIBSAMPLERATE_LIBPATH'],
135         lenv['BF_ICONV_LIBPATH']
136         ])
137
138     libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
139     if lenv['WITH_BF_PYTHON']:
140         libincs += Split(lenv['BF_PYTHON_LIBPATH'])
141     if lenv['WITH_BF_SDL']:
142         libincs += Split(lenv['BF_SDL_LIBPATH'])
143     if lenv['WITH_BF_JACK']:
144         libincs += Split(lenv['BF_JACK_LIBPATH'])
145     if lenv['WITH_BF_SNDFILE']:
146         libincs += Split(lenv['BF_SNDFILE_LIBPATH'])
147     if lenv['WITH_BF_OPENEXR']:
148         libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
149         if lenv['WITH_BF_STATICOPENEXR']:
150             statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
151     if lenv['WITH_BF_TIFF']:
152         libincs += Split(lenv['BF_TIFF_LIBPATH'])
153         if lenv['WITH_BF_STATICTIFF']:
154             statlibs += Split(lenv['BF_TIFF_LIB_STATIC'])
155     if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']:
156         statlibs += Split(lenv['BF_ZLIB_LIB_STATIC'])
157     if lenv['WITH_BF_FFTW3']:
158         libincs += Split(lenv['BF_FFTW3_LIBPATH'])
159         if lenv['WITH_BF_STATICFFTW3']:
160             statlibs += Split(lenv['BF_FFTW3_LIB_STATIC'])
161     if lenv['WITH_BF_FFMPEG'] and lenv['WITH_BF_STATICFFMPEG']:
162         statlibs += Split(lenv['BF_FFMPEG_LIB_STATIC'])
163     if lenv['WITH_BF_INTERNATIONAL']:
164         libincs += Split(lenv['BF_GETTEXT_LIBPATH'])
165         if lenv['WITH_BF_GETTEXT_STATIC']:
166             statlibs += Split(lenv['BF_GETTEXT_LIB_STATIC'])
167         if lenv['WITH_BF_FREETYPE_STATIC']:
168             statlibs += Split(lenv['BF_FREETYPE_LIB_STATIC'])
169     if lenv['WITH_BF_OPENAL']:
170         libincs += Split(lenv['BF_OPENAL_LIBPATH'])
171         if lenv['WITH_BF_STATICOPENAL']:
172             statlibs += Split(lenv['BF_OPENAL_LIB_STATIC'])
173     if lenv['WITH_BF_STATICOPENGL']:
174         statlibs += Split(lenv['BF_OPENGL_LIB_STATIC'])
175     if lenv['WITH_BF_STATICCXX']:
176         statlibs += Split(lenv['BF_CXX_LIB_STATIC'])
177
178     if lenv['WITH_BF_PYTHON'] and lenv['WITH_BF_STATICPYTHON']:
179         statlibs += Split(lenv['BF_PYTHON_LIB_STATIC'])
180
181     if lenv['WITH_BF_SNDFILE'] and lenv['WITH_BF_STATICSNDFILE']:
182         statlibs += Split(lenv['BF_SNDFILE_LIB_STATIC'])
183
184     if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
185         libincs += Split(lenv['BF_PTHREADS_LIBPATH'])
186
187     if lenv['WITH_BF_COLLADA']:
188         libincs += Split(lenv['BF_OPENCOLLADA_LIBPATH'])
189         if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
190             libincs += Split(lenv['BF_PCRE_LIBPATH'])
191             libincs += Split(lenv['BF_EXPAT_LIBPATH'])
192
193     if lenv['WITH_BF_OPENMP']:
194         if lenv['OURPLATFORM'] == 'linuxcross':
195             libincs += Split(lenv['BF_OPENMP_LIBPATH'])
196
197     if lenv['WITH_BF_STATICLIBSAMPLERATE']:
198         statlibs += Split(lenv['BF_LIBSAMPLERATE_LIB_STATIC'])
199
200     # setting this last so any overriding of manually libs could be handled
201     if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
202         libincs.append('/usr/lib')
203
204     if lenv['WITH_BF_JEMALLOC']:
205         libincs += Split(lenv['BF_JEMALLOC_LIBPATH'])
206         if lenv['WITH_BF_STATICJEMALLOC']:
207             statlibs += Split(lenv['BF_JEMALLOC_LIB_STATIC'])
208
209     if lenv['OURPLATFORM']=='linux':
210         if lenv['WITH_BF_3DMOUSE']:
211             libincs += Split(lenv['BF_3DMOUSE_LIBPATH'])
212             if lenv['WITH_BF_STATIC3DMOUSE']:
213                 statlibs += Split(lenv['BF_3DMOUSE_LIB_STATIC'])
214
215     return statlibs, libincs
216
217 def setup_syslibs(lenv):
218     syslibs = [
219         
220         lenv['BF_JPEG_LIB'],
221         lenv['BF_PNG_LIB'],
222         ]
223
224     if not lenv['WITH_BF_FREETYPE_STATIC']:
225         syslibs += Split(lenv['BF_FREETYPE_LIB'])
226     if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']:
227         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'):
228             syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
229         else:
230             syslibs.append(lenv['BF_PYTHON_LIB'])
231     if lenv['WITH_BF_INTERNATIONAL'] and not lenv['WITH_BF_GETTEXT_STATIC']:
232         syslibs += Split(lenv['BF_GETTEXT_LIB'])
233     if lenv['WITH_BF_OPENAL']:
234         if not lenv['WITH_BF_STATICOPENAL']:
235             syslibs += Split(lenv['BF_OPENAL_LIB'])
236     if lenv['WITH_BF_OPENMP'] and lenv['CC'] != 'icc':
237         if lenv['CC'] == 'cl.exe':
238             syslibs += ['vcomp']
239         else:
240             syslibs += ['gomp']
241     if lenv['WITH_BF_ICONV']:
242         syslibs += Split(lenv['BF_ICONV_LIB'])
243     if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
244         syslibs += Split(lenv['BF_OPENEXR_LIB'])
245     if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
246         syslibs += Split(lenv['BF_TIFF_LIB'])
247     if lenv['WITH_BF_ZLIB'] and not lenv['WITH_BF_STATICZLIB']:
248         syslibs += Split(lenv['BF_ZLIB_LIB'])
249     if lenv['WITH_BF_FFMPEG'] and not lenv['WITH_BF_STATICFFMPEG']:
250         syslibs += Split(lenv['BF_FFMPEG_LIB'])
251         if lenv['WITH_BF_OGG']:
252             syslibs += Split(lenv['BF_OGG_LIB'])
253     if lenv['WITH_BF_JACK']:
254             syslibs += Split(lenv['BF_JACK_LIB'])
255     if lenv['WITH_BF_SNDFILE'] and not lenv['WITH_BF_STATICSNDFILE']:
256             syslibs += Split(lenv['BF_SNDFILE_LIB'])
257     if lenv['WITH_BF_FFTW3'] and not lenv['WITH_BF_STATICFFTW3']:
258         syslibs += Split(lenv['BF_FFTW3_LIB'])
259     if lenv['WITH_BF_SDL']:
260         syslibs += Split(lenv['BF_SDL_LIB'])
261     if not lenv['WITH_BF_STATICOPENGL']:
262         syslibs += Split(lenv['BF_OPENGL_LIB'])
263     if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross', 'win64-vc'):
264         syslibs += Split(lenv['BF_PTHREADS_LIB'])
265     if lenv['WITH_BF_COLLADA']:
266         syslibs.append(lenv['BF_PCRE_LIB'])
267         if lenv['BF_DEBUG']:
268             syslibs += [colladalib+'_d' for colladalib in Split(lenv['BF_OPENCOLLADA_LIB'])]
269         else:
270             syslibs += Split(lenv['BF_OPENCOLLADA_LIB'])
271         syslibs.append(lenv['BF_EXPAT_LIB'])
272
273     if not lenv['WITH_BF_STATICLIBSAMPLERATE']:
274         syslibs += Split(lenv['BF_LIBSAMPLERATE_LIB'])
275
276     if lenv['WITH_BF_JEMALLOC']:
277         if not lenv['WITH_BF_STATICJEMALLOC']:
278             syslibs += Split(lenv['BF_JEMALLOC_LIB'])
279
280     if lenv['OURPLATFORM']=='linux':
281         if lenv['WITH_BF_3DMOUSE']:
282             if not lenv['WITH_BF_STATIC3DMOUSE']:
283                 syslibs += Split(lenv['BF_3DMOUSE_LIB'])
284
285     syslibs += lenv['LLIBS']
286
287     return syslibs
288
289 def propose_priorities():
290     print bc.OKBLUE+"Priorities:"+bc.ENDC
291     for t in possible_types:
292         print bc.OKGREEN+"\t"+t+bc.ENDC
293         new_priority = 0
294         curlib = libs[t]
295         sortlist = curlib.keys()
296         sortlist.sort()
297
298         for sk in sortlist:
299             v = curlib[sk]
300             #for p,v in sorted(libs[t].iteritems()):
301             print "\t\t",new_priority, v
302             new_priority += 5
303
304 # emits the necessary file objects for creator.c, to be used in creating
305 # the final blender executable
306 def creator(env):
307     sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
308
309     incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
310
311     defs = []
312     if env['WITH_BF_QUICKTIME']:
313         incs.append(env['BF_QUICKTIME_INC'])
314         defs.append('WITH_QUICKTIME')
315
316     if env['WITH_BF_BINRELOC']:
317         incs.append('#/extern/binreloc/include')
318         defs.append('WITH_BINRELOC')
319
320     if env['WITH_BF_OPENEXR']:
321         defs.append('WITH_OPENEXR')
322
323     if env['WITH_BF_TIFF']:
324         defs.append('WITH_TIFF')
325
326     if not env['WITH_BF_SDL']:
327         defs.append('DISABLE_SDL')
328
329     if env['WITH_BF_LIBMV']:
330         incs.append('#/extern/libmv')
331         defs.append('WITH_LIBMV')
332
333     if env['WITH_BF_PYTHON']:
334         incs.append('#/source/blender/python')
335         defs.append('WITH_PYTHON')
336         if env['BF_DEBUG']:
337             defs.append('_DEBUG')
338
339     if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
340         incs.append(env['BF_PTHREADS_INC'])
341
342     env.Append(CPPDEFINES=defs)
343     env.Append(CPPPATH=incs)
344     obj = [env.Object(root_build_dir+'source/creator/creator/creator', ['#source/creator/creator.c'])]
345
346     return obj
347
348 ## TODO: see if this can be made in an emitter
349 def buildinfo(lenv, build_type):
350     """
351     Generate a buildinfo object
352     """
353     build_date = time.strftime ("%Y-%m-%d")
354     build_time = time.strftime ("%H:%M:%S")
355     build_rev = os.popen('svnversion').read()[:-1] # remove \n
356     if build_rev == '': 
357         build_rev = '-UNKNOWN-'
358     if lenv['BF_DEBUG']:
359         build_type = "Debug"
360         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['BF_DEBUG_CCFLAGS'] + lenv['CPPFLAGS'])
361         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['CPPFLAGS'])
362     else:
363         build_type = "Release"
364         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['REL_CFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
365         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['REL_CXXFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
366
367     build_linkflags = ' '.join(lenv['PLATFORM_LINKFLAGS'])
368
369     obj = []
370     if lenv['BF_BUILDINFO']:
371         lenv.Append (CPPDEFINES = ['BUILD_TIME=\\"%s\\"'%(build_time),
372                                     'BUILD_DATE=\\"%s\\"'%(build_date),
373                                     'BUILD_TYPE=\\"%s\\"'%(build_type),
374                                     'BUILD_REV=\\"%s\\"'%(build_rev),
375                                     'WITH_BUILDINFO',
376                                     'BUILD_PLATFORM=\\"%s:%s\\"'%(platform.system(), platform.architecture()[0]),
377                                     'BUILD_CFLAGS=\\"%s\\"'%(build_cflags),
378                                     'BUILD_CXXFLAGS=\\"%s\\"'%(build_cxxflags),
379                                     'BUILD_LINKFLAGS=\\"%s\\"'%(build_linkflags),
380                                     'BUILD_SYSTEM=\\"SCons\\"'
381                     ])
382
383         lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel'])
384
385         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, ['#source/creator/buildinfo.c'])]
386
387     return obj
388
389 ##### END LIB STUFF ############
390
391 ##### ACTION STUFF #############
392
393 def my_print_cmd_line(self, s, target, source, env):
394     sys.stdout.write(' ' * 70 + '\r')
395     sys.stdout.flush()
396     sys.stdout.write(s + "\r")
397     sys.stdout.flush()
398
399 def my_compile_print(target, source, env):
400     a = '%s' % (source[0])
401     d, f = os.path.split(a)
402     return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
403
404 def my_moc_print(target, source, env):
405     a = '%s' % (source[0])
406     d, f = os.path.split(a)
407     return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
408
409 def my_linking_print(target, source, env):
410     t = '%s' % (target[0])
411     d, f = os.path.split(t)
412     return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
413
414 def my_program_print(target, source, env):
415     t = '%s' % (target[0])
416     d, f = os.path.split(t)
417     return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
418
419 def msvc_hack(env):
420     static_lib = SCons.Tool.createStaticLibBuilder(env)
421     program = SCons.Tool.createProgBuilder(env)
422     
423     env['BUILDERS']['Library'] = static_lib
424     env['BUILDERS']['StaticLibrary'] = static_lib
425     env['BUILDERS']['Program'] = program
426         
427 def set_quiet_output(env):
428     mycaction = Action("$CCCOM", strfunction=my_compile_print)
429     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
430     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
431     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
432     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
433     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
434
435     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
436     static_ob.add_action('.c', mycaction)
437     static_ob.add_action('.cpp', mycppaction)
438     shared_ob.add_action('.c', myshcaction)
439     shared_ob.add_action('.cpp', myshcppaction)
440
441     static_lib = SCons.Builder.Builder(action = mylibaction,
442                                        emitter = '$LIBEMITTER',
443                                        prefix = '$LIBPREFIX',
444                                        suffix = '$LIBSUFFIX',
445                                        src_suffix = '$OBJSUFFIX',
446                                        src_builder = 'StaticObject')
447
448     program = SCons.Builder.Builder(action = mylinkaction,
449                                     emitter = '$PROGEMITTER',
450                                     prefix = '$PROGPREFIX',
451                                     suffix = '$PROGSUFFIX',
452                                     src_suffix = '$OBJSUFFIX',
453                                     src_builder = 'Object',
454                                     target_scanner = SCons.Defaults.ProgScan)
455
456     env['BUILDERS']['Object'] = static_ob
457     env['BUILDERS']['StaticObject'] = static_ob
458     env['BUILDERS']['StaticLibrary'] = static_lib
459     env['BUILDERS']['Library'] = static_lib
460     env['BUILDERS']['Program'] = program
461     if env['BF_LINE_OVERWRITE']:
462         SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
463
464 def untar_pybundle(from_tar,to_dir,exclude_re):
465     tar= tarfile.open(from_tar, mode='r')
466     exclude_re= list(exclude_re) #single re object or list of re objects
467     debug= 0 #list files instead of unpacking
468     good= []
469     if debug: print '\nFiles not being unpacked:\n'
470     for name in tar.getnames():
471         is_bad= 0
472         for r in exclude_re:
473             if r.match(name):
474                 is_bad=1
475                 if debug: print name
476                 break
477         if not is_bad:
478             good.append(tar.getmember(name))
479     if debug:
480         print '\nFiles being unpacked:\n'
481         for g in good:
482             print g
483     else:
484         tar.extractall(to_dir, good)
485
486 def my_winpybundle_print(target, source, env):
487     pass
488
489 def WinPyBundle(target=None, source=None, env=None):
490     import re
491     py_tar= env.subst( env['LCGDIR'] )
492     if py_tar[0]=='#':
493         py_tar= py_tar[1:]
494     if env['BF_DEBUG']:
495         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.tar.gz'
496     else:
497         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
498
499     py_target = env.subst( env['BF_INSTALLDIR'] )
500     if py_target[0]=='#':
501         py_target=py_target[1:]
502     py_target = os.path.join(py_target, VERSION, 'python', 'lib')
503     def printexception(func,path,ex):
504         if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
505             print str(func) + ' failed on ' + str(path)
506     print "Trying to remove existing py bundle."
507     shutil.rmtree(py_target, False, printexception)
508     exclude_re=[re.compile('.*/test/.*'),
509                 re.compile('^config/.*'),
510                 re.compile('^config-*/.*'),
511                 re.compile('^distutils/.*'),
512                 re.compile('^idlelib/.*'),
513                 re.compile('^lib2to3/.*'),
514                 re.compile('^tkinter/.*'),
515                 re.compile('^_tkinter_d.pyd'),
516                 re.compile('^turtledemo'),
517                 re.compile('^turtle.py'),
518                 ]
519
520     print "Unpacking '" + py_tar + "' to '" + py_target + "'"
521     untar_pybundle(py_tar,py_target,exclude_re)
522
523 def  my_appit_print(target, source, env):
524     a = '%s' % (target[0])
525     d, f = os.path.split(a)
526     return "making bundle for " + f
527
528 def AppIt(target=None, source=None, env=None):
529     import shutil
530     import commands
531     import os.path
532     
533     
534     a = '%s' % (target[0])
535     builddir, b = os.path.split(a)
536     libdir = env['LCGDIR'][1:]
537     osxarch = env['MACOSX_ARCHITECTURE']
538     installdir = env['BF_INSTALLDIR']
539     print("compiled architecture: %s"%(osxarch))
540     print("Installing to %s"%(installdir))
541     # TODO, use tar.
542     python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
543     if env['WITH_OSX_STATICPYTHON']:
544         print("unzipping to app-bundle: %s"%(python_zip))
545     else:
546         print("dynamic build - make sure to have python3.x-framework installed")
547     bldroot = env.Dir('.').abspath
548     binary = env['BINARYKIND']
549      
550     if b=='verse':
551         print bc.OKBLUE+"no bundle for verse"+bc.ENDC 
552         return 0
553     
554     sourcedir = bldroot + '/source/darwin/%s.app'%binary
555     sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
556     targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
557     cmd = installdir + '/' +'%s.app'%binary
558     
559     if os.path.isdir(cmd):
560         shutil.rmtree(cmd)
561     shutil.copytree(sourcedir, cmd)
562     cmd = "cat %s | sed s/\$\{MACOSX_BUNDLE_SHORT_VERSION_STRING\}/%s/ | "%(sourceinfo,VERSION)
563     cmd += "sed s/\$\{MACOSX_BUNDLE_LONG_VERSION_STRING\}/%s,\ %s/g > %s"%(VERSION,time.strftime("%Y-%b-%d"),targetinfo)
564     commands.getoutput(cmd)
565     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
566     commands.getoutput(cmd)
567     cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/'%(installdir, binary, VERSION)
568 #    print cmd
569     commands.getoutput(cmd)
570     cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
571     shutil.copy(bldroot + '/release/bin/.blender/.bfont.ttf', cmd)
572     shutil.copy(bldroot + '/release/bin/.blender/.Blanguages', cmd)
573     cmd = 'cp -R %s/release/bin/%s/locale %s/%s.app/Contents/Resources/'%(bldroot,VERSION,installdir,binary)
574     commands.getoutput(cmd)
575     cmd = 'cp -R %s/release/bin/%s/locale %s/%s.app/Contents/MacOS/%s/'%(bldroot,VERSION,installdir,binary,VERSION)
576     commands.getoutput(cmd)
577     cmd = 'cp %s/release/bin/%s/.Blanguages %s/%s.app/Contents/Resources/'%(bldroot,VERSION,installdir,binary)
578     commands.getoutput(cmd)
579     if env['WITH_OSX_STATICPYTHON']:
580         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
581         commands.getoutput(cmd)
582         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
583         commands.getoutput(cmd) 
584
585     if binary == 'blender':#not copy everything for blenderplayer
586         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
587         commands.getoutput(cmd)
588         cmd = 'cp -R %s/release/ui %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
589         commands.getoutput(cmd)
590         cmd = 'cp -R %s/release/io %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
591         commands.getoutput(cmd)
592
593     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
594     commands.getoutput(cmd)
595     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
596     commands.getoutput(cmd)
597     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
598     commands.getoutput(cmd)
599     cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
600     commands.getoutput(cmd)
601
602 # extract copy system python, be sure to update other build systems
603 # when making changes to the files that are copied.
604 def my_unixpybundle_print(target, source, env):
605     pass
606
607 def UnixPyBundle(target=None, source=None, env=None):
608     # Any Unix except osx
609     #-- VERSION/python/lib/python3.1
610     
611     import commands
612     
613     def run(cmd):
614         print 'Install command:', cmd
615         commands.getoutput(cmd)
616
617     dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
618
619     py_src =    env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
620     py_target =    env.subst( dir + '/python/lib/python'+env['BF_PYTHON_VERSION'] )
621     
622     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
623     if os.path.exists(py_target):
624         print 'Using existing python from:'
625         print '\t"%s"' %            py_target
626         print '\t(skipping copy)\n'
627         return
628
629     # Copied from source/creator/CMakeLists.txt, keep in sync.
630     print 'Install python from:'
631     print '\t"%s" into...' % py_src
632     print '\t"%s"\n' % py_target
633
634     run("rm -rf '%s'" % py_target)
635     try:
636         os.makedirs(os.path.dirname(py_target)) # the final part is copied
637     except:
638         pass
639
640     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
641     run("rm -rf '%s/distutils'" % py_target)
642     run("rm -rf '%s/lib2to3'" % py_target)
643     run("rm -rf '%s/config'" % py_target)
644     run("rm -rf '%s/config-*'" % py_target)
645     run("rm -rf '%s/site-packages'" % py_target)
646     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
647     run("rm -rf '%s/idlelib'" % py_target)
648     run("rm -rf '%s/tkinter'" % py_target)
649     run("rm -rf '%s/turtledemo'" % py_target)
650     run("rm -r '%s/turtle.py'" % py_target)
651     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
652
653     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
654     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
655     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
656     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
657     
658
659 #### END ACTION STUFF #########
660
661 def bsc(env, target, source):
662     
663     bd = os.path.dirname(target[0].abspath)
664     bscfile = '\"'+target[0].abspath+'\"'
665     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
666     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
667
668     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
669
670     myfile = open(bscpathtmp[1:-1], 'r')
671     lines = myfile.readlines()
672     myfile.close()
673
674     newfile = open(bscpathtmp[1:-1], 'w')
675     for l in lines:
676         newfile.write('\"'+l[:-1]+'\"\n')
677     newfile.close()
678                 
679     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
680     os.system('del '+bscpathtmp)
681
682 class BlenderEnvironment(SConsEnvironment):
683
684     PyBundleActionAdded = False
685
686     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
687         global libs
688         if not self or not libname or not source:
689             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
690             self.Exit()
691         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc'):
692             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
693             self.Exit()
694         
695         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
696         lenv = self.Clone()
697         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
698             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
699         else:
700             res = lenv.RES(root_build_dir+'lib/'+libname, source)
701
702         
703         SConsEnvironment.Default(self, res)
704         resources.append(res)
705
706     def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None, cc_compileflags=None, cxx_compileflags=None):
707         global vcp
708         if not self or not libname or not sources:
709             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
710             self.Exit()
711
712         def list_substring(quickie, libname):
713             for q in quickie:
714                 if libname.find(q) != -1:
715                     return True
716             return False
717
718         if list_substring(quickie, libname) or len(quickie)==0:
719             if list_substring(quickdebug, libname):
720                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
721             else:
722                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
723             lenv = self.Clone()
724             lenv.Append(CPPPATH=includes)
725             lenv.Append(CPPDEFINES=defines)
726             if lenv['BF_DEBUG'] or (libname in quickdebug):
727                     lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
728                     lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
729                     lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
730             else:
731                     lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
732                     lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
733                     lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
734             if lenv['BF_PROFILE']:
735                     lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
736                     lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
737                     lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
738             if compileflags:
739                 lenv.Replace(CFLAGS = compileflags)
740             if cc_compileflags:
741                 lenv.Replace(CCFLAGS = cc_compileflags)
742             if cxx_compileflags:
743                 lenv.Replace(CXXFLAGS = cxx_compileflags)
744             lenv.Append(CFLAGS = lenv['C_WARN'])
745             lenv.Append(CCFLAGS = lenv['CC_WARN'])
746             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
747
748             if lenv['OURPLATFORM'] == 'win64-vc':
749                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
750
751             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
752                 if lenv['BF_DEBUG']:
753                     lenv.Append(CCFLAGS = ['/MTd'])
754                 else:
755                     lenv.Append(CCFLAGS = ['/MT'])
756             
757             targetdir = root_build_dir+'lib/' + libname
758             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
759                 targetdir = '#'+targetdir
760             lib = lenv.Library(target= targetdir, source=sources)
761             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
762             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
763                 #if targetdir[0] == '#':
764                 #    targetdir = targetdir[1:-1]
765                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
766                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
767                          srcs = sources,
768                          buildtarget = lib,
769                          variant = 'Release',
770                          auto_build_solution=0)
771                 vcp.append(vcproject)
772                 SConsEnvironment.Default(self, vcproject)
773         else:
774             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
775         # note: libs is a global
776         add_lib_to_dict(self, libs, libtype, libname, priority)
777
778     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
779         global vcp
780         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
781         lenv = self.Clone()
782         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
783         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
784             if lenv['BF_DEBUG']:
785                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
786         if  lenv['OURPLATFORM']=='linux':
787             if lenv['WITH_BF_PYTHON']:
788                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
789         if  lenv['OURPLATFORM']=='sunos5':
790             if lenv['WITH_BF_PYTHON']:
791                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
792             if lenv['CXX'].endswith('CC'):
793                  lenv.Replace(LINK = '$CXX')
794         if  lenv['OURPLATFORM']=='darwin':
795             if lenv['WITH_BF_PYTHON']:
796                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
797             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
798         if lenv['BF_PROFILE']:
799             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
800         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
801             lenv.Append(LIBPATH=root_build_dir + '/lib')
802         lenv.Append(LIBPATH=libpath)
803         lenv.Append(LIBS=libs)
804         if lenv['WITH_BF_QUICKTIME']:
805              lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
806              lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
807         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
808         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
809             f = lenv.File(progname + '.bsc', builddir)
810             brs = lenv.Command(f, prog, [bsc])
811             SConsEnvironment.Default(self, brs)
812         SConsEnvironment.Default(self, prog)
813         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
814             print "! ",builddir + "/" + progname + '.sln'
815             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
816                      projects= vcp,
817                      variant = 'Release')
818             SConsEnvironment.Default(self, sln)
819         program_list.append(prog)
820         if  lenv['OURPLATFORM']=='darwin':
821             lenv['BINARYKIND'] = binarykind
822             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
823         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
824             if lenv['WITH_BF_PYTHON']:
825                 if not lenv['WITHOUT_BF_INSTALL'] and not lenv['WITHOUT_BF_PYTHON_INSTALL'] and not BlenderEnvironment.PyBundleActionAdded:
826                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
827                     BlenderEnvironment.PyBundleActionAdded = True
828         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
829             if lenv['WITH_BF_PYTHON']:
830                 if not lenv['WITHOUT_BF_PYTHON_INSTALL'] and not BlenderEnvironment.PyBundleActionAdded:
831                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
832                     BlenderEnvironment.PyBundleActionAdded = True
833         return prog
834
835     def Glob(lenv, pattern):
836         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
837         files = []
838         for i in glob.glob(path + pattern):
839             files.append(string.replace(i, path, ''))
840         return files