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