Merging r48971 through r48980 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     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
709     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
710     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
711     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
712     
713
714 #### END ACTION STUFF #########
715
716 def bsc(env, target, source):
717     
718     bd = os.path.dirname(target[0].abspath)
719     bscfile = '\"'+target[0].abspath+'\"'
720     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
721     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
722
723     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
724
725     myfile = open(bscpathtmp[1:-1], 'r')
726     lines = myfile.readlines()
727     myfile.close()
728
729     newfile = open(bscpathtmp[1:-1], 'w')
730     for l in lines:
731         newfile.write('\"'+l[:-1]+'\"\n')
732     newfile.close()
733                 
734     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
735     os.system('del '+bscpathtmp)
736
737 class BlenderEnvironment(SConsEnvironment):
738
739     PyBundleActionAdded = False
740
741     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
742         global libs
743         if not self or not libname or not source:
744             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
745             self.Exit()
746         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
747             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
748             self.Exit()
749         
750         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
751         lenv = self.Clone()
752         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
753             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
754         else:
755             res = lenv.RES(root_build_dir+'lib/'+libname, source)
756
757         
758         SConsEnvironment.Default(self, res)
759         resources.append(res)
760
761     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):
762         global vcp
763         if not self or not libname or not sources:
764             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
765             self.Exit()
766
767         def list_substring(quickie, libname):
768             for q in quickie:
769                 if libname.find(q) != -1:
770                     return True
771             return False
772
773         if list_substring(quickie, libname) or len(quickie)==0:
774             if list_substring(quickdebug, libname):
775                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
776             else:
777                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
778             lenv = self.Clone()
779             lenv.Append(CPPPATH=includes)
780             lenv.Append(CPPDEFINES=defines)
781             if lenv['BF_DEBUG'] or (libname in quickdebug):
782                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
783                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
784                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
785             else:
786                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
787                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
788                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
789             if lenv['BF_PROFILE']:
790                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
791                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
792                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
793             if compileflags:
794                 lenv.Replace(CFLAGS = compileflags)
795             if cc_compileflags:
796                 lenv.Replace(CCFLAGS = cc_compileflags)
797             if cxx_compileflags:
798                 lenv.Replace(CXXFLAGS = cxx_compileflags)
799             if cc_compilerchange:
800                 lenv.Replace(CC = cc_compilerchange)
801             if cxx_compilerchange:
802                 lenv.Replace(CXX = cxx_compilerchange)
803             lenv.Append(CFLAGS = lenv['C_WARN'])
804             lenv.Append(CCFLAGS = lenv['CC_WARN'])
805             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
806
807             if lenv['OURPLATFORM'] == 'win64-vc':
808                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
809
810             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
811                 if lenv['BF_DEBUG']:
812                     lenv.Append(CCFLAGS = ['/MTd'])
813                 else:
814                     lenv.Append(CCFLAGS = ['/MT'])
815             
816             targetdir = root_build_dir+'lib/' + libname
817             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
818                 targetdir = '#'+targetdir
819             lib = lenv.Library(target= targetdir, source=sources)
820             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
821             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
822                 #if targetdir[0] == '#':
823                 #    targetdir = targetdir[1:-1]
824                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
825                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
826                          srcs = sources,
827                          buildtarget = lib,
828                          variant = 'Release',
829                          auto_build_solution=0)
830                 vcp.append(vcproject)
831                 SConsEnvironment.Default(self, vcproject)
832         else:
833             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
834         # note: libs is a global
835         add_lib_to_dict(self, libs, libtype, libname, priority)
836
837     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
838         global vcp
839         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
840         lenv = self.Clone()
841         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
842         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
843             if lenv['BF_DEBUG']:
844                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
845         if  lenv['OURPLATFORM']=='linux':
846             if lenv['WITH_BF_PYTHON']:
847                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
848         if  lenv['OURPLATFORM']=='sunos5':
849             if lenv['WITH_BF_PYTHON']:
850                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
851             if lenv['CXX'].endswith('CC'):
852                 lenv.Replace(LINK = '$CXX')
853         if  lenv['OURPLATFORM']=='darwin':
854             if lenv['WITH_BF_PYTHON']:
855                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
856             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
857         if lenv['BF_PROFILE']:
858             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
859         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
860             lenv.Append(LIBPATH=root_build_dir + '/lib')
861         lenv.Append(LIBPATH=libpath)
862         lenv.Append(LIBS=libs)
863         if lenv['WITH_BF_QUICKTIME']:
864             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
865             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
866         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
867         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
868             f = lenv.File(progname + '.bsc', builddir)
869             brs = lenv.Command(f, prog, [bsc])
870             SConsEnvironment.Default(self, brs)
871         SConsEnvironment.Default(self, prog)
872         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
873             print "! ",builddir + "/" + progname + '.sln'
874             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
875                      projects= vcp,
876                      variant = 'Release')
877             SConsEnvironment.Default(self, sln)
878         program_list.append(prog)
879         if  lenv['OURPLATFORM']=='darwin':
880             lenv['BINARYKIND'] = binarykind
881             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
882         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
883             if lenv['WITH_BF_PYTHON']:
884                 if (not lenv['WITHOUT_BF_INSTALL'] and 
885                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
886                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
887                     not BlenderEnvironment.PyBundleActionAdded):
888                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
889                     BlenderEnvironment.PyBundleActionAdded = True
890         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
891             if lenv['WITH_BF_PYTHON']:
892                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
893                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
894                     not BlenderEnvironment.PyBundleActionAdded):
895                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
896                     BlenderEnvironment.PyBundleActionAdded = True
897         return prog
898
899     def Glob(lenv, pattern):
900         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
901         files = []
902         for i in glob.glob(path + pattern):
903             files.append(string.replace(i, path, ''))
904         return files