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