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