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