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