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