Made minor revisions (no functional changes).
[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 VERSION_RELEASE_CYCLE = btools.VERSION_RELEASE_CYCLE
38
39 Split = SCons.Util.Split
40 Action = SCons.Action.Action
41 Builder = SCons.Builder.Builder
42 GetBuildPath = SConsEnvironment.GetBuildPath
43
44 # a few globals
45 root_build_dir = ''
46 doc_build_dir = ''
47 quickie = None # Anything else than None if BF_QUICK has been passed
48 quicklist = [] # The list of libraries/programs to compile during a quickie
49 program_list = [] # A list holding Nodes to final binaries, used to create installs
50 arguments = None
51 targets = None
52 resources = []
53
54 #some internals
55 blenderdeps = [] # don't manipulate this one outside this module!
56
57 ##### LIB STUFF ##########
58
59 possible_types = ['core'] # can be set in ie. SConstruct
60 libs = {}
61 vcp = []
62
63 def getresources():
64     return resources
65
66 def init_lib_dict():
67     for pt in possible_types:
68         libs[pt] = {}
69
70 # helper func for add_lib_to_dict
71 def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
72     if not libname in dict[libtype]:
73         done = None
74         while not done:
75             if dict[libtype].has_key(priority):
76                 priority = priority + 1
77             else:
78                 done = True
79         dict[libtype][priority] = libname
80
81 # libtype and priority can both be lists, for defining lib in multiple places
82 def add_lib_to_dict(env, dict = None, libtype = None, libname = None, priority = 100):
83     if not dict or not libtype or not libname:
84         print "Passed wrong arg"
85         env.Exit()
86
87     if type(libtype) is str and type(priority) is int:
88         internal_lib_to_dict(dict, libtype, libname, priority)
89     elif type(libtype) is list and type(priority) is list:
90         if len(libtype)==len(priority):
91             for lt, p in zip(libtype, priority):
92                 internal_lib_to_dict(dict, lt, libname, p)
93         else:
94             print "libtype and priority lists are unequal in length"
95             env.Exit()
96     else:
97         print "Wrong type combinations for libtype and priority. Only str and int or list and list"
98         env.Exit()
99
100 def create_blender_liblist(lenv = None, libtype = None):
101     if not lenv or not libtype:
102         print "missing arg"
103
104     lst = []
105     if libtype in possible_types:
106         curlib = libs[libtype]
107         sortlist = curlib.keys()
108         sortlist.sort()
109         for sk in sortlist:
110             v = curlib[sk]
111             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
112                 target = os.path.abspath(os.getcwd() + os.sep + root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
113             else:
114                 target = os.path.abspath(root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
115             lst.append(target)
116
117     return lst
118
119 ## TODO: static linking
120 def setup_staticlibs(lenv):
121     statlibs = [
122         #here libs for static linking
123     ]
124
125     libincs = []
126
127     if lenv['WITH_BF_FFMPEG']:
128         libincs += Split(lenv['BF_FFMPEG_LIBPATH'])
129
130     libincs.extend([
131         lenv['BF_OPENGL_LIBPATH'],
132         lenv['BF_JPEG_LIBPATH'],
133         lenv['BF_ZLIB_LIBPATH'],
134         lenv['BF_PNG_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_OIIO']:
198         libincs += Split(lenv['BF_OIIO_LIBPATH'])
199         if lenv['WITH_BF_STATICOIIO']:
200             statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
201
202     if lenv['WITH_BF_BOOST']:
203         libincs += Split(lenv['BF_BOOST_LIBPATH'])
204         if lenv['WITH_BF_STATICBOOST']:
205             statlibs += Split(lenv['BF_BOOST_LIB_STATIC'])
206
207     # setting this last so any overriding of manually libs could be handled
208     if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
209         libincs.append('/usr/lib')
210
211     if lenv['WITH_BF_JEMALLOC']:
212         libincs += Split(lenv['BF_JEMALLOC_LIBPATH'])
213         if lenv['WITH_BF_STATICJEMALLOC']:
214             statlibs += Split(lenv['BF_JEMALLOC_LIB_STATIC'])
215
216     if lenv['OURPLATFORM']=='linux':
217         if lenv['WITH_BF_3DMOUSE']:
218             libincs += Split(lenv['BF_3DMOUSE_LIBPATH'])
219             if lenv['WITH_BF_STATIC3DMOUSE']:
220                 statlibs += Split(lenv['BF_3DMOUSE_LIB_STATIC'])
221
222     return statlibs, libincs
223
224 def setup_syslibs(lenv):
225     syslibs = []
226
227     if not lenv['WITH_BF_FREETYPE_STATIC']:
228         syslibs += Split(lenv['BF_FREETYPE_LIB'])
229     if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']:
230         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'):
231             syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
232         else:
233             syslibs.append(lenv['BF_PYTHON_LIB'])
234     if lenv['WITH_BF_INTERNATIONAL'] and not lenv['WITH_BF_GETTEXT_STATIC']:
235         syslibs += Split(lenv['BF_GETTEXT_LIB'])
236     if lenv['WITH_BF_OPENAL']:
237         if not lenv['WITH_BF_STATICOPENAL']:
238             syslibs += Split(lenv['BF_OPENAL_LIB'])
239     if lenv['WITH_BF_OPENMP'] and lenv['CC'] != 'icc':
240         if lenv['CC'] == 'cl.exe':
241             syslibs += ['vcomp']
242         else:
243             syslibs += ['gomp']
244     if lenv['WITH_BF_ICONV']:
245         syslibs += Split(lenv['BF_ICONV_LIB'])
246     if lenv['WITH_BF_OIIO']:
247         if not lenv['WITH_BF_STATICOIIO']:
248             syslibs += Split(lenv['BF_OIIO_LIB'])
249
250     if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
251         syslibs += Split(lenv['BF_OPENEXR_LIB'])
252     if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
253         syslibs += Split(lenv['BF_TIFF_LIB'])
254     if lenv['WITH_BF_ZLIB'] and not lenv['WITH_BF_STATICZLIB']:
255         syslibs += Split(lenv['BF_ZLIB_LIB'])
256     if lenv['WITH_BF_FFMPEG'] and not lenv['WITH_BF_STATICFFMPEG']:
257         syslibs += Split(lenv['BF_FFMPEG_LIB'])
258         if lenv['WITH_BF_OGG']:
259             syslibs += Split(lenv['BF_OGG_LIB'])
260     if lenv['WITH_BF_JACK']:
261         syslibs += Split(lenv['BF_JACK_LIB'])
262     if lenv['WITH_BF_SNDFILE'] and not lenv['WITH_BF_STATICSNDFILE']:
263         syslibs += Split(lenv['BF_SNDFILE_LIB'])
264     if lenv['WITH_BF_FFTW3'] and not lenv['WITH_BF_STATICFFTW3']:
265         syslibs += Split(lenv['BF_FFTW3_LIB'])
266     if lenv['WITH_BF_SDL']:
267         syslibs += Split(lenv['BF_SDL_LIB'])
268     if not lenv['WITH_BF_STATICOPENGL']:
269         syslibs += Split(lenv['BF_OPENGL_LIB'])
270     if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross', 'win64-vc'):
271         syslibs += Split(lenv['BF_PTHREADS_LIB'])
272     if lenv['WITH_BF_COLLADA']:
273         syslibs.append(lenv['BF_PCRE_LIB'])
274         if lenv['BF_DEBUG']:
275             syslibs += [colladalib+'_d' for colladalib in Split(lenv['BF_OPENCOLLADA_LIB'])]
276         else:
277             syslibs += Split(lenv['BF_OPENCOLLADA_LIB'])
278         syslibs.append(lenv['BF_EXPAT_LIB'])
279
280     if lenv['WITH_BF_JEMALLOC']:
281         if not lenv['WITH_BF_STATICJEMALLOC']:
282             syslibs += Split(lenv['BF_JEMALLOC_LIB'])
283
284     if lenv['OURPLATFORM']=='linux':
285         if lenv['WITH_BF_3DMOUSE']:
286             if not lenv['WITH_BF_STATIC3DMOUSE']:
287                 syslibs += Split(lenv['BF_3DMOUSE_LIB'])
288                 
289     if lenv['WITH_BF_BOOST'] and not lenv['WITH_BF_STATICBOOST']:
290         syslibs += Split(lenv['BF_BOOST_LIB'])
291
292     syslibs += Split(lenv['BF_JPEG_LIB'])
293     syslibs += Split(lenv['BF_PNG_LIB'])
294         
295     syslibs += lenv['LLIBS']
296
297     return syslibs
298
299 def propose_priorities():
300     print bc.OKBLUE+"Priorities:"+bc.ENDC
301     for t in possible_types:
302         print bc.OKGREEN+"\t"+t+bc.ENDC
303         new_priority = 0
304         curlib = libs[t]
305         sortlist = curlib.keys()
306         sortlist.sort()
307
308         for sk in sortlist:
309             v = curlib[sk]
310             #for p,v in sorted(libs[t].iteritems()):
311             print "\t\t",new_priority, v
312             new_priority += 5
313
314 # emits the necessary file objects for creator.c, to be used in creating
315 # the final blender executable
316 def creator(env):
317     sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
318
319     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', '#/source/blender/freestyle', env['BF_OPENGL_INC']]
320
321     defs = []
322     if env['WITH_BF_QUICKTIME']:
323         incs.append(env['BF_QUICKTIME_INC'])
324         defs.append('WITH_QUICKTIME')
325
326     if env['WITH_BF_BINRELOC']:
327         incs.append('#/extern/binreloc/include')
328         defs.append('WITH_BINRELOC')
329
330     if env['WITH_BF_OPENEXR']:
331         defs.append('WITH_OPENEXR')
332
333     if env['WITH_BF_TIFF']:
334         defs.append('WITH_TIFF')
335
336     if env['WITH_BF_SDL']:
337         defs.append('WITH_SDL')
338
339     if env['WITH_BF_LIBMV']:
340         incs.append('#/extern/libmv')
341         defs.append('WITH_LIBMV')
342
343     if env['WITH_BF_PYTHON']:
344         incs.append('#/source/blender/python')
345         defs.append('WITH_PYTHON')
346         if env['BF_DEBUG']:
347             defs.append('_DEBUG')
348
349     if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
350         incs.append(env['BF_PTHREADS_INC'])
351
352     env.Append(CPPDEFINES=defs)
353     env.Append(CPPPATH=incs)
354     obj = [env.Object(root_build_dir+'source/creator/creator/creator', ['#source/creator/creator.c'])]
355
356     return obj
357
358 ## TODO: see if this can be made in an emitter
359 def buildinfo(lenv, build_type):
360     """
361     Generate a buildinfo object
362     """
363     build_date = time.strftime ("%Y-%m-%d")
364     build_time = time.strftime ("%H:%M:%S")
365     build_rev = os.popen('svnversion').read()[:-1] # remove \n
366     if build_rev == '': 
367         build_rev = '-UNKNOWN-'
368     if lenv['BF_DEBUG']:
369         build_type = "Debug"
370         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['BF_DEBUG_CCFLAGS'] + lenv['CPPFLAGS'])
371         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['CPPFLAGS'])
372     else:
373         build_type = "Release"
374         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['REL_CFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
375         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['REL_CXXFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
376
377     build_linkflags = ' '.join(lenv['PLATFORM_LINKFLAGS'])
378
379     obj = []
380     if lenv['BF_BUILDINFO']:
381         lenv.Append (CPPDEFINES = ['BUILD_TIME=\\"%s\\"'%(build_time),
382                                     'BUILD_DATE=\\"%s\\"'%(build_date),
383                                     'BUILD_TYPE=\\"%s\\"'%(build_type),
384                                     'BUILD_REV=\\"%s\\"'%(build_rev),
385                                     'WITH_BUILDINFO',
386                                     'BUILD_PLATFORM=\\"%s:%s\\"'%(platform.system(), platform.architecture()[0]),
387                                     'BUILD_CFLAGS=\\"%s\\"'%(build_cflags),
388                                     'BUILD_CXXFLAGS=\\"%s\\"'%(build_cxxflags),
389                                     'BUILD_LINKFLAGS=\\"%s\\"'%(build_linkflags),
390                                     'BUILD_SYSTEM=\\"SCons\\"'
391                     ])
392
393         lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel'])
394
395         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, ['#source/creator/buildinfo.c'])]
396
397     return obj
398
399 ##### END LIB STUFF ############
400
401 ##### ACTION STUFF #############
402
403 def my_print_cmd_line(self, s, target, source, env):
404     sys.stdout.write(' ' * 70 + '\r')
405     sys.stdout.flush()
406     sys.stdout.write(s + "\r")
407     sys.stdout.flush()
408
409 def my_compile_print(target, source, env):
410     a = '%s' % (source[0])
411     d, f = os.path.split(a)
412     return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
413
414 def my_moc_print(target, source, env):
415     a = '%s' % (source[0])
416     d, f = os.path.split(a)
417     return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
418
419 def my_linking_print(target, source, env):
420     t = '%s' % (target[0])
421     d, f = os.path.split(t)
422     return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
423
424 def my_program_print(target, source, env):
425     t = '%s' % (target[0])
426     d, f = os.path.split(t)
427     return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
428
429 def msvc_hack(env):
430     static_lib = SCons.Tool.createStaticLibBuilder(env)
431     program = SCons.Tool.createProgBuilder(env)
432     
433     env['BUILDERS']['Library'] = static_lib
434     env['BUILDERS']['StaticLibrary'] = static_lib
435     env['BUILDERS']['Program'] = program
436         
437 def set_quiet_output(env):
438     mycaction = Action("$CCCOM", strfunction=my_compile_print)
439     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
440     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
441     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
442     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
443     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
444
445     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
446     static_ob.add_action('.c', mycaction)
447     static_ob.add_action('.cpp', mycppaction)
448     shared_ob.add_action('.c', myshcaction)
449     shared_ob.add_action('.cpp', myshcppaction)
450
451     static_lib = SCons.Builder.Builder(action = mylibaction,
452                                        emitter = '$LIBEMITTER',
453                                        prefix = '$LIBPREFIX',
454                                        suffix = '$LIBSUFFIX',
455                                        src_suffix = '$OBJSUFFIX',
456                                        src_builder = 'StaticObject')
457
458     program = SCons.Builder.Builder(action = mylinkaction,
459                                     emitter = '$PROGEMITTER',
460                                     prefix = '$PROGPREFIX',
461                                     suffix = '$PROGSUFFIX',
462                                     src_suffix = '$OBJSUFFIX',
463                                     src_builder = 'Object',
464                                     target_scanner = SCons.Defaults.ProgScan)
465
466     env['BUILDERS']['Object'] = static_ob
467     env['BUILDERS']['StaticObject'] = static_ob
468     env['BUILDERS']['StaticLibrary'] = static_lib
469     env['BUILDERS']['Library'] = static_lib
470     env['BUILDERS']['Program'] = program
471     if env['BF_LINE_OVERWRITE']:
472         SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
473
474 def untar_pybundle(from_tar,to_dir,exclude_re):
475     tar= tarfile.open(from_tar, mode='r')
476     exclude_re= list(exclude_re) #single re object or list of re objects
477     debug= 0 #list files instead of unpacking
478     good= []
479     if debug: print '\nFiles not being unpacked:\n'
480     for name in tar.getnames():
481         is_bad= 0
482         for r in exclude_re:
483             if r.match(name):
484                 is_bad=1
485                 if debug: print name
486                 break
487         if not is_bad:
488             good.append(tar.getmember(name))
489     if debug:
490         print '\nFiles being unpacked:\n'
491         for g in good:
492             print g
493     else:
494         tar.extractall(to_dir, good)
495
496 def my_winpybundle_print(target, source, env):
497     pass
498
499 def WinPyBundle(target=None, source=None, env=None):
500     import re
501     py_tar= env.subst( env['LCGDIR'] )
502     if py_tar[0]=='#':
503         py_tar= py_tar[1:]
504     if env['BF_DEBUG']:
505         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.tar.gz'
506     else:
507         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
508
509     py_target = env.subst( env['BF_INSTALLDIR'] )
510     if py_target[0]=='#':
511         py_target=py_target[1:]
512     py_target = os.path.join(py_target, VERSION, 'python', 'lib')
513     def printexception(func,path,ex):
514         if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
515             print str(func) + ' failed on ' + str(path)
516     print "Trying to remove existing py bundle."
517     shutil.rmtree(py_target, False, printexception)
518     exclude_re=[re.compile('.*/test/.*'),
519                 re.compile('^config/.*'),
520                 re.compile('^config-*/.*'),
521                 re.compile('^distutils/.*'),
522                 re.compile('^idlelib/.*'),
523                 re.compile('^lib2to3/.*'),
524                 re.compile('^tkinter/.*'),
525                 re.compile('^_tkinter_d.pyd'),
526                 re.compile('^turtledemo'),
527                 re.compile('^turtle.py'),
528                 ]
529
530     print "Unpacking '" + py_tar + "' to '" + py_target + "'"
531     untar_pybundle(py_tar,py_target,exclude_re)
532
533 def  my_appit_print(target, source, env):
534     a = '%s' % (target[0])
535     d, f = os.path.split(a)
536     return "making bundle for " + f
537
538 def AppIt(target=None, source=None, env=None):
539     import shutil
540     import commands
541     import os.path
542     
543     
544     a = '%s' % (target[0])
545     builddir, b = os.path.split(a)
546     libdir = env['LCGDIR'][1:]
547     osxarch = env['MACOSX_ARCHITECTURE']
548     installdir = env['BF_INSTALLDIR']
549     print("compiled architecture: %s"%(osxarch))
550     print("Installing to %s"%(installdir))
551     # TODO, use tar.
552     python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
553     if env['WITH_OSX_STATICPYTHON']:
554         print("unzipping to app-bundle: %s"%(python_zip))
555     else:
556         print("dynamic build - make sure to have python3.x-framework installed")
557     bldroot = env.Dir('.').abspath
558     binary = env['BINARYKIND']
559      
560     sourcedir = bldroot + '/source/darwin/%s.app'%binary
561     sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
562     targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
563     cmd = installdir + '/' +'%s.app'%binary
564     
565     if os.path.isdir(cmd):
566         shutil.rmtree(cmd)
567     shutil.copytree(sourcedir, cmd)
568     cmd = "cat %s | sed s/\$\{MACOSX_BUNDLE_SHORT_VERSION_STRING\}/%s/ | "%(sourceinfo,VERSION)
569     cmd += "sed s/\$\{MACOSX_BUNDLE_LONG_VERSION_STRING\}/%s,\ %s/g > %s"%(VERSION,time.strftime("%Y-%b-%d"),targetinfo)
570     commands.getoutput(cmd)
571     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
572     commands.getoutput(cmd)
573     cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/'%(installdir, binary, VERSION)
574     commands.getoutput(cmd)
575     cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
576
577     # blenderplayer doesn't need all the files
578     if binary == 'blender':
579         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/datafiles'%(installdir, binary, VERSION)
580         commands.getoutput(cmd)
581         cmd = 'cp -R %s/release/datafiles/locale %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
582         commands.getoutput(cmd)
583         cmd = 'cp -R %s/release/datafiles/fonts %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
584         commands.getoutput(cmd)
585         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
586         commands.getoutput(cmd)
587
588         if VERSION_RELEASE_CYCLE == "release":
589             cmd = 'rm -rf %s/%s.app/Contents/MacOS/%s/scripts/addons_contrib'%(installdir,binary,VERSION)
590             commands.getoutput(cmd)
591
592         if env['WITH_BF_CYCLES']:
593             croot = '%s/intern/cycles' % (bldroot)
594             cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
595
596             cmd = 'mkdir %s' % (cinstalldir)
597             commands.getoutput(cmd)
598             cmd = 'mkdir %s/kernel' % (cinstalldir)
599             commands.getoutput(cmd)
600             cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
601             commands.getoutput(cmd)
602             cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
603             commands.getoutput(cmd)
604             cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
605             commands.getoutput(cmd)
606             cmd = 'cp -R %s/kernel/svm %s/util/util_color.h %s/util/util_math.h %s/util/util_transform.h %s/util/util_types.h %s/kernel/' % (croot, croot, croot, croot, croot, cinstalldir)
607             commands.getoutput(cmd)
608
609     if env['WITH_OSX_STATICPYTHON']:
610         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
611         commands.getoutput(cmd)
612         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
613         commands.getoutput(cmd)
614
615     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
616     commands.getoutput(cmd)
617     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
618     commands.getoutput(cmd)
619     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
620     commands.getoutput(cmd)
621     cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
622     commands.getoutput(cmd)
623     if env['CC'].endswith('4.6.1'): # for correct errorhandling with gcc 4.6.1 we need the gcc.dylib to link, thus distribute in app-bundle
624         cmd = 'mkdir %s/%s.app/Contents/MacOS/lib'%(installdir, binary)
625         commands.getoutput(cmd)
626         instname = env['BF_CXX']
627         cmd = 'cp %s/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/'%(instname, installdir, binary)
628         commands.getoutput(cmd)
629         cmd = 'install_name_tool -id @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/libgcc_s.1.dylib'%(installdir, binary)
630         commands.getoutput(cmd)
631         cmd = 'install_name_tool -change %s/lib/libgcc_s.1.dylib  @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/%s'%(instname, installdir, binary, binary)
632         commands.getoutput(cmd)
633         cmd = 'rm -rf  %s/set_simulation_threads.app'%(installdir) # first clear omp_num_threads applescript
634         commands.getoutput(cmd)
635         cmd = 'cp -R %s/source/darwin/set_simulation_threads.app %s/'%(bldroot, installdir) # copy the omp_num_threads applescript
636         commands.getoutput(cmd)
637
638 # extract copy system python, be sure to update other build systems
639 # when making changes to the files that are copied.
640 def my_unixpybundle_print(target, source, env):
641     pass
642
643 def UnixPyBundle(target=None, source=None, env=None):
644     # Any Unix except osx
645     #-- VERSION/python/lib/python3.1
646     
647     import commands
648     
649     def run(cmd):
650         print 'Install command:', cmd
651         commands.getoutput(cmd)
652
653     dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
654
655     py_src =    env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
656     py_target =    env.subst( dir + '/python/lib/python'+env['BF_PYTHON_VERSION'] )
657     
658     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
659     if os.path.exists(py_target):
660         print 'Using existing python from:'
661         print '\t"%s"' %            py_target
662         print '\t(skipping copy)\n'
663         return
664
665     # Copied from source/creator/CMakeLists.txt, keep in sync.
666     print 'Install python from:'
667     print '\t"%s" into...' % py_src
668     print '\t"%s"\n' % py_target
669
670     run("rm -rf '%s'" % py_target)
671     try:
672         os.makedirs(os.path.dirname(py_target)) # the final part is copied
673     except:
674         pass
675
676     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
677     run("rm -rf '%s/distutils'" % py_target)
678     run("rm -rf '%s/lib2to3'" % py_target)
679     run("rm -rf '%s/config'" % py_target)
680
681     for f in os.listdir(py_target):
682         if f.startswith("config-"):
683             run("rm -rf '%s/%s'" % (py_target, f))
684
685     run("rm -rf '%s/site-packages'" % py_target)
686     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
687     run("rm -rf '%s/idlelib'" % py_target)
688     run("rm -rf '%s/tkinter'" % py_target)
689     run("rm -rf '%s/turtledemo'" % py_target)
690     run("rm -r '%s/turtle.py'" % py_target)
691     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
692
693     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
694     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
695     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
696     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
697     
698
699 #### END ACTION STUFF #########
700
701 def bsc(env, target, source):
702     
703     bd = os.path.dirname(target[0].abspath)
704     bscfile = '\"'+target[0].abspath+'\"'
705     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
706     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
707
708     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
709
710     myfile = open(bscpathtmp[1:-1], 'r')
711     lines = myfile.readlines()
712     myfile.close()
713
714     newfile = open(bscpathtmp[1:-1], 'w')
715     for l in lines:
716         newfile.write('\"'+l[:-1]+'\"\n')
717     newfile.close()
718                 
719     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
720     os.system('del '+bscpathtmp)
721
722 class BlenderEnvironment(SConsEnvironment):
723
724     PyBundleActionAdded = False
725
726     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
727         global libs
728         if not self or not libname or not source:
729             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
730             self.Exit()
731         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc'):
732             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
733             self.Exit()
734         
735         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
736         lenv = self.Clone()
737         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
738             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
739         else:
740             res = lenv.RES(root_build_dir+'lib/'+libname, source)
741
742         
743         SConsEnvironment.Default(self, res)
744         resources.append(res)
745
746     def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None, cc_compileflags=None, cxx_compileflags=None, cc_compilerchange=None, cxx_compilerchange=None):
747         global vcp
748         if not self or not libname or not sources:
749             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
750             self.Exit()
751
752         def list_substring(quickie, libname):
753             for q in quickie:
754                 if libname.find(q) != -1:
755                     return True
756             return False
757
758         if list_substring(quickie, libname) or len(quickie)==0:
759             if list_substring(quickdebug, libname):
760                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
761             else:
762                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
763             lenv = self.Clone()
764             lenv.Append(CPPPATH=includes)
765             lenv.Append(CPPDEFINES=defines)
766             if lenv['BF_DEBUG'] or (libname in quickdebug):
767                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
768                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
769                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
770             else:
771                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
772                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
773                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
774             if lenv['BF_PROFILE']:
775                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
776                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
777                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
778             if compileflags:
779                 lenv.Replace(CFLAGS = compileflags)
780             if cc_compileflags:
781                 lenv.Replace(CCFLAGS = cc_compileflags)
782             if cxx_compileflags:
783                 lenv.Replace(CXXFLAGS = cxx_compileflags)
784             if cc_compilerchange:
785                 lenv.Replace(CC = cc_compilerchange)
786             if cxx_compilerchange:
787                 lenv.Replace(CXX = cxx_compilerchange)
788             lenv.Append(CFLAGS = lenv['C_WARN'])
789             lenv.Append(CCFLAGS = lenv['CC_WARN'])
790             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
791
792             if lenv['OURPLATFORM'] == 'win64-vc':
793                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
794
795             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
796                 if lenv['BF_DEBUG']:
797                     lenv.Append(CCFLAGS = ['/MTd'])
798                 else:
799                     lenv.Append(CCFLAGS = ['/MT'])
800             
801             targetdir = root_build_dir+'lib/' + libname
802             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
803                 targetdir = '#'+targetdir
804             lib = lenv.Library(target= targetdir, source=sources)
805             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
806             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
807                 #if targetdir[0] == '#':
808                 #    targetdir = targetdir[1:-1]
809                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
810                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
811                          srcs = sources,
812                          buildtarget = lib,
813                          variant = 'Release',
814                          auto_build_solution=0)
815                 vcp.append(vcproject)
816                 SConsEnvironment.Default(self, vcproject)
817         else:
818             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
819         # note: libs is a global
820         add_lib_to_dict(self, libs, libtype, libname, priority)
821
822     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
823         global vcp
824         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
825         lenv = self.Clone()
826         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
827         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
828             if lenv['BF_DEBUG']:
829                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
830         if  lenv['OURPLATFORM']=='linux':
831             if lenv['WITH_BF_PYTHON']:
832                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
833         if  lenv['OURPLATFORM']=='sunos5':
834             if lenv['WITH_BF_PYTHON']:
835                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
836             if lenv['CXX'].endswith('CC'):
837                 lenv.Replace(LINK = '$CXX')
838         if  lenv['OURPLATFORM']=='darwin':
839             if lenv['WITH_BF_PYTHON']:
840                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
841             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
842         if lenv['BF_PROFILE']:
843             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
844         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
845             lenv.Append(LIBPATH=root_build_dir + '/lib')
846         lenv.Append(LIBPATH=libpath)
847         lenv.Append(LIBS=libs)
848         if lenv['WITH_BF_QUICKTIME']:
849             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
850             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
851         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
852         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
853             f = lenv.File(progname + '.bsc', builddir)
854             brs = lenv.Command(f, prog, [bsc])
855             SConsEnvironment.Default(self, brs)
856         SConsEnvironment.Default(self, prog)
857         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
858             print "! ",builddir + "/" + progname + '.sln'
859             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
860                      projects= vcp,
861                      variant = 'Release')
862             SConsEnvironment.Default(self, sln)
863         program_list.append(prog)
864         if  lenv['OURPLATFORM']=='darwin':
865             lenv['BINARYKIND'] = binarykind
866             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
867         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
868             if lenv['WITH_BF_PYTHON']:
869                 if not lenv['WITHOUT_BF_INSTALL'] and not lenv['WITHOUT_BF_PYTHON_INSTALL'] and not BlenderEnvironment.PyBundleActionAdded:
870                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
871                     BlenderEnvironment.PyBundleActionAdded = True
872         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
873             if lenv['WITH_BF_PYTHON']:
874                 if not lenv['WITHOUT_BF_PYTHON_INSTALL'] and not BlenderEnvironment.PyBundleActionAdded:
875                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
876                     BlenderEnvironment.PyBundleActionAdded = True
877         return prog
878
879     def Glob(lenv, pattern):
880         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
881         files = []
882         for i in glob.glob(path + pattern):
883             files.append(string.replace(i, path, ''))
884         return files