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