ecf34759033e10f07159654190ac6c197849124d
[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', 'lib')
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     
847     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
848     if os.path.exists(py_target):
849         print 'Using existing python from:'
850         print '\t"%s"' %            py_target
851         print '\t(skipping copy)\n'
852         return
853
854     # Copied from source/creator/CMakeLists.txt, keep in sync.
855     print 'Install python from:'
856     print '\t"%s" into...' % py_src
857     print '\t"%s"\n' % py_target
858
859     run("rm -rf '%s'" % py_target)
860     try:
861         os.makedirs(os.path.dirname(py_target)) # the final part is copied
862     except:
863         pass
864
865     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
866     run("rm -rf '%s/distutils'" % py_target)
867     run("rm -rf '%s/lib2to3'" % py_target)
868     run("rm -rf '%s/config'" % py_target)
869
870     for f in os.listdir(py_target):
871         if f.startswith("config-"):
872             run("rm -rf '%s/%s'" % (py_target, f))
873
874     run("rm -rf '%s/site-packages'" % py_target)
875     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
876     run("rm -rf '%s/idlelib'" % py_target)
877     run("rm -rf '%s/tkinter'" % py_target)
878     run("rm -rf '%s/turtledemo'" % py_target)
879     run("rm -r '%s/turtle.py'" % py_target)
880     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
881
882     if env['WITH_BF_PYTHON_INSTALL_NUMPY']:
883         numpy_src = py_src + "/site-packages/numpy"
884         numpy_target = py_target + "/site-packages/numpy"
885
886         if os.path.exists(numpy_src):
887             print 'Install numpy from:'
888             print '\t"%s" into...' % numpy_src
889             print '\t"%s"\n' % numpy_target
890
891             run("cp -R '%s' '%s'" % (numpy_src, os.path.dirname(numpy_target)))
892             run("rm -rf '%s/distutils'" % numpy_target)
893             run("rm -rf '%s/oldnumeric'" % numpy_target)
894             run("rm -rf '%s/doc'" % numpy_target)
895             run("rm -rf '%s/tests'" % numpy_target)
896             run("rm -rf '%s/f2py'" % numpy_target)
897             run("find '%s' -type d -name 'include' -prune -exec rm -rf {} ';'" % numpy_target)
898             run("find '%s' -type d -name '*.h' -prune -exec rm -rf {} ';'" % numpy_target)
899             run("find '%s' -type d -name '*.a' -prune -exec rm -rf {} ';'" % numpy_target)
900         else:
901             print 'Failed to find numpy at %s, skipping copying' % numpy_src
902         del numpy_src, numpy_target
903
904     if env['WITH_BF_PYTHON_INSTALL_REQUESTS']:
905         requests_src = py_src + "/site-packages/requests"
906         requests_target = py_target + "/site-packages/requests"
907         if os.path.exists(requests_src):
908             run("cp -R '%s' '%s'" % (requests_src, os.path.dirname(requests_target)))
909             run("find '%s' -type d -name '*.pem -prune -exec rm -rf {} ';'" % requests_target)
910         else:
911             print('Failed to find requests at %s, skipping copying' % requests_src)
912         del requests_src, requests_target
913
914     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
915     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
916     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
917     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
918
919 #### END ACTION STUFF #########
920
921 def bsc(env, target, source):
922     
923     bd = os.path.dirname(target[0].abspath)
924     bscfile = '\"'+target[0].abspath+'\"'
925     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
926     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
927
928     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
929
930     myfile = open(bscpathtmp[1:-1], 'r')
931     lines = myfile.readlines()
932     myfile.close()
933
934     newfile = open(bscpathtmp[1:-1], 'w')
935     for l in lines:
936         newfile.write('\"'+l[:-1]+'\"\n')
937     newfile.close()
938                 
939     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
940     os.system('del '+bscpathtmp)
941
942 class BlenderEnvironment(SConsEnvironment):
943
944     PyBundleActionAdded = False
945
946     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
947         global libs
948         if not self or not libname or not source:
949             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
950             self.Exit()
951         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
952             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
953             self.Exit()
954         
955         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
956         lenv = self.Clone()
957         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
958             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
959         else:
960             res = lenv.RES(root_build_dir+'lib/'+libname, source)
961
962         
963         SConsEnvironment.Default(self, res)
964         resources.append(res)
965
966     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):
967         global vcp
968         
969         # sanity check
970         # run once in a while to check we dont have duplicates
971         if 0:
972             for name, dirs in (("source", sources), ("include", includes)):
973                 files_clean = [os.path.normpath(f) for f in dirs]
974                 files_clean_set = set(files_clean)
975                 if len(files_clean) != len(files_clean_set):
976                     for f in sorted(files_clean_set):
977                         if f != '.' and files_clean.count(f) > 1:
978                             raise Exception("Found duplicate %s %r" % (name, f))
979             del name, dirs, files_clean, files_clean_set, f
980         # end sanity check
981
982         if not self or not libname or not sources:
983             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
984             self.Exit()
985
986         def list_substring(quickie, libname):
987             for q in quickie:
988                 if q in libname:
989                     return True
990             return False
991
992         if list_substring(quickie, libname) or len(quickie)==0:
993             if list_substring(quickdebug, libname):
994                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
995             else:
996                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
997             lenv = self.Clone()
998             lenv.Append(CPPPATH=includes)
999             lenv.Append(CPPDEFINES=defines)
1000             if lenv['BF_DEBUG'] or (libname in quickdebug):
1001                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
1002                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
1003                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
1004             else:
1005                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
1006                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
1007                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
1008             if lenv['BF_PROFILE']:
1009                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
1010                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
1011                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
1012             if compileflags:
1013                 lenv.Replace(CFLAGS = compileflags)
1014             if cc_compileflags:
1015                 lenv.Replace(CCFLAGS = cc_compileflags)
1016             if cxx_compileflags:
1017                 lenv.Replace(CXXFLAGS = cxx_compileflags)
1018             if cc_compilerchange:
1019                 lenv.Replace(CC = cc_compilerchange)
1020             if cxx_compilerchange:
1021                 lenv.Replace(CXX = cxx_compilerchange)
1022             lenv.Append(CFLAGS = lenv['C_WARN'])
1023             lenv.Append(CCFLAGS = lenv['CC_WARN'])
1024             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
1025
1026             if lenv['OURPLATFORM'] == 'win64-vc':
1027                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
1028
1029             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
1030                 if lenv['BF_DEBUG']:
1031                     lenv.Append(CCFLAGS = ['/MTd'])
1032                 else:
1033                     lenv.Append(CCFLAGS = ['/MT'])
1034             
1035             targetdir = root_build_dir+'lib/' + libname
1036             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
1037                 targetdir = '#'+targetdir
1038             lib = lenv.Library(target= targetdir, source=sources)
1039             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
1040             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
1041                 #if targetdir[0] == '#':
1042                 #    targetdir = targetdir[1:-1]
1043                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
1044                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
1045                          srcs = sources,
1046                          buildtarget = lib,
1047                          variant = 'Release',
1048                          auto_build_solution=0)
1049                 vcp.append(vcproject)
1050                 SConsEnvironment.Default(self, vcproject)
1051         else:
1052             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
1053         # note: libs is a global
1054         add_lib_to_dict(self, libs, libtype, libname, priority)
1055
1056     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
1057         global vcp
1058         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
1059         lenv = self.Clone()
1060         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
1061         lenv.Append(LINKFLAGS = lenv['BF_PROGRAM_LINKFLAGS'])
1062         if lenv['OURPLATFORM'] in ('win32-mingw', 'win64-mingw', 'linuxcross', 'cygwin', 'linux'):
1063             lenv.Replace(LINK = '$CXX')
1064         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
1065             if lenv['BF_DEBUG']:
1066                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
1067         if  lenv['OURPLATFORM']=='linux':
1068             if lenv['WITH_BF_PYTHON']:
1069                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1070         if  lenv['OURPLATFORM']=='sunos5':
1071             if lenv['WITH_BF_PYTHON']:
1072                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1073             if lenv['CXX'].endswith('CC'):
1074                 lenv.Replace(LINK = '$CXX')
1075         if  lenv['OURPLATFORM']=='darwin':
1076             if lenv['WITH_BF_PYTHON']:
1077                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
1078             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
1079         if lenv['BF_PROFILE']:
1080             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
1081         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
1082             lenv.Append(LIBPATH=root_build_dir + '/lib')
1083         lenv.Append(LIBPATH=libpath)
1084         lenv.Append(LIBS=libs)
1085         if lenv['WITH_BF_QUICKTIME']:
1086             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
1087             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
1088         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
1089         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
1090             f = lenv.File(progname + '.bsc', builddir)
1091             brs = lenv.Command(f, prog, [bsc])
1092             SConsEnvironment.Default(self, brs)
1093         SConsEnvironment.Default(self, prog)
1094         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
1095             print "! ",builddir + "/" + progname + '.sln'
1096             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
1097                      projects= vcp,
1098                      variant = 'Release')
1099             SConsEnvironment.Default(self, sln)
1100         program_list.append(prog)
1101         if  lenv['OURPLATFORM']=='darwin':
1102             lenv['BINARYKIND'] = binarykind
1103             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
1104         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
1105             if lenv['WITH_BF_PYTHON']:
1106                 if (not lenv['WITHOUT_BF_INSTALL'] and 
1107                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1108                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1109                     not BlenderEnvironment.PyBundleActionAdded):
1110                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
1111                     BlenderEnvironment.PyBundleActionAdded = True
1112         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
1113             if lenv['WITH_BF_PYTHON']:
1114                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1115                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1116                     not BlenderEnvironment.PyBundleActionAdded):
1117                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
1118                     BlenderEnvironment.PyBundleActionAdded = True
1119         return prog
1120
1121     def Glob(lenv, pattern):
1122         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
1123         files = []
1124         for i in glob.glob(path + pattern):
1125             files.append(string.replace(i, path, ''))
1126         return files