SimpleDeform modifications:
[blender.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.path
18 import string
19 import glob
20 import time
21 import sys
22
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()
30
31 Split = SCons.Util.Split
32 Action = SCons.Action.Action
33 Builder = SCons.Builder.Builder
34 GetBuildPath = SConsEnvironment.GetBuildPath
35
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 = []
44
45 #some internals
46 blenderdeps = [] # don't manipulate this one outside this module!
47
48 ##### LIB STUFF ##########
49
50 possible_types = ['core'] # can be set in ie. SConstruct
51 libs = {}
52
53 def getresources():
54     return resources
55
56 def init_lib_dict():
57     for pt in possible_types:
58         libs[pt] = {}
59
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
70
71 # libtype and priority can both be lists, for defining lib in multiple places
72 def add_lib_to_dict(env, dict = None, libtype = None, libname = None, priority = 100):
73     if not dict or not libtype or not libname:
74         print "Passed wrong arg"
75         env.Exit()
76
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             env.Exit()
86     else:
87         print "Wrong type combinations for libtype and priority. Only str and int or list and list"
88         env.Exit()
89
90 def create_blender_liblist(lenv = None, libtype = None):
91     if not lenv or not libtype:
92         print "missing arg"
93
94     lst = []
95     if libtype in possible_types:
96         curlib = libs[libtype]
97         sortlist = curlib.keys()
98         sortlist.sort()
99         for sk in sortlist:
100             v = curlib[sk]
101             lst.append('#' + root_build_dir + 'lib/'+lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
102
103     return lst
104
105 ## TODO: static linking
106 def setup_staticlibs(lenv):
107     statlibs = [
108         #here libs for static linking
109     ]
110     libincs = [
111         '/usr/lib',
112         lenv['BF_PYTHON_LIBPATH'],
113         lenv['BF_OPENGL_LIBPATH'],
114         lenv['BF_SDL_LIBPATH'],
115         lenv['BF_JPEG_LIBPATH'],
116         lenv['BF_PNG_LIBPATH'],
117         lenv['BF_ZLIB_LIBPATH'],
118         lenv['BF_ICONV_LIBPATH']
119         ]
120     libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
121     libincs += Split(lenv['BF_FFMPEG_LIBPATH'])
122
123     if lenv['WITH_BF_INTERNATIONAL']:
124         libincs += Split(lenv['BF_GETTEXT_LIBPATH'])
125         libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
126     if lenv['WITH_BF_OPENAL']:
127         libincs += Split(lenv['BF_OPENAL_LIBPATH'])
128
129     if lenv['WITH_BF_STATICOPENGL']:
130         statlibs += Split(lenv['BF_OPENGL_LIB_STATIC'])
131
132     if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross'):
133         libincs += Split(lenv['BF_PTHREADS_LIBPATH'])
134
135     return statlibs, libincs
136
137 def setup_syslibs(lenv):
138     syslibs = [
139         
140         lenv['BF_JPEG_LIB'],
141         lenv['BF_PNG_LIB'],
142         lenv['BF_ZLIB_LIB']
143         ]
144     if lenv['BF_DEBUG']==1 and lenv['OURPLATFORM'] in ('win32-vc'):
145         syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
146     else:
147         syslibs.append(lenv['BF_PYTHON_LIB'])
148     if lenv['WITH_BF_INTERNATIONAL']:
149         syslibs += Split(lenv['BF_FREETYPE_LIB'])
150         syslibs += Split(lenv['BF_GETTEXT_LIB'])
151     if lenv['WITH_BF_OPENAL']:
152        syslibs += Split(lenv['BF_OPENAL_LIB'])
153     if lenv['WITH_BF_OPENMP'] and lenv['CC'] != 'icc':
154         syslibs += ['gomp']
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'])
166
167     syslibs += Split(lenv['LLIBS'])
168
169     return syslibs
170
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         curlib = libs[t]
177         sortlist = curlib.keys()
178         sortlist.sort()
179
180         for sk in sortlist:
181             v = curlib[sk]
182             #for p,v in sorted(libs[t].iteritems()):
183             print "\t\t",new_priority, v
184             new_priority += 5
185
186 ## TODO: see if this can be made in an emitter
187 def buildinfo(lenv, build_type):
188     """
189     Generate a buildinfo object
190     """
191     build_date = time.strftime ("%Y-%m-%d")
192     build_time = time.strftime ("%H:%M:%S")
193     build_rev = os.popen('svnversion').read()[:-1] # remove \n
194
195     obj = []
196     if lenv['BF_BUILDINFO']==1: #user_options_dict['USE_BUILDINFO'] == 1:
197         if sys.platform=='win32':
198             build_info_file = open("source/creator/winbuildinfo.h", 'w')
199             build_info_file.write("char *build_date=\"%s\";\n"%build_date)
200             build_info_file.write("char *build_time=\"%s\";\n"%build_time)
201             build_info_file.write("char *build_rev=\"%s\";\n"%build_rev)
202             build_info_file.write("char *build_platform=\"win32\";\n")
203             build_info_file.write("char *build_type=\"dynamic\";\n")
204             build_info_file.close()
205             lenv.Append (CPPDEFINES = ['NAN_BUILDINFO', 'BUILD_DATE'])
206         else:
207             lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
208                                         'BUILD_DATE=\'"%s"\''%(build_date),
209                                         'BUILD_TYPE=\'"dynamic"\'',
210                                         'BUILD_REV=\'"%s"\''%(build_rev),
211                                         'NAN_BUILDINFO',
212                                         'BUILD_PLATFORM=\'"%s"\''%(sys.platform)])
213         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
214                         [root_build_dir+'source/creator/buildinfo.c'])]
215     return obj
216
217 ##### END LIB STUFF ############
218
219 ##### ACTION STUFF #############
220
221 def my_compile_print(target, source, env):
222     a = '%s' % (source[0])
223     d, f = os.path.split(a)
224     return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
225
226 def my_moc_print(target, source, env):
227     a = '%s' % (source[0])
228     d, f = os.path.split(a)
229     return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
230
231 def my_linking_print(target, source, env):
232     t = '%s' % (target[0])
233     d, f = os.path.split(t)
234     return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
235
236 def my_program_print(target, source, env):
237     t = '%s' % (target[0])
238     d, f = os.path.split(t)
239     return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
240
241 def msvc_hack(env):
242     static_lib = SCons.Tool.createStaticLibBuilder(env)
243     program = SCons.Tool.createProgBuilder(env)
244     
245     env['BUILDERS']['Library'] = static_lib
246     env['BUILDERS']['StaticLibrary'] = static_lib
247     env['BUILDERS']['Program'] = program
248         
249 def set_quiet_output(env):
250     mycaction = Action("$CCCOM", strfunction=my_compile_print)
251     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
252     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
253     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
254     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
255     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
256
257     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
258     static_ob.add_action('.c', mycaction)
259     static_ob.add_action('.cpp', mycppaction)
260     shared_ob.add_action('.c', myshcaction)
261     shared_ob.add_action('.cpp', myshcppaction)
262
263     static_lib = SCons.Builder.Builder(action = mylibaction,
264                                        emitter = '$LIBEMITTER',
265                                        prefix = '$LIBPREFIX',
266                                        suffix = '$LIBSUFFIX',
267                                        src_suffix = '$OBJSUFFIX',
268                                        src_builder = 'StaticObject')
269
270     program = SCons.Builder.Builder(action = mylinkaction,
271                                     emitter = '$PROGEMITTER',
272                                     prefix = '$PROGPREFIX',
273                                     suffix = '$PROGSUFFIX',
274                                     src_suffix = '$OBJSUFFIX',
275                                     src_builder = 'Object',
276                                     target_scanner = SCons.Defaults.ProgScan)
277
278     env['BUILDERS']['Object'] = static_ob
279     env['BUILDERS']['StaticObject'] = static_ob
280     env['BUILDERS']['StaticLibrary'] = static_lib
281     env['BUILDERS']['Library'] = static_lib
282     env['BUILDERS']['Program'] = program
283
284 def  my_appit_print(target, source, env):
285     a = '%s' % (target[0])
286     d, f = os.path.split(a)
287     return "making bundle for " + f
288
289 def AppIt(target=None, source=None, env=None):
290     import shutil
291     import commands
292     import os.path
293     
294     
295     a = '%s' % (target[0])
296     builddir, b = os.path.split(a)
297
298     bldroot = env.Dir('.').abspath
299     binary = env['BINARYKIND']
300      
301     if b=='verse':
302         print bc.OKBLUE+"no bundle for verse"+bc.ENDC 
303         return 0
304    
305     
306     sourcedir = bldroot + '/source/darwin/%s.app'%binary
307     sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
308     targetinfo = builddir +'/' + "%s.app/Contents/Info.plist"%binary
309     cmd = builddir + '/' +'%s.app'%binary
310     
311     if os.path.isdir(cmd):
312         shutil.rmtree(cmd)
313     shutil.copytree(sourcedir, cmd)
314     cmd = "cat %s | sed s/VERSION/`cat release/VERSION`/ | sed s/DATE/`date +'%%Y-%%b-%%d'`/ > %s"%(sourceinfo,targetinfo)
315     commands.getoutput(cmd)
316     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,builddir, binary, binary)
317     commands.getoutput(cmd)
318     cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/'%(builddir, binary)
319     print cmd
320     commands.getoutput(cmd)
321     cmd = builddir + '/%s.app/Contents/MacOS/.blender'%binary
322     shutil.copy(bldroot + '/bin/.blender/.bfont.ttf', cmd)
323     shutil.copy(bldroot + '/bin/.blender/.Blanguages', cmd)
324     cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
325     commands.getoutput(cmd) 
326     cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
327     commands.getoutput(cmd) 
328     cmd = 'cp %s/bin/.blender/.Blanguages %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
329     commands.getoutput(cmd) 
330     cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
331     commands.getoutput(cmd)
332     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(builddir,binary, binary)
333     commands.getoutput(cmd)
334     cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(builddir, binary)
335     commands.getoutput(cmd)
336     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(builddir, binary)
337     commands.getoutput(cmd)
338
339 #### END ACTION STUFF #########
340
341 def bsc(env, target, source):
342     
343     bd = os.path.dirname(target[0].abspath)
344     bscfile = '\"'+target[0].abspath+'\"'
345     bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
346     bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
347
348     os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
349
350     myfile = open(bscpathtmp[1:-1], 'r')
351     lines = myfile.readlines()
352     myfile.close()
353
354     newfile = open(bscpathtmp[1:-1], 'w')
355     for l in lines:
356         newfile.write('\"'+l[:-1]+'\"\n')
357     newfile.close()
358                 
359     os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
360     os.system('del '+bscpathtmp)
361
362 class BlenderEnvironment(SConsEnvironment):
363
364     def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
365         global libs
366         if not self or not libname or not source:
367             print bc.FAIL+'Cannot continue.  Missing argument for BlenderRes '+libname+bc.ENDC
368             self.Exit()
369         if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross'):
370             print bc.FAIL+'BlenderRes is for windows only!'+bc.END
371             self.Exit()
372         
373         print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
374         lenv = self.Copy()
375         res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
376       
377         SConsEnvironment.Default(self, res)
378         resources.append(res)
379
380     def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None):
381         if not self or not libname or not sources:
382             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
383             self.Exit()
384         if libname in quickie or len(quickie)==0:
385             if libname in quickdebug: 
386                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
387             else:
388                 print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
389             lenv = self.Copy()
390             lenv.Append(CPPPATH=includes)
391             lenv.Append(CPPDEFINES=defines)
392             if lenv['WITH_BF_GAMEENGINE']:
393                     lenv.Append(CPPDEFINES=['GAMEBLENDER=1'])
394             if lenv['WITH_BF_BULLET']:
395                     lenv.Append(CPPDEFINES=['WITH_BULLET=1'])
396             # debug or not
397             # CXXFLAGS defaults to CCFLAGS, therefore
398             #  we Replace() rather than Append() to CXXFLAGS the first time
399             lenv.Replace(CXXFLAGS = lenv['CCFLAGS'])
400             if lenv['BF_DEBUG'] or (libname in quickdebug):
401                     lenv.Append(CCFLAGS = Split(lenv['BF_DEBUG_FLAGS']))
402                     lenv.Append( CXXFLAGS = Split(lenv['BF_DEBUG_FLAGS']))
403             else:
404                     lenv.Append(CCFLAGS = lenv['REL_CFLAGS'])
405                     lenv.Append(CXXFLAGS = lenv['REL_CCFLAGS'])
406             if lenv['BF_PROFILE']:
407                     lenv.Append(CCFLAGS = Split(lenv['BF_PROFILE_FLAGS']),
408                                 CXXFLAGS = Split(lenv['BF_PROFILE_FLAGS']))
409             if compileflags:
410                 lenv.Append(CCFLAGS = compileflags)
411                 lenv.Append(CXXFLAGS = compileflags)
412             lenv.Append(CCFLAGS = Split(lenv['C_WARN']))
413             lenv.Append(CXXFLAGS = Split(lenv['CC_WARN']))
414             lib = lenv.Library(target= '#'+root_build_dir+'lib/'+libname, source=sources)
415             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
416         else:
417             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
418         # note: libs is a global
419         add_lib_to_dict(self, libs, libtype, libname, priority)
420
421     def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''):
422         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
423         lenv = self.Copy()
424         if lenv['OURPLATFORM'] in ['win32-vc', 'cygwin']:
425             lenv.Append(LINKFLAGS = Split(lenv['PLATFORM_LINKFLAGS']))
426             if lenv['BF_DEBUG']:
427                 lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb'])
428         if  lenv['OURPLATFORM']=='linux2':
429             lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
430             lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
431         if  lenv['OURPLATFORM']=='sunos5':
432             lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
433             lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
434             if lenv['CXX'].endswith('CC'):
435                  lenv.Replace(LINK = '$CXX')
436         if  lenv['OURPLATFORM']=='darwin':
437             lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
438             lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
439             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
440         if lenv['BF_PROFILE']:
441                 lenv.Append(LINKFLAGS = lenv['BF_PROFILE_FLAGS'])
442         lenv.Append(CPPPATH=includes)
443         lenv.Append(LIBPATH=libpath)
444         lenv.Append(LIBS=libs)
445         if lenv['WITH_BF_QUICKTIME']:
446              lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
447              lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
448         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
449         if lenv['BF_DEBUG'] and lenv['OURPLATFORM']=='win32-vc' and lenv['BF_BSC']:
450             f = lenv.File(progname + '.bsc', builddir)
451             brs = lenv.Command(f, prog, [bsc])
452             SConsEnvironment.Default(self, brs)
453         SConsEnvironment.Default(self, prog)
454         program_list.append(prog)
455         if  lenv['OURPLATFORM']=='darwin':
456             lenv['BINARYKIND'] = binarykind
457             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
458         return prog
459
460     def Glob(lenv, pattern):
461         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
462         files = []
463         for i in glob.glob(path + pattern):
464             files.append(string.replace(i, path, ''))
465         return files