Merging r48284 through r48288 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         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
591         commands.getoutput(cmd)
592
593         if VERSION_RELEASE_CYCLE == "release":
594             cmd = 'rm -rf %s/%s.app/Contents/MacOS/%s/scripts/addons_contrib'%(installdir,binary,VERSION)
595             commands.getoutput(cmd)
596
597         if env['WITH_BF_CYCLES']:
598             croot = '%s/intern/cycles' % (bldroot)
599             cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
600
601             cmd = 'mkdir %s' % (cinstalldir)
602             commands.getoutput(cmd)
603             cmd = 'mkdir %s/kernel' % (cinstalldir)
604             commands.getoutput(cmd)
605             cmd = 'mkdir %s/lib' % (cinstalldir)
606             commands.getoutput(cmd)
607             cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
608             commands.getoutput(cmd)
609             cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
610             commands.getoutput(cmd)
611             cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
612             commands.getoutput(cmd)
613             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)
614             commands.getoutput(cmd)
615             cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
616             commands.getoutput(cmd)
617
618     if env['WITH_OSX_STATICPYTHON']:
619         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
620         commands.getoutput(cmd)
621         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
622         commands.getoutput(cmd)
623
624     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
625     commands.getoutput(cmd)
626     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
627     commands.getoutput(cmd)
628     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
629     commands.getoutput(cmd)
630     cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
631     commands.getoutput(cmd)
632     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
633         cmd = 'mkdir %s/%s.app/Contents/MacOS/lib'%(installdir, binary)
634         commands.getoutput(cmd)
635         instname = env['BF_CXX']
636         cmd = 'cp %s/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/'%(instname, installdir, binary)
637         commands.getoutput(cmd)
638         cmd = 'install_name_tool -id @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/libgcc_s.1.dylib'%(installdir, binary)
639         commands.getoutput(cmd)
640         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)
641         commands.getoutput(cmd)
642         cmd = 'rm -rf  %s/set_simulation_threads.app'%(installdir) # first clear omp_num_threads applescript
643         commands.getoutput(cmd)
644         cmd = 'cp -R %s/source/darwin/set_simulation_threads.app %s/'%(bldroot, installdir) # copy the omp_num_threads applescript
645         commands.getoutput(cmd)
646
647 # extract copy system python, be sure to update other build systems
648 # when making changes to the files that are copied.
649 def my_unixpybundle_print(target, source, env):
650     pass
651
652 def UnixPyBundle(target=None, source=None, env=None):
653     # Any Unix except osx
654     #-- VERSION/python/lib/python3.1
655     
656     import commands
657     
658     def run(cmd):
659         print 'Install command:', cmd
660         commands.getoutput(cmd)
661
662     dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
663
664     lib = env['BF_PYTHON_LIBPATH'].split(os.sep)[-1]
665     target_lib = "lib64" if lib == "lib64" else "lib"
666
667     py_src =    env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
668     py_target =    env.subst( dir + '/python/' + target_lib + '/python'+env['BF_PYTHON_VERSION'] )
669     
670     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
671     if os.path.exists(py_target):
672         print 'Using existing python from:'
673         print '\t"%s"' %            py_target
674         print '\t(skipping copy)\n'
675         return
676
677     # Copied from source/creator/CMakeLists.txt, keep in sync.
678     print 'Install python from:'
679     print '\t"%s" into...' % py_src
680     print '\t"%s"\n' % py_target
681
682     run("rm -rf '%s'" % py_target)
683     try:
684         os.makedirs(os.path.dirname(py_target)) # the final part is copied
685     except:
686         pass
687
688     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
689     run("rm -rf '%s/distutils'" % py_target)
690     run("rm -rf '%s/lib2to3'" % py_target)
691     run("rm -rf '%s/config'" % py_target)
692
693     for f in os.listdir(py_target):
694         if f.startswith("config-"):
695             run("rm -rf '%s/%s'" % (py_target, f))
696
697     run("rm -rf '%s/site-packages'" % py_target)
698     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
699     run("rm -rf '%s/idlelib'" % py_target)
700     run("rm -rf '%s/tkinter'" % py_target)
701     run("rm -rf '%s/turtledemo'" % py_target)
702     run("rm -r '%s/turtle.py'" % py_target)
703     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
704
705     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
706     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
707     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
708     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
709     
710
711 #### END ACTION STUFF #########
712
713 def bsc(env, target, source):
714     
715     bd = os.path.dirname(target[0].abspath)
716     bscfile = '\"'+target[0].abspath+'\"'
717     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
718     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
719
720     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
721
722     myfile = open(bscpathtmp[1:-1], 'r')
723     lines = myfile.readlines()
724     myfile.close()
725
726     newfile = open(bscpathtmp[1:-1], 'w')
727     for l in lines:
728         newfile.write('\"'+l[:-1]+'\"\n')
729     newfile.close()
730                 
731     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
732     os.system('del '+bscpathtmp)
733
734 class BlenderEnvironment(SConsEnvironment):
735
736     PyBundleActionAdded = False
737
738     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
739         global libs
740         if not self or not libname or not source:
741             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
742             self.Exit()
743         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
744             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
745             self.Exit()
746         
747         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
748         lenv = self.Clone()
749         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
750             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
751         else:
752             res = lenv.RES(root_build_dir+'lib/'+libname, source)
753
754         
755         SConsEnvironment.Default(self, res)
756         resources.append(res)
757
758     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):
759         global vcp
760         if not self or not libname or not sources:
761             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
762             self.Exit()
763
764         def list_substring(quickie, libname):
765             for q in quickie:
766                 if libname.find(q) != -1:
767                     return True
768             return False
769
770         if list_substring(quickie, libname) or len(quickie)==0:
771             if list_substring(quickdebug, libname):
772                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
773             else:
774                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
775             lenv = self.Clone()
776             lenv.Append(CPPPATH=includes)
777             lenv.Append(CPPDEFINES=defines)
778             if lenv['BF_DEBUG'] or (libname in quickdebug):
779                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
780                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
781                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
782             else:
783                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
784                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
785                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
786             if lenv['BF_PROFILE']:
787                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
788                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
789                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
790             if compileflags:
791                 lenv.Replace(CFLAGS = compileflags)
792             if cc_compileflags:
793                 lenv.Replace(CCFLAGS = cc_compileflags)
794             if cxx_compileflags:
795                 lenv.Replace(CXXFLAGS = cxx_compileflags)
796             if cc_compilerchange:
797                 lenv.Replace(CC = cc_compilerchange)
798             if cxx_compilerchange:
799                 lenv.Replace(CXX = cxx_compilerchange)
800             lenv.Append(CFLAGS = lenv['C_WARN'])
801             lenv.Append(CCFLAGS = lenv['CC_WARN'])
802             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
803
804             if lenv['OURPLATFORM'] == 'win64-vc':
805                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
806
807             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
808                 if lenv['BF_DEBUG']:
809                     lenv.Append(CCFLAGS = ['/MTd'])
810                 else:
811                     lenv.Append(CCFLAGS = ['/MT'])
812             
813             targetdir = root_build_dir+'lib/' + libname
814             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
815                 targetdir = '#'+targetdir
816             lib = lenv.Library(target= targetdir, source=sources)
817             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
818             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
819                 #if targetdir[0] == '#':
820                 #    targetdir = targetdir[1:-1]
821                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
822                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
823                          srcs = sources,
824                          buildtarget = lib,
825                          variant = 'Release',
826                          auto_build_solution=0)
827                 vcp.append(vcproject)
828                 SConsEnvironment.Default(self, vcproject)
829         else:
830             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
831         # note: libs is a global
832         add_lib_to_dict(self, libs, libtype, libname, priority)
833
834     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
835         global vcp
836         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
837         lenv = self.Clone()
838         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
839         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
840             if lenv['BF_DEBUG']:
841                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
842         if  lenv['OURPLATFORM']=='linux':
843             if lenv['WITH_BF_PYTHON']:
844                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
845         if  lenv['OURPLATFORM']=='sunos5':
846             if lenv['WITH_BF_PYTHON']:
847                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
848             if lenv['CXX'].endswith('CC'):
849                 lenv.Replace(LINK = '$CXX')
850         if  lenv['OURPLATFORM']=='darwin':
851             if lenv['WITH_BF_PYTHON']:
852                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
853             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
854         if lenv['BF_PROFILE']:
855             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
856         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
857             lenv.Append(LIBPATH=root_build_dir + '/lib')
858         lenv.Append(LIBPATH=libpath)
859         lenv.Append(LIBS=libs)
860         if lenv['WITH_BF_QUICKTIME']:
861             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
862             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
863         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
864         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
865             f = lenv.File(progname + '.bsc', builddir)
866             brs = lenv.Command(f, prog, [bsc])
867             SConsEnvironment.Default(self, brs)
868         SConsEnvironment.Default(self, prog)
869         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
870             print "! ",builddir + "/" + progname + '.sln'
871             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
872                      projects= vcp,
873                      variant = 'Release')
874             SConsEnvironment.Default(self, sln)
875         program_list.append(prog)
876         if  lenv['OURPLATFORM']=='darwin':
877             lenv['BINARYKIND'] = binarykind
878             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
879         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
880             if lenv['WITH_BF_PYTHON']:
881                 if (not lenv['WITHOUT_BF_INSTALL'] and 
882                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
883                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
884                     not BlenderEnvironment.PyBundleActionAdded):
885                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
886                     BlenderEnvironment.PyBundleActionAdded = True
887         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
888             if lenv['WITH_BF_PYTHON']:
889                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
890                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
891                     not BlenderEnvironment.PyBundleActionAdded):
892                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
893                     BlenderEnvironment.PyBundleActionAdded = True
894         return prog
895
896     def Glob(lenv, pattern):
897         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
898         files = []
899         for i in glob.glob(path + pattern):
900             files.append(string.replace(i, path, ''))
901         return files