quiet all -Wshadow warnings in the compositor.
[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     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
697     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
698     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
699     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
700     
701
702 #### END ACTION STUFF #########
703
704 def bsc(env, target, source):
705     
706     bd = os.path.dirname(target[0].abspath)
707     bscfile = '\"'+target[0].abspath+'\"'
708     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
709     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
710
711     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
712
713     myfile = open(bscpathtmp[1:-1], 'r')
714     lines = myfile.readlines()
715     myfile.close()
716
717     newfile = open(bscpathtmp[1:-1], 'w')
718     for l in lines:
719         newfile.write('\"'+l[:-1]+'\"\n')
720     newfile.close()
721                 
722     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
723     os.system('del '+bscpathtmp)
724
725 class BlenderEnvironment(SConsEnvironment):
726
727     PyBundleActionAdded = False
728
729     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
730         global libs
731         if not self or not libname or not source:
732             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
733             self.Exit()
734         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
735             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
736             self.Exit()
737         
738         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
739         lenv = self.Clone()
740         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
741             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
742         else:
743             res = lenv.RES(root_build_dir+'lib/'+libname, source)
744
745         
746         SConsEnvironment.Default(self, res)
747         resources.append(res)
748
749     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):
750         global vcp
751         if not self or not libname or not sources:
752             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
753             self.Exit()
754
755         def list_substring(quickie, libname):
756             for q in quickie:
757                 if libname.find(q) != -1:
758                     return True
759             return False
760
761         if list_substring(quickie, libname) or len(quickie)==0:
762             if list_substring(quickdebug, libname):
763                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
764             else:
765                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
766             lenv = self.Clone()
767             lenv.Append(CPPPATH=includes)
768             lenv.Append(CPPDEFINES=defines)
769             if lenv['BF_DEBUG'] or (libname in quickdebug):
770                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
771                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
772                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
773             else:
774                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
775                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
776                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
777             if lenv['BF_PROFILE']:
778                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
779                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
780                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
781             if compileflags:
782                 lenv.Replace(CFLAGS = compileflags)
783             if cc_compileflags:
784                 lenv.Replace(CCFLAGS = cc_compileflags)
785             if cxx_compileflags:
786                 lenv.Replace(CXXFLAGS = cxx_compileflags)
787             if cc_compilerchange:
788                 lenv.Replace(CC = cc_compilerchange)
789             if cxx_compilerchange:
790                 lenv.Replace(CXX = cxx_compilerchange)
791             lenv.Append(CFLAGS = lenv['C_WARN'])
792             lenv.Append(CCFLAGS = lenv['CC_WARN'])
793             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
794
795             if lenv['OURPLATFORM'] == 'win64-vc':
796                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
797
798             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
799                 if lenv['BF_DEBUG']:
800                     lenv.Append(CCFLAGS = ['/MTd'])
801                 else:
802                     lenv.Append(CCFLAGS = ['/MT'])
803             
804             targetdir = root_build_dir+'lib/' + libname
805             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
806                 targetdir = '#'+targetdir
807             lib = lenv.Library(target= targetdir, source=sources)
808             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
809             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
810                 #if targetdir[0] == '#':
811                 #    targetdir = targetdir[1:-1]
812                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
813                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
814                          srcs = sources,
815                          buildtarget = lib,
816                          variant = 'Release',
817                          auto_build_solution=0)
818                 vcp.append(vcproject)
819                 SConsEnvironment.Default(self, vcproject)
820         else:
821             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
822         # note: libs is a global
823         add_lib_to_dict(self, libs, libtype, libname, priority)
824
825     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
826         global vcp
827         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
828         lenv = self.Clone()
829         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
830         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
831             if lenv['BF_DEBUG']:
832                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
833         if  lenv['OURPLATFORM']=='linux':
834             if lenv['WITH_BF_PYTHON']:
835                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
836         if  lenv['OURPLATFORM']=='sunos5':
837             if lenv['WITH_BF_PYTHON']:
838                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
839             if lenv['CXX'].endswith('CC'):
840                 lenv.Replace(LINK = '$CXX')
841         if  lenv['OURPLATFORM']=='darwin':
842             if lenv['WITH_BF_PYTHON']:
843                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
844             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
845         if lenv['BF_PROFILE']:
846             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
847         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
848             lenv.Append(LIBPATH=root_build_dir + '/lib')
849         lenv.Append(LIBPATH=libpath)
850         lenv.Append(LIBS=libs)
851         if lenv['WITH_BF_QUICKTIME']:
852             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
853             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
854         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
855         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
856             f = lenv.File(progname + '.bsc', builddir)
857             brs = lenv.Command(f, prog, [bsc])
858             SConsEnvironment.Default(self, brs)
859         SConsEnvironment.Default(self, prog)
860         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
861             print "! ",builddir + "/" + progname + '.sln'
862             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
863                      projects= vcp,
864                      variant = 'Release')
865             SConsEnvironment.Default(self, sln)
866         program_list.append(prog)
867         if  lenv['OURPLATFORM']=='darwin':
868             lenv['BINARYKIND'] = binarykind
869             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
870         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
871             if lenv['WITH_BF_PYTHON']:
872                 if (not lenv['WITHOUT_BF_INSTALL'] and 
873                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
874                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
875                     not BlenderEnvironment.PyBundleActionAdded):
876                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
877                     BlenderEnvironment.PyBundleActionAdded = True
878         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
879             if lenv['WITH_BF_PYTHON']:
880                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
881                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
882                     not BlenderEnvironment.PyBundleActionAdded):
883                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
884                     BlenderEnvironment.PyBundleActionAdded = True
885         return prog
886
887     def Glob(lenv, pattern):
888         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
889         files = []
890         for i in glob.glob(path + pattern):
891             files.append(string.replace(i, path, ''))
892         return files