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