Fix for [#20294] Switching to particle mode after changing number of hair particles...
[blender-staging.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         if lenv['WITH_BF_LCMS']:
220                 syslibs.append(lenv['BF_LCMS_LIB'])
221         if lenv['WITH_BF_COLLADA']:
222                 syslibs.append(lenv['BF_PCRE_LIB'])
223                 syslibs += Split(lenv['BF_OPENCOLLADA_LIB'])
224                 syslibs.append(lenv['BF_EXPAT_LIB'])
225
226
227         syslibs += lenv['LLIBS']
228
229         return syslibs
230
231 def propose_priorities():
232         print bc.OKBLUE+"Priorities:"+bc.ENDC
233         for t in possible_types:
234                 print bc.OKGREEN+"\t"+t+bc.ENDC
235                 new_priority = 0
236                 curlib = libs[t]
237                 sortlist = curlib.keys()
238                 sortlist.sort()
239
240                 for sk in sortlist:
241                         v = curlib[sk]
242                         #for p,v in sorted(libs[t].iteritems()):
243                         print "\t\t",new_priority, v
244                         new_priority += 5
245
246 ## TODO: see if this can be made in an emitter
247 def buildinfo(lenv, build_type):
248         """
249         Generate a buildinfo object
250         """
251         build_date = time.strftime ("%Y-%m-%d")
252         build_time = time.strftime ("%H:%M:%S")
253         build_rev = os.popen('svnversion').read()[:-1] # remove \n
254
255         obj = []
256         if lenv['BF_BUILDINFO']:
257                 lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
258                                                                         'BUILD_DATE=\'"%s"\''%(build_date),
259                                                                         'BUILD_TYPE=\'"dynamic"\'',
260                                                                         'BUILD_REV=\'"%s"\''%(build_rev),
261                                                                         'NAN_BUILDINFO',
262                                                                         'BUILD_PLATFORM=\'"%s"\''%(sys.platform)])
263                 obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
264                                                 [root_build_dir+'source/creator/buildinfo.c'])]
265         return obj
266
267 ##### END LIB STUFF ############
268
269 ##### ACTION STUFF #############
270
271 def my_compile_print(target, source, env):
272         a = '%s' % (source[0])
273         d, f = os.path.split(a)
274         return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
275
276 def my_moc_print(target, source, env):
277         a = '%s' % (source[0])
278         d, f = os.path.split(a)
279         return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
280
281 def my_linking_print(target, source, env):
282         t = '%s' % (target[0])
283         d, f = os.path.split(t)
284         return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
285
286 def my_program_print(target, source, env):
287         t = '%s' % (target[0])
288         d, f = os.path.split(t)
289         return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
290
291 def msvc_hack(env):
292         static_lib = SCons.Tool.createStaticLibBuilder(env)
293         program = SCons.Tool.createProgBuilder(env)
294         
295         env['BUILDERS']['Library'] = static_lib
296         env['BUILDERS']['StaticLibrary'] = static_lib
297         env['BUILDERS']['Program'] = program
298                 
299 def set_quiet_output(env):
300         mycaction = Action("$CCCOM", strfunction=my_compile_print)
301         myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
302         mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
303         myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
304         mylibaction = Action("$ARCOM", strfunction=my_linking_print)
305         mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
306
307         static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
308         static_ob.add_action('.c', mycaction)
309         static_ob.add_action('.cpp', mycppaction)
310         shared_ob.add_action('.c', myshcaction)
311         shared_ob.add_action('.cpp', myshcppaction)
312
313         static_lib = SCons.Builder.Builder(action = mylibaction,
314                                                                            emitter = '$LIBEMITTER',
315                                                                            prefix = '$LIBPREFIX',
316                                                                            suffix = '$LIBSUFFIX',
317                                                                            src_suffix = '$OBJSUFFIX',
318                                                                            src_builder = 'StaticObject')
319
320         program = SCons.Builder.Builder(action = mylinkaction,
321                                                                         emitter = '$PROGEMITTER',
322                                                                         prefix = '$PROGPREFIX',
323                                                                         suffix = '$PROGSUFFIX',
324                                                                         src_suffix = '$OBJSUFFIX',
325                                                                         src_builder = 'Object',
326                                                                         target_scanner = SCons.Defaults.ProgScan)
327
328         env['BUILDERS']['Object'] = static_ob
329         env['BUILDERS']['StaticObject'] = static_ob
330         env['BUILDERS']['StaticLibrary'] = static_lib
331         env['BUILDERS']['Library'] = static_lib
332         env['BUILDERS']['Program'] = program
333
334         
335 class CompZipFile(zipfile.ZipFile):
336         """Partial copy of python2.6's zipfile.ZipFile (see http://www.python.org)
337         to get a extractall() that works on py2.5 and probably earlier distributions."""
338         def __init__(self, file, mode="r", compression=zipfile.ZIP_STORED, allowZip64=False):
339                 zipfile.ZipFile.__init__(self, file, mode, compression, allowZip64)
340                 if not hasattr(self,"extractall"): # use our method 
341                         print "Debug: Using comp_extractall!"
342                         self.extractall= self.comp_extractall
343
344         def comp_extractall(self, path=None, members=None, pwd=None): #renamed method
345                 """Extract all members from the archive to the current working
346                         directory. `path' specifies a different directory to extract to.
347                         `members' is optional and must be a subset of the list returned
348                         by namelist().
349                 """
350                 if members is None:
351                         members = self.namelist()
352
353                 for zipinfo in members:
354                         self.comp_extract(zipinfo, path, pwd) # use our method 
355
356         def comp_extract(self, member, path=None, pwd=None): #renamed method
357                 """Extract a member from the archive to the current working directory,
358                         using its full name. Its file information is extracted as accurately
359                         as possible. `member' may be a filename or a ZipInfo object. You can
360                         specify a different directory using `path'.
361                 """
362                 if not isinstance(member, zipfile.ZipInfo):
363                         member = self.getinfo(member)
364
365                 if path is None:
366                         path = os.getcwd()
367
368                 return self.comp_extract_member(member, path, pwd) # use our method 
369
370         def comp_extract_member(self, member, targetpath, pwd): #renamed method
371                 """Extract the ZipInfo object 'member' to a physical
372                         file on the path targetpath.
373                 """
374                 # build the destination pathname, replacing
375                 # forward slashes to platform specific separators.
376                 if targetpath[-1:] in (os.path.sep, os.path.altsep):
377                         targetpath = targetpath[:-1]
378
379                 # don't include leading "/" from file name if present
380                 if member.filename[0] == '/':
381                         targetpath = os.path.join(targetpath, member.filename[1:])
382                 else:
383                         targetpath = os.path.join(targetpath, member.filename)
384
385                 targetpath = os.path.normpath(targetpath)
386
387                 # Create all upper directories if necessary.
388                 upperdirs = os.path.dirname(targetpath)
389                 if upperdirs and not os.path.exists(upperdirs):
390                         os.makedirs(upperdirs)
391
392                 if member.filename[-1] == '/':
393                         os.mkdir(targetpath)
394                         return targetpath
395
396                 #use StrinIO instead so we don't have to reproduce more functionality.
397                 source = cStringIO.StringIO(self.read(member.filename))
398                 target = file(targetpath, "wb")
399                 shutil.copyfileobj(source, target)
400                 source.close()
401                 target.close()
402
403                 return targetpath
404
405 def unzip_pybundle(from_zip,to_dir,exclude_re):
406         
407         zip= CompZipFile(from_zip, mode='r')
408         exclude_re= list(exclude_re) #single re object or list of re objects
409         debug= 0 #list files instead of unpacking
410         good= []
411         if debug: print '\nFiles not being unpacked:\n'
412         for name in zip.namelist():
413                 is_bad= 0
414                 for r in exclude_re:
415                         if r.match(name):
416                                 is_bad=1
417                                 if debug: print name
418                                 break
419                 if not is_bad:
420                         good.append(name)
421         if debug:
422                 print '\nFiles being unpacked:\n'
423                 for g in good:
424                         print g
425         else:
426                 zip.extractall(to_dir, good)
427
428 def my_winpybundle_print(target, source, env):
429         pass
430
431 def WinPyBundle(target=None, source=None, env=None):
432         import re
433         py_zip= env.subst( env['LCGDIR'] )
434         if py_zip[0]=='#':
435                 py_zip= py_zip[1:]
436         py_zip+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.zip'
437
438         py_target = env.subst( env['BF_INSTALLDIR'] )
439         if py_target[0]=='#':
440                 py_target=py_target[1:]
441         py_target+= '/.blender/python/lib/' 
442         def printexception(func,path,ex):
443                 if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
444                         print str(func) + ' failed on ' + str(path)
445         print "Trying to remove existing py bundle."
446         shutil.rmtree(py_target, False, printexception)
447         exclude_re=[re.compile('.*/test/.*'),
448                                 re.compile('^config/.*'),
449                                 re.compile('^distutils/.*'),
450                                 re.compile('^idlelib/.*'),
451                                 re.compile('^lib2to3/.*'),
452                                 re.compile('^tkinter/.*')]
453         print "Unpacking '" + py_zip + "' to '" + py_target + "'"
454         unzip_pybundle(py_zip,py_target,exclude_re)
455
456 def  my_appit_print(target, source, env):
457         a = '%s' % (target[0])
458         d, f = os.path.split(a)
459         return "making bundle for " + f
460
461 def AppIt(target=None, source=None, env=None):
462         import shutil
463         import commands
464         import os.path
465         
466         
467         a = '%s' % (target[0])
468         builddir, b = os.path.split(a)
469         libdir = env['LCGDIR'][1:]
470         osxarch = env['MACOSX_ARCHITECTURE']
471         print("compiled architecture: %s"%(osxarch))
472         if  libdir == '../lib/darwin-9.x.universal':
473                 python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
474         else:
475                 python_zip = 'python.zip' # compatibility for darwin8 python.zip
476         print("unzipping to app-bundle: %s"%(python_zip))
477         bldroot = env.Dir('.').abspath
478         binary = env['BINARYKIND']
479          
480         if b=='verse':
481                 print bc.OKBLUE+"no bundle for verse"+bc.ENDC 
482                 return 0
483         
484         sourcedir = bldroot + '/source/darwin/%s.app'%binary
485         sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
486         targetinfo = builddir +'/' + "%s.app/Contents/Info.plist"%binary
487         cmd = builddir + '/' +'%s.app'%binary
488         
489         if os.path.isdir(cmd):
490                 shutil.rmtree(cmd)
491         shutil.copytree(sourcedir, cmd)
492         cmd = "cat %s | sed s/VERSION/`cat release/VERSION`/ | sed s/DATE/`date +'%%Y-%%b-%%d'`/ > %s"%(sourceinfo,targetinfo)
493         commands.getoutput(cmd)
494         cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,builddir, binary, binary)
495         commands.getoutput(cmd)
496         cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/'%(builddir, binary)
497 #       print cmd
498         commands.getoutput(cmd)
499         cmd = builddir + '/%s.app/Contents/MacOS/.blender'%binary
500         shutil.copy(bldroot + '/bin/.blender/.bfont.ttf', cmd)
501         shutil.copy(bldroot + '/bin/.blender/.Blanguages', cmd)
502         cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
503         commands.getoutput(cmd) 
504         cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
505         commands.getoutput(cmd) 
506         cmd = 'cp %s/bin/.blender/.Blanguages %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
507         commands.getoutput(cmd) 
508         cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/python/'%(builddir,binary)
509         commands.getoutput(cmd) 
510         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/.blender/python/'%(libdir,python_zip,builddir,binary)
511         commands.getoutput(cmd) 
512         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
513         commands.getoutput(cmd)
514         cmd = 'cp -R %s/release/ui %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
515         commands.getoutput(cmd)
516         cmd = 'cp -R %s/release/io %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
517         commands.getoutput(cmd)
518         cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(builddir,binary, binary)
519         commands.getoutput(cmd)
520         cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(builddir, binary)
521         commands.getoutput(cmd)
522         cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(builddir, binary)
523         commands.getoutput(cmd)
524         cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(builddir, binary)
525         commands.getoutput(cmd)
526
527 # extract copy system python, be sure to update other build systems
528 # when making changes to the files that are copied.
529 def my_unixpybundle_print(target, source, env):
530         pass
531
532 def UnixPyBundle(target=None, source=None, env=None):
533         # Any Unix except osx
534         #-- .blender/python/lib/python3.1
535         
536         import commands
537         
538         def run(cmd):
539                 print 'Install command:', cmd
540                 commands.getoutput(cmd)
541         
542         if env['WITH_BF_FHS']:  dir = os.path.join(env['BF_INSTALLDIR'], 'share', 'blender', env['BF_VERSION']) # BLENDERPATH
543         else:                                   dir = os.path.join(env['BF_INSTALLDIR'], '.blender')
544         
545         py_src =        env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
546         py_target =     env.subst( dir + '/python/lib/python'+env['BF_PYTHON_VERSION'] )
547         
548         # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
549         if os.path.exists(py_target):
550                 print 'Using existing python from:'
551                 print '\t"%s"' %                        py_target
552                 print '\t(skipping copy)\n'
553                 return
554                 
555         
556         # Copied from source/creator/CMakeLists.txt, keep in sync.
557         print 'Install python from:'
558         print '\t"%s" into...' %        py_src
559         print '\t"%s"\n' %                      py_target
560         
561         run('rm -rf "%s"' % py_target)
562         try:    os.makedirs(os.path.dirname(py_target)) # the final part is copied
563         except:pass
564         
565         run('cp -R "%s" "%s"' % (py_src, os.path.dirname(py_target)))
566         run('rm -rf "%s/distutils"' % py_target)
567         run('rm -rf "%s/lib2to3"' % py_target)
568         run('rm -rf "%s/idlelib"' % py_target)
569         run('rm -rf "%s/tkinter"' % py_target)
570         run('rm -rf "%s/config"' % py_target)
571
572         run('rm -rf "%s/site-packages"' % py_target)
573         run('mkdir "%s/site-packages"' % py_target)    # python needs it.'
574
575         run('rm -f "%s/lib-dynload/_tkinter.so"' % py_target)
576         run('find "%s" -name "test" -prune -exec rm -rf {} \;' % py_target)
577         run('find "%s" -name "*.py?" -exec rm -rf {} \;' % py_target)
578         run('find "%s" -name "*.so"-exec strip -s {} \;' % py_target)
579
580 #### END ACTION STUFF #########
581
582 def bsc(env, target, source):
583         
584         bd = os.path.dirname(target[0].abspath)
585         bscfile = '\"'+target[0].abspath+'\"'
586         bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
587         bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
588
589         os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
590
591         myfile = open(bscpathtmp[1:-1], 'r')
592         lines = myfile.readlines()
593         myfile.close()
594
595         newfile = open(bscpathtmp[1:-1], 'w')
596         for l in lines:
597                 newfile.write('\"'+l[:-1]+'\"\n')
598         newfile.close()
599                                 
600         os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
601         os.system('del '+bscpathtmp)
602
603 class BlenderEnvironment(SConsEnvironment):
604
605         def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
606                 global libs
607                 if not self or not libname or not source:
608                         print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
609                         self.Exit()
610                 if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc'):
611                         print bc.FAIL+'BlenderRes is for windows only!'+bc.END
612                         self.Exit()
613                 
614                 print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
615                 lenv = self.Clone()
616                 if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
617                         res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
618                 else:
619                         res = lenv.RES(root_build_dir+'lib/'+libname, source)
620
621                 
622                 SConsEnvironment.Default(self, res)
623                 resources.append(res)
624
625         def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None, cc_compileflags=None, cxx_compileflags=None):
626                 global vcp
627                 if not self or not libname or not sources:
628                         print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
629                         self.Exit()
630
631                 def list_substring(quickie, libname):
632                         for q in quickie:
633                                 if libname.find(q) != -1:
634                                         return True
635                         return False
636
637                 if list_substring(quickie, libname) or len(quickie)==0:
638                         if list_substring(quickdebug, libname):
639                                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
640                         else:
641                                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
642                         lenv = self.Clone()
643                         lenv.Append(CPPPATH=includes)
644                         lenv.Append(CPPDEFINES=defines)
645                         if lenv['BF_DEBUG'] or (libname in quickdebug):
646                                         lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
647                                         lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
648                                         lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
649                         else:
650                                         lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
651                                         lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
652                                         lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
653                         if lenv['BF_PROFILE']:
654                                         lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
655                                         lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
656                                         lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
657                         if compileflags:
658                                 lenv.Replace(CFLAGS = compileflags)
659                         if cc_compileflags:
660                                 lenv.Replace(CCFLAGS = cc_compileflags)
661                         if cxx_compileflags:
662                                 lenv.Replace(CXXFLAGS = cxx_compileflags)
663                         lenv.Append(CFLAGS = lenv['C_WARN'])
664                         lenv.Append(CCFLAGS = lenv['CC_WARN'])
665                         lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
666
667                         if lenv['OURPLATFORM'] == 'win64-vc':
668                                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
669
670                         if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
671                                 if lenv['BF_DEBUG']:
672                                         lenv.Append(CCFLAGS = ['/MTd'])
673                                 else:
674                                         lenv.Append(CCFLAGS = ['/MT'])
675                         
676                         targetdir = root_build_dir+'lib/' + libname
677                         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
678                                 targetdir = '#'+targetdir
679                         lib = lenv.Library(target= targetdir, source=sources)
680                         SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
681                         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
682                                 #if targetdir[0] == '#':
683                                 #       targetdir = targetdir[1:-1]
684                                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
685                                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
686                                                  srcs = sources,
687                                                  buildtarget = lib,
688                                                  variant = 'Release',
689                                                  auto_build_solution=0)
690                                 vcp.append(vcproject)
691                                 SConsEnvironment.Default(self, vcproject)
692                 else:
693                         print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
694                 # note: libs is a global
695                 add_lib_to_dict(self, libs, libtype, libname, priority)
696
697         def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''):
698                 global vcp
699                 print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
700                 lenv = self.Clone()
701                 if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
702                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
703                         lenv.Append(LINKFLAGS = ['/FORCE:MULTIPLE'])
704                         if lenv['BF_DEBUG']:
705                                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb'])
706                 if  lenv['OURPLATFORM']=='linux2':
707                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
708                         if lenv['WITH_BF_PYTHON']:
709                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
710                 if  lenv['OURPLATFORM']=='sunos5':
711                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
712                         if lenv['WITH_BF_PYTHON']:
713                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
714                         if lenv['CXX'].endswith('CC'):
715                                  lenv.Replace(LINK = '$CXX')
716                 if  lenv['OURPLATFORM']=='darwin':
717                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
718                         if lenv['WITH_BF_PYTHON']:
719                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
720                         lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
721                 if lenv['BF_PROFILE']:
722                         lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
723                 lenv.Append(CPPPATH=includes)
724                 if root_build_dir[0]==os.sep or root_build_dir[1]==':':
725                         lenv.Append(LIBPATH=root_build_dir + '/lib')
726                 lenv.Append(LIBPATH=libpath)
727                 lenv.Append(LIBS=libs)
728                 if lenv['WITH_BF_QUICKTIME']:
729                          lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
730                          lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
731                 prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
732                 if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
733                         f = lenv.File(progname + '.bsc', builddir)
734                         brs = lenv.Command(f, prog, [bsc])
735                         SConsEnvironment.Default(self, brs)
736                 SConsEnvironment.Default(self, prog)
737                 if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
738                         print "! ",builddir + "/" + progname + '.sln'
739                         sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
740                                          projects= vcp,
741                                          variant = 'Release')
742                         SConsEnvironment.Default(self, sln)
743                 program_list.append(prog)
744                 if  lenv['OURPLATFORM']=='darwin':
745                         lenv['BINARYKIND'] = binarykind
746                         lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
747                 elif os.sep == '/': # any unix
748                         if lenv['WITH_BF_PYTHON']:
749                                 if not lenv['WITHOUT_BF_INSTALL'] and not lenv['WITHOUT_BF_PYTHON_INSTALL']:
750                                         lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
751                 elif lenv['OURPLATFORM'].startswith('win'): # windows
752                         if lenv['WITH_BF_PYTHON']:
753                                 if not lenv['WITHOUT_BF_PYTHON_INSTALL']:
754                                         lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
755                 return prog
756
757         def Glob(lenv, pattern):
758                 path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
759                 files = []
760                 for i in glob.glob(path + pattern):
761                         files.append(string.replace(i, path, ''))
762                 return files