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