ee35586814dc69ceedbd181d507495982020996c
[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 string
19 import ctypes as ct
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.Subst
33 import SCons.Tool
34 import bcolors
35 bc = bcolors.bcolors()
36 import btools
37 VERSION = btools.VERSION
38 VERSION_RELEASE_CYCLE = btools.VERSION_RELEASE_CYCLE
39
40 Split = SCons.Util.Split
41 Action = SCons.Action.Action
42 Builder = SCons.Builder.Builder
43 GetBuildPath = SConsEnvironment.GetBuildPath
44
45 # a few globals
46 root_build_dir = ''
47 doc_build_dir = ''
48 quickie = None # Anything else than None if BF_QUICK has been passed
49 quicklist = [] # The list of libraries/programs to compile during a quickie
50 program_list = [] # A list holding Nodes to final binaries, used to create installs
51 arguments = None
52 targets = None
53 resources = []
54 allowed_bitnesses = {4 : 32, 8 : 64} # only expecting 32-bit or 64-bit
55 bitness = allowed_bitnesses[ct.sizeof(ct.c_void_p)]
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     if lenv['WITH_BF_STATICJPEG']:
139         statlibs += Split(lenv['BF_JPEG_LIB_STATIC'])
140     if lenv['WITH_BF_STATICPNG']:
141         statlibs += Split(lenv['BF_PNG_LIB_STATIC'])
142
143     libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
144     if lenv['WITH_BF_PYTHON']:
145         libincs += Split(lenv['BF_PYTHON_LIBPATH'])
146     if lenv['WITH_BF_SDL']:
147         libincs += Split(lenv['BF_SDL_LIBPATH'])
148     if lenv['WITH_BF_JACK'] and not lenv['WITH_BF_JACK_DYNLOAD']:
149         libincs += Split(lenv['BF_JACK_LIBPATH'])
150     if lenv['WITH_BF_SNDFILE']:
151         libincs += Split(lenv['BF_SNDFILE_LIBPATH'])
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_FFTW3']:
157         libincs += Split(lenv['BF_FFTW3_LIBPATH'])
158         if lenv['WITH_BF_STATICFFTW3']:
159             statlibs += Split(lenv['BF_FFTW3_LIB_STATIC'])
160     '''
161     if lenv['WITH_BF_ELTOPO']:
162         libincs += Split(lenv['BF_LAPACK_LIBPATH'])
163         if lenv['WITH_BF_STATICLAPACK']:
164             statlibs += Split(lenv['BF_LAPACK_LIB_STATIC'])
165     '''
166     if lenv['WITH_BF_FFMPEG'] and lenv['WITH_BF_STATICFFMPEG']:
167         statlibs += Split(lenv['BF_FFMPEG_LIB_STATIC'])
168     if lenv['WITH_BF_INTERNATIONAL']:
169         if lenv['WITH_BF_FREETYPE_STATIC']:
170             statlibs += Split(lenv['BF_FREETYPE_LIB_STATIC'])
171     if lenv['WITH_BF_OPENAL']:
172         libincs += Split(lenv['BF_OPENAL_LIBPATH'])
173         if lenv['WITH_BF_STATICOPENAL']:
174             statlibs += Split(lenv['BF_OPENAL_LIB_STATIC'])
175     if lenv['WITH_BF_STATICOPENGL']:
176         statlibs += Split(lenv['BF_OPENGL_LIB_STATIC'])
177     if lenv['WITH_BF_STATICCXX']:
178         statlibs += Split(lenv['BF_CXX_LIB_STATIC'])
179
180     if lenv['WITH_BF_PYTHON'] and lenv['WITH_BF_STATICPYTHON']:
181         statlibs += Split(lenv['BF_PYTHON_LIB_STATIC'])
182
183     if lenv['WITH_BF_SNDFILE'] and lenv['WITH_BF_STATICSNDFILE']:
184         statlibs += Split(lenv['BF_SNDFILE_LIB_STATIC'])
185
186     if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
187         libincs += Split(lenv['BF_PTHREADS_LIBPATH'])
188
189     if lenv['WITH_BF_COLLADA']:
190         libincs += Split(lenv['BF_OPENCOLLADA_LIBPATH'])
191         if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
192             libincs += Split(lenv['BF_PCRE_LIBPATH'])
193             libincs += Split(lenv['BF_EXPAT_LIBPATH'])
194         if lenv['WITH_BF_STATICOPENCOLLADA']:
195             statlibs += Split(lenv['BF_OPENCOLLADA_LIB_STATIC'])
196
197     if lenv['WITH_BF_OPENMP']:
198         if lenv['OURPLATFORM'] == 'linuxcross':
199             libincs += Split(lenv['BF_OPENMP_LIBPATH'])
200         if lenv['WITH_BF_STATICOPENMP']:
201             statlibs += Split(lenv['BF_OPENMP_LIB_STATIC'])
202             
203     if lenv['WITH_BF_OIIO']:
204         libincs += Split(lenv['BF_OIIO_LIBPATH'])
205         if lenv['WITH_BF_STATICOIIO']:
206             statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
207     if lenv['WITH_BF_OPENEXR']:
208         libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
209         if lenv['WITH_BF_STATICOPENEXR']:
210             statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
211     if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']:
212         statlibs += Split(lenv['BF_ZLIB_LIB_STATIC'])
213
214     if lenv['WITH_BF_OCIO']:
215         libincs += Split(lenv['BF_OCIO_LIBPATH'])
216         if lenv['WITH_BF_STATICOCIO']:
217             statlibs += Split(lenv['BF_OCIO_LIB_STATIC'])
218
219     if lenv['WITH_BF_BOOST']:
220         libincs += Split(lenv['BF_BOOST_LIBPATH'])
221         if lenv['WITH_BF_STATICBOOST']:
222             statlibs += Split(lenv['BF_BOOST_LIB_STATIC'])
223
224     if lenv['WITH_BF_CYCLES_OSL']:
225         libincs += Split(lenv['BF_OSL_LIBPATH'])
226         if lenv['WITH_BF_STATICOSL']:
227             statlibs += Split(lenv['BF_OSL_LIB_STATIC'])
228
229     if lenv['WITH_BF_LLVM']:
230         libincs += Split(lenv['BF_LLVM_LIBPATH'])
231         if lenv['WITH_BF_STATICLLVM']:
232             statlibs += Split(lenv['BF_LLVM_LIB_STATIC'])
233
234     if lenv['WITH_BF_JEMALLOC']:
235         libincs += Split(lenv['BF_JEMALLOC_LIBPATH'])
236         if lenv['WITH_BF_STATICJEMALLOC']:
237             statlibs += Split(lenv['BF_JEMALLOC_LIB_STATIC'])
238
239     if lenv['OURPLATFORM']=='linux':
240         if lenv['WITH_BF_3DMOUSE']:
241             libincs += Split(lenv['BF_3DMOUSE_LIBPATH'])
242             if lenv['WITH_BF_STATIC3DMOUSE']:
243                 statlibs += Split(lenv['BF_3DMOUSE_LIB_STATIC'])
244
245     # setting this last so any overriding of manually libs could be handled
246     if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross', 'win64-mingw'):
247         # We must remove any previous items defining this path, for same reason stated above!
248         libincs = [e for e in libincs if SCons.Subst.scons_subst(e, lenv, gvars=lenv.Dictionary()) != "/usr/lib"]
249         libincs.append('/usr/lib')
250
251     return statlibs, libincs
252
253 def setup_syslibs(lenv):
254     syslibs = []
255
256     if not lenv['WITH_BF_FREETYPE_STATIC']:
257         syslibs += Split(lenv['BF_FREETYPE_LIB'])
258     if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']:
259         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw', 'win64-mingw'):
260             syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
261         else:
262             syslibs.append(lenv['BF_PYTHON_LIB'])
263     if lenv['WITH_BF_OPENAL']:
264         if not lenv['WITH_BF_STATICOPENAL']:
265             syslibs += Split(lenv['BF_OPENAL_LIB'])
266     if lenv['WITH_BF_OPENMP'] and lenv['CC'] != 'icc' and lenv['C_COMPILER_ID'] != 'clang' and not lenv['WITH_BF_STATICOPENMP']:
267         if lenv['CC'] == 'cl.exe':
268             syslibs += ['vcomp']
269         else:
270             syslibs += ['gomp']
271     if lenv['WITH_BF_ICONV']:
272         syslibs += Split(lenv['BF_ICONV_LIB'])
273     if lenv['WITH_BF_OIIO']:
274         if not lenv['WITH_BF_STATICOIIO']:
275             syslibs += Split(lenv['BF_OIIO_LIB'])
276
277     if lenv['WITH_BF_OCIO']:
278         if not lenv['WITH_BF_STATICOCIO']:
279             syslibs += Split(lenv['BF_OCIO_LIB'])
280
281     if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
282         syslibs += Split(lenv['BF_OPENEXR_LIB'])
283     if lenv['WITH_BF_ZLIB'] and not lenv['WITH_BF_STATICZLIB']:
284         syslibs += Split(lenv['BF_ZLIB_LIB'])
285     if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
286         syslibs += Split(lenv['BF_TIFF_LIB'])
287     if lenv['WITH_BF_FFMPEG'] and not lenv['WITH_BF_STATICFFMPEG']:
288         syslibs += Split(lenv['BF_FFMPEG_LIB'])
289         if lenv['WITH_BF_OGG']:
290             syslibs += Split(lenv['BF_OGG_LIB'])
291     if lenv['WITH_BF_JACK'] and not lenv['WITH_BF_JACK_DYNLOAD']:
292         syslibs += Split(lenv['BF_JACK_LIB'])
293     if lenv['WITH_BF_SNDFILE'] and not lenv['WITH_BF_STATICSNDFILE']:
294         syslibs += Split(lenv['BF_SNDFILE_LIB'])
295     if lenv['WITH_BF_FFTW3'] and not lenv['WITH_BF_STATICFFTW3']:
296         syslibs += Split(lenv['BF_FFTW3_LIB'])
297     '''
298     if lenv['WITH_BF_ELTOPO']:
299         syslibs += Split(lenv['BF_LAPACK_LIB'])
300     '''
301     if lenv['WITH_BF_SDL']:
302         syslibs += Split(lenv['BF_SDL_LIB'])
303     if not lenv['WITH_BF_STATICOPENGL']:
304         syslibs += Split(lenv['BF_OPENGL_LIB'])
305     if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
306         syslibs += Split(lenv['BF_PTHREADS_LIB'])
307     if lenv['WITH_BF_COLLADA'] and not lenv['WITH_BF_STATICOPENCOLLADA']:
308         syslibs.append(lenv['BF_PCRE_LIB'])
309         if lenv['BF_DEBUG'] and (lenv['OURPLATFORM'] != 'linux'):
310             syslibs += [colladalib+'_d' for colladalib in Split(lenv['BF_OPENCOLLADA_LIB'])]
311         else:
312             syslibs += Split(lenv['BF_OPENCOLLADA_LIB'])
313         syslibs.append(lenv['BF_EXPAT_LIB'])
314
315     if lenv['WITH_BF_JEMALLOC']:
316         if not lenv['WITH_BF_STATICJEMALLOC']:
317             syslibs += Split(lenv['BF_JEMALLOC_LIB'])
318
319     if lenv['OURPLATFORM']=='linux':
320         if lenv['WITH_BF_3DMOUSE']:
321             if not lenv['WITH_BF_STATIC3DMOUSE']:
322                 syslibs += Split(lenv['BF_3DMOUSE_LIB'])
323                 
324     if lenv['WITH_BF_BOOST'] and not lenv['WITH_BF_STATICBOOST']:
325         syslibs += Split(lenv['BF_BOOST_LIB'])
326         
327         if lenv['WITH_BF_INTERNATIONAL']:
328             syslibs += Split(lenv['BF_BOOST_LIB_INTERNATIONAL'])
329
330     if lenv['WITH_BF_CYCLES_OSL'] and not lenv['WITH_BF_STATICOSL']:
331         syslibs += Split(lenv['BF_OSL_LIB'])
332
333     if lenv['WITH_BF_LLVM'] and not lenv['WITH_BF_STATICLLVM']:
334         syslibs += Split(lenv['BF_LLVM_LIB'])
335
336     if not lenv['WITH_BF_STATICJPEG']:
337         syslibs += Split(lenv['BF_JPEG_LIB'])
338
339     if not lenv['WITH_BF_STATICPNG']:
340         syslibs += Split(lenv['BF_PNG_LIB'])
341
342     syslibs += lenv['LLIBS']
343
344     return syslibs
345
346 def propose_priorities():
347     print bc.OKBLUE+"Priorities:"+bc.ENDC
348     for t in possible_types:
349         print bc.OKGREEN+"\t"+t+bc.ENDC
350         new_priority = 0
351         curlib = libs[t]
352         sortlist = curlib.keys()
353         sortlist.sort()
354
355         for sk in sortlist:
356             v = curlib[sk]
357             #for p,v in sorted(libs[t].iteritems()):
358             print "\t\t",new_priority, v
359             new_priority += 5
360
361 # emits the necessary file objects for creator.c, to be used in creating
362 # the final blender executable
363 def creator(env):
364     sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
365
366     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']]
367
368     defs = []
369
370     if env['WITH_BF_BINRELOC']:
371         incs.append('#/extern/binreloc/include')
372         defs.append('WITH_BINRELOC')
373
374     if env['WITH_BF_SDL']:
375         defs.append('WITH_SDL')
376
377     if env['WITH_BF_LIBMV']:
378         incs.append('#/extern/libmv')
379         defs.append('WITH_LIBMV')
380
381     if env['WITH_BF_FFMPEG']:
382         defs.append('WITH_FFMPEG')
383
384     if env['WITH_BF_PYTHON']:
385         incs.append('#/source/blender/python')
386         defs.append('WITH_PYTHON')
387         if env['BF_DEBUG']:
388             defs.append('_DEBUG')
389
390     if env['WITH_BF_FREESTYLE']:
391         incs.append('#/source/blender/freestyle')
392         defs.append('WITH_FREESTYLE')
393
394     if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
395         incs.append(env['BF_PTHREADS_INC'])
396         incs.append('#/intern/utfconv')
397
398     env.Append(CPPDEFINES=defs)
399     env.Append(CPPPATH=incs)
400     obj = [env.Object(root_build_dir+'source/creator/creator/creator', ['#source/creator/creator.c'])]
401
402     return obj
403
404 ## TODO: see if this can be made in an emitter
405 def buildinfo(lenv, build_type):
406     """
407     Generate a buildinfo object
408     """
409     build_date = time.strftime ("%Y-%m-%d")
410     build_time = time.strftime ("%H:%M:%S")
411
412     if os.path.isdir(os.path.abspath('.git')):
413         build_commit_timestamp = os.popen('git log -1 --format=%ct').read().strip()
414         if not build_commit_timestamp:
415             # Git command not found
416             build_hash = 'unknown'
417             build_commit_timestamp = '0'
418             build_branch = 'unknown'
419         else:
420             import subprocess
421             no_upstream = False
422
423             process = subprocess.Popen(['git', 'rev-parse', '--short', '@{u}'],
424                                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
425             build_hash, stderr = process.communicate()
426             build_hash = build_hash.strip()
427             build_branch = os.popen('git rev-parse --abbrev-ref HEAD').read().strip()
428
429             if build_branch == 'HEAD':
430                 master_check = os.popen('git branch --list master --contains ' + build_hash).read().strip()
431                 if master_check == 'master':
432                     build_branch = 'master'
433                 else:
434                     head_hash = os.popen('git rev-parse HEAD').read().strip()
435                     tag_hashes = os.popen('git show-ref --tags -d').read()
436                     if tag_hashes.find(head_hash) != -1:
437                         build_branch = 'master'
438
439             if build_hash == '':
440                 build_hash = os.popen('git rev-parse --short HEAD').read().strip()
441                 no_upstream = True
442             else:
443                 older_commits = os.popen('git log --oneline HEAD..@{u}').read().strip()
444                 if older_commits:
445                     build_hash = os.popen('git rev-parse --short HEAD').read().strip()
446
447             # ## Check for local modifications
448             has_local_changes = False
449
450             # Update GIT index before getting dirty files
451             os.system('git update-index -q --refresh')
452             changed_files = os.popen('git diff-index --name-only HEAD --').read().strip()
453
454             if changed_files:
455                 has_local_changes = True
456             elif no_upstream == False:
457                 unpushed_log = os.popen('git log --oneline @{u}..').read().strip()
458                 has_local_changes = unpushed_log != ''
459
460             if build_branch.startswith('blender-v'):
461                 build_branch = 'master'
462
463             if has_local_changes:
464                 build_branch += ' (modified)'
465     else:
466         build_hash = 'unknown'
467         build_commit_timestamp = '0'
468         build_branch = 'unknown'
469
470     if lenv['BF_DEBUG']:
471         build_type = "Debug"
472         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['BF_DEBUG_CCFLAGS'] + lenv['CPPFLAGS'])
473         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['CPPFLAGS'])
474     else:
475         build_type = "Release"
476         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['REL_CFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
477         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['REL_CXXFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
478
479     build_linkflags = ' '.join(lenv['PLATFORM_LINKFLAGS'])
480
481     obj = []
482     if lenv['BF_BUILDINFO']:
483         lenv.Append (CPPDEFINES = ['BUILD_TIME=\\"%s\\"'%(build_time),
484                                     'BUILD_DATE=\\"%s\\"'%(build_date),
485                                     'BUILD_TYPE=\\"%s\\"'%(build_type),
486                                     'BUILD_HASH=\\"%s\\"'%(build_hash),
487                                     'BUILD_COMMIT_TIMESTAMP=%s'%(build_commit_timestamp),
488                                     'BUILD_BRANCH=\\"%s\\"'%(build_branch),
489                                     'WITH_BUILDINFO',
490                                     'BUILD_PLATFORM=\\"%s:%s\\"'%(platform.system(), platform.architecture()[0]),
491                                     'BUILD_CFLAGS=\\"%s\\"'%(build_cflags),
492                                     'BUILD_CXXFLAGS=\\"%s\\"'%(build_cxxflags),
493                                     'BUILD_LINKFLAGS=\\"%s\\"'%(build_linkflags),
494                                     'BUILD_SYSTEM=\\"SCons\\"'
495                     ])
496
497         lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel'])
498
499         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, ['#source/creator/buildinfo.c'])]
500
501     return obj
502
503 ##### END LIB STUFF ############
504
505 ##### ACTION STUFF #############
506
507 def my_print_cmd_line(self, s, target, source, env):
508     sys.stdout.write(' ' * 70 + '\r')
509     sys.stdout.flush()
510     sys.stdout.write(s + "\r")
511     sys.stdout.flush()
512
513 def my_compile_print(target, source, env):
514     a = '%s' % (source[0])
515     d, f = os.path.split(a)
516     return bc.OKBLUE + "Compiling" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
517
518 def my_moc_print(target, source, env):
519     a = '%s' % (source[0])
520     d, f = os.path.split(a)
521     return bc.OKBLUE + "Creating MOC" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
522
523 def my_linking_print(target, source, env):
524     t = '%s' % (target[0])
525     d, f = os.path.split(t)
526     return bc.OKBLUE + "Linking library" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
527
528 def my_program_print(target, source, env):
529     t = '%s' % (target[0])
530     d, f = os.path.split(t)
531     return bc.OKBLUE + "Linking program" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
532
533 def msvc_hack(env):
534     static_lib = SCons.Tool.createStaticLibBuilder(env)
535     program = SCons.Tool.createProgBuilder(env)
536     
537     env['BUILDERS']['Library'] = static_lib
538     env['BUILDERS']['StaticLibrary'] = static_lib
539     env['BUILDERS']['Program'] = program
540         
541 def set_quiet_output(env):
542     mycaction = Action("$CCCOM", strfunction=my_compile_print)
543     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
544     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
545     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
546     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
547     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
548
549     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
550     static_ob.add_action('.c', mycaction)
551     static_ob.add_action('.cpp', mycppaction)
552     static_ob.add_action('.cc', mycppaction)
553     shared_ob.add_action('.c', myshcaction)
554     shared_ob.add_action('.cc', myshcppaction)
555
556     static_lib = SCons.Builder.Builder(action = mylibaction,
557                                        emitter = '$LIBEMITTER',
558                                        prefix = '$LIBPREFIX',
559                                        suffix = '$LIBSUFFIX',
560                                        src_suffix = '$OBJSUFFIX',
561                                        src_builder = 'StaticObject')
562
563     program = SCons.Builder.Builder(action = mylinkaction,
564                                     emitter = '$PROGEMITTER',
565                                     prefix = '$PROGPREFIX',
566                                     suffix = '$PROGSUFFIX',
567                                     src_suffix = '$OBJSUFFIX',
568                                     src_builder = 'Object',
569                                     target_scanner = SCons.Defaults.ProgScan)
570
571     env['BUILDERS']['Object'] = static_ob
572     env['BUILDERS']['StaticObject'] = static_ob
573     env['BUILDERS']['StaticLibrary'] = static_lib
574     env['BUILDERS']['Library'] = static_lib
575     env['BUILDERS']['Program'] = program
576     if env['BF_LINE_OVERWRITE']:
577         SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
578
579 def untar_pybundle(from_tar,to_dir,exclude_re):
580     tar= tarfile.open(from_tar, mode='r')
581     exclude_re= list(exclude_re) #single re object or list of re objects
582     debug= 0 #list files instead of unpacking
583     good= []
584     if debug: print '\nFiles not being unpacked:\n'
585     for name in tar.getnames():
586         is_bad= 0
587         for r in exclude_re:
588             if r.match(name):
589                 is_bad=1
590                 if debug: print name
591                 break
592         if not is_bad:
593             good.append(tar.getmember(name))
594     if debug:
595         print '\nFiles being unpacked:\n'
596         for g in good:
597             print g
598     else:
599         tar.extractall(to_dir, good)
600
601 def my_winpybundle_print(target, source, env):
602     pass
603
604 def WinPyBundle(target=None, source=None, env=None):
605     import re
606     py_tar = env.subst(env['LCGDIR']).lstrip("#")
607     if env['BF_DEBUG']:
608         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.tar.gz'
609     else:
610         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
611
612     py_target = env.subst(env['BF_INSTALLDIR']).lstrip("#")
613     py_target = os.path.join(py_target, VERSION, 'python', 'lib')
614     def printexception(func,path,ex):
615         if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
616             print str(func) + ' failed on ' + str(path)
617     print "Trying to remove existing py bundle."
618     shutil.rmtree(py_target, False, printexception)
619     exclude_re=[re.compile('.*/test'),
620                 re.compile('^test'),
621                 re.compile('^distutils'),
622                 re.compile('^idlelib'),
623                 re.compile('^lib2to3'),
624                 re.compile('^tkinter'),
625                 re.compile('^_tkinter_d.pyd'),
626                 re.compile('^turtledemo'),
627                 re.compile('^turtle.py'),
628                 ]
629
630     print "Unpacking '" + py_tar + "' to '" + py_target + "'"
631     untar_pybundle(py_tar,py_target,exclude_re)
632
633     # -------------
634     # Extract Numpy
635     if env['WITH_BF_PYTHON_INSTALL_NUMPY']:
636         py_tar = env.subst(env['LCGDIR']).lstrip("#")
637         py_tar += '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_numpy_1.8.tar.gz'
638
639         py_target = env.subst(env['BF_INSTALLDIR']).lstrip("#")
640         py_target = os.path.join(py_target, VERSION, 'python', 'lib', 'site-packages')
641         # rmtree handled above
642         # files are cleaned up in their archive
643         exclude_re = []
644         print("Unpacking '" + py_tar + "' to '" + py_target + "'")
645         untar_pybundle(py_tar, py_target, exclude_re)
646
647     # --------------------
648     # Copy 'site-packages'
649     py_dir = env.subst(env['LCGDIR']).lstrip("#")
650     py_dir += '/release/site-packages'
651     # grr, we have to do one by one because the dir exists
652     for f in os.listdir(py_dir):
653         fn_src = os.path.join(py_dir, f)
654         fn_dst = os.path.join(py_target, f)
655
656         shutil.rmtree(fn_dst, False, printexception)
657         shutil.copytree(fn_src, fn_dst)
658
659
660
661 def  my_appit_print(target, source, env):
662     a = '%s' % (target[0])
663     d, f = os.path.split(a)
664     return "making bundle for " + f
665
666 def AppIt(target=None, source=None, env=None):
667     import shutil
668     import commands
669     import os.path
670     
671     
672     a = '%s' % (target[0])
673     builddir, b = os.path.split(a)
674     libdir = env['LCGDIR'][1:]
675     osxarch = env['MACOSX_ARCHITECTURE']
676     installdir = env['BF_INSTALLDIR']
677     print("compiled architecture: %s"%(osxarch))
678     print("Installing to %s"%(installdir))
679     # TODO, use tar.
680     python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
681     if env['WITH_OSX_STATICPYTHON']:
682         print("unzipping to app-bundle: %s"%(python_zip))
683     else:
684         print("dynamic build - make sure to have python3.x-framework installed")
685     bldroot = env.Dir('.').abspath
686     binary = env['BINARYKIND']
687      
688     sourcedir = bldroot + '/release/darwin/%s.app' % binary
689     sourceinfo = bldroot + "/release/darwin/%s.app/Contents/Info.plist"%binary
690     targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
691     cmd = installdir + '/' +'%s.app'%binary
692     
693     if os.path.isdir(cmd):
694         shutil.rmtree(cmd)
695     shutil.copytree(sourcedir, cmd)
696     cmd = "cat %s | sed s/\$\{MACOSX_BUNDLE_SHORT_VERSION_STRING\}/%s/ | "%(sourceinfo,VERSION)
697     cmd += "sed s/\$\{MACOSX_BUNDLE_LONG_VERSION_STRING\}/%s,\ %s/g > %s"%(VERSION,time.strftime("%Y-%b-%d"),targetinfo)
698     commands.getoutput(cmd)
699     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
700     commands.getoutput(cmd)
701     cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/'%(installdir, binary, VERSION)
702     commands.getoutput(cmd)
703     cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
704
705     # blenderplayer doesn't need all the files
706     if binary == 'blender':
707         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/datafiles'%(installdir, binary, VERSION)
708         commands.getoutput(cmd)
709         cmd = 'cp -R %s/release/datafiles/fonts %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
710         commands.getoutput(cmd)
711         mo_dir = os.path.join(builddir[:-4], "locale")
712         for f in os.listdir(mo_dir):
713             cmd = 'ditto %s/%s %s/%s.app/Contents/MacOS/%s/datafiles/locale/%s/LC_MESSAGES/blender.mo'%(mo_dir, f, installdir, binary, VERSION, f[:-3])
714             commands.getoutput(cmd)
715         cmd = 'cp %s/release/datafiles/locale/languages %s/%s.app/Contents/MacOS/%s/datafiles/locale/'%(bldroot, installdir, binary, VERSION)
716         commands.getoutput(cmd)
717
718         if env['WITH_BF_OCIO']:
719             cmd = 'cp -R %s/release/datafiles/colormanagement %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
720             commands.getoutput(cmd)
721         
722         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
723         commands.getoutput(cmd)
724
725         if VERSION_RELEASE_CYCLE == "release":
726             cmd = 'rm -rf %s/%s.app/Contents/MacOS/%s/scripts/addons_contrib'%(installdir,binary,VERSION)
727             commands.getoutput(cmd)
728
729         if env['WITH_BF_CYCLES']:
730             croot = '%s/intern/cycles' % (bldroot)
731             cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
732
733             cmd = 'mkdir %s' % (cinstalldir)
734             commands.getoutput(cmd)
735             cmd = 'mkdir %s/kernel' % (cinstalldir)
736             commands.getoutput(cmd)
737             cmd = 'mkdir %s/lib' % (cinstalldir)
738             commands.getoutput(cmd)
739             cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
740             commands.getoutput(cmd)
741             cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
742             commands.getoutput(cmd)
743             cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
744             commands.getoutput(cmd)
745             cmd = 'cp -R %s/kernel/svm %s/kernel/closure %s/kernel/geom %s/util/util_color.h %s/util/util_half.h %s/util/util_math.h %s/util/util_transform.h %s/util/util_types.h %s/kernel/' % (croot, croot, croot, croot, croot, croot, croot, croot, cinstalldir)
746             commands.getoutput(cmd)
747             cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
748             commands.getoutput(cmd)
749
750             if env['WITH_BF_CYCLES_OSL']:
751                 cmd = 'mkdir %s/shader' % (cinstalldir)
752                 commands.getoutput(cmd)
753                 cmd = 'cp -R %s/kernel/shaders/*.h %s/shader' % (croot, cinstalldir)
754                 commands.getoutput(cmd)
755                 cmd = 'cp -R %s/../intern/cycles/kernel/shaders/*.oso %s/shader' % (builddir, cinstalldir)
756                 commands.getoutput(cmd)
757
758     if env['WITH_OSX_STATICPYTHON']:
759         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
760         commands.getoutput(cmd)
761         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
762         commands.getoutput(cmd)
763         cmd = 'cp -R %s/release/site-packages/ %s/%s.app/Contents/MacOS/%s/python/lib/python%s/site-packages/'%(libdir,installdir,binary,VERSION,env['BF_PYTHON_VERSION'])
764         commands.getoutput(cmd)
765
766     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
767     commands.getoutput(cmd)
768     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
769     commands.getoutput(cmd)
770     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
771     commands.getoutput(cmd)
772     cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
773     commands.getoutput(cmd)
774     cmd = 'SetFile -d "%s)" -m "%s)" %s/%s.app'%(time.strftime("%m/%d/%Y %H:%M"),time.strftime("%m/%d/%Y %H:%M"),installdir,binary) # give the bundles actual creation/modification date
775     commands.getoutput(cmd)
776     if env['WITH_BF_OPENMP']:
777         if env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6.1': # for correct errorhandling with gcc >= 4.6.1 we need the gcc.dylib and gomp.dylib to link, thus distribute in app-bundle
778             print "Bundling libgcc and libgomp"
779             instname = env['BF_CXX']
780             cmd = 'ditto --arch %s %s/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libgcc
781             commands.getoutput(cmd)
782             cmd = 'install_name_tool -id @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/libgcc_s.1.dylib'%(installdir, binary) # change id of libgcc
783             commands.getoutput(cmd)
784             cmd = 'ditto --arch %s %s/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libgomp
785             commands.getoutput(cmd)
786             cmd = 'install_name_tool -id @executable_path/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/lib/libgomp.1.dylib'%(installdir, binary) # change id of libgomp
787             commands.getoutput(cmd)
788             cmd = 'install_name_tool -change %s/lib/libgcc_s.1.dylib  @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/libgomp.1.dylib'%(instname, installdir, binary) # change ref to libgcc
789             commands.getoutput(cmd)
790             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) # change ref to libgcc ( blender )
791             commands.getoutput(cmd)
792             cmd = 'install_name_tool -change %s/lib/libgomp.1.dylib  @executable_path/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/%s'%(instname, installdir, binary, binary) # change ref to libgomp ( blender )
793             commands.getoutput(cmd)
794         if env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.4':
795             print "Bundling libiomp5"
796             instname = env['LCGDIR'][1:] # made libiomp5 part of blender libs
797             cmd = 'ditto --arch %s %s/openmp/lib/libiomp5.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libiomp5
798             commands.getoutput(cmd)
799             cmd = 'install_name_tool -id @loader_path/lib/libiomp5.dylib %s/%s.app/Contents/MacOS/lib/libiomp5.dylib'%(installdir, binary) # change id of libiomp5
800             commands.getoutput(cmd)
801             cmd = 'install_name_tool -change @loader_path/libiomp5.dylib  @loader_path/lib/libiomp5.dylib %s/%s.app/Contents/MacOS/%s'%(installdir, binary, binary) # change ref to libiomp5 ( blender )
802             commands.getoutput(cmd)
803
804 # extract copy system python, be sure to update other build systems
805 # when making changes to the files that are copied.
806 def my_unixpybundle_print(target, source, env):
807     pass
808
809 def UnixPyBundle(target=None, source=None, env=None):
810     # Any Unix except osx
811     #-- VERSION/python/lib/python3.1
812     
813     import commands
814     
815     def run(cmd):
816         print 'Install command:', cmd
817         commands.getoutput(cmd)
818
819     dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
820
821     lib = env['BF_PYTHON_LIBPATH'].split(os.sep)[-1]
822     target_lib = "lib64" if lib == "lib64" else "lib"
823
824     py_src =    env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
825     py_target =    env.subst( dir + '/python/' + target_lib + '/python'+env['BF_PYTHON_VERSION'] )
826     
827     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
828     if os.path.exists(py_target):
829         print 'Using existing python from:'
830         print '\t"%s"' %            py_target
831         print '\t(skipping copy)\n'
832         return
833
834     # Copied from source/creator/CMakeLists.txt, keep in sync.
835     print 'Install python from:'
836     print '\t"%s" into...' % py_src
837     print '\t"%s"\n' % py_target
838
839     run("rm -rf '%s'" % py_target)
840     try:
841         os.makedirs(os.path.dirname(py_target)) # the final part is copied
842     except:
843         pass
844
845     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
846     run("rm -rf '%s/distutils'" % py_target)
847     run("rm -rf '%s/lib2to3'" % py_target)
848     run("rm -rf '%s/config'" % py_target)
849
850     for f in os.listdir(py_target):
851         if f.startswith("config-"):
852             run("rm -rf '%s/%s'" % (py_target, f))
853
854     run("rm -rf '%s/site-packages'" % py_target)
855     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
856     run("rm -rf '%s/idlelib'" % py_target)
857     run("rm -rf '%s/tkinter'" % py_target)
858     run("rm -rf '%s/turtledemo'" % py_target)
859     run("rm -r '%s/turtle.py'" % py_target)
860     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
861
862     if env['WITH_BF_PYTHON_INSTALL_NUMPY']:
863         numpy_src = py_src + "/site-packages/numpy"
864         numpy_target = py_target + "/site-packages/numpy"
865
866         if os.path.exists(numpy_src):
867             print 'Install numpy from:'
868             print '\t"%s" into...' % numpy_src
869             print '\t"%s"\n' % numpy_target
870
871             run("cp -R '%s' '%s'" % (numpy_src, os.path.dirname(numpy_target)))
872             run("rm -rf '%s/distutils'" % numpy_target)
873             run("rm -rf '%s/oldnumeric'" % numpy_target)
874             run("rm -rf '%s/doc'" % numpy_target)
875             run("rm -rf '%s/tests'" % numpy_target)
876             run("rm -rf '%s/f2py'" % numpy_target)
877             run("find '%s' -type d -name 'include' -prune -exec rm -rf {} ';'" % numpy_target)
878             run("find '%s' -type d -name '*.h' -prune -exec rm -rf {} ';'" % numpy_target)
879             run("find '%s' -type d -name '*.a' -prune -exec rm -rf {} ';'" % numpy_target)
880         else:
881             print 'Failed to find numpy at %s, skipping copying' % numpy_src
882         del numpy_src, numpy_target
883
884     if env['WITH_BF_PYTHON_INSTALL_REQUESTS']:
885         requests_src = py_src + "/site-packages/requests"
886         requests_target = py_target + "/site-packages/requests"
887         if os.path.exists(requests_src):
888             run("cp -R '%s' '%s'" % (requests_src, os.path.dirname(requests_target)))
889             run("find '%s' -type d -name '*.pem -prune -exec rm -rf {} ';'" % requests_target)
890         else:
891             print('Failed to find requests at %s, skipping copying' % requests_src)
892         del requests_src, requests_target
893
894     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
895     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
896     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
897     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
898
899 #### END ACTION STUFF #########
900
901 def bsc(env, target, source):
902     
903     bd = os.path.dirname(target[0].abspath)
904     bscfile = '\"'+target[0].abspath+'\"'
905     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
906     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
907
908     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
909
910     myfile = open(bscpathtmp[1:-1], 'r')
911     lines = myfile.readlines()
912     myfile.close()
913
914     newfile = open(bscpathtmp[1:-1], 'w')
915     for l in lines:
916         newfile.write('\"'+l[:-1]+'\"\n')
917     newfile.close()
918                 
919     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
920     os.system('del '+bscpathtmp)
921
922 class BlenderEnvironment(SConsEnvironment):
923
924     PyBundleActionAdded = False
925
926     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
927         global libs
928         if not self or not libname or not source:
929             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
930             self.Exit()
931         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
932             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
933             self.Exit()
934         
935         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
936         lenv = self.Clone()
937         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
938             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
939         else:
940             res = lenv.RES(root_build_dir+'lib/'+libname, source)
941
942         
943         SConsEnvironment.Default(self, res)
944         resources.append(res)
945
946     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):
947         global vcp
948         
949         # sanity check
950         # run once in a while to check we dont have duplicates
951         if 0:
952             for name, dirs in (("source", sources), ("include", includes)):
953                 files_clean = [os.path.normpath(f) for f in dirs]
954                 files_clean_set = set(files_clean)
955                 if len(files_clean) != len(files_clean_set):
956                     for f in sorted(files_clean_set):
957                         if f != '.' and files_clean.count(f) > 1:
958                             raise Exception("Found duplicate %s %r" % (name, f))
959             del name, dirs, files_clean, files_clean_set, f
960         # end sanity check
961
962         if not self or not libname or not sources:
963             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
964             self.Exit()
965
966         def list_substring(quickie, libname):
967             for q in quickie:
968                 if q in libname:
969                     return True
970             return False
971
972         if list_substring(quickie, libname) or len(quickie)==0:
973             if list_substring(quickdebug, libname):
974                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
975             else:
976                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
977             lenv = self.Clone()
978             lenv.Append(CPPPATH=includes)
979             lenv.Append(CPPDEFINES=defines)
980             if lenv['BF_DEBUG'] or (libname in quickdebug):
981                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
982                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
983                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
984             else:
985                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
986                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
987                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
988             if lenv['BF_PROFILE']:
989                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
990                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
991                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
992             if compileflags:
993                 lenv.Replace(CFLAGS = compileflags)
994             if cc_compileflags:
995                 lenv.Replace(CCFLAGS = cc_compileflags)
996             if cxx_compileflags:
997                 lenv.Replace(CXXFLAGS = cxx_compileflags)
998             if cc_compilerchange:
999                 lenv.Replace(CC = cc_compilerchange)
1000             if cxx_compilerchange:
1001                 lenv.Replace(CXX = cxx_compilerchange)
1002             lenv.Append(CFLAGS = lenv['C_WARN'])
1003             lenv.Append(CCFLAGS = lenv['CC_WARN'])
1004             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
1005
1006             if lenv['OURPLATFORM'] == 'win64-vc':
1007                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
1008
1009             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
1010                 if lenv['BF_DEBUG']:
1011                     lenv.Append(CCFLAGS = ['/MTd'])
1012                 else:
1013                     lenv.Append(CCFLAGS = ['/MT'])
1014             
1015             targetdir = root_build_dir+'lib/' + libname
1016             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
1017                 targetdir = '#'+targetdir
1018             lib = lenv.Library(target= targetdir, source=sources)
1019             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
1020             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
1021                 #if targetdir[0] == '#':
1022                 #    targetdir = targetdir[1:-1]
1023                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
1024                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
1025                          srcs = sources,
1026                          buildtarget = lib,
1027                          variant = 'Release',
1028                          auto_build_solution=0)
1029                 vcp.append(vcproject)
1030                 SConsEnvironment.Default(self, vcproject)
1031         else:
1032             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
1033         # note: libs is a global
1034         add_lib_to_dict(self, libs, libtype, libname, priority)
1035
1036     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
1037         global vcp
1038         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
1039         lenv = self.Clone()
1040         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
1041         lenv.Append(LINKFLAGS = lenv['BF_PROGRAM_LINKFLAGS'])
1042         if lenv['OURPLATFORM'] in ('win32-mingw', 'win64-mingw', 'linuxcross', 'cygwin', 'linux'):
1043             lenv.Replace(LINK = '$CXX')
1044         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
1045             if lenv['BF_DEBUG']:
1046                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
1047         if  lenv['OURPLATFORM']=='linux':
1048             if lenv['WITH_BF_PYTHON']:
1049                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1050         if  lenv['OURPLATFORM']=='sunos5':
1051             if lenv['WITH_BF_PYTHON']:
1052                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1053             if lenv['CXX'].endswith('CC'):
1054                 lenv.Replace(LINK = '$CXX')
1055         if  lenv['OURPLATFORM']=='darwin':
1056             if lenv['WITH_BF_PYTHON']:
1057                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1058             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
1059         if lenv['BF_PROFILE']:
1060             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
1061         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
1062             lenv.Append(LIBPATH=root_build_dir + '/lib')
1063         lenv.Append(LIBPATH=libpath)
1064         lenv.Append(LIBS=libs)
1065         if lenv['WITH_BF_QUICKTIME']:
1066             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
1067             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
1068         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
1069         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
1070             f = lenv.File(progname + '.bsc', builddir)
1071             brs = lenv.Command(f, prog, [bsc])
1072             SConsEnvironment.Default(self, brs)
1073         SConsEnvironment.Default(self, prog)
1074         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
1075             print "! ",builddir + "/" + progname + '.sln'
1076             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
1077                      projects= vcp,
1078                      variant = 'Release')
1079             SConsEnvironment.Default(self, sln)
1080         program_list.append(prog)
1081         if  lenv['OURPLATFORM']=='darwin':
1082             lenv['BINARYKIND'] = binarykind
1083             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
1084         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
1085             if lenv['WITH_BF_PYTHON']:
1086                 if (not lenv['WITHOUT_BF_INSTALL'] and 
1087                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1088                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1089                     not BlenderEnvironment.PyBundleActionAdded):
1090                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
1091                     BlenderEnvironment.PyBundleActionAdded = True
1092         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
1093             if lenv['WITH_BF_PYTHON']:
1094                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1095                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1096                     not BlenderEnvironment.PyBundleActionAdded):
1097                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
1098                     BlenderEnvironment.PyBundleActionAdded = True
1099         return prog
1100
1101     def Glob(lenv, pattern):
1102         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
1103         files = []
1104         for i in glob.glob(path + pattern):
1105             files.append(string.replace(i, path, ''))
1106         return files