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