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