155b4e800bb11a879fc4763b328484265f67fbbf
[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'):
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', 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         incs.append('#/intern/utfconv')
344
345     env.Append(CPPDEFINES=defs)
346     env.Append(CPPPATH=incs)
347     obj = [env.Object(root_build_dir+'source/creator/creator/creator', ['#source/creator/creator.c'])]
348
349     return obj
350
351 ## TODO: see if this can be made in an emitter
352 def buildinfo(lenv, build_type):
353     """
354     Generate a buildinfo object
355     """
356     build_date = time.strftime ("%Y-%m-%d")
357     build_time = time.strftime ("%H:%M:%S")
358     build_rev = os.popen('svnversion').read()[:-1] # remove \n
359     if build_rev == '': 
360         build_rev = '-UNKNOWN-'
361     if lenv['BF_DEBUG']:
362         build_type = "Debug"
363         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['BF_DEBUG_CCFLAGS'] + lenv['CPPFLAGS'])
364         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['CPPFLAGS'])
365     else:
366         build_type = "Release"
367         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['REL_CFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
368         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['REL_CXXFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
369
370     build_linkflags = ' '.join(lenv['PLATFORM_LINKFLAGS'])
371
372     obj = []
373     if lenv['BF_BUILDINFO']:
374         lenv.Append (CPPDEFINES = ['BUILD_TIME=\\"%s\\"'%(build_time),
375                                     'BUILD_DATE=\\"%s\\"'%(build_date),
376                                     'BUILD_TYPE=\\"%s\\"'%(build_type),
377                                     'BUILD_REV=\\"%s\\"'%(build_rev),
378                                     'WITH_BUILDINFO',
379                                     'BUILD_PLATFORM=\\"%s:%s\\"'%(platform.system(), platform.architecture()[0]),
380                                     'BUILD_CFLAGS=\\"%s\\"'%(build_cflags),
381                                     'BUILD_CXXFLAGS=\\"%s\\"'%(build_cxxflags),
382                                     'BUILD_LINKFLAGS=\\"%s\\"'%(build_linkflags),
383                                     'BUILD_SYSTEM=\\"SCons\\"'
384                     ])
385
386         lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel'])
387
388         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, ['#source/creator/buildinfo.c'])]
389
390     return obj
391
392 ##### END LIB STUFF ############
393
394 ##### ACTION STUFF #############
395
396 def my_print_cmd_line(self, s, target, source, env):
397     sys.stdout.write(' ' * 70 + '\r')
398     sys.stdout.flush()
399     sys.stdout.write(s + "\r")
400     sys.stdout.flush()
401
402 def my_compile_print(target, source, env):
403     a = '%s' % (source[0])
404     d, f = os.path.split(a)
405     return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
406
407 def my_moc_print(target, source, env):
408     a = '%s' % (source[0])
409     d, f = os.path.split(a)
410     return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
411
412 def my_linking_print(target, source, env):
413     t = '%s' % (target[0])
414     d, f = os.path.split(t)
415     return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
416
417 def my_program_print(target, source, env):
418     t = '%s' % (target[0])
419     d, f = os.path.split(t)
420     return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
421
422 def msvc_hack(env):
423     static_lib = SCons.Tool.createStaticLibBuilder(env)
424     program = SCons.Tool.createProgBuilder(env)
425     
426     env['BUILDERS']['Library'] = static_lib
427     env['BUILDERS']['StaticLibrary'] = static_lib
428     env['BUILDERS']['Program'] = program
429         
430 def set_quiet_output(env):
431     mycaction = Action("$CCCOM", strfunction=my_compile_print)
432     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
433     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
434     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
435     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
436     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
437
438     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
439     static_ob.add_action('.c', mycaction)
440     static_ob.add_action('.cpp', mycppaction)
441     static_ob.add_action('.cc', mycppaction)
442     shared_ob.add_action('.c', myshcaction)
443     shared_ob.add_action('.cc', myshcppaction)
444
445     static_lib = SCons.Builder.Builder(action = mylibaction,
446                                        emitter = '$LIBEMITTER',
447                                        prefix = '$LIBPREFIX',
448                                        suffix = '$LIBSUFFIX',
449                                        src_suffix = '$OBJSUFFIX',
450                                        src_builder = 'StaticObject')
451
452     program = SCons.Builder.Builder(action = mylinkaction,
453                                     emitter = '$PROGEMITTER',
454                                     prefix = '$PROGPREFIX',
455                                     suffix = '$PROGSUFFIX',
456                                     src_suffix = '$OBJSUFFIX',
457                                     src_builder = 'Object',
458                                     target_scanner = SCons.Defaults.ProgScan)
459
460     env['BUILDERS']['Object'] = static_ob
461     env['BUILDERS']['StaticObject'] = static_ob
462     env['BUILDERS']['StaticLibrary'] = static_lib
463     env['BUILDERS']['Library'] = static_lib
464     env['BUILDERS']['Program'] = program
465     if env['BF_LINE_OVERWRITE']:
466         SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
467
468 def untar_pybundle(from_tar,to_dir,exclude_re):
469     tar= tarfile.open(from_tar, mode='r')
470     exclude_re= list(exclude_re) #single re object or list of re objects
471     debug= 0 #list files instead of unpacking
472     good= []
473     if debug: print '\nFiles not being unpacked:\n'
474     for name in tar.getnames():
475         is_bad= 0
476         for r in exclude_re:
477             if r.match(name):
478                 is_bad=1
479                 if debug: print name
480                 break
481         if not is_bad:
482             good.append(tar.getmember(name))
483     if debug:
484         print '\nFiles being unpacked:\n'
485         for g in good:
486             print g
487     else:
488         tar.extractall(to_dir, good)
489
490 def my_winpybundle_print(target, source, env):
491     pass
492
493 def WinPyBundle(target=None, source=None, env=None):
494     import re
495     py_tar= env.subst( env['LCGDIR'] )
496     if py_tar[0]=='#':
497         py_tar= py_tar[1:]
498     if env['BF_DEBUG']:
499         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.tar.gz'
500     else:
501         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
502
503     py_target = env.subst( env['BF_INSTALLDIR'] )
504     if py_target[0]=='#':
505         py_target=py_target[1:]
506     py_target = os.path.join(py_target, VERSION, 'python', 'lib')
507     def printexception(func,path,ex):
508         if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
509             print str(func) + ' failed on ' + str(path)
510     print "Trying to remove existing py bundle."
511     shutil.rmtree(py_target, False, printexception)
512     exclude_re=[re.compile('.*/test/.*'),
513                 re.compile('^config/.*'),
514                 re.compile('^config-*/.*'),
515                 re.compile('^distutils/.*'),
516                 re.compile('^idlelib/.*'),
517                 re.compile('^lib2to3/.*'),
518                 re.compile('^tkinter/.*'),
519                 re.compile('^_tkinter_d.pyd'),
520                 re.compile('^turtledemo'),
521                 re.compile('^turtle.py'),
522                 ]
523
524     print "Unpacking '" + py_tar + "' to '" + py_target + "'"
525     untar_pybundle(py_tar,py_target,exclude_re)
526
527 def  my_appit_print(target, source, env):
528     a = '%s' % (target[0])
529     d, f = os.path.split(a)
530     return "making bundle for " + f
531
532 def AppIt(target=None, source=None, env=None):
533     import shutil
534     import commands
535     import os.path
536     
537     
538     a = '%s' % (target[0])
539     builddir, b = os.path.split(a)
540     libdir = env['LCGDIR'][1:]
541     osxarch = env['MACOSX_ARCHITECTURE']
542     installdir = env['BF_INSTALLDIR']
543     print("compiled architecture: %s"%(osxarch))
544     print("Installing to %s"%(installdir))
545     # TODO, use tar.
546     python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
547     if env['WITH_OSX_STATICPYTHON']:
548         print("unzipping to app-bundle: %s"%(python_zip))
549     else:
550         print("dynamic build - make sure to have python3.x-framework installed")
551     bldroot = env.Dir('.').abspath
552     binary = env['BINARYKIND']
553      
554     sourcedir = bldroot + '/source/darwin/%s.app'%binary
555     sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
556     targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
557     cmd = installdir + '/' +'%s.app'%binary
558     
559     if os.path.isdir(cmd):
560         shutil.rmtree(cmd)
561     shutil.copytree(sourcedir, cmd)
562     cmd = "cat %s | sed s/\$\{MACOSX_BUNDLE_SHORT_VERSION_STRING\}/%s/ | "%(sourceinfo,VERSION)
563     cmd += "sed s/\$\{MACOSX_BUNDLE_LONG_VERSION_STRING\}/%s,\ %s/g > %s"%(VERSION,time.strftime("%Y-%b-%d"),targetinfo)
564     commands.getoutput(cmd)
565     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
566     commands.getoutput(cmd)
567     cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/'%(installdir, binary, VERSION)
568     commands.getoutput(cmd)
569     cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
570
571     # blenderplayer doesn't need all the files
572     if binary == 'blender':
573         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/datafiles'%(installdir, binary, VERSION)
574         commands.getoutput(cmd)
575         cmd = 'cp -R %s/release/datafiles/locale %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
576         commands.getoutput(cmd)
577         cmd = 'cp -R %s/release/datafiles/fonts %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
578         commands.getoutput(cmd)
579         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
580         commands.getoutput(cmd)
581
582         if VERSION_RELEASE_CYCLE == "release":
583             cmd = 'rm -rf %s/%s.app/Contents/MacOS/%s/scripts/addons_contrib'%(installdir,binary,VERSION)
584             commands.getoutput(cmd)
585
586         if env['WITH_BF_CYCLES']:
587             croot = '%s/intern/cycles' % (bldroot)
588             cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
589
590             cmd = 'mkdir %s' % (cinstalldir)
591             commands.getoutput(cmd)
592             cmd = 'mkdir %s/kernel' % (cinstalldir)
593             commands.getoutput(cmd)
594             cmd = 'mkdir %s/lib' % (cinstalldir)
595             commands.getoutput(cmd)
596             cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
597             commands.getoutput(cmd)
598             cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
599             commands.getoutput(cmd)
600             cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
601             commands.getoutput(cmd)
602             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)
603             commands.getoutput(cmd)
604             cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
605             commands.getoutput(cmd)
606
607     if env['WITH_OSX_STATICPYTHON']:
608         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
609         commands.getoutput(cmd)
610         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
611         commands.getoutput(cmd)
612
613     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
614     commands.getoutput(cmd)
615     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
616     commands.getoutput(cmd)
617     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
618     commands.getoutput(cmd)
619     cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
620     commands.getoutput(cmd)
621     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
622         cmd = 'mkdir %s/%s.app/Contents/MacOS/lib'%(installdir, binary)
623         commands.getoutput(cmd)
624         instname = env['BF_CXX']
625         cmd = 'cp %s/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/'%(instname, installdir, binary)
626         commands.getoutput(cmd)
627         cmd = 'install_name_tool -id @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/libgcc_s.1.dylib'%(installdir, binary)
628         commands.getoutput(cmd)
629         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)
630         commands.getoutput(cmd)
631         cmd = 'rm -rf  %s/set_simulation_threads.app'%(installdir) # first clear omp_num_threads applescript
632         commands.getoutput(cmd)
633         cmd = 'cp -R %s/source/darwin/set_simulation_threads.app %s/'%(bldroot, installdir) # copy the omp_num_threads applescript
634         commands.getoutput(cmd)
635
636 # extract copy system python, be sure to update other build systems
637 # when making changes to the files that are copied.
638 def my_unixpybundle_print(target, source, env):
639     pass
640
641 def UnixPyBundle(target=None, source=None, env=None):
642     # Any Unix except osx
643     #-- VERSION/python/lib/python3.1
644     
645     import commands
646     
647     def run(cmd):
648         print 'Install command:', cmd
649         commands.getoutput(cmd)
650
651     dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
652
653     lib = env['BF_PYTHON_LIBPATH'].split(os.sep)[-1]
654     target_lib = "lib64" if lib == "lib64" else "lib"
655
656     py_src =    env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
657     py_target =    env.subst( dir + '/python/' + target_lib + '/python'+env['BF_PYTHON_VERSION'] )
658     
659     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
660     if os.path.exists(py_target):
661         print 'Using existing python from:'
662         print '\t"%s"' %            py_target
663         print '\t(skipping copy)\n'
664         return
665
666     # Copied from source/creator/CMakeLists.txt, keep in sync.
667     print 'Install python from:'
668     print '\t"%s" into...' % py_src
669     print '\t"%s"\n' % py_target
670
671     run("rm -rf '%s'" % py_target)
672     try:
673         os.makedirs(os.path.dirname(py_target)) # the final part is copied
674     except:
675         pass
676
677     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
678     run("rm -rf '%s/distutils'" % py_target)
679     run("rm -rf '%s/lib2to3'" % py_target)
680     run("rm -rf '%s/config'" % py_target)
681
682     for f in os.listdir(py_target):
683         if f.startswith("config-"):
684             run("rm -rf '%s/%s'" % (py_target, f))
685
686     run("rm -rf '%s/site-packages'" % py_target)
687     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
688     run("rm -rf '%s/idlelib'" % py_target)
689     run("rm -rf '%s/tkinter'" % py_target)
690     run("rm -rf '%s/turtledemo'" % py_target)
691     run("rm -r '%s/turtle.py'" % py_target)
692     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
693
694     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
695     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
696     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
697     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
698     
699
700 #### END ACTION STUFF #########
701
702 def bsc(env, target, source):
703     
704     bd = os.path.dirname(target[0].abspath)
705     bscfile = '\"'+target[0].abspath+'\"'
706     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
707     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
708
709     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
710
711     myfile = open(bscpathtmp[1:-1], 'r')
712     lines = myfile.readlines()
713     myfile.close()
714
715     newfile = open(bscpathtmp[1:-1], 'w')
716     for l in lines:
717         newfile.write('\"'+l[:-1]+'\"\n')
718     newfile.close()
719                 
720     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
721     os.system('del '+bscpathtmp)
722
723 class BlenderEnvironment(SConsEnvironment):
724
725     PyBundleActionAdded = False
726
727     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
728         global libs
729         if not self or not libname or not source:
730             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
731             self.Exit()
732         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc'):
733             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
734             self.Exit()
735         
736         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
737         lenv = self.Clone()
738         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
739             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
740         else:
741             res = lenv.RES(root_build_dir+'lib/'+libname, source)
742
743         
744         SConsEnvironment.Default(self, res)
745         resources.append(res)
746
747     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):
748         global vcp
749         if not self or not libname or not sources:
750             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
751             self.Exit()
752
753         def list_substring(quickie, libname):
754             for q in quickie:
755                 if libname.find(q) != -1:
756                     return True
757             return False
758
759         if list_substring(quickie, libname) or len(quickie)==0:
760             if list_substring(quickdebug, libname):
761                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
762             else:
763                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
764             lenv = self.Clone()
765             lenv.Append(CPPPATH=includes)
766             lenv.Append(CPPDEFINES=defines)
767             if lenv['BF_DEBUG'] or (libname in quickdebug):
768                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
769                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
770                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
771             else:
772                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
773                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
774                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
775             if lenv['BF_PROFILE']:
776                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
777                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
778                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
779             if compileflags:
780                 lenv.Replace(CFLAGS = compileflags)
781             if cc_compileflags:
782                 lenv.Replace(CCFLAGS = cc_compileflags)
783             if cxx_compileflags:
784                 lenv.Replace(CXXFLAGS = cxx_compileflags)
785             if cc_compilerchange:
786                 lenv.Replace(CC = cc_compilerchange)
787             if cxx_compilerchange:
788                 lenv.Replace(CXX = cxx_compilerchange)
789             lenv.Append(CFLAGS = lenv['C_WARN'])
790             lenv.Append(CCFLAGS = lenv['CC_WARN'])
791             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
792
793             if lenv['OURPLATFORM'] == 'win64-vc':
794                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
795
796             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
797                 if lenv['BF_DEBUG']:
798                     lenv.Append(CCFLAGS = ['/MTd'])
799                 else:
800                     lenv.Append(CCFLAGS = ['/MT'])
801             
802             targetdir = root_build_dir+'lib/' + libname
803             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
804                 targetdir = '#'+targetdir
805             lib = lenv.Library(target= targetdir, source=sources)
806             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
807             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
808                 #if targetdir[0] == '#':
809                 #    targetdir = targetdir[1:-1]
810                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
811                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
812                          srcs = sources,
813                          buildtarget = lib,
814                          variant = 'Release',
815                          auto_build_solution=0)
816                 vcp.append(vcproject)
817                 SConsEnvironment.Default(self, vcproject)
818         else:
819             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
820         # note: libs is a global
821         add_lib_to_dict(self, libs, libtype, libname, priority)
822
823     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
824         global vcp
825         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
826         lenv = self.Clone()
827         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
828         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
829             if lenv['BF_DEBUG']:
830                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
831         if  lenv['OURPLATFORM']=='linux':
832             if lenv['WITH_BF_PYTHON']:
833                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
834         if  lenv['OURPLATFORM']=='sunos5':
835             if lenv['WITH_BF_PYTHON']:
836                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
837             if lenv['CXX'].endswith('CC'):
838                 lenv.Replace(LINK = '$CXX')
839         if  lenv['OURPLATFORM']=='darwin':
840             if lenv['WITH_BF_PYTHON']:
841                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
842             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
843         if lenv['BF_PROFILE']:
844             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
845         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
846             lenv.Append(LIBPATH=root_build_dir + '/lib')
847         lenv.Append(LIBPATH=libpath)
848         lenv.Append(LIBS=libs)
849         if lenv['WITH_BF_QUICKTIME']:
850             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
851             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
852         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
853         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
854             f = lenv.File(progname + '.bsc', builddir)
855             brs = lenv.Command(f, prog, [bsc])
856             SConsEnvironment.Default(self, brs)
857         SConsEnvironment.Default(self, prog)
858         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
859             print "! ",builddir + "/" + progname + '.sln'
860             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
861                      projects= vcp,
862                      variant = 'Release')
863             SConsEnvironment.Default(self, sln)
864         program_list.append(prog)
865         if  lenv['OURPLATFORM']=='darwin':
866             lenv['BINARYKIND'] = binarykind
867             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
868         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
869             if lenv['WITH_BF_PYTHON']:
870                 if not lenv['WITHOUT_BF_INSTALL'] and not lenv['WITHOUT_BF_PYTHON_INSTALL'] and not BlenderEnvironment.PyBundleActionAdded:
871                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
872                     BlenderEnvironment.PyBundleActionAdded = True
873         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
874             if lenv['WITH_BF_PYTHON']:
875                 if not lenv['WITHOUT_BF_PYTHON_INSTALL'] and not BlenderEnvironment.PyBundleActionAdded:
876                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
877                     BlenderEnvironment.PyBundleActionAdded = True
878         return prog
879
880     def Glob(lenv, pattern):
881         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
882         files = []
883         for i in glob.glob(path + pattern):
884             files.append(string.replace(i, path, ''))
885         return files