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