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