OSX/scons: according to last commit, , use the version variable
[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
434             if build_hash == '':
435                 build_hash = os.popen('git rev-parse --short HEAD').read().strip()
436                 no_upstream = True
437             else:
438                 older_commits = os.popen('git log --oneline HEAD..@{u}').read().strip()
439                 if older_commits:
440                     build_hash = os.popen('git rev-parse --short HEAD').read().strip()
441
442             # ## Check for local modifications
443             has_local_changes = False
444
445             # Update GIT index before getting dirty files
446             os.system('git update-index -q --refresh')
447             changed_files = os.popen('git diff-index --name-only HEAD --').read().strip()
448
449             if changed_files:
450                 has_local_changes = True
451             elif no_upstream == False:
452                 unpushed_log = os.popen('git log --oneline @{u}..').read().strip()
453                 has_local_changes = unpushed_log != ''
454
455             if has_local_changes:
456                 build_branch += ' (modified)'
457     else:
458         build_hash = 'unknown'
459         build_commit_timestamp = '0'
460         build_branch = 'unknown'
461
462     if lenv['BF_DEBUG']:
463         build_type = "Debug"
464         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['BF_DEBUG_CCFLAGS'] + lenv['CPPFLAGS'])
465         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['CPPFLAGS'])
466     else:
467         build_type = "Release"
468         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['REL_CFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
469         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['REL_CXXFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
470
471     build_linkflags = ' '.join(lenv['PLATFORM_LINKFLAGS'])
472
473     obj = []
474     if lenv['BF_BUILDINFO']:
475         lenv.Append (CPPDEFINES = ['BUILD_TIME=\\"%s\\"'%(build_time),
476                                     'BUILD_DATE=\\"%s\\"'%(build_date),
477                                     'BUILD_TYPE=\\"%s\\"'%(build_type),
478                                     'BUILD_HASH=\\"%s\\"'%(build_hash),
479                                     'BUILD_COMMIT_TIMESTAMP=%s'%(build_commit_timestamp),
480                                     'BUILD_BRANCH=\\"%s\\"'%(build_branch),
481                                     'WITH_BUILDINFO',
482                                     'BUILD_PLATFORM=\\"%s:%s\\"'%(platform.system(), platform.architecture()[0]),
483                                     'BUILD_CFLAGS=\\"%s\\"'%(build_cflags),
484                                     'BUILD_CXXFLAGS=\\"%s\\"'%(build_cxxflags),
485                                     'BUILD_LINKFLAGS=\\"%s\\"'%(build_linkflags),
486                                     'BUILD_SYSTEM=\\"SCons\\"'
487                     ])
488
489         lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel'])
490
491         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, ['#source/creator/buildinfo.c'])]
492
493     return obj
494
495 ##### END LIB STUFF ############
496
497 ##### ACTION STUFF #############
498
499 def my_print_cmd_line(self, s, target, source, env):
500     sys.stdout.write(' ' * 70 + '\r')
501     sys.stdout.flush()
502     sys.stdout.write(s + "\r")
503     sys.stdout.flush()
504
505 def my_compile_print(target, source, env):
506     a = '%s' % (source[0])
507     d, f = os.path.split(a)
508     return bc.OKBLUE + "Compiling" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
509
510 def my_moc_print(target, source, env):
511     a = '%s' % (source[0])
512     d, f = os.path.split(a)
513     return bc.OKBLUE + "Creating MOC" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
514
515 def my_linking_print(target, source, env):
516     t = '%s' % (target[0])
517     d, f = os.path.split(t)
518     return bc.OKBLUE + "Linking library" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
519
520 def my_program_print(target, source, env):
521     t = '%s' % (target[0])
522     d, f = os.path.split(t)
523     return bc.OKBLUE + "Linking program" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
524
525 def msvc_hack(env):
526     static_lib = SCons.Tool.createStaticLibBuilder(env)
527     program = SCons.Tool.createProgBuilder(env)
528     
529     env['BUILDERS']['Library'] = static_lib
530     env['BUILDERS']['StaticLibrary'] = static_lib
531     env['BUILDERS']['Program'] = program
532         
533 def set_quiet_output(env):
534     mycaction = Action("$CCCOM", strfunction=my_compile_print)
535     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
536     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
537     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
538     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
539     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
540
541     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
542     static_ob.add_action('.c', mycaction)
543     static_ob.add_action('.cpp', mycppaction)
544     static_ob.add_action('.cc', mycppaction)
545     shared_ob.add_action('.c', myshcaction)
546     shared_ob.add_action('.cc', myshcppaction)
547
548     static_lib = SCons.Builder.Builder(action = mylibaction,
549                                        emitter = '$LIBEMITTER',
550                                        prefix = '$LIBPREFIX',
551                                        suffix = '$LIBSUFFIX',
552                                        src_suffix = '$OBJSUFFIX',
553                                        src_builder = 'StaticObject')
554
555     program = SCons.Builder.Builder(action = mylinkaction,
556                                     emitter = '$PROGEMITTER',
557                                     prefix = '$PROGPREFIX',
558                                     suffix = '$PROGSUFFIX',
559                                     src_suffix = '$OBJSUFFIX',
560                                     src_builder = 'Object',
561                                     target_scanner = SCons.Defaults.ProgScan)
562
563     env['BUILDERS']['Object'] = static_ob
564     env['BUILDERS']['StaticObject'] = static_ob
565     env['BUILDERS']['StaticLibrary'] = static_lib
566     env['BUILDERS']['Library'] = static_lib
567     env['BUILDERS']['Program'] = program
568     if env['BF_LINE_OVERWRITE']:
569         SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
570
571 def untar_pybundle(from_tar,to_dir,exclude_re):
572     tar= tarfile.open(from_tar, mode='r')
573     exclude_re= list(exclude_re) #single re object or list of re objects
574     debug= 0 #list files instead of unpacking
575     good= []
576     if debug: print '\nFiles not being unpacked:\n'
577     for name in tar.getnames():
578         is_bad= 0
579         for r in exclude_re:
580             if r.match(name):
581                 is_bad=1
582                 if debug: print name
583                 break
584         if not is_bad:
585             good.append(tar.getmember(name))
586     if debug:
587         print '\nFiles being unpacked:\n'
588         for g in good:
589             print g
590     else:
591         tar.extractall(to_dir, good)
592
593 def my_winpybundle_print(target, source, env):
594     pass
595
596 def WinPyBundle(target=None, source=None, env=None):
597     import re
598     py_tar = env.subst(env['LCGDIR']).lstrip("#")
599     if env['BF_DEBUG']:
600         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.tar.gz'
601     else:
602         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
603
604     py_target = env.subst(env['BF_INSTALLDIR']).lstrip("#")
605     py_target = os.path.join(py_target, VERSION, 'python', 'lib')
606     def printexception(func,path,ex):
607         if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
608             print str(func) + ' failed on ' + str(path)
609     print "Trying to remove existing py bundle."
610     shutil.rmtree(py_target, False, printexception)
611     exclude_re=[re.compile('.*/test'),
612                 re.compile('^test'),
613                 re.compile('^distutils'),
614                 re.compile('^idlelib'),
615                 re.compile('^lib2to3'),
616                 re.compile('^tkinter'),
617                 re.compile('^_tkinter_d.pyd'),
618                 re.compile('^turtledemo'),
619                 re.compile('^turtle.py'),
620                 ]
621
622     print "Unpacking '" + py_tar + "' to '" + py_target + "'"
623     untar_pybundle(py_tar,py_target,exclude_re)
624
625     # -------------
626     # Extract Numpy
627     py_tar = env.subst(env['LCGDIR']).lstrip("#")
628     py_tar += '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_numpy_1.8.tar.gz'
629
630     py_target = env.subst(env['BF_INSTALLDIR']).lstrip("#")
631     py_target = os.path.join(py_target, VERSION, 'python', 'lib', 'site-packages')
632     # rmtree handled above
633     # files are cleaned up in their archive
634     exclude_re = []
635     print("Unpacking '" + py_tar + "' to '" + py_target + "'")
636     untar_pybundle(py_tar, py_target, exclude_re)
637
638     # --------------------
639     # Copy 'site-packages'
640     py_dir = env.subst(env['LCGDIR']).lstrip("#")
641     py_dir += '/release/site-packages'
642     # grr, we have to do one by one because the dir exists
643     for f in os.listdir(py_dir):
644         fn_src = os.path.join(py_dir, f)
645         fn_dst = os.path.join(py_target, f)
646
647         shutil.rmtree(fn_dst, False, printexception)
648         shutil.copytree(fn_src, fn_dst)
649
650
651
652 def  my_appit_print(target, source, env):
653     a = '%s' % (target[0])
654     d, f = os.path.split(a)
655     return "making bundle for " + f
656
657 def AppIt(target=None, source=None, env=None):
658     import shutil
659     import commands
660     import os.path
661     
662     
663     a = '%s' % (target[0])
664     builddir, b = os.path.split(a)
665     libdir = env['LCGDIR'][1:]
666     osxarch = env['MACOSX_ARCHITECTURE']
667     installdir = env['BF_INSTALLDIR']
668     print("compiled architecture: %s"%(osxarch))
669     print("Installing to %s"%(installdir))
670     # TODO, use tar.
671     python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
672     if env['WITH_OSX_STATICPYTHON']:
673         print("unzipping to app-bundle: %s"%(python_zip))
674     else:
675         print("dynamic build - make sure to have python3.x-framework installed")
676     bldroot = env.Dir('.').abspath
677     binary = env['BINARYKIND']
678      
679     sourcedir = bldroot + '/release/darwin/%s.app' % binary
680     sourceinfo = bldroot + "/release/darwin/%s.app/Contents/Info.plist"%binary
681     targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
682     cmd = installdir + '/' +'%s.app'%binary
683     
684     if os.path.isdir(cmd):
685         shutil.rmtree(cmd)
686     shutil.copytree(sourcedir, cmd)
687     cmd = "cat %s | sed s/\$\{MACOSX_BUNDLE_SHORT_VERSION_STRING\}/%s/ | "%(sourceinfo,VERSION)
688     cmd += "sed s/\$\{MACOSX_BUNDLE_LONG_VERSION_STRING\}/%s,\ %s/g > %s"%(VERSION,time.strftime("%Y-%b-%d"),targetinfo)
689     commands.getoutput(cmd)
690     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
691     commands.getoutput(cmd)
692     cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/'%(installdir, binary, VERSION)
693     commands.getoutput(cmd)
694     cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
695
696     # blenderplayer doesn't need all the files
697     if binary == 'blender':
698         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/datafiles'%(installdir, binary, VERSION)
699         commands.getoutput(cmd)
700         cmd = 'cp -R %s/release/datafiles/fonts %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
701         commands.getoutput(cmd)
702         mo_dir = os.path.join(builddir[:-4], "locale")
703         for f in os.listdir(mo_dir):
704             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])
705             commands.getoutput(cmd)
706         cmd = 'cp %s/release/datafiles/locale/languages %s/%s.app/Contents/MacOS/%s/datafiles/locale/'%(bldroot, installdir, binary, VERSION)
707         commands.getoutput(cmd)
708
709         if env['WITH_BF_OCIO']:
710             cmd = 'cp -R %s/release/datafiles/colormanagement %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
711             commands.getoutput(cmd)
712         
713         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
714         commands.getoutput(cmd)
715
716         if VERSION_RELEASE_CYCLE == "release":
717             cmd = 'rm -rf %s/%s.app/Contents/MacOS/%s/scripts/addons_contrib'%(installdir,binary,VERSION)
718             commands.getoutput(cmd)
719
720         if env['WITH_BF_CYCLES']:
721             croot = '%s/intern/cycles' % (bldroot)
722             cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
723
724             cmd = 'mkdir %s' % (cinstalldir)
725             commands.getoutput(cmd)
726             cmd = 'mkdir %s/kernel' % (cinstalldir)
727             commands.getoutput(cmd)
728             cmd = 'mkdir %s/lib' % (cinstalldir)
729             commands.getoutput(cmd)
730             cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
731             commands.getoutput(cmd)
732             cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
733             commands.getoutput(cmd)
734             cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
735             commands.getoutput(cmd)
736             cmd = 'cp -R %s/kernel/svm %s/kernel/closure %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, cinstalldir)
737             commands.getoutput(cmd)
738             cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
739             commands.getoutput(cmd)
740
741             if env['WITH_BF_CYCLES_OSL']:
742                 cmd = 'mkdir %s/shader' % (cinstalldir)
743                 commands.getoutput(cmd)
744                 cmd = 'cp -R %s/kernel/shaders/*.h %s/shader' % (croot, cinstalldir)
745                 commands.getoutput(cmd)
746                 cmd = 'cp -R %s/../intern/cycles/kernel/shaders/*.oso %s/shader' % (builddir, cinstalldir)
747                 commands.getoutput(cmd)
748
749     if env['WITH_OSX_STATICPYTHON']:
750         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
751         commands.getoutput(cmd)
752         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
753         commands.getoutput(cmd)
754         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'])
755         commands.getoutput(cmd)
756
757     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
758     commands.getoutput(cmd)
759     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
760     commands.getoutput(cmd)
761     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
762     commands.getoutput(cmd)
763     cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
764     commands.getoutput(cmd)
765     if env['WITH_BF_OPENMP']:
766         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
767             print "Bundling libgcc and libgomp"
768             instname = env['BF_CXX']
769             cmd = 'ditto --arch %s %s/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libgcc
770             commands.getoutput(cmd)
771             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
772             commands.getoutput(cmd)
773             cmd = 'ditto --arch %s %s/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libgomp
774             commands.getoutput(cmd)
775             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
776             commands.getoutput(cmd)
777             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
778             commands.getoutput(cmd)
779             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 )
780             commands.getoutput(cmd)
781             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 )
782             commands.getoutput(cmd)
783         if env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.4':
784             print "Bundling libiomp5"
785             instname = env['LCGDIR'][1:] # made libiomp5 part of blender libs
786             cmd = 'ditto --arch %s %s/openmp/lib/libiomp5.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libiomp5
787             commands.getoutput(cmd)
788             cmd = 'install_name_tool -id @loader_path/lib/libiomp5.dylib %s/%s.app/Contents/MacOS/lib/libiomp5.dylib'%(installdir, binary) # change id of libiomp5
789             commands.getoutput(cmd)
790             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 )
791             commands.getoutput(cmd)
792
793 # extract copy system python, be sure to update other build systems
794 # when making changes to the files that are copied.
795 def my_unixpybundle_print(target, source, env):
796     pass
797
798 def UnixPyBundle(target=None, source=None, env=None):
799     # Any Unix except osx
800     #-- VERSION/python/lib/python3.1
801     
802     import commands
803     
804     def run(cmd):
805         print 'Install command:', cmd
806         commands.getoutput(cmd)
807
808     dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
809
810     lib = env['BF_PYTHON_LIBPATH'].split(os.sep)[-1]
811     target_lib = "lib64" if lib == "lib64" else "lib"
812
813     py_src =    env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
814     py_target =    env.subst( dir + '/python/' + target_lib + '/python'+env['BF_PYTHON_VERSION'] )
815     
816     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
817     if os.path.exists(py_target):
818         print 'Using existing python from:'
819         print '\t"%s"' %            py_target
820         print '\t(skipping copy)\n'
821         return
822
823     # Copied from source/creator/CMakeLists.txt, keep in sync.
824     print 'Install python from:'
825     print '\t"%s" into...' % py_src
826     print '\t"%s"\n' % py_target
827
828     run("rm -rf '%s'" % py_target)
829     try:
830         os.makedirs(os.path.dirname(py_target)) # the final part is copied
831     except:
832         pass
833
834     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
835     run("rm -rf '%s/distutils'" % py_target)
836     run("rm -rf '%s/lib2to3'" % py_target)
837     run("rm -rf '%s/config'" % py_target)
838
839     for f in os.listdir(py_target):
840         if f.startswith("config-"):
841             run("rm -rf '%s/%s'" % (py_target, f))
842
843     run("rm -rf '%s/site-packages'" % py_target)
844     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
845     run("rm -rf '%s/idlelib'" % py_target)
846     run("rm -rf '%s/tkinter'" % py_target)
847     run("rm -rf '%s/turtledemo'" % py_target)
848     run("rm -r '%s/turtle.py'" % py_target)
849     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
850
851     if env['WITH_BF_PYTHON_INSTALL_NUMPY']:
852         numpy_src = py_src + "/site-packages/numpy"
853         numpy_target = py_target + "/site-packages/numpy"
854
855         if os.path.exists(numpy_src):
856             print 'Install numpy from:'
857             print '\t"%s" into...' % numpy_src
858             print '\t"%s"\n' % numpy_target
859
860             run("cp -R '%s' '%s'" % (numpy_src, os.path.dirname(numpy_target)))
861             run("rm -rf '%s/distutils'" % numpy_target)
862             run("rm -rf '%s/oldnumeric'" % numpy_target)
863             run("rm -rf '%s/doc'" % numpy_target)
864             run("rm -rf '%s/tests'" % numpy_target)
865             run("rm -rf '%s/f2py'" % numpy_target)
866             run("find '%s' -type d -name 'include' -prune -exec rm -rf {} ';'" % numpy_target)
867             run("find '%s' -type d -name '*.h' -prune -exec rm -rf {} ';'" % numpy_target)
868             run("find '%s' -type d -name '*.a' -prune -exec rm -rf {} ';'" % numpy_target)
869         else:
870             print 'Failed to find numpy at %s, skipping copying' % numpy_src
871         del numpy_src, numpy_target
872
873     if env['WITH_BF_PYTHON_INSTALL_REQUESTS']:
874         requests_src = py_src + "/site-packages/requests"
875         requests_target = py_target + "/site-packages/requests"
876         if os.path.exists(requests_src):
877             run("cp -R '%s' '%s'" % (requests_src, os.path.dirname(requests_target)))
878             run("find '%s' -type d -name '*.pem -prune -exec rm -rf {} ';'" % requests_target)
879         else:
880             print('Failed to find requests at %s, skipping copying' % requests_src)
881         del requests_src, requests_target
882
883     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
884     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
885     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
886     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
887
888 #### END ACTION STUFF #########
889
890 def bsc(env, target, source):
891     
892     bd = os.path.dirname(target[0].abspath)
893     bscfile = '\"'+target[0].abspath+'\"'
894     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
895     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
896
897     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
898
899     myfile = open(bscpathtmp[1:-1], 'r')
900     lines = myfile.readlines()
901     myfile.close()
902
903     newfile = open(bscpathtmp[1:-1], 'w')
904     for l in lines:
905         newfile.write('\"'+l[:-1]+'\"\n')
906     newfile.close()
907                 
908     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
909     os.system('del '+bscpathtmp)
910
911 class BlenderEnvironment(SConsEnvironment):
912
913     PyBundleActionAdded = False
914
915     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
916         global libs
917         if not self or not libname or not source:
918             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
919             self.Exit()
920         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
921             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
922             self.Exit()
923         
924         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
925         lenv = self.Clone()
926         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
927             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
928         else:
929             res = lenv.RES(root_build_dir+'lib/'+libname, source)
930
931         
932         SConsEnvironment.Default(self, res)
933         resources.append(res)
934
935     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):
936         global vcp
937         
938         # sanity check
939         # run once in a while to check we dont have duplicates
940         if 0:
941             for name, dirs in (("source", sources), ("include", includes)):
942                 files_clean = [os.path.normpath(f) for f in dirs]
943                 files_clean_set = set(files_clean)
944                 if len(files_clean) != len(files_clean_set):
945                     for f in sorted(files_clean_set):
946                         if f != '.' and files_clean.count(f) > 1:
947                             raise Exception("Found duplicate %s %r" % (name, f))
948             del name, dirs, files_clean, files_clean_set, f
949         # end sanity check
950
951         if not self or not libname or not sources:
952             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
953             self.Exit()
954
955         def list_substring(quickie, libname):
956             for q in quickie:
957                 if q in libname:
958                     return True
959             return False
960
961         if list_substring(quickie, libname) or len(quickie)==0:
962             if list_substring(quickdebug, libname):
963                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
964             else:
965                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
966             lenv = self.Clone()
967             lenv.Append(CPPPATH=includes)
968             lenv.Append(CPPDEFINES=defines)
969             if lenv['BF_DEBUG'] or (libname in quickdebug):
970                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
971                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
972                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
973             else:
974                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
975                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
976                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
977             if lenv['BF_PROFILE']:
978                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
979                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
980                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
981             if compileflags:
982                 lenv.Replace(CFLAGS = compileflags)
983             if cc_compileflags:
984                 lenv.Replace(CCFLAGS = cc_compileflags)
985             if cxx_compileflags:
986                 lenv.Replace(CXXFLAGS = cxx_compileflags)
987             if cc_compilerchange:
988                 lenv.Replace(CC = cc_compilerchange)
989             if cxx_compilerchange:
990                 lenv.Replace(CXX = cxx_compilerchange)
991             lenv.Append(CFLAGS = lenv['C_WARN'])
992             lenv.Append(CCFLAGS = lenv['CC_WARN'])
993             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
994
995             if lenv['OURPLATFORM'] == 'win64-vc':
996                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
997
998             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
999                 if lenv['BF_DEBUG']:
1000                     lenv.Append(CCFLAGS = ['/MTd'])
1001                 else:
1002                     lenv.Append(CCFLAGS = ['/MT'])
1003             
1004             targetdir = root_build_dir+'lib/' + libname
1005             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
1006                 targetdir = '#'+targetdir
1007             lib = lenv.Library(target= targetdir, source=sources)
1008             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
1009             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
1010                 #if targetdir[0] == '#':
1011                 #    targetdir = targetdir[1:-1]
1012                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
1013                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
1014                          srcs = sources,
1015                          buildtarget = lib,
1016                          variant = 'Release',
1017                          auto_build_solution=0)
1018                 vcp.append(vcproject)
1019                 SConsEnvironment.Default(self, vcproject)
1020         else:
1021             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
1022         # note: libs is a global
1023         add_lib_to_dict(self, libs, libtype, libname, priority)
1024
1025     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
1026         global vcp
1027         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
1028         lenv = self.Clone()
1029         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
1030         lenv.Append(LINKFLAGS = lenv['BF_PROGRAM_LINKFLAGS'])
1031         if lenv['OURPLATFORM'] in ('win32-mingw', 'win64-mingw', 'linuxcross', 'cygwin', 'linux'):
1032             lenv.Replace(LINK = '$CXX')
1033         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
1034             if lenv['BF_DEBUG']:
1035                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
1036         if  lenv['OURPLATFORM']=='linux':
1037             if lenv['WITH_BF_PYTHON']:
1038                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1039         if  lenv['OURPLATFORM']=='sunos5':
1040             if lenv['WITH_BF_PYTHON']:
1041                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1042             if lenv['CXX'].endswith('CC'):
1043                 lenv.Replace(LINK = '$CXX')
1044         if  lenv['OURPLATFORM']=='darwin':
1045             if lenv['WITH_BF_PYTHON']:
1046                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1047             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
1048         if lenv['BF_PROFILE']:
1049             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
1050         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
1051             lenv.Append(LIBPATH=root_build_dir + '/lib')
1052         lenv.Append(LIBPATH=libpath)
1053         lenv.Append(LIBS=libs)
1054         if lenv['WITH_BF_QUICKTIME']:
1055             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
1056             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
1057         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
1058         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
1059             f = lenv.File(progname + '.bsc', builddir)
1060             brs = lenv.Command(f, prog, [bsc])
1061             SConsEnvironment.Default(self, brs)
1062         SConsEnvironment.Default(self, prog)
1063         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
1064             print "! ",builddir + "/" + progname + '.sln'
1065             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
1066                      projects= vcp,
1067                      variant = 'Release')
1068             SConsEnvironment.Default(self, sln)
1069         program_list.append(prog)
1070         if  lenv['OURPLATFORM']=='darwin':
1071             lenv['BINARYKIND'] = binarykind
1072             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
1073         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
1074             if lenv['WITH_BF_PYTHON']:
1075                 if (not lenv['WITHOUT_BF_INSTALL'] and 
1076                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1077                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1078                     not BlenderEnvironment.PyBundleActionAdded):
1079                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
1080                     BlenderEnvironment.PyBundleActionAdded = True
1081         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
1082             if lenv['WITH_BF_PYTHON']:
1083                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1084                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1085                     not BlenderEnvironment.PyBundleActionAdded):
1086                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
1087                     BlenderEnvironment.PyBundleActionAdded = True
1088         return prog
1089
1090     def Glob(lenv, pattern):
1091         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
1092         files = []
1093         for i in glob.glob(path + pattern):
1094             files.append(string.replace(i, path, ''))
1095         return files