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