Merge branch 'cb/render'
[plumiferos.git] / tools / Blender.py
blob08128ae0d8fb4d88eadb134ea8daa11c5d80a8d7
1 #!/usr/bin/env python
3 """
4 tools.BlenderEnvironment
6 This environment builds on SCons.Script.SConscript.SConsEnvironment
8 * library repository
9 * custom printout
10 * wrapper functions
12 TODO: clean up and sanitise code - crosscheck with btools and SConstruct
13 to kill any code duplication
15 """
17 import os.path
18 import string
19 import glob
20 import time
21 import sys
23 from SCons.Script.SConscript import SConsEnvironment
24 import SCons.Action
25 import SCons.Util
26 import SCons.Builder
27 import SCons.Tool
28 import bcolors
29 bc = bcolors.bcolors()
31 Split = SCons.Util.Split
32 Action = SCons.Action.Action
33 Builder = SCons.Builder.Builder
34 GetBuildPath = SConsEnvironment.GetBuildPath
36 # a few globals
37 root_build_dir = ''
38 quickie = None # Anything else than None if BF_QUICK has been passed
39 quicklist = [] # The list of libraries/programs to compile during a quickie
40 program_list = [] # A list holding Nodes to final binaries, used to create installs
41 arguments = None
42 targets = None
43 resources = []
45 #some internals
46 blenderdeps = [] # don't manipulate this one outside this module!
48 ##### LIB STUFF ##########
50 possible_types = ['core'] # can be set in ie. SConstruct
51 libs = {}
53 def getresources():
54 return resources
56 def init_lib_dict():
57 for pt in possible_types:
58 libs[pt] = {}
60 # helper func for add_lib_to_dict
61 def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
62 if not libname in dict[libtype]:
63 done = None
64 while not done:
65 if dict[libtype].has_key(priority):
66 priority = priority + 1
67 else:
68 done = True
69 dict[libtype][priority] = libname
71 # libtype and priority can both be lists, for defining lib in multiple places
72 def add_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
73 if not dict or not libtype or not libname:
74 print "Passed wrong arg"
75 Exit()
77 if type(libtype) is str and type(priority) is int:
78 internal_lib_to_dict(dict, libtype, libname, priority)
79 elif type(libtype) is list and type(priority) is list:
80 if len(libtype)==len(priority):
81 for lt, p in zip(libtype, priority):
82 internal_lib_to_dict(dict, lt, libname, p)
83 else:
84 print "libtype and priority lists are unequal in length"
85 Exit()
86 else:
87 print "Wrong type combinations for libtype and priority. Only str and int or list and list"
88 Exit()
90 def create_blender_liblist(lenv = None, libtype = None):
91 if not lenv or not libtype:
92 print "missing arg"
94 lst = []
95 if libtype in possible_types:
96 sortlist = []
97 for k,v in libs[libtype].iteritems():
98 sortlist.append(k)
99 sortlist.sort()
100 curlib = libs[libtype]
101 for sk in sortlist:
102 v = curlib[sk]
103 lst.append('#' + root_build_dir + 'lib/'+lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
105 return lst
107 ## TODO: static linking
108 def setup_staticlibs(lenv):
109 statlibs = [
110 #here libs for static linking
112 libincs = [
113 '/usr/lib',
114 lenv['BF_PYTHON_LIBPATH'],
115 lenv['BF_OPENGL_LIBPATH'],
116 lenv['BF_SDL_LIBPATH'],
117 lenv['BF_JPEG_LIBPATH'],
118 lenv['BF_PNG_LIBPATH'],
119 lenv['BF_ZLIB_LIBPATH'],
120 lenv['BF_ICONV_LIBPATH']
122 libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
123 libincs += Split(lenv['BF_FFMPEG_LIBPATH'])
125 if lenv['WITH_BF_INTERNATIONAL']:
126 libincs += Split(lenv['BF_GETTEXT_LIBPATH'])
127 libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
128 if lenv['WITH_BF_OPENAL']:
129 libincs += Split(lenv['BF_OPENAL_LIBPATH'])
131 if lenv['WITH_BF_STATICOPENGL']:
132 statlibs += Split(lenv['BF_OPENGL_LIB_STATIC'])
134 if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross'):
135 libincs += Split(lenv['BF_PTHREADS_LIBPATH'])
137 return statlibs, libincs
139 def setup_syslibs(lenv):
140 syslibs = [
142 lenv['BF_JPEG_LIB'],
143 lenv['BF_PNG_LIB'],
144 lenv['BF_ZLIB_LIB']
146 if lenv['BF_DEBUG']==1 and lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
147 syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
148 else:
149 syslibs.append(lenv['BF_PYTHON_LIB'])
150 if lenv['WITH_BF_INTERNATIONAL']:
151 syslibs += Split(lenv['BF_FREETYPE_LIB'])
152 syslibs += Split(lenv['BF_GETTEXT_LIB'])
153 if lenv['WITH_BF_OPENAL']:
154 syslibs += Split(lenv['BF_OPENAL_LIB'])
155 if lenv['WITH_BF_ICONV']:
156 syslibs += Split(lenv['BF_ICONV_LIB'])
157 if lenv['WITH_BF_OPENEXR']:
158 syslibs += Split(lenv['BF_OPENEXR_LIB'])
159 if lenv['WITH_BF_FFMPEG']:
160 syslibs += Split(lenv['BF_FFMPEG_LIB'])
161 syslibs += Split(lenv['BF_SDL_LIB'])
162 if not lenv['WITH_BF_STATICOPENGL']:
163 syslibs += Split(lenv['BF_OPENGL_LIB'])
164 if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross'):
165 syslibs += Split(lenv['BF_PTHREADS_LIB'])
167 syslibs += Split(lenv['LLIBS'])
169 return syslibs
171 def propose_priorities():
172 print bc.OKBLUE+"Priorities:"+bc.ENDC
173 for t in possible_types:
174 print bc.OKGREEN+"\t"+t+bc.ENDC
175 new_priority = 0
176 sortlist = []
177 for k,v in libs[t].iteritems():
178 sortlist.append(k)
179 sortlist.sort()
180 curlib = libs[t]
181 for sk in sortlist:
182 v = curlib[sk]
183 #for p,v in sorted(libs[t].iteritems()):
184 print "\t\t",new_priority, v
185 new_priority += 5
187 ## TODO: see if this can be made in an emitter
188 def buildinfo(lenv, build_type):
190 Generate a buildinfo object
192 build_date = time.strftime ("%Y-%m-%d")
193 build_time = time.strftime ("%H:%M:%S")
194 build_rev = os.popen('svnversion').read()[:-1] # remove \n
196 obj = []
197 if lenv['BF_BUILDINFO']==1: #user_options_dict['USE_BUILDINFO'] == 1:
198 if sys.platform=='win32':
199 build_info_file = open("source/creator/winbuildinfo.h", 'w')
200 build_info_file.write("char *build_date=\"%s\";\n"%build_date)
201 build_info_file.write("char *build_time=\"%s\";\n"%build_time)
202 build_info_file.write("char *build_rev=\"%s\";\n"%build_rev)
203 build_info_file.write("char *build_platform=\"win32\";\n")
204 build_info_file.write("char *build_type=\"dynamic\";\n")
205 build_info_file.close()
206 lenv.Append (CPPDEFINES = ['NAN_BUILDINFO', 'BUILD_DATE'])
207 else:
208 lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
209 'BUILD_DATE=\'"%s"\''%(build_date),
210 'BUILD_TYPE=\'"dynamic"\'',
211 'BUILD_REV=\'"%s"\''%(build_rev),
212 'NAN_BUILDINFO',
213 'BUILD_PLATFORM=\'"%s"\''%(sys.platform)])
214 obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
215 [root_build_dir+'source/creator/buildinfo.c'])]
216 return obj
218 ##### END LIB STUFF ############
220 ##### ACTION STUFF #############
222 def my_compile_print(target, source, env):
223 a = '%s' % (source[0])
224 d, f = os.path.split(a)
225 return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
227 def my_moc_print(target, source, env):
228 a = '%s' % (source[0])
229 d, f = os.path.split(a)
230 return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
232 def my_linking_print(target, source, env):
233 t = '%s' % (target[0])
234 d, f = os.path.split(t)
235 return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
237 def my_program_print(target, source, env):
238 t = '%s' % (target[0])
239 d, f = os.path.split(t)
240 return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
242 def msvc_hack(env):
243 static_lib = SCons.Tool.createStaticLibBuilder(env)
244 program = SCons.Tool.createProgBuilder(env)
246 env['BUILDERS']['Library'] = static_lib
247 env['BUILDERS']['StaticLibrary'] = static_lib
248 env['BUILDERS']['Program'] = program
250 def set_quiet_output(env):
251 mycaction = Action("$CCCOM", strfunction=my_compile_print)
252 myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
253 mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
254 myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
255 mylibaction = Action("$ARCOM", strfunction=my_linking_print)
256 mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
258 static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
259 static_ob.add_action('.c', mycaction)
260 static_ob.add_action('.cpp', mycppaction)
261 shared_ob.add_action('.c', myshcaction)
262 shared_ob.add_action('.cpp', myshcppaction)
264 static_lib = SCons.Builder.Builder(action = mylibaction,
265 emitter = '$LIBEMITTER',
266 prefix = '$LIBPREFIX',
267 suffix = '$LIBSUFFIX',
268 src_suffix = '$OBJSUFFIX',
269 src_builder = 'StaticObject')
271 program = SCons.Builder.Builder(action = mylinkaction,
272 emitter = '$PROGEMITTER',
273 prefix = '$PROGPREFIX',
274 suffix = '$PROGSUFFIX',
275 src_suffix = '$OBJSUFFIX',
276 src_builder = 'Object',
277 target_scanner = SCons.Defaults.ProgScan)
279 env['BUILDERS']['Object'] = static_ob
280 env['BUILDERS']['StaticObject'] = static_ob
281 env['BUILDERS']['StaticLibrary'] = static_lib
282 env['BUILDERS']['Library'] = static_lib
283 env['BUILDERS']['Program'] = program
285 def my_appit_print(target, source, env):
286 a = '%s' % (target[0])
287 d, f = os.path.split(a)
288 return "making bundle for " + f
290 def AppIt(target=None, source=None, env=None):
291 import shutil
292 import commands
293 import os.path
296 a = '%s' % (target[0])
297 builddir, b = os.path.split(a)
299 bldroot = env.Dir('.').abspath
300 binary = env['BINARYKIND']
302 if b=='verse':
303 print bc.OKBLUE+"no bundle for verse"+bc.ENDC
304 return 0
307 sourcedir = bldroot + '/source/darwin/%s.app'%binary
308 sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
309 targetinfo = builddir +'/' + "%s.app/Contents/Info.plist"%binary
310 cmd = builddir + '/' +'%s.app'%binary
312 if os.path.isdir(cmd):
313 shutil.rmtree(cmd)
314 shutil.copytree(sourcedir, cmd)
315 cmd = "cat %s | sed s/VERSION/`cat release/VERSION`/ | sed s/DATE/`date +'%%Y-%%b-%%d'`/ > %s"%(sourceinfo,targetinfo)
316 commands.getoutput(cmd)
317 cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,builddir, binary, binary)
318 commands.getoutput(cmd)
319 cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/'%(builddir, binary)
320 print cmd
321 commands.getoutput(cmd)
322 cmd = builddir + '/%s.app/Contents/MacOS/.blender'%binary
323 shutil.copy(bldroot + '/bin/.blender/.bfont.ttf', cmd)
324 shutil.copy(bldroot + '/bin/.blender/.Blanguages', cmd)
325 cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
326 commands.getoutput(cmd)
327 cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
328 commands.getoutput(cmd)
329 cmd = 'cp %s/bin/.blender/.Blanguages %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
330 commands.getoutput(cmd)
331 cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
332 commands.getoutput(cmd)
333 cmd = 'chmod +x %s/%s.app/Contents/MacOS/%s'%(builddir,binary, binary)
334 commands.getoutput(cmd)
335 cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(builddir, binary)
336 commands.getoutput(cmd)
337 cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(builddir, binary)
338 commands.getoutput(cmd)
340 #### END ACTION STUFF #########
342 def bsc(env, target, source):
344 bd = os.path.dirname(target[0].abspath)
345 bscfile = '\"'+target[0].abspath+'\"'
346 bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
347 bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
349 os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
351 myfile = open(bscpathtmp[1:-1], 'r')
352 lines = myfile.readlines()
353 myfile.close()
355 newfile = open(bscpathtmp[1:-1], 'w')
356 for l in lines:
357 newfile.write('\"'+l[:-1]+'\"\n')
358 newfile.close()
360 os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
361 os.system('del '+bscpathtmp)
363 class BlenderEnvironment(SConsEnvironment):
365 def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
366 global libs
367 if not self or not libname or not source:
368 print bc.FAIL+'Cannot continue. Missing argument for BlenderRes '+libname+bc.ENDC
369 Exit()
370 if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross'):
371 print bc.FAIL+'BlenderRes is for windows only!'+bc.END
372 self.Exit()
374 print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
375 lenv = self.Copy()
376 res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
378 SConsEnvironment.Default(self, res)
379 resources.append(res)
381 def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None):
382 if not self or not libname or not sources:
383 print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
384 Exit()
385 if libname in quickie or len(quickie)==0:
386 if libname in quickdebug:
387 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
388 else:
389 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
390 lenv = self.Copy()
391 lenv.Append(CPPPATH=includes)
392 lenv.Append(CPPDEFINES=defines)
393 if lenv['WITH_BF_GAMEENGINE']:
394 lenv.Append(CPPDEFINES=['GAMEBLENDER=1'])
395 # debug or not
396 # CXXFLAGS defaults to CCFLAGS, therefore
397 # we Replace() rather than Append() to CXXFLAGS the first time
398 if lenv['BF_DEBUG'] or (libname in quickdebug):
399 lenv.Append(CCFLAGS = Split(lenv['BF_DEBUG_FLAGS']))
400 lenv.Replace( CXXFLAGS = Split(lenv['BF_DEBUG_FLAGS']))
401 else:
402 lenv.Append(CCFLAGS = lenv['REL_CFLAGS'])
403 lenv.Replace(CXXFLAGS = lenv['REL_CCFLAGS'])
404 if lenv['BF_PROFILE']:
405 lenv.Append(CCFLAGS = Split(lenv['BF_PROFILE_FLAGS']),
406 CXXFLAGS = Split(lenv['BF_PROFILE_FLAGS']))
407 if compileflags:
408 lenv.Append(CCFLAGS = compileflags)
409 lenv.Append(CXXFLAGS = compileflags)
410 lenv.Append(CCFLAGS = Split(lenv['C_WARN']))
411 lenv.Append(CXXFLAGS = Split(lenv['CC_WARN']))
412 lib = lenv.Library(target= '#'+root_build_dir+'lib/'+libname, source=sources)
413 SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
414 else:
415 print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
416 # note: libs is a global
417 add_lib_to_dict(libs, libtype, libname, priority)
419 def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''):
420 print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
421 lenv = self.Copy()
422 if lenv['OURPLATFORM'] in ['win32-vc', 'cygwin']:
423 lenv.Append(LINKFLAGS = Split(lenv['PLATFORM_LINKFLAGS']))
424 if lenv['BF_DEBUG']:
425 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb'])
426 if lenv['OURPLATFORM']=='linux2':
427 lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
428 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
429 if lenv['OURPLATFORM']=='sunos5':
430 lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
431 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
432 if lenv['OURPLATFORM']=='darwin':
433 lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
434 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
435 lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
436 if lenv['BF_PROFILE']:
437 lenv.Append(LINKFLAGS = lenv['BF_PROFILE_FLAGS'])
438 lenv.Append(CPPPATH=includes)
439 lenv.Append(LIBPATH=libpath)
440 lenv.Append(LIBS=libs)
441 if lenv['WITH_BF_QUICKTIME']:
442 lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
443 lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
444 prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
445 if lenv['BF_DEBUG'] and lenv['OURPLATFORM']=='win32-vc' and lenv['BF_BSC']:
446 f = lenv.File(progname + '.bsc', builddir)
447 brs = lenv.Command(f, prog, [bsc])
448 SConsEnvironment.Default(self, brs)
449 SConsEnvironment.Default(self, prog)
450 program_list.append(prog)
451 if lenv['OURPLATFORM']=='darwin':
452 lenv['BINARYKIND'] = binarykind
453 lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
454 return prog
456 def Glob(lenv, pattern):
457 path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
458 files = []
459 for i in glob.glob(path + pattern):
460 files.append(string.replace(i, path, ''))
461 return files