Merge from trunk -r 23968:24181.
[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         # Copied from source/creator/CMakeLists.txt, keep in sync.
550         print 'Install python from:'
551         print '\t"%s" into...' %        py_src
552         print '\t"%s"\n' %                      py_target
553         
554         run('rm -rf "%s"' % py_target)
555         try:    os.makedirs(os.path.dirname(py_target)) # the final part is copied
556         except:pass
557         
558         run('cp -R "%s" "%s"' % (py_src, os.path.dirname(py_target)))
559         run('rm -rf "%s/distutils"' % py_target)
560         run('rm -rf "%s/lib2to3"' % py_target)
561         run('rm -rf "%s/idlelib"' % py_target)
562         run('rm -rf "%s/tkinter"' % py_target)
563         run('rm -rf "%s/config"' % py_target)
564
565         run('rm -rf "%s/site-packages"' % py_target)
566         run('mkdir "%s/site-packages"' % py_target)    # python needs it.'
567
568         run('rm -f "%s/lib-dynload/_tkinter.so"' % py_target)
569         run('find "%s" -name "test" -prune -exec rm -rf {} \;' % py_target)
570         run('find "%s" -name "*.py?" -exec rm -rf {} \;' % py_target)
571         run('find "%s" -name "*.so"-exec strip -s {} \;' % py_target)
572
573 #### END ACTION STUFF #########
574
575 def bsc(env, target, source):
576         
577         bd = os.path.dirname(target[0].abspath)
578         bscfile = '\"'+target[0].abspath+'\"'
579         bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
580         bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
581
582         os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
583
584         myfile = open(bscpathtmp[1:-1], 'r')
585         lines = myfile.readlines()
586         myfile.close()
587
588         newfile = open(bscpathtmp[1:-1], 'w')
589         for l in lines:
590                 newfile.write('\"'+l[:-1]+'\"\n')
591         newfile.close()
592                                 
593         os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
594         os.system('del '+bscpathtmp)
595
596 class BlenderEnvironment(SConsEnvironment):
597
598         def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
599                 global libs
600                 if not self or not libname or not source:
601                         print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
602                         self.Exit()
603                 if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc'):
604                         print bc.FAIL+'BlenderRes is for windows only!'+bc.END
605                         self.Exit()
606                 
607                 print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
608                 lenv = self.Clone()
609                 if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
610                         res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
611                 else:
612                         res = lenv.RES(root_build_dir+'lib/'+libname, source)
613
614                 
615                 SConsEnvironment.Default(self, res)
616                 resources.append(res)
617
618         def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None, cc_compileflags=None, cxx_compileflags=None):
619                 global vcp
620                 if not self or not libname or not sources:
621                         print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
622                         self.Exit()
623
624                 def list_substring(quickie, libname):
625                         for q in quickie:
626                                 if libname.find(q) != -1:
627                                         return True
628                         return False
629
630                 if list_substring(quickie, libname) or len(quickie)==0:
631                         if list_substring(quickdebug, libname):
632                                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
633                         else:
634                                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
635                         lenv = self.Clone()
636                         lenv.Append(CPPPATH=includes)
637                         lenv.Append(CPPDEFINES=defines)
638                         if lenv['BF_DEBUG'] or (libname in quickdebug):
639                                         lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
640                                         lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
641                                         lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
642                         else:
643                                         lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
644                                         lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
645                                         lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
646                         if lenv['BF_PROFILE']:
647                                         lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
648                                         lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
649                                         lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
650                         if compileflags:
651                                 lenv.Replace(CFLAGS = compileflags)
652                         if cc_compileflags:
653                                 lenv.Replace(CCFLAGS = cc_compileflags)
654                         if cxx_compileflags:
655                                 lenv.Replace(CXXFLAGS = cxx_compileflags)
656                         lenv.Append(CFLAGS = lenv['C_WARN'])
657                         lenv.Append(CCFLAGS = lenv['CC_WARN'])
658                         lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
659
660                         if lenv['OURPLATFORM'] == 'win64-vc':
661                                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
662
663                         if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
664                                 if lenv['BF_DEBUG']:
665                                         lenv.Append(CCFLAGS = ['/MTd'])
666                                 else:
667                                         lenv.Append(CCFLAGS = ['/MT'])
668                         
669                         targetdir = root_build_dir+'lib/' + libname
670                         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
671                                 targetdir = '#'+targetdir
672                         lib = lenv.Library(target= targetdir, source=sources)
673                         SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
674                         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
675                                 #if targetdir[0] == '#':
676                                 #       targetdir = targetdir[1:-1]
677                                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
678                                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
679                                                  srcs = sources,
680                                                  buildtarget = lib,
681                                                  variant = 'Release',
682                                                  auto_build_solution=0)
683                                 vcp.append(vcproject)
684                                 SConsEnvironment.Default(self, vcproject)
685                 else:
686                         print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
687                 # note: libs is a global
688                 add_lib_to_dict(self, libs, libtype, libname, priority)
689
690         def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''):
691                 global vcp
692                 print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
693                 lenv = self.Clone()
694                 if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
695                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
696                         lenv.Append(LINKFLAGS = ['/FORCE:MULTIPLE'])
697                         if lenv['BF_DEBUG']:
698                                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb'])
699                 if  lenv['OURPLATFORM']=='linux2':
700                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
701                         if lenv['WITH_BF_PYTHON']:
702                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
703                 if  lenv['OURPLATFORM']=='sunos5':
704                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
705                         if lenv['WITH_BF_PYTHON']:
706                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
707                         if lenv['CXX'].endswith('CC'):
708                                  lenv.Replace(LINK = '$CXX')
709                 if  lenv['OURPLATFORM']=='darwin':
710                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
711                         if lenv['WITH_BF_PYTHON']:
712                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
713                         lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
714                 if lenv['BF_PROFILE']:
715                         lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
716                 lenv.Append(CPPPATH=includes)
717                 if root_build_dir[0]==os.sep or root_build_dir[1]==':':
718                         lenv.Append(LIBPATH=root_build_dir + '/lib')
719                 lenv.Append(LIBPATH=libpath)
720                 lenv.Append(LIBS=libs)
721                 if lenv['WITH_BF_QUICKTIME']:
722                          lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
723                          lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
724                 prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
725                 if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
726                         f = lenv.File(progname + '.bsc', builddir)
727                         brs = lenv.Command(f, prog, [bsc])
728                         SConsEnvironment.Default(self, brs)
729                 SConsEnvironment.Default(self, prog)
730                 if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
731                         print "! ",builddir + "/" + progname + '.sln'
732                         sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
733                                          projects= vcp,
734                                          variant = 'Release')
735                         SConsEnvironment.Default(self, sln)
736                 program_list.append(prog)
737                 if  lenv['OURPLATFORM']=='darwin':
738                         lenv['BINARYKIND'] = binarykind
739                         lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
740                 elif os.sep == '/': # any unix
741                         if lenv['WITH_BF_PYTHON']:
742                                 if not lenv['WITHOUT_BF_INSTALL'] and not lenv['WITHOUT_BF_PYTHON_INSTALL']:
743                                         lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
744                 elif lenv['OURPLATFORM'].startswith('win'): # windows
745                         if lenv['WITH_BF_PYTHON']:
746                                 if not lenv['WITHOUT_BF_PYTHON_INSTALL']:
747                                         lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
748                 return prog
749
750         def Glob(lenv, pattern):
751                 path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
752                 files = []
753                 for i in glob.glob(path + pattern):
754                         files.append(string.replace(i, path, ''))
755                 return files