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