COLLADA branch: merge from trunk -r 25745:26429.
[blender-staging.git] / 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 zipfile
24 import shutil
25 import cStringIO
26
27 from SCons.Script.SConscript import SConsEnvironment
28 import SCons.Action
29 import SCons.Util
30 import SCons.Builder
31 import SCons.Tool
32 import bcolors
33 bc = bcolors.bcolors()
34
35 Split = SCons.Util.Split
36 Action = SCons.Action.Action
37 Builder = SCons.Builder.Builder
38 GetBuildPath = SConsEnvironment.GetBuildPath
39
40 # a few globals
41 root_build_dir = ''
42 doc_build_dir = ''
43 quickie = None # Anything else than None if BF_QUICK has been passed
44 quicklist = [] # The list of libraries/programs to compile during a quickie
45 program_list = [] # A list holding Nodes to final binaries, used to create installs
46 arguments = None
47 targets = None
48 resources = []
49
50 #some internals
51 blenderdeps = [] # don't manipulate this one outside this module!
52
53 ##### LIB STUFF ##########
54
55 possible_types = ['core'] # can be set in ie. SConstruct
56 libs = {}
57 vcp = []
58
59 def getresources():
60         return resources
61
62 def init_lib_dict():
63         for pt in possible_types:
64                 libs[pt] = {}
65
66 # helper func for add_lib_to_dict
67 def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
68         if not libname in dict[libtype]:
69                 done = None
70                 while not done:
71                         if dict[libtype].has_key(priority):
72                                 priority = priority + 1
73                         else:
74                                 done = True
75                 dict[libtype][priority] = libname
76
77 # libtype and priority can both be lists, for defining lib in multiple places
78 def add_lib_to_dict(env, dict = None, libtype = None, libname = None, priority = 100):
79         if not dict or not libtype or not libname:
80                 print "Passed wrong arg"
81                 env.Exit()
82
83         if type(libtype) is str and type(priority) is int:
84                 internal_lib_to_dict(dict, libtype, libname, priority)
85         elif type(libtype) is list and type(priority) is list:
86                 if len(libtype)==len(priority):
87                         for lt, p in zip(libtype, priority):
88                                 internal_lib_to_dict(dict, lt, libname, p)
89                 else:
90                         print "libtype and priority lists are unequal in length"
91                         env.Exit()
92         else:
93                 print "Wrong type combinations for libtype and priority. Only str and int or list and list"
94                 env.Exit()
95
96 def create_blender_liblist(lenv = None, libtype = None):
97         if not lenv or not libtype:
98                 print "missing arg"
99
100         lst = []
101         if libtype in possible_types:
102                 curlib = libs[libtype]
103                 sortlist = curlib.keys()
104                 sortlist.sort()
105                 for sk in sortlist:
106                         v = curlib[sk]
107                         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
108                                 target = os.path.abspath(os.getcwd() + os.sep + root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
109                         else:
110                                 target = os.path.abspath(root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
111                         lst.append(target)
112
113         return lst
114
115 ## TODO: static linking
116 def setup_staticlibs(lenv):
117         statlibs = [
118                 #here libs for static linking
119         ]
120         libincs = [
121                 '/usr/lib',
122                 lenv['BF_OPENGL_LIBPATH'],
123                 lenv['BF_JPEG_LIBPATH'],
124                 lenv['BF_PNG_LIBPATH'],
125                 lenv['BF_ZLIB_LIBPATH'],
126                 lenv['BF_LIBSAMPLERATE_LIBPATH'],
127                 lenv['BF_ICONV_LIBPATH']
128                 ]
129
130         libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
131         if lenv['WITH_BF_PYTHON']:
132                 libincs += Split(lenv['BF_PYTHON_LIBPATH'])
133         if lenv['WITH_BF_SDL']:
134                 libincs += Split(lenv['BF_SDL_LIBPATH'])
135         if lenv['WITH_BF_FFMPEG']:
136                 libincs += Split(lenv['BF_FFMPEG_LIBPATH'])
137         if lenv['WITH_BF_JACK']:
138                 libincs += Split(lenv['BF_JACK_LIBPATH'])
139         if lenv['WITH_BF_SNDFILE']:
140                 libincs += Split(lenv['BF_SNDFILE_LIBPATH'])
141         if lenv['WITH_BF_OPENEXR']:
142                 libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
143                 if lenv['WITH_BF_STATICOPENEXR']:
144                         statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
145         if lenv['WITH_BF_FFTW3']:
146                 libincs += Split(lenv['BF_FFTW3_LIBPATH'])
147         if lenv['WITH_BF_INTERNATIONAL']:
148                 libincs += Split(lenv['BF_GETTEXT_LIBPATH'])
149         if lenv['WITH_BF_OPENAL']:
150                 libincs += Split(lenv['BF_OPENAL_LIBPATH'])
151                 if lenv['WITH_BF_STATICOPENAL']:
152                         statlibs += Split(lenv['BF_OPENAL_LIB_STATIC'])
153         if lenv['WITH_BF_STATICOPENGL']:
154                 statlibs += Split(lenv['BF_OPENGL_LIB_STATIC'])
155         if lenv['WITH_BF_STATICCXX']:
156                 statlibs += Split(lenv['BF_CXX_LIB_STATIC'])
157
158         if lenv['WITH_BF_PYTHON'] and lenv['WITH_BF_STATICPYTHON']:
159                 statlibs += Split(lenv['BF_PYTHON_LIB_STATIC'])
160
161         if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
162                 libincs += Split(lenv['BF_PTHREADS_LIBPATH'])
163
164         if lenv['WITH_BF_COLLADA']:
165                 libincs += Split(lenv['BF_OPENCOLLADA_LIBPATH'])
166                 if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
167                         libincs += Split(lenv['BF_PCRE_LIBPATH'])
168                         libincs += Split(lenv['BF_EXPAT_LIBPATH'])
169
170
171         return statlibs, libincs
172
173 def setup_syslibs(lenv):
174         syslibs = [
175                 
176                 lenv['BF_JPEG_LIB'],
177                 lenv['BF_PNG_LIB'],
178                 lenv['BF_ZLIB_LIB'],
179                 lenv['BF_LIBSAMPLERATE_LIB']
180                 ]
181
182         syslibs += Split(lenv['BF_FREETYPE_LIB'])
183         if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']:
184                 if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'):
185                         syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
186                 else:
187                         syslibs.append(lenv['BF_PYTHON_LIB'])
188         if lenv['WITH_BF_INTERNATIONAL']:
189                 syslibs += Split(lenv['BF_GETTEXT_LIB'])
190         if lenv['WITH_BF_OPENAL']:
191                 if not lenv['WITH_BF_STATICOPENAL']:
192                         syslibs += Split(lenv['BF_OPENAL_LIB'])
193         if lenv['WITH_BF_OPENMP'] and lenv['CC'] != 'icc':
194                 if lenv['CC'] == 'cl.exe':
195                         syslibs += ['vcomp']
196                 else:
197                         syslibs += ['gomp']
198         if lenv['WITH_BF_ICONV']:
199                 syslibs += Split(lenv['BF_ICONV_LIB'])
200         if lenv['WITH_BF_OPENEXR']:
201                 if not lenv['WITH_BF_STATICOPENEXR']:
202                         syslibs += Split(lenv['BF_OPENEXR_LIB'])
203         if lenv['WITH_BF_FFMPEG']:
204                 syslibs += Split(lenv['BF_FFMPEG_LIB'])
205                 if lenv['WITH_BF_OGG']:
206                         syslibs += Split(lenv['BF_OGG_LIB'])
207         if lenv['WITH_BF_JACK']:
208                         syslibs += Split(lenv['BF_JACK_LIB'])
209         if lenv['WITH_BF_SNDFILE']:
210                         syslibs += Split(lenv['BF_SNDFILE_LIB'])
211         if lenv['WITH_BF_FFTW3']:
212                 syslibs += Split(lenv['BF_FFTW3_LIB'])
213         if lenv['WITH_BF_SDL']:
214                 syslibs += Split(lenv['BF_SDL_LIB'])
215         if not lenv['WITH_BF_STATICOPENGL']:
216                 syslibs += Split(lenv['BF_OPENGL_LIB'])
217         if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross', 'win64-vc'):
218                 syslibs += Split(lenv['BF_PTHREADS_LIB'])
219
220         if lenv['WITH_BF_LCMS']:
221                 syslibs.append(lenv['BF_LCMS_LIB'])
222         if lenv['WITH_BF_COLLADA']:
223                 syslibs.append(lenv['BF_PCRE_LIB'])
224                 syslibs += Split(lenv['BF_OPENCOLLADA_LIB'])
225                 syslibs.append(lenv['BF_EXPAT_LIB'])
226
227
228         syslibs += lenv['LLIBS']
229
230         return syslibs
231
232 def propose_priorities():
233         print bc.OKBLUE+"Priorities:"+bc.ENDC
234         for t in possible_types:
235                 print bc.OKGREEN+"\t"+t+bc.ENDC
236                 new_priority = 0
237                 curlib = libs[t]
238                 sortlist = curlib.keys()
239                 sortlist.sort()
240
241                 for sk in sortlist:
242                         v = curlib[sk]
243                         #for p,v in sorted(libs[t].iteritems()):
244                         print "\t\t",new_priority, v
245                         new_priority += 5
246
247 ## TODO: see if this can be made in an emitter
248 def buildinfo(lenv, build_type):
249         """
250         Generate a buildinfo object
251         """
252         build_date = time.strftime ("%Y-%m-%d")
253         build_time = time.strftime ("%H:%M:%S")
254         build_rev = os.popen('svnversion').read()[:-1] # remove \n
255
256         obj = []
257         if lenv['BF_BUILDINFO']:
258                 lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
259                                                                         'BUILD_DATE=\'"%s"\''%(build_date),
260                                                                         'BUILD_TYPE=\'"dynamic"\'',
261                                                                         'BUILD_REV=\'"%s"\''%(build_rev),
262                                                                         'NAN_BUILDINFO',
263                                                                         'BUILD_PLATFORM=\'"%s"\''%(sys.platform)])
264                 obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
265                                                 [root_build_dir+'source/creator/buildinfo.c'])]
266         return obj
267
268 ##### END LIB STUFF ############
269
270 ##### ACTION STUFF #############
271
272 def my_print_cmd_line(self, s, target, source, env):
273         sys.stdout.write(' ' * 70 + '\r')
274         sys.stdout.flush()
275         sys.stdout.write(s + "\r")
276         sys.stdout.flush()
277
278 def my_compile_print(target, source, env):
279         a = '%s' % (source[0])
280         d, f = os.path.split(a)
281         return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
282
283 def my_moc_print(target, source, env):
284         a = '%s' % (source[0])
285         d, f = os.path.split(a)
286         return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
287
288 def my_linking_print(target, source, env):
289         t = '%s' % (target[0])
290         d, f = os.path.split(t)
291         return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
292
293 def my_program_print(target, source, env):
294         t = '%s' % (target[0])
295         d, f = os.path.split(t)
296         return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
297
298 def msvc_hack(env):
299         static_lib = SCons.Tool.createStaticLibBuilder(env)
300         program = SCons.Tool.createProgBuilder(env)
301         
302         env['BUILDERS']['Library'] = static_lib
303         env['BUILDERS']['StaticLibrary'] = static_lib
304         env['BUILDERS']['Program'] = program
305                 
306 def set_quiet_output(env):
307         mycaction = Action("$CCCOM", strfunction=my_compile_print)
308         myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
309         mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
310         myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
311         mylibaction = Action("$ARCOM", strfunction=my_linking_print)
312         mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
313
314         static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
315         static_ob.add_action('.c', mycaction)
316         static_ob.add_action('.cpp', mycppaction)
317         shared_ob.add_action('.c', myshcaction)
318         shared_ob.add_action('.cpp', myshcppaction)
319
320         static_lib = SCons.Builder.Builder(action = mylibaction,
321                                                                            emitter = '$LIBEMITTER',
322                                                                            prefix = '$LIBPREFIX',
323                                                                            suffix = '$LIBSUFFIX',
324                                                                            src_suffix = '$OBJSUFFIX',
325                                                                            src_builder = 'StaticObject')
326
327         program = SCons.Builder.Builder(action = mylinkaction,
328                                                                         emitter = '$PROGEMITTER',
329                                                                         prefix = '$PROGPREFIX',
330                                                                         suffix = '$PROGSUFFIX',
331                                                                         src_suffix = '$OBJSUFFIX',
332                                                                         src_builder = 'Object',
333                                                                         target_scanner = SCons.Defaults.ProgScan)
334
335         env['BUILDERS']['Object'] = static_ob
336         env['BUILDERS']['StaticObject'] = static_ob
337         env['BUILDERS']['StaticLibrary'] = static_lib
338         env['BUILDERS']['Library'] = static_lib
339         env['BUILDERS']['Program'] = program
340         if env['BF_LINE_OVERWRITE']:
341                 SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
342
343         
344 class CompZipFile(zipfile.ZipFile):
345         """Partial copy of python2.6's zipfile.ZipFile (see http://www.python.org)
346         to get a extractall() that works on py2.5 and probably earlier distributions."""
347         def __init__(self, file, mode="r", compression=zipfile.ZIP_STORED, allowZip64=False):
348                 zipfile.ZipFile.__init__(self, file, mode, compression, allowZip64)
349                 if not hasattr(self,"extractall"): # use our method 
350                         print "Debug: Using comp_extractall!"
351                         self.extractall= self.comp_extractall
352
353         def comp_extractall(self, path=None, members=None, pwd=None): #renamed method
354                 """Extract all members from the archive to the current working
355                         directory. `path' specifies a different directory to extract to.
356                         `members' is optional and must be a subset of the list returned
357                         by namelist().
358                 """
359                 if members is None:
360                         members = self.namelist()
361
362                 for zipinfo in members:
363                         self.comp_extract(zipinfo, path, pwd) # use our method 
364
365         def comp_extract(self, member, path=None, pwd=None): #renamed method
366                 """Extract a member from the archive to the current working directory,
367                         using its full name. Its file information is extracted as accurately
368                         as possible. `member' may be a filename or a ZipInfo object. You can
369                         specify a different directory using `path'.
370                 """
371                 if not isinstance(member, zipfile.ZipInfo):
372                         member = self.getinfo(member)
373
374                 if path is None:
375                         path = os.getcwd()
376
377                 return self.comp_extract_member(member, path, pwd) # use our method 
378
379         def comp_extract_member(self, member, targetpath, pwd): #renamed method
380                 """Extract the ZipInfo object 'member' to a physical
381                         file on the path targetpath.
382                 """
383                 # build the destination pathname, replacing
384                 # forward slashes to platform specific separators.
385                 if targetpath[-1:] in (os.path.sep, os.path.altsep):
386                         targetpath = targetpath[:-1]
387
388                 # don't include leading "/" from file name if present
389                 if member.filename[0] == '/':
390                         targetpath = os.path.join(targetpath, member.filename[1:])
391                 else:
392                         targetpath = os.path.join(targetpath, member.filename)
393
394                 targetpath = os.path.normpath(targetpath)
395
396                 # Create all upper directories if necessary.
397                 upperdirs = os.path.dirname(targetpath)
398                 if upperdirs and not os.path.exists(upperdirs):
399                         os.makedirs(upperdirs)
400
401                 if member.filename[-1] == '/':
402                         os.mkdir(targetpath)
403                         return targetpath
404
405                 #use StrinIO instead so we don't have to reproduce more functionality.
406                 source = cStringIO.StringIO(self.read(member.filename))
407                 target = file(targetpath, "wb")
408                 shutil.copyfileobj(source, target)
409                 source.close()
410                 target.close()
411
412                 return targetpath
413
414 def unzip_pybundle(from_zip,to_dir,exclude_re):
415         
416         zip= CompZipFile(from_zip, mode='r')
417         exclude_re= list(exclude_re) #single re object or list of re objects
418         debug= 0 #list files instead of unpacking
419         good= []
420         if debug: print '\nFiles not being unpacked:\n'
421         for name in zip.namelist():
422                 is_bad= 0
423                 for r in exclude_re:
424                         if r.match(name):
425                                 is_bad=1
426                                 if debug: print name
427                                 break
428                 if not is_bad:
429                         good.append(name)
430         if debug:
431                 print '\nFiles being unpacked:\n'
432                 for g in good:
433                         print g
434         else:
435                 zip.extractall(to_dir, good)
436
437 def my_winpybundle_print(target, source, env):
438         pass
439
440 def WinPyBundle(target=None, source=None, env=None):
441         import re
442         py_zip= env.subst( env['LCGDIR'] )
443         if py_zip[0]=='#':
444                 py_zip= py_zip[1:]
445         py_zip+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.zip'
446
447         py_target = env.subst( env['BF_INSTALLDIR'] )
448         if py_target[0]=='#':
449                 py_target=py_target[1:]
450         py_target+= '/.blender/python/lib/' 
451         def printexception(func,path,ex):
452                 if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
453                         print str(func) + ' failed on ' + str(path)
454         print "Trying to remove existing py bundle."
455         shutil.rmtree(py_target, False, printexception)
456         exclude_re=[re.compile('.*/test/.*'),
457                                 re.compile('^config/.*'),
458                                 re.compile('^distutils/.*'),
459                                 re.compile('^idlelib/.*'),
460                                 re.compile('^lib2to3/.*'),
461                                 re.compile('^tkinter/.*')]
462         print "Unpacking '" + py_zip + "' to '" + py_target + "'"
463         unzip_pybundle(py_zip,py_target,exclude_re)
464
465 def  my_appit_print(target, source, env):
466         a = '%s' % (target[0])
467         d, f = os.path.split(a)
468         return "making bundle for " + f
469
470 def AppIt(target=None, source=None, env=None):
471         import shutil
472         import commands
473         import os.path
474         
475         
476         a = '%s' % (target[0])
477         builddir, b = os.path.split(a)
478         libdir = env['LCGDIR'][1:]
479         osxarch = env['MACOSX_ARCHITECTURE']
480         print("compiled architecture: %s"%(osxarch))
481         if  libdir == '../lib/darwin-9.x.universal':
482                 python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
483         else:
484                 python_zip = 'python.zip' # compatibility for darwin8 python.zip
485         print("unzipping to app-bundle: %s"%(python_zip))
486         bldroot = env.Dir('.').abspath
487         binary = env['BINARYKIND']
488          
489         if b=='verse':
490                 print bc.OKBLUE+"no bundle for verse"+bc.ENDC 
491                 return 0
492         
493         sourcedir = bldroot + '/source/darwin/%s.app'%binary
494         sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
495         targetinfo = builddir +'/' + "%s.app/Contents/Info.plist"%binary
496         cmd = builddir + '/' +'%s.app'%binary
497         
498         if os.path.isdir(cmd):
499                 shutil.rmtree(cmd)
500         shutil.copytree(sourcedir, cmd)
501         cmd = "cat %s | sed s/VERSION/`cat release/VERSION`/ | sed s/DATE/`date +'%%Y-%%b-%%d'`/ > %s"%(sourceinfo,targetinfo)
502         commands.getoutput(cmd)
503         cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,builddir, binary, binary)
504         commands.getoutput(cmd)
505         cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/'%(builddir, binary)
506 #       print cmd
507         commands.getoutput(cmd)
508         cmd = builddir + '/%s.app/Contents/MacOS/.blender'%binary
509         shutil.copy(bldroot + '/bin/.blender/.bfont.ttf', cmd)
510         shutil.copy(bldroot + '/bin/.blender/.Blanguages', cmd)
511         cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
512         commands.getoutput(cmd) 
513         cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
514         commands.getoutput(cmd) 
515         cmd = 'cp %s/bin/.blender/.Blanguages %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
516         commands.getoutput(cmd) 
517         cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/python/'%(builddir,binary)
518         commands.getoutput(cmd) 
519         cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/MacOS/.blender/python/'%(libdir,python_zip,builddir,binary)
520         commands.getoutput(cmd) 
521         cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
522         commands.getoutput(cmd)
523         cmd = 'cp -R %s/release/ui %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
524         commands.getoutput(cmd)
525         cmd = 'cp -R %s/release/io %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
526         commands.getoutput(cmd)
527         cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(builddir,binary, binary)
528         commands.getoutput(cmd)
529         cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(builddir, binary)
530         commands.getoutput(cmd)
531         cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(builddir, binary)
532         commands.getoutput(cmd)
533         cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(builddir, binary)
534         commands.getoutput(cmd)
535
536 # extract copy system python, be sure to update other build systems
537 # when making changes to the files that are copied.
538 def my_unixpybundle_print(target, source, env):
539         pass
540
541 def UnixPyBundle(target=None, source=None, env=None):
542         # Any Unix except osx
543         #-- .blender/python/lib/python3.1
544         
545         import commands
546         
547         def run(cmd):
548                 print 'Install command:', cmd
549                 commands.getoutput(cmd)
550         
551         if env['WITH_BF_FHS']:  dir = os.path.join(env['BF_INSTALLDIR'], 'share', 'blender', env['BF_VERSION']) # BLENDERPATH
552         else:                                   dir = os.path.join(env['BF_INSTALLDIR'], '.blender')
553         
554         py_src =        env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
555         py_target =     env.subst( dir + '/python/lib/python'+env['BF_PYTHON_VERSION'] )
556         
557         # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
558         if os.path.exists(py_target):
559                 print 'Using existing python from:'
560                 print '\t"%s"' %                        py_target
561                 print '\t(skipping copy)\n'
562                 return
563                 
564         
565         # Copied from source/creator/CMakeLists.txt, keep in sync.
566         print 'Install python from:'
567         print '\t"%s" into...' %        py_src
568         print '\t"%s"\n' %                      py_target
569         
570         run('rm -rf "%s"' % py_target)
571         try:    os.makedirs(os.path.dirname(py_target)) # the final part is copied
572         except:pass
573         
574         run('cp -R "%s" "%s"' % (py_src, os.path.dirname(py_target)))
575         run('rm -rf "%s/distutils"' % py_target)
576         run('rm -rf "%s/lib2to3"' % py_target)
577         run('rm -rf "%s/idlelib"' % py_target)
578         run('rm -rf "%s/tkinter"' % py_target)
579         run('rm -rf "%s/config"' % py_target)
580
581         run('rm -rf "%s/site-packages"' % py_target)
582         run('mkdir "%s/site-packages"' % py_target)    # python needs it.'
583
584         run('rm -f "%s/lib-dynload/_tkinter.so"' % py_target)
585         run('find "%s" -name "test" -prune -exec rm -rf {} \;' % py_target)
586         run('find "%s" -name "*.py?" -exec rm -rf {} \;' % py_target)
587         run('find "%s" -name "*.so"-exec strip -s {} \;' % py_target)
588
589 #### END ACTION STUFF #########
590
591 def bsc(env, target, source):
592         
593         bd = os.path.dirname(target[0].abspath)
594         bscfile = '\"'+target[0].abspath+'\"'
595         bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
596         bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
597
598         os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
599
600         myfile = open(bscpathtmp[1:-1], 'r')
601         lines = myfile.readlines()
602         myfile.close()
603
604         newfile = open(bscpathtmp[1:-1], 'w')
605         for l in lines:
606                 newfile.write('\"'+l[:-1]+'\"\n')
607         newfile.close()
608                                 
609         os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
610         os.system('del '+bscpathtmp)
611
612 class BlenderEnvironment(SConsEnvironment):
613
614         def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
615                 global libs
616                 if not self or not libname or not source:
617                         print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
618                         self.Exit()
619                 if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc'):
620                         print bc.FAIL+'BlenderRes is for windows only!'+bc.END
621                         self.Exit()
622                 
623                 print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
624                 lenv = self.Clone()
625                 if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
626                         res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
627                 else:
628                         res = lenv.RES(root_build_dir+'lib/'+libname, source)
629
630                 
631                 SConsEnvironment.Default(self, res)
632                 resources.append(res)
633
634         def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None, cc_compileflags=None, cxx_compileflags=None):
635                 global vcp
636                 if not self or not libname or not sources:
637                         print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
638                         self.Exit()
639
640                 def list_substring(quickie, libname):
641                         for q in quickie:
642                                 if libname.find(q) != -1:
643                                         return True
644                         return False
645
646                 if list_substring(quickie, libname) or len(quickie)==0:
647                         if list_substring(quickdebug, libname):
648                                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
649                         else:
650                                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
651                         lenv = self.Clone()
652                         lenv.Append(CPPPATH=includes)
653                         lenv.Append(CPPDEFINES=defines)
654                         if lenv['BF_DEBUG'] or (libname in quickdebug):
655                                         lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
656                                         lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
657                                         lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
658                         else:
659                                         lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
660                                         lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
661                                         lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
662                         if lenv['BF_PROFILE']:
663                                         lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
664                                         lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
665                                         lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
666                         if compileflags:
667                                 lenv.Replace(CFLAGS = compileflags)
668                         if cc_compileflags:
669                                 lenv.Replace(CCFLAGS = cc_compileflags)
670                         if cxx_compileflags:
671                                 lenv.Replace(CXXFLAGS = cxx_compileflags)
672                         lenv.Append(CFLAGS = lenv['C_WARN'])
673                         lenv.Append(CCFLAGS = lenv['CC_WARN'])
674                         lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
675
676                         if lenv['OURPLATFORM'] == 'win64-vc':
677                                 lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
678
679                         if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
680                                 if lenv['BF_DEBUG']:
681                                         lenv.Append(CCFLAGS = ['/MTd'])
682                                 else:
683                                         lenv.Append(CCFLAGS = ['/MT'])
684                         
685                         targetdir = root_build_dir+'lib/' + libname
686                         if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
687                                 targetdir = '#'+targetdir
688                         lib = lenv.Library(target= targetdir, source=sources)
689                         SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
690                         if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
691                                 #if targetdir[0] == '#':
692                                 #       targetdir = targetdir[1:-1]
693                                 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
694                                 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
695                                                  srcs = sources,
696                                                  buildtarget = lib,
697                                                  variant = 'Release',
698                                                  auto_build_solution=0)
699                                 vcp.append(vcproject)
700                                 SConsEnvironment.Default(self, vcproject)
701                 else:
702                         print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
703                 # note: libs is a global
704                 add_lib_to_dict(self, libs, libtype, libname, priority)
705
706         def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''):
707                 global vcp
708                 print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
709                 lenv = self.Clone()
710                 if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
711                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
712                         lenv.Append(LINKFLAGS = ['/FORCE:MULTIPLE'])
713                         if lenv['BF_DEBUG']:
714                                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb'])
715                 if  lenv['OURPLATFORM']=='linux2':
716                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
717                         if lenv['WITH_BF_PYTHON']:
718                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
719                 if  lenv['OURPLATFORM']=='sunos5':
720                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
721                         if lenv['WITH_BF_PYTHON']:
722                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
723                         if lenv['CXX'].endswith('CC'):
724                                  lenv.Replace(LINK = '$CXX')
725                 if  lenv['OURPLATFORM']=='darwin':
726                         lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
727                         if lenv['WITH_BF_PYTHON']:
728                                 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
729                         lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
730                 if lenv['BF_PROFILE']:
731                         lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
732                 lenv.Append(CPPPATH=includes)
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 == '/': # any unix
757                         if lenv['WITH_BF_PYTHON']:
758                                 if not lenv['WITHOUT_BF_INSTALL'] and not lenv['WITHOUT_BF_PYTHON_INSTALL']:
759                                         lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
760                 elif lenv['OURPLATFORM'].startswith('win'): # windows
761                         if lenv['WITH_BF_PYTHON']:
762                                 if not lenv['WITHOUT_BF_PYTHON_INSTALL']:
763                                         lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
764                 return prog
765
766         def Glob(lenv, pattern):
767                 path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
768                 files = []
769                 for i in glob.glob(path + pattern):
770                         files.append(string.replace(i, path, ''))
771                 return files