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