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