9bce91ba9a58c7cccffa6295fce1f31edbfe4533
[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     build_rev = os.popen('svnversion').read()[:-1] # remove \n
414     if build_rev == '': 
415         build_rev = '-UNKNOWN-'
416     if lenv['BF_DEBUG']:
417         build_type = "Debug"
418         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['BF_DEBUG_CCFLAGS'] + lenv['CPPFLAGS'])
419         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['CPPFLAGS'])
420     else:
421         build_type = "Release"
422         build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['REL_CFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
423         build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['REL_CXXFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
424
425     build_linkflags = ' '.join(lenv['PLATFORM_LINKFLAGS'])
426
427     obj = []
428     if lenv['BF_BUILDINFO']:
429         lenv.Append (CPPDEFINES = ['BUILD_TIME=\\"%s\\"'%(build_time),
430                                     'BUILD_DATE=\\"%s\\"'%(build_date),
431                                     'BUILD_TYPE=\\"%s\\"'%(build_type),
432                                     'BUILD_REV=\\"%s\\"'%(build_rev),
433                                     'WITH_BUILDINFO',
434                                     'BUILD_PLATFORM=\\"%s:%s\\"'%(platform.system(), platform.architecture()[0]),
435                                     'BUILD_CFLAGS=\\"%s\\"'%(build_cflags),
436                                     'BUILD_CXXFLAGS=\\"%s\\"'%(build_cxxflags),
437                                     'BUILD_LINKFLAGS=\\"%s\\"'%(build_linkflags),
438                                     'BUILD_SYSTEM=\\"SCons\\"'
439                     ])
440
441         lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel'])
442
443         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, ['#source/creator/buildinfo.c'])]
444
445     return obj
446
447 ##### END LIB STUFF ############
448
449 ##### ACTION STUFF #############
450
451 def my_print_cmd_line(self, s, target, source, env):
452     sys.stdout.write(' ' * 70 + '\r')
453     sys.stdout.flush()
454     sys.stdout.write(s + "\r")
455     sys.stdout.flush()
456
457 def my_compile_print(target, source, env):
458     a = '%s' % (source[0])
459     d, f = os.path.split(a)
460     return bc.OKBLUE + "Compiling" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
461
462 def my_moc_print(target, source, env):
463     a = '%s' % (source[0])
464     d, f = os.path.split(a)
465     return bc.OKBLUE + "Creating MOC" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
466
467 def my_linking_print(target, source, env):
468     t = '%s' % (target[0])
469     d, f = os.path.split(t)
470     return bc.OKBLUE + "Linking library" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
471
472 def my_program_print(target, source, env):
473     t = '%s' % (target[0])
474     d, f = os.path.split(t)
475     return bc.OKBLUE + "Linking program" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
476
477 def msvc_hack(env):
478     static_lib = SCons.Tool.createStaticLibBuilder(env)
479     program = SCons.Tool.createProgBuilder(env)
480     
481     env['BUILDERS']['Library'] = static_lib
482     env['BUILDERS']['StaticLibrary'] = static_lib
483     env['BUILDERS']['Program'] = program
484         
485 def set_quiet_output(env):
486     mycaction = Action("$CCCOM", strfunction=my_compile_print)
487     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
488     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
489     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
490     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
491     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
492
493     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
494     static_ob.add_action('.c', mycaction)
495     static_ob.add_action('.cpp', mycppaction)
496     static_ob.add_action('.cc', mycppaction)
497     shared_ob.add_action('.c', myshcaction)
498     shared_ob.add_action('.cc', myshcppaction)
499
500     static_lib = SCons.Builder.Builder(action = mylibaction,
501                                        emitter = '$LIBEMITTER',
502                                        prefix = '$LIBPREFIX',
503                                        suffix = '$LIBSUFFIX',
504                                        src_suffix = '$OBJSUFFIX',
505                                        src_builder = 'StaticObject')
506
507     program = SCons.Builder.Builder(action = mylinkaction,
508                                     emitter = '$PROGEMITTER',
509                                     prefix = '$PROGPREFIX',
510                                     suffix = '$PROGSUFFIX',
511                                     src_suffix = '$OBJSUFFIX',
512                                     src_builder = 'Object',
513                                     target_scanner = SCons.Defaults.ProgScan)
514
515     env['BUILDERS']['Object'] = static_ob
516     env['BUILDERS']['StaticObject'] = static_ob
517     env['BUILDERS']['StaticLibrary'] = static_lib
518     env['BUILDERS']['Library'] = static_lib
519     env['BUILDERS']['Program'] = program
520     if env['BF_LINE_OVERWRITE']:
521         SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
522
523 def untar_pybundle(from_tar,to_dir,exclude_re):
524     tar= tarfile.open(from_tar, mode='r')
525     exclude_re= list(exclude_re) #single re object or list of re objects
526     debug= 0 #list files instead of unpacking
527     good= []
528     if debug: print '\nFiles not being unpacked:\n'
529     for name in tar.getnames():
530         is_bad= 0
531         for r in exclude_re:
532             if r.match(name):
533                 is_bad=1
534                 if debug: print name
535                 break
536         if not is_bad:
537             good.append(tar.getmember(name))
538     if debug:
539         print '\nFiles being unpacked:\n'
540         for g in good:
541             print g
542     else:
543         tar.extractall(to_dir, good)
544
545 def my_winpybundle_print(target, source, env):
546     pass
547
548 def WinPyBundle(target=None, source=None, env=None):
549     import re
550     py_tar= env.subst( env['LCGDIR'] )
551     if py_tar[0]=='#':
552         py_tar= py_tar[1:]
553     if env['BF_DEBUG']:
554         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.tar.gz'
555     else:
556         py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
557
558     py_target = env.subst( env['BF_INSTALLDIR'] )
559     if py_target[0]=='#':
560         py_target=py_target[1:]
561     py_target = os.path.join(py_target, VERSION, 'python', 'lib')
562     def printexception(func,path,ex):
563         if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
564             print str(func) + ' failed on ' + str(path)
565     print "Trying to remove existing py bundle."
566     shutil.rmtree(py_target, False, printexception)
567     exclude_re=[re.compile('.*/test'),
568                 re.compile('^test'),
569                 re.compile('^distutils'),
570                 re.compile('^idlelib'),
571                 re.compile('^lib2to3'),
572                 re.compile('^tkinter'),
573                 re.compile('^_tkinter_d.pyd'),
574                 re.compile('^turtledemo'),
575                 re.compile('^turtle.py'),
576                 ]
577
578     print "Unpacking '" + py_tar + "' to '" + py_target + "'"
579     untar_pybundle(py_tar,py_target,exclude_re)
580
581 def  my_appit_print(target, source, env):
582     a = '%s' % (target[0])
583     d, f = os.path.split(a)
584     return "making bundle for " + f
585
586 def AppIt(target=None, source=None, env=None):
587     import shutil
588     import commands
589     import os.path
590     
591     
592     a = '%s' % (target[0])
593     builddir, b = os.path.split(a)
594     libdir = env['LCGDIR'][1:]
595     osxarch = env['MACOSX_ARCHITECTURE']
596     installdir = env['BF_INSTALLDIR']
597     print("compiled architecture: %s"%(osxarch))
598     print("Installing to %s"%(installdir))
599     # TODO, use tar.
600     python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
601     if env['WITH_OSX_STATICPYTHON']:
602         print("unzipping to app-bundle: %s"%(python_zip))
603     else:
604         print("dynamic build - make sure to have python3.x-framework installed")
605     bldroot = env.Dir('.').abspath
606     binary = env['BINARYKIND']
607      
608     sourcedir = bldroot + '/release/darwin/%s.app' % binary
609     sourceinfo = bldroot + "/release/darwin/%s.app/Contents/Info.plist"%binary
610     targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
611     cmd = installdir + '/' +'%s.app'%binary
612     
613     if os.path.isdir(cmd):
614         shutil.rmtree(cmd)
615     shutil.copytree(sourcedir, cmd)
616     cmd = "cat %s | sed s/\$\{MACOSX_BUNDLE_SHORT_VERSION_STRING\}/%s/ | "%(sourceinfo,VERSION)
617     cmd += "sed s/\$\{MACOSX_BUNDLE_LONG_VERSION_STRING\}/%s,\ %s/g > %s"%(VERSION,time.strftime("%Y-%b-%d"),targetinfo)
618     commands.getoutput(cmd)
619     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
620     commands.getoutput(cmd)
621     cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/'%(installdir, binary, VERSION)
622     commands.getoutput(cmd)
623     cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
624
625     # blenderplayer doesn't need all the files
626     if binary == 'blender':
627         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/datafiles'%(installdir, binary, VERSION)
628         commands.getoutput(cmd)
629         cmd = 'cp -R %s/release/datafiles/locale %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
630         commands.getoutput(cmd)
631         cmd = 'cp -R %s/release/datafiles/fonts %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
632         commands.getoutput(cmd)
633         if env['WITH_BF_OCIO']:
634             cmd = 'cp -R %s/release/datafiles/colormanagement %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
635             commands.getoutput(cmd)
636         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
637         commands.getoutput(cmd)
638
639         if VERSION_RELEASE_CYCLE == "release":
640             cmd = 'rm -rf %s/%s.app/Contents/MacOS/%s/scripts/addons_contrib'%(installdir,binary,VERSION)
641             commands.getoutput(cmd)
642
643         if env['WITH_BF_CYCLES']:
644             croot = '%s/intern/cycles' % (bldroot)
645             cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
646
647             cmd = 'mkdir %s' % (cinstalldir)
648             commands.getoutput(cmd)
649             cmd = 'mkdir %s/kernel' % (cinstalldir)
650             commands.getoutput(cmd)
651             cmd = 'mkdir %s/lib' % (cinstalldir)
652             commands.getoutput(cmd)
653             cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
654             commands.getoutput(cmd)
655             cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
656             commands.getoutput(cmd)
657             cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
658             commands.getoutput(cmd)
659             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)
660             commands.getoutput(cmd)
661             cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
662             commands.getoutput(cmd)
663
664             if env['WITH_BF_CYCLES_OSL']:
665                 cmd = 'mkdir %s/shader' % (cinstalldir)
666                 commands.getoutput(cmd)
667                 cmd = 'cp -R %s/kernel/shaders/*.h %s/shader' % (croot, cinstalldir)
668                 commands.getoutput(cmd)
669                 cmd = 'cp -R %s/../intern/cycles/kernel/shaders/*.oso %s/shader' % (builddir, cinstalldir)
670                 commands.getoutput(cmd)
671
672     if env['WITH_OSX_STATICPYTHON']:
673         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
674         commands.getoutput(cmd)
675         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
676         commands.getoutput(cmd)
677
678     if env['XCODE_CUR_VER'] >= 5:
679         # For OSX 10.9/Xcode5 subcomponents also must be codesigned. To make this work we need a plist in the versioned libdir
680         # We copy for now the plist from main bundle, note: Blender must be run once before codesigning to have the py caches generated and taken into account
681                 # After this we can run: codesign -s IDENTITY blender.app --deep
682         cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/Resources/'%(installdir,binary, VERSION)
683         commands.getoutput(cmd)
684         cmd = 'cp %s/%s.app/Contents/Info.plist %s/%s.app/Contents/MacOS/%s/Resources'%(installdir,binary,installdir,binary, VERSION)
685         commands.getoutput(cmd)
686
687     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
688     commands.getoutput(cmd)
689     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
690     commands.getoutput(cmd)
691     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
692     commands.getoutput(cmd)
693     cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
694     commands.getoutput(cmd)
695     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
696         cmd = 'mkdir %s/%s.app/Contents/MacOS/lib'%(installdir, binary)
697         commands.getoutput(cmd)
698         instname = env['BF_CXX']
699         cmd = 'ditto --arch %s %s/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libgcc
700         commands.getoutput(cmd)
701         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
702         commands.getoutput(cmd)
703         cmd = 'ditto --arch %s %s/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/lib/'%(osxarch, instname, installdir, binary) # copy libgomp
704         commands.getoutput(cmd)
705         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
706         commands.getoutput(cmd)
707         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
708         commands.getoutput(cmd)
709         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 )
710         commands.getoutput(cmd)
711         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 )
712         commands.getoutput(cmd)
713
714 # extract copy system python, be sure to update other build systems
715 # when making changes to the files that are copied.
716 def my_unixpybundle_print(target, source, env):
717     pass
718
719 def UnixPyBundle(target=None, source=None, env=None):
720     # Any Unix except osx
721     #-- VERSION/python/lib/python3.1
722     
723     import commands
724     
725     def run(cmd):
726         print 'Install command:', cmd
727         commands.getoutput(cmd)
728
729     dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
730
731     lib = env['BF_PYTHON_LIBPATH'].split(os.sep)[-1]
732     target_lib = "lib64" if lib == "lib64" else "lib"
733
734     py_src =    env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
735     py_target =    env.subst( dir + '/python/' + target_lib + '/python'+env['BF_PYTHON_VERSION'] )
736     
737     # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
738     if os.path.exists(py_target):
739         print 'Using existing python from:'
740         print '\t"%s"' %            py_target
741         print '\t(skipping copy)\n'
742         return
743
744     # Copied from source/creator/CMakeLists.txt, keep in sync.
745     print 'Install python from:'
746     print '\t"%s" into...' % py_src
747     print '\t"%s"\n' % py_target
748
749     run("rm -rf '%s'" % py_target)
750     try:
751         os.makedirs(os.path.dirname(py_target)) # the final part is copied
752     except:
753         pass
754
755     run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
756     run("rm -rf '%s/distutils'" % py_target)
757     run("rm -rf '%s/lib2to3'" % py_target)
758     run("rm -rf '%s/config'" % py_target)
759
760     for f in os.listdir(py_target):
761         if f.startswith("config-"):
762             run("rm -rf '%s/%s'" % (py_target, f))
763
764     run("rm -rf '%s/site-packages'" % py_target)
765     run("mkdir '%s/site-packages'" % py_target)    # python needs it.'
766     run("rm -rf '%s/idlelib'" % py_target)
767     run("rm -rf '%s/tkinter'" % py_target)
768     run("rm -rf '%s/turtledemo'" % py_target)
769     run("rm -r '%s/turtle.py'" % py_target)
770     run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
771
772     if env['WITH_BF_PYTHON_INSTALL_NUMPY']:
773         numpy_src = py_src + "/site-packages/numpy"
774         numpy_target = py_target + "/site-packages/numpy"
775
776         if os.path.exists(numpy_src):
777             print 'Install numpy from:'
778             print '\t"%s" into...' % numpy_src
779             print '\t"%s"\n' % numpy_target
780
781             run("cp -R '%s' '%s'" % (numpy_src, os.path.dirname(numpy_target)))
782             run("rm -rf '%s/distutils'" % numpy_target)
783             run("rm -rf '%s/oldnumeric'" % numpy_target)
784             run("rm -rf '%s/doc'" % numpy_target)
785             run("rm -rf '%s/tests'" % numpy_target)
786             run("rm -rf '%s/f2py'" % numpy_target)
787             run("find '%s' -type d -name 'include' -prune -exec rm -rf {} ';'" % numpy_target)
788             run("find '%s' -type d -name '*.h' -prune -exec rm -rf {} ';'" % numpy_target)
789             run("find '%s' -type d -name '*.a' -prune -exec rm -rf {} ';'" % numpy_target)
790         else:
791             print 'Failed to find numpy at %s, skipping copying' % numpy_src
792
793     run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
794     run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
795     run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
796     run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
797
798 #### END ACTION STUFF #########
799
800 def bsc(env, target, source):
801     
802     bd = os.path.dirname(target[0].abspath)
803     bscfile = '\"'+target[0].abspath+'\"'
804     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
805     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
806
807     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
808
809     myfile = open(bscpathtmp[1:-1], 'r')
810     lines = myfile.readlines()
811     myfile.close()
812
813     newfile = open(bscpathtmp[1:-1], 'w')
814     for l in lines:
815         newfile.write('\"'+l[:-1]+'\"\n')
816     newfile.close()
817                 
818     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
819     os.system('del '+bscpathtmp)
820
821 class BlenderEnvironment(SConsEnvironment):
822
823     PyBundleActionAdded = False
824
825     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
826         global libs
827         if not self or not libname or not source:
828             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
829             self.Exit()
830         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
831             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
832             self.Exit()
833         
834         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
835         lenv = self.Clone()
836         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
837             res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
838         else:
839             res = lenv.RES(root_build_dir+'lib/'+libname, source)
840
841         
842         SConsEnvironment.Default(self, res)
843         resources.append(res)
844
845     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):
846         global vcp
847         
848         # sanity check
849         # run once in a while to check we dont have duplicates
850         if 0:
851             for name, dirs in (("source", sources), ("include", includes)):
852                 files_clean = [os.path.normpath(f) for f in dirs]
853                 files_clean_set = set(files_clean)
854                 if len(files_clean) != len(files_clean_set):
855                     for f in sorted(files_clean_set):
856                         if f != '.' and files_clean.count(f) > 1:
857                             raise Exception("Found duplicate %s %r" % (name, f))
858             del name, dirs, files_clean, files_clean_set, f
859         # end sanity check
860
861         if not self or not libname or not sources:
862             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
863             self.Exit()
864
865         def list_substring(quickie, libname):
866             for q in quickie:
867                 if q in libname:
868                     return True
869             return False
870
871         if list_substring(quickie, libname) or len(quickie)==0:
872             if list_substring(quickdebug, libname):
873                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
874             else:
875                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
876             lenv = self.Clone()
877             lenv.Append(CPPPATH=includes)
878             lenv.Append(CPPDEFINES=defines)
879             if lenv['BF_DEBUG'] or (libname in quickdebug):
880                 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
881                 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
882                 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
883             else:
884                 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
885                 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
886                 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
887             if lenv['BF_PROFILE']:
888                 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
889                 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
890                 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
891             if compileflags:
892                 lenv.Replace(CFLAGS = compileflags)
893             if cc_compileflags:
894                 lenv.Replace(CCFLAGS = cc_compileflags)
895             if cxx_compileflags:
896                 lenv.Replace(CXXFLAGS = cxx_compileflags)
897             if cc_compilerchange:
898                 lenv.Replace(CC = cc_compilerchange)
899             if cxx_compilerchange:
900                 lenv.Replace(CXX = cxx_compilerchange)
901             lenv.Append(CFLAGS = lenv['C_WARN'])
902             lenv.Append(CCFLAGS = lenv['CC_WARN'])
903             lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
904
905             if lenv['OURPLATFORM'] == 'win64-vc':
906                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
907
908             if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
909                 if lenv['BF_DEBUG']:
910                     lenv.Append(CCFLAGS = ['/MTd'])
911                 else:
912                     lenv.Append(CCFLAGS = ['/MT'])
913             
914             targetdir = root_build_dir+'lib/' + libname
915             if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
916                 targetdir = '#'+targetdir
917             lib = lenv.Library(target= targetdir, source=sources)
918             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
919             if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
920                 #if targetdir[0] == '#':
921                 #    targetdir = targetdir[1:-1]
922                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
923                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
924                          srcs = sources,
925                          buildtarget = lib,
926                          variant = 'Release',
927                          auto_build_solution=0)
928                 vcp.append(vcproject)
929                 SConsEnvironment.Default(self, vcproject)
930         else:
931             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
932         # note: libs is a global
933         add_lib_to_dict(self, libs, libtype, libname, priority)
934
935     def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
936         global vcp
937         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
938         lenv = self.Clone()
939         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
940         lenv.Append(LINKFLAGS = lenv['BF_PROGRAM_LINKFLAGS'])
941         if lenv['OURPLATFORM'] in ('win32-mingw', 'win64-mingw', 'linuxcross', 'cygwin', 'linux'):
942             lenv.Replace(LINK = '$CXX')
943         if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
944             if lenv['BF_DEBUG']:
945                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
946         if  lenv['OURPLATFORM']=='linux':
947             if lenv['WITH_BF_PYTHON']:
948                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
949         if  lenv['OURPLATFORM']=='sunos5':
950             if lenv['WITH_BF_PYTHON']:
951                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
952             if lenv['CXX'].endswith('CC'):
953                 lenv.Replace(LINK = '$CXX')
954         if  lenv['OURPLATFORM']=='darwin':
955             if lenv['WITH_BF_PYTHON']:
956                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
957             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
958         if lenv['BF_PROFILE']:
959             lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
960         if root_build_dir[0]==os.sep or root_build_dir[1]==':':
961             lenv.Append(LIBPATH=root_build_dir + '/lib')
962         lenv.Append(LIBPATH=libpath)
963         lenv.Append(LIBS=libs)
964         if lenv['WITH_BF_QUICKTIME']:
965             lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
966             lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
967         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
968         if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
969             f = lenv.File(progname + '.bsc', builddir)
970             brs = lenv.Command(f, prog, [bsc])
971             SConsEnvironment.Default(self, brs)
972         SConsEnvironment.Default(self, prog)
973         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
974             print "! ",builddir + "/" + progname + '.sln'
975             sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
976                      projects= vcp,
977                      variant = 'Release')
978             SConsEnvironment.Default(self, sln)
979         program_list.append(prog)
980         if  lenv['OURPLATFORM']=='darwin':
981             lenv['BINARYKIND'] = binarykind
982             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
983         elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
984             if lenv['WITH_BF_PYTHON']:
985                 if (not lenv['WITHOUT_BF_INSTALL'] and 
986                     not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
987                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
988                     not BlenderEnvironment.PyBundleActionAdded):
989                     lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
990                     BlenderEnvironment.PyBundleActionAdded = True
991         elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
992             if lenv['WITH_BF_PYTHON']:
993                 if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and 
994                     not lenv['WITHOUT_BF_PYTHON_UNPACK'] and 
995                     not BlenderEnvironment.PyBundleActionAdded):
996                     lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
997                     BlenderEnvironment.PyBundleActionAdded = True
998         return prog
999
1000     def Glob(lenv, pattern):
1001         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
1002         files = []
1003         for i in glob.glob(path + pattern):
1004             files.append(string.replace(i, path, ''))
1005         return files