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