SCons: cleaner determination of 32-bit/64-bit builds
[blender.git] / build_files / scons / tools / Blender.py
1 #!/usr/bin/env python
2
3 """
4 tools.BlenderEnvironment
5
6 This environment builds on SCons.Script.SConscript.SConsEnvironment
7
8 * library repository
9 * custom printout
10 * wrapper functions
11
12 TODO: clean up and sanitise code - crosscheck with btools and SConstruct
13 to kill any code duplication
14
15 """
16
17 import os
18 import string
19 import ctypes as ct
20 import glob
21 import time
22 import sys
23 import tarfile
24 import shutil
25 import cStringIO
26 import platform
27
28 from SCons.Script.SConscript import SConsEnvironment
29 import SCons.Action
30 import SCons.Util
31 import SCons.Builder
32 import SCons.Subst
33 import SCons.Tool
34 import bcolors
35 bc = bcolors.bcolors()
36 import btools
37 VERSION = btools.VERSION
38 VERSION_RELEASE_CYCLE = btools.VERSION_RELEASE_CYCLE
39
40 Split = SCons.Util.Split
41 Action = SCons.Action.Action
42 Builder = SCons.Builder.Builder
43 GetBuildPath = SConsEnvironment.GetBuildPath
44
45 # a few globals
46 root_build_dir = ''
47 doc_build_dir = ''
48 quickie = None # Anything else than None if BF_QUICK has been passed
49 quicklist = [] # The list of libraries/programs to compile during a quickie
50 program_list = [] # A list holding Nodes to final binaries, used to create installs
51 arguments = None
52 targets = None
53 resources = []
54 allowed_bitnesses = {4 : 32, 8 : 64} # only expecting 32-bit or 64-bit
55 bitness = allowed_bitnesses[ct.sizeof(ct.c_void_p)]
56
57 ##### LIB STUFF ##########
58
59 possible_types = ['core'] # can be set in ie. SConstruct
60 libs = {}
61 vcp = []
62
63 def getresources():
64     return resources
65
66 def init_lib_dict():
67     for pt in possible_types:
68         libs[pt] = {}
69
70 # helper func for add_lib_to_dict
71 def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
72     if not libname in dict[libtype]:
73         done = None
74         while not done:
75             if dict[libtype].has_key(priority):
76                 priority = priority + 1
77             else:
78                 done = True
79         dict[libtype][priority] = libname
80
81 # libtype and priority can both be lists, for defining lib in multiple places
82 def add_lib_to_dict(env, dict = None, libtype = None, libname = None, priority = 100):
83     if not dict or not libtype or not libname:
84         print "Passed wrong arg"
85         env.Exit()
86
87     if type(libtype) is str and type(priority) is int:
88         internal_lib_to_dict(dict, libtype, libname, priority)
89     elif type(libtype) is list and type(priority) is list:
90         if len(libtype)==len(priority):
91             for lt, p in zip(libtype, priority):
92                 internal_lib_to_dict(dict, lt, libname, p)
93         else:
94             print "libtype and priority lists are unequal in length"
95             env.Exit()
96     else:
97         print "Wrong type combinations for libtype and priority. Only str and int or list and list"
98         env.Exit()
99
100 def create_blender_liblist(lenv = None, libtype = None):
101     if not lenv or not libtype:
102         print "missing arg"
103
104     lst = []
105     if libtype in possible_types:
106         curlib = libs[libtype]
107         sortlist = curlib.keys()
108         sortlist.sort()
109         for sk in sortlist:
110             v = curlib[sk]
111             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
112                 target = os.path.abspath(os.getcwd() + os.sep + root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
113             else:
114                 target = os.path.abspath(root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
115             lst.append(target)
116
117     return lst
118
119 ## TODO: static linking
120 def setup_staticlibs(lenv):
121     statlibs = [
122         #here libs for static linking
123     ]
124
125     libincs = []
126
127     if lenv['WITH_BF_FFMPEG']:
128         libincs += Split(lenv['BF_FFMPEG_LIBPATH'])
129
130     libincs.extend([
131         lenv['BF_OPENGL_LIBPATH'],
132         lenv['BF_JPEG_LIBPATH'],
133         lenv['BF_ZLIB_LIBPATH'],
134         lenv['BF_PNG_LIBPATH'],
135         lenv['BF_ICONV_LIBPATH']
136         ])
137
138     if lenv['WITH_BF_STATICJPEG']:
139         statlibs += Split(lenv['BF_JPEG_LIB_STATIC'])
140     if lenv['WITH_BF_STATICPNG']:
141         statlibs += Split(lenv['BF_PNG_LIB_STATIC'])
142
143     libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
144     if lenv['WITH_BF_PYTHON']:
145         libincs += Split(lenv['BF_PYTHON_LIBPATH'])
146     if lenv['WITH_BF_SDL']:
147         libincs += Split(lenv['BF_SDL_LIBPATH'])
148     if lenv['WITH_BF_JACK'] and not lenv['WITH_BF_JACK_DYNLOAD']:
149         libincs += Split(lenv['BF_JACK_LIBPATH'])
150     if lenv['WITH_BF_SNDFILE']:
151         libincs += Split(lenv['BF_SNDFILE_LIBPATH'])
152     if lenv['WITH_BF_TIFF']:
153         libincs += Split(lenv['BF_TIFF_LIBPATH'])
154         if lenv['WITH_BF_STATICTIFF']:
155             statlibs += Split(lenv['BF_TIFF_LIB_STATIC'])
156     if lenv['WITH_BF_FFTW3']:
157         libincs += Split(lenv['BF_FFTW3_LIBPATH'])
158         if lenv['WITH_BF_STATICFFTW3']:
159             statlibs += Split(lenv['BF_FFTW3_LIB_STATIC'])
160     '''
161     if lenv['WITH_BF_ELTOPO']:
162         libincs += Split(lenv['BF_LAPACK_LIBPATH'])
163         if lenv['WITH_BF_STATICLAPACK']:
164             statlibs += Split(lenv['BF_LAPACK_LIB_STATIC'])
165     '''
166     if lenv['WITH_BF_FFMPEG'] and lenv['WITH_BF_STATICFFMPEG']:
167         statlibs += Split(lenv['BF_FFMPEG_LIB_STATIC'])
168     if lenv['WITH_BF_INTERNATIONAL']:
169         if lenv['WITH_BF_FREETYPE_STATIC']:
170             statlibs += Split(lenv['BF_FREETYPE_LIB_STATIC'])
171     if lenv['WITH_BF_OPENAL']:
172         libincs += Split(lenv['BF_OPENAL_LIBPATH'])
173         if lenv['WITH_BF_STATICOPENAL']:
174             statlibs += Split(lenv['BF_OPENAL_LIB_STATIC'])
175     if lenv['WITH_BF_STATICOPENGL']:
176         statlibs += Split(lenv['BF_OPENGL_LIB_STATIC'])
177     if lenv['WITH_BF_STATICCXX']:
178         statlibs += Split(lenv['BF_CXX_LIB_STATIC'])
179
180     if lenv['WITH_BF_PYTHON'] and lenv['WITH_BF_STATICPYTHON']:
181         statlibs += Split(lenv['BF_PYTHON_LIB_STATIC'])
182
183     if lenv['WITH_BF_SNDFILE'] and lenv['WITH_BF_STATICSNDFILE']:
184         statlibs += Split(lenv['BF_SNDFILE_LIB_STATIC'])
185
186     if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
187         libincs += Split(lenv['BF_PTHREADS_LIBPATH'])
188
189     if lenv['WITH_BF_COLLADA']:
190         libincs += Split(lenv['BF_OPENCOLLADA_LIBPATH'])
191         if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
192             libincs += Split(lenv['BF_PCRE_LIBPATH'])
193             libincs += Split(lenv['BF_EXPAT_LIBPATH'])
194         if lenv['WITH_BF_STATICOPENCOLLADA']:
195             statlibs += Split(lenv['BF_OPENCOLLADA_LIB_STATIC'])
196
197     if lenv['WITH_BF_OPENMP']:
198         if lenv['OURPLATFORM'] == 'linuxcross':
199             libincs += Split(lenv['BF_OPENMP_LIBPATH'])
200         if lenv['WITH_BF_STATICOPENMP']:
201             statlibs += Split(lenv['BF_OPENMP_LIB_STATIC'])
202             
203     if lenv['WITH_BF_OIIO']:
204         libincs += Split(lenv['BF_OIIO_LIBPATH'])
205         if lenv['WITH_BF_STATICOIIO']:
206             statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
207     if lenv['WITH_BF_OPENEXR']:
208         libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
209         if lenv['WITH_BF_STATICOPENEXR']:
210             statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
211     if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']:
212         statlibs += Split(lenv['BF_ZLIB_LIB_STATIC'])
213
214     if lenv['WITH_BF_OCIO']:
215         libincs += Split(lenv['BF_OCIO_LIBPATH'])
216         if lenv['WITH_BF_STATICOCIO']:
217             statlibs += Split(lenv['BF_OCIO_LIB_STATIC'])
218
219     if lenv['WITH_BF_BOOST']:
220         libincs += Split(lenv['BF_BOOST_LIBPATH'])
221         if lenv['WITH_BF_STATICBOOST']:
222             statlibs += Split(lenv['BF_BOOST_LIB_STATIC'])
223
224     if lenv['WITH_BF_CYCLES_OSL']:
225         libincs += Split(lenv['BF_OSL_LIBPATH'])
226         if lenv['WITH_BF_STATICOSL']:
227             statlibs += Split(lenv['BF_OSL_LIB_STATIC'])
228
229     if lenv['WITH_BF_LLVM']:
230         libincs += Split(lenv['BF_LLVM_LIBPATH'])
231         if lenv['WITH_BF_STATICLLVM']:
232             statlibs += Split(lenv['BF_LLVM_LIB_STATIC'])
233
234     if lenv['WITH_BF_JEMALLOC']:
235         libincs += Split(lenv['BF_JEMALLOC_LIBPATH'])
236         if lenv['WITH_BF_STATICJEMALLOC']:
237             statlibs += Split(lenv['BF_JEMALLOC_LIB_STATIC'])
238
239     if lenv['OURPLATFORM']=='linux':
240         if lenv['WITH_BF_3DMOUSE']:
241             libincs += Split(lenv['BF_3DMOUSE_LIBPATH'])
242             if lenv['WITH_BF_STATIC3DMOUSE']:
243                 statlibs += Split(lenv['BF_3DMOUSE_LIB_STATIC'])
244
245     # setting this last so any overriding of manually libs could be handled
246     if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross', 'win64-mingw'):
247         # We must remove any previous items defining this path, for same reason stated above!
248         libincs = [e for e in libincs if SCons.Subst.scons_subst(e, lenv, gvars=lenv.Dictionary()) != "/usr/lib"]
249         libincs.append('/usr/lib')
250
251     return statlibs, libincs
252
253 def setup_syslibs(lenv):
254     syslibs = []
255
256     if not lenv['WITH_BF_FREETYPE_STATIC']:
257         syslibs += Split(lenv['BF_FREETYPE_LIB'])
258     if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']:
259         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw', 'win64-mingw'):
260             syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
261         else:
262             syslibs.append(lenv['BF_PYTHON_LIB'])
263     if lenv['WITH_BF_OPENAL']:
264         if not lenv['WITH_BF_STATICOPENAL']:
265             syslibs += Split(lenv['BF_OPENAL_LIB'])
266     if lenv['WITH_BF_OPENMP'] and lenv['CC'] != 'icc' and not lenv['WITH_BF_STATICOPENMP']:
267         if lenv['CC'] == 'cl.exe':
268             syslibs += ['vcomp']
269         else:
270             syslibs += ['gomp']
271     if lenv['WITH_BF_ICONV']:
272         syslibs += Split(lenv['BF_ICONV_LIB'])
273     if lenv['WITH_BF_OIIO']:
274         if not lenv['WITH_BF_STATICOIIO']:
275             syslibs += Split(lenv['BF_OIIO_LIB'])
276
277     if lenv['WITH_BF_OCIO']:
278         if not lenv['WITH_BF_STATICOCIO']:
279             syslibs += Split(lenv['BF_OCIO_LIB'])
280
281     if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
282         syslibs += Split(lenv['BF_OPENEXR_LIB'])
283     if lenv['WITH_BF_ZLIB'] and not lenv['WITH_BF_STATICZLIB']:
284         syslibs += Split(lenv['BF_ZLIB_LIB'])
285     if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
286         syslibs += Split(lenv['BF_TIFF_LIB'])
287     if lenv['WITH_BF_FFMPEG'] and not lenv['WITH_BF_STATICFFMPEG']:
288         syslibs += Split(lenv['BF_FFMPEG_LIB'])
289         if lenv['WITH_BF_OGG']:
290             syslibs += Split(lenv['BF_OGG_LIB'])
291     if lenv['WITH_BF_JACK'] and not lenv['WITH_BF_JACK_DYNLOAD']:
292         syslibs += Split(lenv['BF_JACK_LIB'])
293     if lenv['WITH_BF_SNDFILE'] and not lenv['WITH_BF_STATICSNDFILE']:
294         syslibs += Split(lenv['BF_SNDFILE_LIB'])
295     if lenv['WITH_BF_FFTW3'] and not lenv['WITH_BF_STATICFFTW3']:
296         syslibs += Split(lenv['BF_FFTW3_LIB'])
297     '''
298     if lenv['WITH_BF_ELTOPO']:
299         syslibs += Split(lenv['BF_LAPACK_LIB'])
300     '''
301     if lenv['WITH_BF_SDL']:
302         syslibs += Split(lenv['BF_SDL_LIB'])
303     if not lenv['WITH_BF_STATICOPENGL']:
304         syslibs += Split(lenv['BF_OPENGL_LIB'])
305     if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
306         syslibs += Split(lenv['BF_PTHREADS_LIB'])
307     if lenv['WITH_BF_COLLADA'] and not lenv['WITH_BF_STATICOPENCOLLADA']:
308         syslibs.append(lenv['BF_PCRE_LIB'])
309         if lenv['BF_DEBUG'] and (lenv['OURPLATFORM'] != 'linux'):
310             syslibs += [colladalib+'_d' for colladalib in Split(lenv['BF_OPENCOLLADA_LIB'])]
311         else:
312             syslibs += Split(lenv['BF_OPENCOLLADA_LIB'])
313         syslibs.append(lenv['BF_EXPAT_LIB'])
314
315     if lenv['WITH_BF_JEMALLOC']:
316         if not lenv['WITH_BF_STATICJEMALLOC']:
317             syslibs += Split(lenv['BF_JEMALLOC_LIB'])
318
319     if lenv['OURPLATFORM']=='linux':
320         if lenv['WITH_BF_3DMOUSE']:
321             if not lenv['WITH_BF_STATIC3DMOUSE']:
322                 syslibs += Split(lenv['BF_3DMOUSE_LIB'])
323                 
324     if lenv['WITH_BF_BOOST'] and not lenv['WITH_BF_STATICBOOST']:
325         syslibs += Split(lenv['BF_BOOST_LIB'])
326         
327         if lenv['WITH_BF_INTERNATIONAL']:
328             syslibs += Split(lenv['BF_BOOST_LIB_INTERNATIONAL'])
329
330     if lenv['WITH_BF_CYCLES_OSL'] and not lenv['WITH_BF_STATICOSL']:
331         syslibs += Split(lenv['BF_OSL_LIB'])
332
333     if lenv['WITH_BF_LLVM'] and not lenv['WITH_BF_STATICLLVM']:
334         syslibs += Split(lenv['BF_LLVM_LIB'])
335
336     if not lenv['WITH_BF_STATICJPEG']:
337         syslibs += Split(lenv['BF_JPEG_LIB'])
338
339     if not lenv['WITH_BF_STATICPNG']:
340         syslibs += Split(lenv['BF_PNG_LIB'])
341
342     syslibs += lenv['LLIBS']
343
344     return syslibs
345
346 def propose_priorities():
347     print bc.OKBLUE+"Priorities:"+bc.ENDC
348     for t in possible_types:
349         print bc.OKGREEN+"\t"+t+bc.ENDC
350         new_priority = 0
351         curlib = libs[t]
352         sortlist = curlib.keys()
353         sortlist.sort()
354
355         for sk in sortlist:
356             v = curlib[sk]
357             #for p,v in sorted(libs[t].iteritems()):
358             print "\t\t",new_priority, v
359             new_priority += 5
360
361 # emits the necessary file objects for creator.c, to be used in creating
362 # the final blender executable
363 def creator(env):
364     sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
365
366     incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
367
368     defs = []
369
370     if env['WITH_BF_BINRELOC']:
371         incs.append('#/extern/binreloc/include')
372         defs.append('WITH_BINRELOC')
373
374     if env['WITH_BF_SDL']:
375         defs.append('WITH_SDL')
376
377     if env['WITH_BF_LIBMV']:
378         incs.append('#/extern/libmv')
379         defs.append('WITH_LIBMV')
380
381     if env['WITH_BF_FFMPEG']:
382         defs.append('WITH_FFMPEG')
383
384     if env['WITH_BF_PYTHON']:
385         incs.append('#/source/blender/python')
386         defs.append('WITH_PYTHON')
387         if env['BF_DEBUG']:
388             defs.append('_DEBUG')
389
390     if env['WITH_BF_FREESTYLE']:
391         incs.append('#/source/blender/freestyle')
392         defs.append('WITH_FREESTYLE')
393
394     if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
395         incs.append(env['BF_PTHREADS_INC'])
396         incs.append('#/intern/utfconv')
397
398     env.Append(CPPDEFINES=defs)
399     env.Append(CPPPATH=incs)
400     obj = [env.Object(root_build_dir+'source/creator/creator/creator', ['#source/creator/creator.c'])]
401
402     return obj
403
404 ## TODO: see if this can be made in an emitter
405 def buildinfo(lenv, build_type):
406     """
407     Generate a buildinfo object
408     """
409     build_date = time.strftime ("%Y-%m-%d")
410     build_time = time.strftime ("%H:%M:%S")
411
412     if os.path.isdir(os.path.abspath('.git')):
413         build_commit_timestamp = os.popen('git log -1 --format=%ct').read().strip()
414         if not build_commit_timestamp:
415             # Git command not found
416             build_hash = 'unknown'
417             build_commit_timestamp = '0'
418             build_branch = 'unknown'
419         else:
420             import subprocess
421             no_upstream = False
422
423             process = subprocess.Popen(['git', 'rev-parse', '--short', '@{u}'],
424                                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
425             build_hash, stderr = process.communicate()
426             build_hash = build_hash.strip()
427             build_branch = os.popen('git rev-parse --abbrev-ref HEAD').read().strip()
428
429             if build_hash == '':
430                 build_hash = os.popen('git rev-parse --short HEAD').read().strip()
431                 no_upstream = True
432
433             # ## Check for local modifications
434             has_local_changes = False
435
436             # Update GIT index before getting dirty files
437             os.system('git update-index -q --refresh')
438             changed_files = os.popen('git diff-index --name-only HEAD --').read().strip()
439
440             if changed_files:
441                 has_local_changes = True
442             elif no_upstream == False:
443                 unpushed_log = os.popen('git log @{u}..').read().strip()
444                 has_local_changes = unpushed_log != ''
445
446             if has_local_changes:
447                 build_branch += ' (modified)'
448     else:
449         build_hash = 'unknown'
450         build_commit_timestamp = '0'
451         build_branch = 'unknown'
452
453     if lenv['BF_DEBUG']:
454         build_type = "Debug"
455         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['BF_DEBUG_CCFLAGS'] + lenv['CPPFLAGS'])
456         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['CPPFLAGS'])
457     else:
458         build_type = "Release"
459         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['REL_CFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
460         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['REL_CXXFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
461
462     build_linkflags = ' '.join(lenv['PLATFORM_LINKFLAGS'])
463
464     obj = []
465     if lenv['BF_BUILDINFO']:
466         lenv.Append (CPPDEFINES = ['BUILD_TIME=\\"%s\\"'%(build_time),
467                                     'BUILD_DATE=\\"%s\\"'%(build_date),
468                                     'BUILD_TYPE=\\"%s\\"'%(build_type),
469                                     'BUILD_HASH=\\"%s\\"'%(build_hash),
470                                     'BUILD_COMMIT_TIMESTAMP=%s'%(build_commit_timestamp),
471                                     'BUILD_BRANCH=\\"%s\\"'%(build_branch),
472                                     'WITH_BUILDINFO',
473                                     'BUILD_PLATFORM=\\"%s:%s\\"'%(platform.system(), platform.architecture()[0]),
474                                     'BUILD_CFLAGS=\\"%s\\"'%(build_cflags),
475                                     'BUILD_CXXFLAGS=\\"%s\\"'%(build_cxxflags),
476                                     'BUILD_LINKFLAGS=\\"%s\\"'%(build_linkflags),
477                                     'BUILD_SYSTEM=\\"SCons\\"'
478                     ])
479
480         lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel'])
481
482         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, ['#source/creator/buildinfo.c'])]
483
484     return obj
485
486 ##### END LIB STUFF ############
487
488 ##### ACTION STUFF #############
489
490 def my_print_cmd_line(self, s, target, source, env):
491     sys.stdout.write(' ' * 70 + '\r')
492     sys.stdout.flush()
493     sys.stdout.write(s + "\r")
494     sys.stdout.flush()
495
496 def my_compile_print(target, source, env):
497     a = '%s' % (source[0])
498     d, f = os.path.split(a)
499     return bc.OKBLUE + "Compiling" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
500
501 def my_moc_print(target, source, env):
502     a = '%s' % (source[0])
503     d, f = os.path.split(a)
504     return bc.OKBLUE + "Creating MOC" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
505
506 def my_linking_print(target, source, env):
507     t = '%s' % (target[0])
508     d, f = os.path.split(t)
509     return bc.OKBLUE + "Linking library" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
510
511 def my_program_print(target, source, env):
512     t = '%s' % (target[0])
513     d, f = os.path.split(t)
514     return bc.OKBLUE + "Linking program" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
515
516 def msvc_hack(env):
517     static_lib = SCons.Tool.createStaticLibBuilder(env)
518     program = SCons.Tool.createProgBuilder(env)
519     
520     env['BUILDERS']['Library'] = static_lib
521     env['BUILDERS']['StaticLibrary'] = static_lib
522     env['BUILDERS']['Program'] = program
523         
524 def set_quiet_output(env):
525     mycaction = Action("$CCCOM", strfunction=my_compile_print)
526     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
527     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
528     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
529     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
530     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
531
532     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
533     static_ob.add_action('.c', mycaction)
534     static_ob.add_action('.cpp', mycppaction)
535     static_ob.add_action('.cc', mycppaction)
536     shared_ob.add_action('.c', myshcaction)
537     shared_ob.add_action('.cc', myshcppaction)
538
539     static_lib = SCons.Builder.Builder(action = mylibaction,
540                                        emitter = '$LIBEMITTER',
541                                        prefix = '$LIBPREFIX',
542                                        suffix = '$LIBSUFFIX',
543                                        src_suffix = '$OBJSUFFIX',
544                                        src_builder = 'StaticObject')
545
546     program = SCons.Builder.Builder(action = mylinkaction,
547                                     emitter = '$PROGEMITTER',
548                                     prefix = '$PROGPREFIX',
549                                     suffix = '$PROGSUFFIX',
550                                     src_suffix = '$OBJSUFFIX',
551                                     src_builder = 'Object',
552                                     target_scanner = SCons.Defaults.ProgScan)
553
554     env['BUILDERS']['Object'] = static_ob
555     env['BUILDERS']['StaticObject'] = static_ob
556     env['BUILDERS']['StaticLibrary'] = static_lib
557     env['BUILDERS']['Library'] = static_lib
558     env['BUILDERS']['Program'] = program
559     if env['BF_LINE_OVERWRITE']:
560         SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
561
562 def untar_pybundle(from_tar,to_dir,exclude_re):
563     tar= tarfile.open(from_tar, mode='r')
564     exclude_re= list(exclude_re) #single re object or list of re objects
565     debug= 0 #list files instead of unpacking
566     good= []
567     if debug: print '\nFiles not being unpacked:\n'
568     for name in tar.getnames():
569         is_bad= 0
570         for r in exclude_re:
571             if r.match(name):
572                 is_bad=1
573                 if debug: print name
574                 break
575         if not is_bad:
576             good.append(tar.getmember(name))
577     if debug:
578         print '\nFiles being unpacked:\n'
579         for g in good:
580             print g
581     else:
582         tar.extractall(to_dir, good)
583
584 def my_winpybundle_print(target, source, env):
585     pass
586
587 def WinPyBundle(target=None, source=None, env=None):
588     import re
589     py_tar= env.subst( env['LCGDIR'] )
590     if py_tar[0]=='#':
591         py_tar= py_tar[1:]
592     if env['BF_DEBUG']:
593         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.tar.gz'
594     else:
595         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
596
597     py_target = env.subst( env['BF_INSTALLDIR'] )
598     if py_target[0]=='#':
599         py_target=py_target[1:]
600     py_target = os.path.join(py_target, VERSION, 'python', 'lib')
601     def printexception(func,path,ex):
602         if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
603             print str(func) + ' failed on ' + str(path)
604     print "Trying to remove existing py bundle."
605     shutil.rmtree(py_target, False, printexception)
606     exclude_re=[re.compile('.*/test'),
607                 re.compile('^test'),
608                 re.compile('^distutils'),
609                 re.compile('^idlelib'),
610                 re.compile('^lib2to3'),
611                 re.compile('^tkinter'),
612                 re.compile('^_tkinter_d.pyd'),
613                 re.compile('^turtledemo'),
614                 re.compile('^turtle.py'),
615                 ]
616
617     print "Unpacking '" + py_tar + "' to '" + py_target + "'"
618     untar_pybundle(py_tar,py_target,exclude_re)
619
620 def  my_appit_print(target, source, env):
621     a = '%s' % (target[0])
622     d, f = os.path.split(a)
623     return "making bundle for " + f
624
625 def AppIt(target=None, source=None, env=None):
626     import shutil
627     import commands
628     import os.path
629     
630     
631     a = '%s' % (target[0])
632     builddir, b = os.path.split(a)
633     libdir = env['LCGDIR'][1:]
634     osxarch = env['MACOSX_ARCHITECTURE']
635     installdir = env['BF_INSTALLDIR']
636     print("compiled architecture: %s"%(osxarch))
637     print("Installing to %s"%(installdir))
638     # TODO, use tar.
639     python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
640     if env['WITH_OSX_STATICPYTHON']:
641         print("unzipping to app-bundle: %s"%(python_zip))
642     else:
643         print("dynamic build - make sure to have python3.x-framework installed")
644     bldroot = env.Dir('.').abspath
645     binary = env['BINARYKIND']
646      
647     sourcedir = bldroot + '/release/darwin/%s.app' % binary
648     sourceinfo = bldroot + "/release/darwin/%s.app/Contents/Info.plist"%binary
649     targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
650     cmd = installdir + '/' +'%s.app'%binary
651     
652     if os.path.isdir(cmd):
653         shutil.rmtree(cmd)
654     shutil.copytree(sourcedir, cmd)
655     cmd = "cat %s | sed s/\$\{MACOSX_BUNDLE_SHORT_VERSION_STRING\}/%s/ | "%(sourceinfo,VERSION)
656     cmd += "sed s/\$\{MACOSX_BUNDLE_LONG_VERSION_STRING\}/%s,\ %s/g > %s"%(VERSION,time.strftime("%Y-%b-%d"),targetinfo)
657     commands.getoutput(cmd)
658     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
659     commands.getoutput(cmd)
660     cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/'%(installdir, binary, VERSION)
661     commands.getoutput(cmd)
662     cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
663
664     # blenderplayer doesn't need all the files
665     if binary == 'blender':
666         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/datafiles'%(installdir, binary, VERSION)
667         commands.getoutput(cmd)
668         cmd = 'cp -R %s/release/datafiles/fonts %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
669         commands.getoutput(cmd)
670         cmd = 'cp -R %s/release/datafiles/locale/languages %s/%s.app/Contents/MacOS/%s/datafiles/locale/'%(bldroot, installdir, binary, VERSION)
671         commands.getoutput(cmd)
672         mo_dir = os.path.join(builddir[:-4], "locale")
673         for f in os.listdir(mo_dir):
674             cmd = 'ditto %s/%s %s/%s.app/Contents/MacOS/%s/datafiles/locale/%s/LC_MESSAGES/blender.mo'%(mo_dir, f, installdir, binary, VERSION, f[:-3])
675             commands.getoutput(cmd)
676
677         if env['WITH_BF_OCIO']:
678             cmd = 'cp -R %s/release/datafiles/colormanagement %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
679             commands.getoutput(cmd)
680         
681         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
682         commands.getoutput(cmd)
683
684         if VERSION_RELEASE_CYCLE == "release":
685             cmd = 'rm -rf %s/%s.app/Contents/MacOS/%s/scripts/addons_contrib'%(installdir,binary,VERSION)
686             commands.getoutput(cmd)
687
688         if env['WITH_BF_CYCLES']:
689             croot = '%s/intern/cycles' % (bldroot)
690             cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
691
692             cmd = 'mkdir %s' % (cinstalldir)
693             commands.getoutput(cmd)
694             cmd = 'mkdir %s/kernel' % (cinstalldir)
695             commands.getoutput(cmd)
696             cmd = 'mkdir %s/lib' % (cinstalldir)
697             commands.getoutput(cmd)
698             cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
699             commands.getoutput(cmd)
700             cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
701             commands.getoutput(cmd)
702             cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
703             commands.getoutput(cmd)
704             cmd = 'cp -R %s/kernel/svm %s/kernel/closure %s/util/util_color.h %s/util/util_half.h %s/util/util_math.h %s/util/util_transform.h %s/util/util_types.h %s/kernel/' % (croot, croot, croot, croot, croot, croot, croot, cinstalldir)
705             commands.getoutput(cmd)
706             cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
707             commands.getoutput(cmd)
708
709             if env['WITH_BF_CYCLES_OSL']:
710                 cmd = 'mkdir %s/shader' % (cinstalldir)
711                 commands.getoutput(cmd)
712                 cmd = 'cp -R %s/kernel/shaders/*.h %s/shader' % (croot, cinstalldir)
713                 commands.getoutput(cmd)
714                 cmd = 'cp -R %s/../intern/cycles/kernel/shaders/*.oso %s/shader' % (builddir, cinstalldir)
715                 commands.getoutput(cmd)
716
717     if env['WITH_OSX_STATICPYTHON']:
718         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
719         commands.getoutput(cmd)
720         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
721         commands.getoutput(cmd)
722
723     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
724     commands.getoutput(cmd)
725     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
726     commands.getoutput(cmd)
727     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
728     commands.getoutput(cmd)
729     cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
730     commands.getoutput(cmd)
731     if env['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
732         print "Bundling libgcc and libgomp"
733         instname = env['BF_CXX']
734         cmd = 'ditto --arch %s %s/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libgcc
735         commands.getoutput(cmd)
736         cmd = 'install_name_tool -id @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/libgcc_s.1.dylib'%(installdir, binary) # change id of libgcc
737         commands.getoutput(cmd)
738         cmd = 'ditto --arch %s %s/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libgomp
739         commands.getoutput(cmd)
740         cmd = 'install_name_tool -id @executable_path/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/lib/libgomp.1.dylib'%(installdir, binary) # change id of libgomp
741         commands.getoutput(cmd)
742         cmd = 'install_name_tool -change %s/lib/libgcc_s.1.dylib  @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/libgomp.1.dylib'%(instname, installdir, binary) # change ref to libgcc
743         commands.getoutput(cmd)
744         cmd = 'install_name_tool -change %s/lib/libgcc_s.1.dylib  @executable_path/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/%s'%(instname, installdir, binary, binary) # change ref to libgcc ( blender )
745         commands.getoutput(cmd)
746         cmd = 'install_name_tool -change %s/lib/libgomp.1.dylib  @executable_path/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/%s'%(instname, installdir, binary, binary) # change ref to libgomp ( blender )
747         commands.getoutput(cmd)
748
749 # extract copy system python, be sure to update other build systems
750 # when making changes to the files that are copied.
751 def my_unixpybundle_print(target, source, env):
752     pass
753
754 def UnixPyBundle(target=None, source=None, env=None):
755     # Any Unix except osx
756     #-- VERSION/python/lib/python3.1
757     
758     import commands
759     
760     def run(cmd):
761         print 'Install command:', cmd
762         commands.getoutput(cmd)
763
764     dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
765
766     lib = env['BF_PYTHON_LIBPATH'].split(os.sep)[-1]
767     target_lib = "lib64" if lib == "lib64" else "lib"
768
769     py_src =    env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
770     py_target =    env.subst( dir + '/python/' + target_lib + '/python'+env['BF_PYTHON_VERSION'] )
771     
772     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
773     if os.path.exists(py_target):
774         print 'Using existing python from:'
775         print '\t"%s"' %            py_target
776         print '\t(skipping copy)\n'
777         return
778
779     # Copied from source/creator/CMakeLists.txt, keep in sync.
780     print 'Install python from:'
781     print '\t"%s" into...' % py_src
782     print '\t"%s"\n' % py_target
783
784     run("rm -rf '%s'" % py_target)
785     try:
786         os.makedirs(os.path.dirname(py_target)) # the final part is copied
787     except:
788         pass
789
790     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
791     run("rm -rf '%s/distutils'" % py_target)
792     run("rm -rf '%s/lib2to3'" % py_target)
793     run("rm -rf '%s/config'" % py_target)
794
795     for f in os.listdir(py_target):
796         if f.startswith("config-"):
797             run("rm -rf '%s/%s'" % (py_target, f))
798
799     run("rm -rf '%s/site-packages'" % py_target)
800     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
801     run("rm -rf '%s/idlelib'" % py_target)
802     run("rm -rf '%s/tkinter'" % py_target)
803     run("rm -rf '%s/turtledemo'" % py_target)
804     run("rm -r '%s/turtle.py'" % py_target)
805     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
806
807     if env['WITH_BF_PYTHON_INSTALL_NUMPY']:
808         numpy_src = py_src + "/site-packages/numpy"
809         numpy_target = py_target + "/site-packages/numpy"
810
811         if os.path.exists(numpy_src):
812             print 'Install numpy from:'
813             print '\t"%s" into...' % numpy_src
814             print '\t"%s"\n' % numpy_target
815
816             run("cp -R '%s' '%s'" % (numpy_src, os.path.dirname(numpy_target)))
817             run("rm -rf '%s/distutils'" % numpy_target)
818             run("rm -rf '%s/oldnumeric'" % numpy_target)
819             run("rm -rf '%s/doc'" % numpy_target)
820             run("rm -rf '%s/tests'" % numpy_target)
821             run("rm -rf '%s/f2py'" % numpy_target)
822             run("find '%s' -type d -name 'include' -prune -exec rm -rf {} ';'" % numpy_target)
823             run("find '%s' -type d -name '*.h' -prune -exec rm -rf {} ';'" % numpy_target)
824             run("find '%s' -type d -name '*.a' -prune -exec rm -rf {} ';'" % numpy_target)
825         else:
826             print 'Failed to find numpy at %s, skipping copying' % numpy_src
827
828     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
829     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
830     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
831     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
832
833 #### END ACTION STUFF #########
834
835 def bsc(env, target, source):
836     
837     bd = os.path.dirname(target[0].abspath)
838     bscfile = '\"'+target[0].abspath+'\"'
839     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
840     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
841
842     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
843
844     myfile = open(bscpathtmp[1:-1], 'r')
845     lines = myfile.readlines()
846     myfile.close()
847
848     newfile = open(bscpathtmp[1:-1], 'w')
849     for l in lines:
850         newfile.write('\"'+l[:-1]+'\"\n')
851     newfile.close()
852                 
853     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
854     os.system('del '+bscpathtmp)
855
856 class BlenderEnvironment(SConsEnvironment):
857
858     PyBundleActionAdded = False
859
860     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
861         global libs
862         if not self or not libname or not source:
863             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
864             self.Exit()
865         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
866             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
867             self.Exit()
868         
869         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
870         lenv = self.Clone()
871         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
872             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
873         else:
874             res = lenv.RES(root_build_dir+'lib/'+libname, source)
875
876         
877         SConsEnvironment.Default(self, res)
878         resources.append(res)
879
880     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):
881         global vcp
882         
883         # sanity check
884         # run once in a while to check we dont have duplicates
885         if 0:
886             for name, dirs in (("source", sources), ("include", includes)):
887                 files_clean = [os.path.normpath(f) for f in dirs]
888                 files_clean_set = set(files_clean)
889                 if len(files_clean) != len(files_clean_set):
890                     for f in sorted(files_clean_set):
891                         if f != '.' and files_clean.count(f) > 1:
892                             raise Exception("Found duplicate %s %r" % (name, f))
893             del name, dirs, files_clean, files_clean_set, f
894         # end sanity check
895
896         if not self or not libname or not sources:
897             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
898             self.Exit()
899
900         def list_substring(quickie, libname):
901             for q in quickie:
902                 if q in libname:
903                     return True
904             return False
905
906         if list_substring(quickie, libname) or len(quickie)==0:
907             if list_substring(quickdebug, libname):
908                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
909             else:
910                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
911             lenv = self.Clone()
912             lenv.Append(CPPPATH=includes)
913             lenv.Append(CPPDEFINES=defines)
914             if lenv['BF_DEBUG'] or (libname in quickdebug):
915                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
916                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
917                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
918             else:
919                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
920                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
921                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
922             if lenv['BF_PROFILE']:
923                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
924                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
925                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
926             if compileflags:
927                 lenv.Replace(CFLAGS = compileflags)
928             if cc_compileflags:
929                 lenv.Replace(CCFLAGS = cc_compileflags)
930             if cxx_compileflags:
931                 lenv.Replace(CXXFLAGS = cxx_compileflags)
932             if cc_compilerchange:
933                 lenv.Replace(CC = cc_compilerchange)
934             if cxx_compilerchange:
935                 lenv.Replace(CXX = cxx_compilerchange)
936             lenv.Append(CFLAGS = lenv['C_WARN'])
937             lenv.Append(CCFLAGS = lenv['CC_WARN'])
938             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
939
940             if lenv['OURPLATFORM'] == 'win64-vc':
941                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
942
943             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
944                 if lenv['BF_DEBUG']:
945                     lenv.Append(CCFLAGS = ['/MTd'])
946                 else:
947                     lenv.Append(CCFLAGS = ['/MT'])
948             
949             targetdir = root_build_dir+'lib/' + libname
950             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
951                 targetdir = '#'+targetdir
952             lib = lenv.Library(target= targetdir, source=sources)
953             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
954             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
955                 #if targetdir[0] == '#':
956                 #    targetdir = targetdir[1:-1]
957                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
958                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
959                          srcs = sources,
960                          buildtarget = lib,
961                          variant = 'Release',
962                          auto_build_solution=0)
963                 vcp.append(vcproject)
964                 SConsEnvironment.Default(self, vcproject)
965         else:
966             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
967         # note: libs is a global
968         add_lib_to_dict(self, libs, libtype, libname, priority)
969
970     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
971         global vcp
972         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
973         lenv = self.Clone()
974         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
975         lenv.Append(LINKFLAGS = lenv['BF_PROGRAM_LINKFLAGS'])
976         if lenv['OURPLATFORM'] in ('win32-mingw', 'win64-mingw', 'linuxcross', 'cygwin', 'linux'):
977             lenv.Replace(LINK = '$CXX')
978         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
979             if lenv['BF_DEBUG']:
980                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
981         if  lenv['OURPLATFORM']=='linux':
982             if lenv['WITH_BF_PYTHON']:
983                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
984         if  lenv['OURPLATFORM']=='sunos5':
985             if lenv['WITH_BF_PYTHON']:
986                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
987             if lenv['CXX'].endswith('CC'):
988                 lenv.Replace(LINK = '$CXX')
989         if  lenv['OURPLATFORM']=='darwin':
990             if lenv['WITH_BF_PYTHON']:
991                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
992             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
993         if lenv['BF_PROFILE']:
994             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
995         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
996             lenv.Append(LIBPATH=root_build_dir + '/lib')
997         lenv.Append(LIBPATH=libpath)
998         lenv.Append(LIBS=libs)
999         if lenv['WITH_BF_QUICKTIME']:
1000             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
1001             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
1002         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
1003         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
1004             f = lenv.File(progname + '.bsc', builddir)
1005             brs = lenv.Command(f, prog, [bsc])
1006             SConsEnvironment.Default(self, brs)
1007         SConsEnvironment.Default(self, prog)
1008         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
1009             print "! ",builddir + "/" + progname + '.sln'
1010             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
1011                      projects= vcp,
1012                      variant = 'Release')
1013             SConsEnvironment.Default(self, sln)
1014         program_list.append(prog)
1015         if  lenv['OURPLATFORM']=='darwin':
1016             lenv['BINARYKIND'] = binarykind
1017             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
1018         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
1019             if lenv['WITH_BF_PYTHON']:
1020                 if (not lenv['WITHOUT_BF_INSTALL'] and 
1021                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1022                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1023                     not BlenderEnvironment.PyBundleActionAdded):
1024                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
1025                     BlenderEnvironment.PyBundleActionAdded = True
1026         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
1027             if lenv['WITH_BF_PYTHON']:
1028                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
1029                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
1030                     not BlenderEnvironment.PyBundleActionAdded):
1031                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
1032                     BlenderEnvironment.PyBundleActionAdded = True
1033         return prog
1034
1035     def Glob(lenv, pattern):
1036         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
1037         files = []
1038         for i in glob.glob(path + pattern):
1039             files.append(string.replace(i, path, ''))
1040         return files