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