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