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