Tell what platform and its bitness in BUILD_PLATFORM
[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
281         obj = []
282         if lenv['BF_BUILDINFO']:
283                 lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
284                                                                         'BUILD_DATE=\'"%s"\''%(build_date),
285                                                                         'BUILD_TYPE=\'"dynamic"\'',
286                                                                         'BUILD_REV=\'"%s"\''%(build_rev),
287                                                                         'NAN_BUILDINFO',
288                                                                         'BUILD_PLATFORM=\'"%s %s"\''%(platform.system(), platform.architecture()[0])])
289                 obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
290                                                 [root_build_dir+'source/creator/buildinfo.c'])]
291         return obj
292
293 ##### END LIB STUFF ############
294
295 ##### ACTION STUFF #############
296
297 def my_print_cmd_line(self, s, target, source, env):
298         sys.stdout.write(' ' * 70 + '\r')
299         sys.stdout.flush()
300         sys.stdout.write(s + "\r")
301         sys.stdout.flush()
302
303 def my_compile_print(target, source, env):
304         a = '%s' % (source[0])
305         d, f = os.path.split(a)
306         return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
307
308 def my_moc_print(target, source, env):
309         a = '%s' % (source[0])
310         d, f = os.path.split(a)
311         return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
312
313 def my_linking_print(target, source, env):
314         t = '%s' % (target[0])
315         d, f = os.path.split(t)
316         return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
317
318 def my_program_print(target, source, env):
319         t = '%s' % (target[0])
320         d, f = os.path.split(t)
321         return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
322
323 def msvc_hack(env):
324         static_lib = SCons.Tool.createStaticLibBuilder(env)
325         program = SCons.Tool.createProgBuilder(env)
326         
327         env['BUILDERS']['Library'] = static_lib
328         env['BUILDERS']['StaticLibrary'] = static_lib
329         env['BUILDERS']['Program'] = program
330                 
331 def set_quiet_output(env):
332         mycaction = Action("$CCCOM", strfunction=my_compile_print)
333         myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
334         mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
335         myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
336         mylibaction = Action("$ARCOM", strfunction=my_linking_print)
337         mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
338
339         static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
340         static_ob.add_action('.c', mycaction)
341         static_ob.add_action('.cpp', mycppaction)
342         shared_ob.add_action('.c', myshcaction)
343         shared_ob.add_action('.cpp', myshcppaction)
344
345         static_lib = SCons.Builder.Builder(action = mylibaction,
346                                                                            emitter = '$LIBEMITTER',
347                                                                            prefix = '$LIBPREFIX',
348                                                                            suffix = '$LIBSUFFIX',
349                                                                            src_suffix = '$OBJSUFFIX',
350                                                                            src_builder = 'StaticObject')
351
352         program = SCons.Builder.Builder(action = mylinkaction,
353                                                                         emitter = '$PROGEMITTER',
354                                                                         prefix = '$PROGPREFIX',
355                                                                         suffix = '$PROGSUFFIX',
356                                                                         src_suffix = '$OBJSUFFIX',
357                                                                         src_builder = 'Object',
358                                                                         target_scanner = SCons.Defaults.ProgScan)
359
360         env['BUILDERS']['Object'] = static_ob
361         env['BUILDERS']['StaticObject'] = static_ob
362         env['BUILDERS']['StaticLibrary'] = static_lib
363         env['BUILDERS']['Library'] = static_lib
364         env['BUILDERS']['Program'] = program
365         if env['BF_LINE_OVERWRITE']:
366                 SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
367
368         
369 class CompZipFile(zipfile.ZipFile):
370         """Partial copy of python2.6's zipfile.ZipFile (see http://www.python.org)
371         to get a extractall() that works on py2.5 and probably earlier distributions."""
372         def __init__(self, file, mode="r", compression=zipfile.ZIP_STORED, allowZip64=False):
373                 if sys.version_info < (2, 6):
374                         zipfile.ZipFile.__init__(self, file, mode, compression)
375                 else:
376                         zipfile.ZipFile.__init__(self, file, mode, compression, allowZip64)
377
378                 if not hasattr(self,"extractall"): # use our method 
379                         print "Debug: Using comp_extractall!"
380                         self.extractall= self.comp_extractall
381
382         def comp_extractall(self, path=None, members=None, pwd=None): #renamed method
383                 """Extract all members from the archive to the current working
384                         directory. `path' specifies a different directory to extract to.
385                         `members' is optional and must be a subset of the list returned
386                         by namelist().
387                 """
388                 if members is None:
389                         members = self.namelist()
390
391                 for zipinfo in members:
392                         self.comp_extract(zipinfo, path, pwd) # use our method 
393
394         def comp_extract(self, member, path=None, pwd=None): #renamed method
395                 """Extract a member from the archive to the current working directory,
396                         using its full name. Its file information is extracted as accurately
397                         as possible. `member' may be a filename or a ZipInfo object. You can
398                         specify a different directory using `path'.
399                 """
400                 if not isinstance(member, zipfile.ZipInfo):
401                         member = self.getinfo(member)
402
403                 if path is None:
404                         path = os.getcwd()
405
406                 return self.comp_extract_member(member, path, pwd) # use our method 
407
408         def comp_extract_member(self, member, targetpath, pwd): #renamed method
409                 """Extract the ZipInfo object 'member' to a physical
410                         file on the path targetpath.
411                 """
412                 # build the destination pathname, replacing
413                 # forward slashes to platform specific separators.
414                 if targetpath[-1:] in (os.path.sep, os.path.altsep):
415                         targetpath = targetpath[:-1]
416
417                 # don't include leading "/" from file name if present
418                 if member.filename[0] == '/':
419                         targetpath = os.path.join(targetpath, member.filename[1:])
420                 else:
421                         targetpath = os.path.join(targetpath, member.filename)
422
423                 targetpath = os.path.normpath(targetpath)
424
425                 # Create all upper directories if necessary.
426                 upperdirs = os.path.dirname(targetpath)
427                 if upperdirs and not os.path.exists(upperdirs):
428                         os.makedirs(upperdirs)
429
430                 if member.filename[-1] == '/':
431                         os.mkdir(targetpath)
432                         return targetpath
433
434                 #use StrinIO instead so we don't have to reproduce more functionality.
435                 source = cStringIO.StringIO(self.read(member.filename))
436                 target = file(targetpath, "wb")
437                 shutil.copyfileobj(source, target)
438                 source.close()
439                 target.close()
440
441                 return targetpath
442
443 def unzip_pybundle(from_zip,to_dir,exclude_re):
444         
445         zip= CompZipFile(from_zip, mode='r')
446         exclude_re= list(exclude_re) #single re object or list of re objects
447         debug= 0 #list files instead of unpacking
448         good= []
449         if debug: print '\nFiles not being unpacked:\n'
450         for name in zip.namelist():
451                 is_bad= 0
452                 for r in exclude_re:
453                         if r.match(name):
454                                 is_bad=1
455                                 if debug: print name
456                                 break
457                 if not is_bad:
458                         good.append(name)
459         if debug:
460                 print '\nFiles being unpacked:\n'
461                 for g in good:
462                         print g
463         else:
464                 zip.extractall(to_dir, good)
465
466 def my_winpybundle_print(target, source, env):
467         pass
468
469 def WinPyBundle(target=None, source=None, env=None):
470         import re
471         py_zip= env.subst( env['LCGDIR'] )
472         if py_zip[0]=='#':
473                 py_zip= py_zip[1:]
474         if env['BF_DEBUG']:
475                 py_zip+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.zip'
476         else:
477                 py_zip+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.zip'
478
479         py_target = env.subst( env['BF_INSTALLDIR'] )
480         if py_target[0]=='#':
481                 py_target=py_target[1:]
482         py_target = os.path.join(py_target, VERSION, 'python', 'lib')
483         def printexception(func,path,ex):
484                 if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
485                         print str(func) + ' failed on ' + str(path)
486         print "Trying to remove existing py bundle."
487         shutil.rmtree(py_target, False, printexception)
488         exclude_re=[re.compile('.*/test/.*'),
489                                 re.compile('^config/.*'),
490                                 re.compile('^distutils/.*'),
491                                 re.compile('^idlelib/.*'),
492                                 re.compile('^lib2to3/.*'),
493                                 re.compile('^tkinter/.*')]
494         print "Unpacking '" + py_zip + "' to '" + py_target + "'"
495         unzip_pybundle(py_zip,py_target,exclude_re)
496
497 def  my_appit_print(target, source, env):
498         a = '%s' % (target[0])
499         d, f = os.path.split(a)
500         return "making bundle for " + f
501
502 def AppIt(target=None, source=None, env=None):
503         import shutil
504         import commands
505         import os.path
506         
507         
508         a = '%s' % (target[0])
509         builddir, b = os.path.split(a)
510         libdir = env['LCGDIR'][1:]
511         osxarch = env['MACOSX_ARCHITECTURE']
512         installdir = env['BF_INSTALLDIR']
513         print("compiled architecture: %s"%(osxarch))
514         print("Installing to %s"%(installdir))
515         python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
516         print("unzipping to app-bundle: %s"%(python_zip))
517         bldroot = env.Dir('.').abspath
518         binary = env['BINARYKIND']
519          
520         if b=='verse':
521                 print bc.OKBLUE+"no bundle for verse"+bc.ENDC 
522                 return 0
523         
524         sourcedir = bldroot + '/source/darwin/%s.app'%binary
525         sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
526         targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
527         cmd = installdir + '/' +'%s.app'%binary
528         
529         if os.path.isdir(cmd):
530                 shutil.rmtree(cmd)
531         shutil.copytree(sourcedir, cmd)
532         cmd = "cat %s | sed s/VERSION/`cat release/VERSION`/ | sed s/DATE/`date +'%%Y-%%b-%%d'`/ > %s"%(sourceinfo,targetinfo)
533         commands.getoutput(cmd)
534         cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
535         commands.getoutput(cmd)
536         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/'%(installdir, binary, VERSION)
537 #       print cmd
538         commands.getoutput(cmd)
539         cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
540         shutil.copy(bldroot + '/release/bin/.blender/.bfont.ttf', cmd)
541         shutil.copy(bldroot + '/release/bin/.blender/.Blanguages', cmd)
542         cmd = 'cp -R %s/release/bin/%s/locale %s/%s.app/Contents/Resources/'%(bldroot,VERSION,installdir,binary)
543         commands.getoutput(cmd)
544         cmd = 'cp -R %s/release/bin/%s/locale %s/%s.app/Contents/MacOS/%s/'%(bldroot,VERSION,installdir,binary,VERSION)
545         commands.getoutput(cmd)
546         cmd = 'cp %s/release/bin/%s/.Blanguages %s/%s.app/Contents/Resources/'%(bldroot,VERSION,installdir,binary)
547         commands.getoutput(cmd)
548         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
549         commands.getoutput(cmd)
550         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
551         commands.getoutput(cmd) 
552         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
553         commands.getoutput(cmd)
554         cmd = 'cp -R %s/release/ui %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
555         commands.getoutput(cmd)
556         cmd = 'cp -R %s/release/io %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
557         commands.getoutput(cmd)
558         cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
559         commands.getoutput(cmd)
560         cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
561         commands.getoutput(cmd)
562         cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
563         commands.getoutput(cmd)
564         cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
565         commands.getoutput(cmd)
566
567 # extract copy system python, be sure to update other build systems
568 # when making changes to the files that are copied.
569 def my_unixpybundle_print(target, source, env):
570         pass
571
572 def UnixPyBundle(target=None, source=None, env=None):
573         # Any Unix except osx
574         #-- VERSION/python/lib/python3.1
575         
576         import commands
577         
578         def run(cmd):
579                 print 'Install command:', cmd
580                 commands.getoutput(cmd)
581
582         dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
583
584         py_src =        env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
585         py_target =     env.subst( dir + '/python/lib/python'+env['BF_PYTHON_VERSION'] )
586         
587         # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
588         if os.path.exists(py_target):
589                 print 'Using existing python from:'
590                 print '\t"%s"' %                        py_target
591                 print '\t(skipping copy)\n'
592                 return
593                 
594         
595         # Copied from source/creator/CMakeLists.txt, keep in sync.
596         print 'Install python from:'
597         print '\t"%s" into...' %        py_src
598         print '\t"%s"\n' %                      py_target
599         
600         run('rm -rf "%s"' % py_target)
601         try:    os.makedirs(os.path.dirname(py_target)) # the final part is copied
602         except:pass
603         
604         run('cp -R "%s" "%s"' % (py_src, os.path.dirname(py_target)))
605         run('rm -rf "%s/distutils"' % py_target)
606         run('rm -rf "%s/lib2to3"' % py_target)
607         run('rm -rf "%s/idlelib"' % py_target)
608         run('rm -rf "%s/tkinter"' % py_target)
609         run('rm -rf "%s/config"' % py_target)
610
611         run('rm -rf "%s/site-packages"' % py_target)
612         run('mkdir "%s/site-packages"' % py_target)    # python needs it.'
613
614         run('rm -f "%s/lib-dynload/_tkinter.so"' % py_target)
615         run('find "%s" -name "test" -prune -exec rm -rf {} \;' % py_target)
616         run('find "%s" -name "*.py?" -exec rm -rf {} \;' % py_target)
617         run('find "%s" -name "*.so"-exec strip -s {} \;' % py_target)
618
619 #### END ACTION STUFF #########
620
621 def bsc(env, target, source):
622         
623         bd = os.path.dirname(target[0].abspath)
624         bscfile = '\"'+target[0].abspath+'\"'
625         bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
626         bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
627
628         os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
629
630         myfile = open(bscpathtmp[1:-1], 'r')
631         lines = myfile.readlines()
632         myfile.close()
633
634         newfile = open(bscpathtmp[1:-1], 'w')
635         for l in lines:
636                 newfile.write('\"'+l[:-1]+'\"\n')
637         newfile.close()
638                                 
639         os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
640         os.system('del '+bscpathtmp)
641
642 class BlenderEnvironment(SConsEnvironment):
643
644         def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
645                 global libs
646                 if not self or not libname or not source:
647                         print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
648                         self.Exit()
649                 if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc'):
650                         print bc.FAIL+'BlenderRes is for windows only!'+bc.END
651                         self.Exit()
652                 
653                 print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
654                 lenv = self.Clone()
655                 if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
656                         res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
657                 else:
658                         res = lenv.RES(root_build_dir+'lib/'+libname, source)
659
660                 
661                 SConsEnvironment.Default(self, res)
662                 resources.append(res)
663
664         def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None, cc_compileflags=None, cxx_compileflags=None):
665                 global vcp
666                 if not self or not libname or not sources:
667                         print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
668                         self.Exit()
669
670                 def list_substring(quickie, libname):
671                         for q in quickie:
672                                 if libname.find(q) != -1:
673                                         return True
674                         return False
675
676                 if list_substring(quickie, libname) or len(quickie)==0:
677                         if list_substring(quickdebug, libname):
678                                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
679                         else:
680                                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
681                         lenv = self.Clone()
682                         lenv.Append(CPPPATH=includes)
683                         lenv.Append(CPPDEFINES=defines)
684                         if lenv['BF_DEBUG'] or (libname in quickdebug):
685                                         lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
686                                         lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
687                                         lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
688                         else:
689                                         lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
690                                         lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
691                                         lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
692                         if lenv['BF_PROFILE']:
693                                         lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
694                                         lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
695                                         lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
696                         if compileflags:
697                                 lenv.Replace(CFLAGS = compileflags)
698                         if cc_compileflags:
699                                 lenv.Replace(CCFLAGS = cc_compileflags)
700                         if cxx_compileflags:
701                                 lenv.Replace(CXXFLAGS = cxx_compileflags)
702                         lenv.Append(CFLAGS = lenv['C_WARN'])
703                         lenv.Append(CCFLAGS = lenv['CC_WARN'])
704                         lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
705
706                         if lenv['OURPLATFORM'] == 'win64-vc':
707                                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
708
709                         if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
710                                 if lenv['BF_DEBUG']:
711                                         lenv.Append(CCFLAGS = ['/MTd'])
712                                 else:
713                                         lenv.Append(CCFLAGS = ['/MT'])
714                         
715                         targetdir = root_build_dir+'lib/' + libname
716                         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
717                                 targetdir = '#'+targetdir
718                         lib = lenv.Library(target= targetdir, source=sources)
719                         SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
720                         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
721                                 #if targetdir[0] == '#':
722                                 #       targetdir = targetdir[1:-1]
723                                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
724                                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
725                                                  srcs = sources,
726                                                  buildtarget = lib,
727                                                  variant = 'Release',
728                                                  auto_build_solution=0)
729                                 vcp.append(vcproject)
730                                 SConsEnvironment.Default(self, vcproject)
731                 else:
732                         print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
733                 # note: libs is a global
734                 add_lib_to_dict(self, libs, libtype, libname, priority)
735
736         def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
737                 global vcp
738                 print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
739                 lenv = self.Clone()
740                 if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
741                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
742                         lenv.Append(LINKFLAGS = ['/FORCE:MULTIPLE'])
743                         if lenv['BF_DEBUG']:
744                                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb'])
745                 if  lenv['OURPLATFORM']=='linux2':
746                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
747                         if lenv['WITH_BF_PYTHON']:
748                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
749                 if  lenv['OURPLATFORM']=='sunos5':
750                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
751                         if lenv['WITH_BF_PYTHON']:
752                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
753                         if lenv['CXX'].endswith('CC'):
754                                  lenv.Replace(LINK = '$CXX')
755                 if  lenv['OURPLATFORM']=='darwin':
756                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
757                         if lenv['WITH_BF_PYTHON']:
758                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
759                         lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
760                 if lenv['BF_PROFILE']:
761                         lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
762                 if root_build_dir[0]==os.sep or root_build_dir[1]==':':
763                         lenv.Append(LIBPATH=root_build_dir + '/lib')
764                 lenv.Append(LIBPATH=libpath)
765                 lenv.Append(LIBS=libs)
766                 if lenv['WITH_BF_QUICKTIME']:
767                          lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
768                          lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
769                 prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
770                 if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
771                         f = lenv.File(progname + '.bsc', builddir)
772                         brs = lenv.Command(f, prog, [bsc])
773                         SConsEnvironment.Default(self, brs)
774                 SConsEnvironment.Default(self, prog)
775                 if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
776                         print "! ",builddir + "/" + progname + '.sln'
777                         sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
778                                          projects= vcp,
779                                          variant = 'Release')
780                         SConsEnvironment.Default(self, sln)
781                 program_list.append(prog)
782                 if  lenv['OURPLATFORM']=='darwin':
783                         lenv['BINARYKIND'] = binarykind
784                         lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
785                 elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
786                         if lenv['WITH_BF_PYTHON']:
787                                 if not lenv['WITHOUT_BF_INSTALL'] and not lenv['WITHOUT_BF_PYTHON_INSTALL']:
788                                         lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
789                 elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
790                         if lenv['WITH_BF_PYTHON']:
791                                 if not lenv['WITHOUT_BF_PYTHON_INSTALL']:
792                                         lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
793                 return prog
794
795         def Glob(lenv, pattern):
796                 path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
797                 files = []
798                 for i in glob.glob(path + pattern):
799                         files.append(string.replace(i, path, ''))
800                 return files