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