d5f9446e86a1a946387da9d2417c1455c6ecb1e7
[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/python3.3/site-packages/'%(libdir,installdir,binary,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
872     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
873     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
874     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
875     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
876
877 #### END ACTION STUFF #########
878
879 def bsc(env, target, source):
880     
881     bd = os.path.dirname(target[0].abspath)
882     bscfile = '\"'+target[0].abspath+'\"'
883     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
884     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
885
886     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
887
888     myfile = open(bscpathtmp[1:-1], 'r')
889     lines = myfile.readlines()
890     myfile.close()
891
892     newfile = open(bscpathtmp[1:-1], 'w')
893     for l in lines:
894         newfile.write('\"'+l[:-1]+'\"\n')
895     newfile.close()
896                 
897     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
898     os.system('del '+bscpathtmp)
899
900 class BlenderEnvironment(SConsEnvironment):
901
902     PyBundleActionAdded = False
903
904     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
905         global libs
906         if not self or not libname or not source:
907             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
908             self.Exit()
909         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
910             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
911             self.Exit()
912         
913         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
914         lenv = self.Clone()
915         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
916             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
917         else:
918             res = lenv.RES(root_build_dir+'lib/'+libname, source)
919
920         
921         SConsEnvironment.Default(self, res)
922         resources.append(res)
923
924     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):
925         global vcp
926         
927         # sanity check
928         # run once in a while to check we dont have duplicates
929         if 0:
930             for name, dirs in (("source", sources), ("include", includes)):
931                 files_clean = [os.path.normpath(f) for f in dirs]
932                 files_clean_set = set(files_clean)
933                 if len(files_clean) != len(files_clean_set):
934                     for f in sorted(files_clean_set):
935                         if f != '.' and files_clean.count(f) > 1:
936                             raise Exception("Found duplicate %s %r" % (name, f))
937             del name, dirs, files_clean, files_clean_set, f
938         # end sanity check
939
940         if not self or not libname or not sources:
941             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
942             self.Exit()
943
944         def list_substring(quickie, libname):
945             for q in quickie:
946                 if q in libname:
947                     return True
948             return False
949
950         if list_substring(quickie, libname) or len(quickie)==0:
951             if list_substring(quickdebug, libname):
952                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
953             else:
954                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
955             lenv = self.Clone()
956             lenv.Append(CPPPATH=includes)
957             lenv.Append(CPPDEFINES=defines)
958             if lenv['BF_DEBUG'] or (libname in quickdebug):
959                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
960                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
961                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
962             else:
963                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
964                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
965                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
966             if lenv['BF_PROFILE']:
967                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
968                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
969                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
970             if compileflags:
971                 lenv.Replace(CFLAGS = compileflags)
972             if cc_compileflags:
973                 lenv.Replace(CCFLAGS = cc_compileflags)
974             if cxx_compileflags:
975                 lenv.Replace(CXXFLAGS = cxx_compileflags)
976             if cc_compilerchange:
977                 lenv.Replace(CC = cc_compilerchange)
978             if cxx_compilerchange:
979                 lenv.Replace(CXX = cxx_compilerchange)
980             lenv.Append(CFLAGS = lenv['C_WARN'])
981             lenv.Append(CCFLAGS = lenv['CC_WARN'])
982             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
983
984             if lenv['OURPLATFORM'] == 'win64-vc':
985                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
986
987             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
988                 if lenv['BF_DEBUG']:
989                     lenv.Append(CCFLAGS = ['/MTd'])
990                 else:
991                     lenv.Append(CCFLAGS = ['/MT'])
992             
993             targetdir = root_build_dir+'lib/' + libname
994             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
995                 targetdir = '#'+targetdir
996             lib = lenv.Library(target= targetdir, source=sources)
997             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
998             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
999                 #if targetdir[0] == '#':
1000                 #    targetdir = targetdir[1:-1]
1001                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
1002                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
1003                          srcs = sources,
1004                          buildtarget = lib,
1005                          variant = 'Release',
1006                          auto_build_solution=0)
1007                 vcp.append(vcproject)
1008                 SConsEnvironment.Default(self, vcproject)
1009         else:
1010             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
1011         # note: libs is a global
1012         add_lib_to_dict(self, libs, libtype, libname, priority)
1013
1014     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
1015         global vcp
1016         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
1017         lenv = self.Clone()
1018         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
1019         lenv.Append(LINKFLAGS = lenv['BF_PROGRAM_LINKFLAGS'])
1020         if lenv['OURPLATFORM'] in ('win32-mingw', 'win64-mingw', 'linuxcross', 'cygwin', 'linux'):
1021             lenv.Replace(LINK = '$CXX')
1022         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
1023             if lenv['BF_DEBUG']:
1024                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
1025         if  lenv['OURPLATFORM']=='linux':
1026             if lenv['WITH_BF_PYTHON']:
1027                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1028         if  lenv['OURPLATFORM']=='sunos5':
1029             if lenv['WITH_BF_PYTHON']:
1030                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1031             if lenv['CXX'].endswith('CC'):
1032                 lenv.Replace(LINK = '$CXX')
1033         if  lenv['OURPLATFORM']=='darwin':
1034             if lenv['WITH_BF_PYTHON']:
1035                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1036             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
1037         if lenv['BF_PROFILE']:
1038             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
1039         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
1040             lenv.Append(LIBPATH=root_build_dir + '/lib')
1041         lenv.Append(LIBPATH=libpath)
1042         lenv.Append(LIBS=libs)
1043         if lenv['WITH_BF_QUICKTIME']:
1044             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
1045             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
1046         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
1047         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
1048             f = lenv.File(progname + '.bsc', builddir)
1049             brs = lenv.Command(f, prog, [bsc])
1050             SConsEnvironment.Default(self, brs)
1051         SConsEnvironment.Default(self, prog)
1052         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
1053             print "! ",builddir + "/" + progname + '.sln'
1054             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
1055                      projects= vcp,
1056                      variant = 'Release')
1057             SConsEnvironment.Default(self, sln)
1058         program_list.append(prog)
1059         if  lenv['OURPLATFORM']=='darwin':
1060             lenv['BINARYKIND'] = binarykind
1061             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
1062         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
1063             if lenv['WITH_BF_PYTHON']:
1064                 if (not lenv['WITHOUT_BF_INSTALL'] and 
1065                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1066                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1067                     not BlenderEnvironment.PyBundleActionAdded):
1068                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
1069                     BlenderEnvironment.PyBundleActionAdded = True
1070         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
1071             if lenv['WITH_BF_PYTHON']:
1072                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1073                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1074                     not BlenderEnvironment.PyBundleActionAdded):
1075                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
1076                     BlenderEnvironment.PyBundleActionAdded = True
1077         return prog
1078
1079     def Glob(lenv, pattern):
1080         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
1081         files = []
1082         for i in glob.glob(path + pattern):
1083             files.append(string.replace(i, path, ''))
1084         return files