4 tools.BlenderEnvironment
6 This environment builds on SCons.Script.SConscript.SConsEnvironment
12 TODO: clean up and sanitise code - crosscheck with btools and SConstruct
13 to kill any code duplication
24 from SCons.Script.SConscript import SConsEnvironment
30 bc = bcolors.bcolors()
32 Split = SCons.Util.Split
33 Action = SCons.Action.Action
34 Builder = SCons.Builder.Builder
35 GetBuildPath = SConsEnvironment.GetBuildPath
40 quickie = None # Anything else than None if BF_QUICK has been passed
41 quicklist = [] # The list of libraries/programs to compile during a quickie
42 program_list = [] # A list holding Nodes to final binaries, used to create installs
48 blenderdeps = [] # don't manipulate this one outside this module!
50 ##### LIB STUFF ##########
52 possible_types = ['core'] # can be set in ie. SConstruct
60 for pt in possible_types:
63 # helper func for add_lib_to_dict
64 def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
65 if not libname in dict[libtype]:
68 if dict[libtype].has_key(priority):
69 priority = priority + 1
72 dict[libtype][priority] = libname
74 # libtype and priority can both be lists, for defining lib in multiple places
75 def add_lib_to_dict(env, dict = None, libtype = None, libname = None, priority = 100):
76 if not dict or not libtype or not libname:
77 print "Passed wrong arg"
80 if type(libtype) is str and type(priority) is int:
81 internal_lib_to_dict(dict, libtype, libname, priority)
82 elif type(libtype) is list and type(priority) is list:
83 if len(libtype)==len(priority):
84 for lt, p in zip(libtype, priority):
85 internal_lib_to_dict(dict, lt, libname, p)
87 print "libtype and priority lists are unequal in length"
90 print "Wrong type combinations for libtype and priority. Only str and int or list and list"
93 def create_blender_liblist(lenv = None, libtype = None):
94 if not lenv or not libtype:
98 if libtype in possible_types:
99 curlib = libs[libtype]
100 sortlist = curlib.keys()
104 target = os.path.abspath(os.getcwd() + os.sep + root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
109 ## TODO: static linking
110 def setup_staticlibs(lenv):
112 #here libs for static linking
115 lenv['BF_OPENGL_LIBPATH'],
116 lenv['BF_JPEG_LIBPATH'],
117 lenv['BF_PNG_LIBPATH'],
118 lenv['BF_ZLIB_LIBPATH'],
119 lenv['BF_ICONV_LIBPATH']
122 if lenv['OURPLATFORM'] != 'linuxcross':
123 libincs = ['/usr/lib'] + libincs
125 libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
126 if lenv['WITH_BF_PYTHON']:
127 libincs += Split(lenv['BF_PYTHON_LIBPATH'])
128 if lenv['WITH_BF_SDL']:
129 libincs += Split(lenv['BF_SDL_LIBPATH'])
130 if lenv['WITH_BF_FFMPEG']:
131 libincs += Split(lenv['BF_FFMPEG_LIBPATH'])
132 if lenv['WITH_BF_OPENEXR']:
133 libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
134 if lenv['WITH_BF_STATICOPENEXR']:
135 statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
136 if lenv['WITH_BF_INTERNATIONAL']:
137 libincs += Split(lenv['BF_GETTEXT_LIBPATH'])
138 if lenv['WITH_BF_OPENAL']:
139 libincs += Split(lenv['BF_OPENAL_LIBPATH'])
140 if lenv['WITH_BF_STATICOPENAL']:
141 statlibs += Split(lenv['BF_OPENAL_LIB_STATIC'])
142 if lenv['WITH_BF_STATICOPENGL']:
143 statlibs += Split(lenv['BF_OPENGL_LIB_STATIC'])
144 if lenv['WITH_BF_STATICCXX']:
145 statlibs += Split(lenv['BF_CXX_LIB_STATIC'])
147 if lenv['WITH_BF_PYTHON'] and lenv['WITH_BF_STATICPYTHON']:
148 statlibs += Split(lenv['BF_PYTHON_LIB_STATIC'])
150 if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
151 libincs += Split(lenv['BF_PTHREADS_LIBPATH'])
153 return statlibs, libincs
155 def setup_syslibs(lenv):
163 syslibs += Split(lenv['BF_FREETYPE_LIB'])
164 if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']:
165 if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
166 syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
168 syslibs.append(lenv['BF_PYTHON_LIB'])
169 if lenv['WITH_BF_INTERNATIONAL']:
170 syslibs += Split(lenv['BF_GETTEXT_LIB'])
171 if lenv['WITH_BF_OPENAL']:
172 if not lenv['WITH_BF_STATICOPENAL']:
173 syslibs += Split(lenv['BF_OPENAL_LIB'])
174 if lenv['WITH_BF_OPENMP'] and lenv['CC'] != 'icc':
175 if lenv['CC'] == 'cl.exe':
179 if lenv['WITH_BF_ICONV']:
180 syslibs += Split(lenv['BF_ICONV_LIB'])
181 if lenv['WITH_BF_OPENEXR']:
182 if not lenv['WITH_BF_STATICOPENEXR']:
183 syslibs += Split(lenv['BF_OPENEXR_LIB'])
184 if lenv['WITH_BF_FFMPEG']:
185 syslibs += Split(lenv['BF_FFMPEG_LIB'])
186 if lenv['WITH_BF_OGG']:
187 syslibs += Split(lenv['BF_OGG_LIB'])
188 if lenv['WITH_BF_SDL']:
189 syslibs += Split(lenv['BF_SDL_LIB'])
190 if not lenv['WITH_BF_STATICOPENGL']:
191 syslibs += Split(lenv['BF_OPENGL_LIB'])
192 if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross', 'win64-vc'):
193 syslibs += Split(lenv['BF_PTHREADS_LIB'])
194 if lenv['WITH_BF_LCMS']:
195 syslibs.append(lenv['BF_LCMS_LIB'])
198 syslibs += lenv['LLIBS']
202 def propose_priorities():
203 print bc.OKBLUE+"Priorities:"+bc.ENDC
204 for t in possible_types:
205 print bc.OKGREEN+"\t"+t+bc.ENDC
208 sortlist = curlib.keys()
213 #for p,v in sorted(libs[t].iteritems()):
214 print "\t\t",new_priority, v
217 ## TODO: see if this can be made in an emitter
218 def buildinfo(lenv, build_type):
220 Generate a buildinfo object
222 build_date = time.strftime ("%Y-%m-%d")
223 build_time = time.strftime ("%H:%M:%S")
224 build_rev = os.popen('svnversion').read()[:-1] # remove \n
227 if lenv['BF_BUILDINFO']:
228 if sys.platform=='win32' or lenv['OURPLATFORM']=='linuxcross':
229 build_info_file = open("source/creator/winbuildinfo.h", 'w')
230 build_info_file.write("char *build_date=\"%s\";\n"%build_date)
231 build_info_file.write("char *build_time=\"%s\";\n"%build_time)
232 build_info_file.write("char *build_rev=\"%s\";\n"%build_rev)
233 build_info_file.write("char *build_platform=\"win32\";\n")
234 build_info_file.write("char *build_type=\"dynamic\";\n")
235 build_info_file.close()
236 lenv.Append (CPPDEFINES = ['NAN_BUILDINFO', 'BUILD_DATE'])
238 lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
239 'BUILD_DATE=\'"%s"\''%(build_date),
240 'BUILD_TYPE=\'"dynamic"\'',
241 'BUILD_REV=\'"%s"\''%(build_rev),
243 'BUILD_PLATFORM=\'"%s"\''%(sys.platform)])
244 obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
245 [root_build_dir+'source/creator/buildinfo.c'])]
248 ##### END LIB STUFF ############
250 ##### ACTION STUFF #############
252 def my_compile_print(target, source, env):
253 a = '%s' % (source[0])
254 d, f = os.path.split(a)
255 return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
257 def my_moc_print(target, source, env):
258 a = '%s' % (source[0])
259 d, f = os.path.split(a)
260 return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
262 def my_linking_print(target, source, env):
263 t = '%s' % (target[0])
264 d, f = os.path.split(t)
265 return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
267 def my_program_print(target, source, env):
268 t = '%s' % (target[0])
269 d, f = os.path.split(t)
270 return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
273 static_lib = SCons.Tool.createStaticLibBuilder(env)
274 program = SCons.Tool.createProgBuilder(env)
276 env['BUILDERS']['Library'] = static_lib
277 env['BUILDERS']['StaticLibrary'] = static_lib
278 env['BUILDERS']['Program'] = program
280 def set_quiet_output(env):
281 mycaction = Action("$CCCOM", strfunction=my_compile_print)
282 myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
283 mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
284 myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
285 mylibaction = Action("$ARCOM", strfunction=my_linking_print)
286 mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
288 static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
289 static_ob.add_action('.c', mycaction)
290 static_ob.add_action('.cpp', mycppaction)
291 shared_ob.add_action('.c', myshcaction)
292 shared_ob.add_action('.cpp', myshcppaction)
294 static_lib = SCons.Builder.Builder(action = mylibaction,
295 emitter = '$LIBEMITTER',
296 prefix = '$LIBPREFIX',
297 suffix = '$LIBSUFFIX',
298 src_suffix = '$OBJSUFFIX',
299 src_builder = 'StaticObject')
301 program = SCons.Builder.Builder(action = mylinkaction,
302 emitter = '$PROGEMITTER',
303 prefix = '$PROGPREFIX',
304 suffix = '$PROGSUFFIX',
305 src_suffix = '$OBJSUFFIX',
306 src_builder = 'Object',
307 target_scanner = SCons.Defaults.ProgScan)
309 env['BUILDERS']['Object'] = static_ob
310 env['BUILDERS']['StaticObject'] = static_ob
311 env['BUILDERS']['StaticLibrary'] = static_lib
312 env['BUILDERS']['Library'] = static_lib
313 env['BUILDERS']['Program'] = program
315 def my_appit_print(target, source, env):
316 a = '%s' % (target[0])
317 d, f = os.path.split(a)
318 return "making bundle for " + f
320 def AppIt(target=None, source=None, env=None):
326 a = '%s' % (target[0])
327 builddir, b = os.path.split(a)
329 bldroot = env.Dir('.').abspath
330 binary = env['BINARYKIND']
333 print bc.OKBLUE+"no bundle for verse"+bc.ENDC
336 sourcedir = bldroot + '/source/darwin/%s.app'%binary
337 sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
338 targetinfo = builddir +'/' + "%s.app/Contents/Info.plist"%binary
339 cmd = builddir + '/' +'%s.app'%binary
341 if os.path.isdir(cmd):
343 shutil.copytree(sourcedir, cmd)
344 cmd = "cat %s | sed s/VERSION/`cat release/VERSION`/ | sed s/DATE/`date +'%%Y-%%b-%%d'`/ > %s"%(sourceinfo,targetinfo)
345 commands.getoutput(cmd)
346 cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,builddir, binary, binary)
347 commands.getoutput(cmd)
348 cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/'%(builddir, binary)
350 commands.getoutput(cmd)
351 cmd = builddir + '/%s.app/Contents/MacOS/.blender'%binary
352 shutil.copy(bldroot + '/bin/.blender/.bfont.ttf', cmd)
353 shutil.copy(bldroot + '/bin/.blender/.Blanguages', cmd)
354 cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
355 commands.getoutput(cmd)
356 cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
357 commands.getoutput(cmd)
358 cmd = 'cp %s/bin/.blender/.Blanguages %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
359 commands.getoutput(cmd)
360 cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
361 commands.getoutput(cmd)
362 cmd = 'cp -R %s/release/ui %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
363 commands.getoutput(cmd)
364 cmd = 'chmod +x %s/%s.app/Contents/MacOS/%s'%(builddir,binary, binary)
365 commands.getoutput(cmd)
366 cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(builddir, binary)
367 commands.getoutput(cmd)
368 cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(builddir, binary)
369 commands.getoutput(cmd)
371 #### END ACTION STUFF #########
373 def bsc(env, target, source):
375 bd = os.path.dirname(target[0].abspath)
376 bscfile = '\"'+target[0].abspath+'\"'
377 bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
378 bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
380 os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
382 myfile = open(bscpathtmp[1:-1], 'r')
383 lines = myfile.readlines()
386 newfile = open(bscpathtmp[1:-1], 'w')
388 newfile.write('\"'+l[:-1]+'\"\n')
391 os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
392 os.system('del '+bscpathtmp)
394 class BlenderEnvironment(SConsEnvironment):
396 def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
398 if not self or not libname or not source:
399 print bc.FAIL+'Cannot continue. Missing argument for BlenderRes '+libname+bc.ENDC
401 if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc'):
402 print bc.FAIL+'BlenderRes is for windows only!'+bc.END
405 print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
407 res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
409 SConsEnvironment.Default(self, res)
410 resources.append(res)
412 def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None, cc_compileflags=None, cxx_compileflags=None):
414 if not self or not libname or not sources:
415 print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
418 def list_substring(quickie, libname):
420 if libname.find(q) != -1:
424 if list_substring(quickie, libname) or len(quickie)==0:
425 if list_substring(quickdebug, libname):
426 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
428 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
430 lenv.Append(CPPPATH=includes)
431 lenv.Append(CPPDEFINES=defines)
432 if lenv['BF_DEBUG'] or (libname in quickdebug):
433 lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
434 lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
435 lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
437 lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
438 lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
439 lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
440 if lenv['BF_PROFILE']:
441 lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
442 lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
443 lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
445 lenv.Replace(CFLAGS = compileflags)
447 lenv.Replace(CCFLAGS = cc_compileflags)
449 lenv.Replace(CXXFLAGS = cxx_compileflags)
450 lenv.Append(CFLAGS = lenv['C_WARN'])
451 lenv.Append(CCFLAGS = lenv['CC_WARN'])
452 lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
454 if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
456 lenv.Append(CCFLAGS = ['/MTd'])
458 lenv.Append(CCFLAGS = ['/MT'])
460 targetdir = root_build_dir+'lib/' + libname
461 if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
462 targetdir = '#'+targetdir
463 lib = lenv.Library(target= targetdir, source=sources)
464 SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
465 if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
466 #if targetdir[0] == '#':
467 # targetdir = targetdir[1:-1]
468 print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
469 vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
473 auto_build_solution=0)
474 vcp.append(vcproject)
475 SConsEnvironment.Default(self, vcproject)
477 print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
478 # note: libs is a global
479 add_lib_to_dict(self, libs, libtype, libname, priority)
481 def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''):
483 print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
485 if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
486 lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
487 lenv.Append(LINKFLAGS = ['/FORCE:MULTIPLE'])
489 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb'])
490 if lenv['OURPLATFORM']=='linux2':
491 lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
492 if lenv['WITH_BF_PYTHON']:
493 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
494 if lenv['OURPLATFORM']=='sunos5':
495 lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
496 if lenv['WITH_BF_PYTHON']:
497 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
498 if lenv['CXX'].endswith('CC'):
499 lenv.Replace(LINK = '$CXX')
500 if lenv['OURPLATFORM']=='darwin':
501 lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
502 if lenv['WITH_BF_PYTHON']:
503 lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
504 lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
505 if lenv['BF_PROFILE']:
506 lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
507 lenv.Append(CPPPATH=includes)
508 if root_build_dir[0]==os.sep or root_build_dir[1]==':':
509 lenv.Append(LIBPATH=root_build_dir + '/lib')
510 lenv.Append(LIBPATH=libpath)
511 lenv.Append(LIBS=libs)
512 if lenv['WITH_BF_QUICKTIME']:
513 lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
514 lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
515 prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
516 if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
517 f = lenv.File(progname + '.bsc', builddir)
518 brs = lenv.Command(f, prog, [bsc])
519 SConsEnvironment.Default(self, brs)
520 SConsEnvironment.Default(self, prog)
521 if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
522 print "! ",builddir + "/" + progname + '.sln'
523 sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
526 SConsEnvironment.Default(self, sln)
527 program_list.append(prog)
528 if lenv['OURPLATFORM']=='darwin':
529 lenv['BINARYKIND'] = binarykind
530 lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
533 def Glob(lenv, pattern):
534 path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
536 for i in glob.glob(path + pattern):
537 files.append(string.replace(i, path, ''))