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