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