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