Adds ffmpeg-support on Linux-platforms. Since ffmpeg is installed
[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 import os.path
17 import string
18 import glob
19 import time
20 import sys
21
22 from SCons.Script.SConscript import SConsEnvironment
23 import SCons.Action
24 import SCons.Util
25 import SCons.Builder
26 import SCons.Tool
27 import bcolors
28 bc = bcolors.bcolors()
29
30 Split = SCons.Util.Split
31 Action = SCons.Action.Action
32 Builder = SCons.Builder.Builder
33 GetBuildPath = SConsEnvironment.GetBuildPath
34
35 # a few globals
36 root_build_dir = ''
37 quickie = None # Anything else than None if BF_QUICK has been passed
38 quicklist = [] # The list of libraries/programs to compile during a quickie
39 program_list = [] # A list holding Nodes to final binaries, used to create installs
40 arguments = None
41 targets = None
42
43 #some internals
44 blenderdeps = [] # don't manipulate this one outside this module!
45
46 ##### LIB STUFF ##########
47
48 possible_types = ['core'] # can be set in ie. SConstruct
49 libs = {}
50 def init_lib_dict():
51     for pt in possible_types:
52         libs[pt] = {}
53
54 # helper func for add_lib_to_dict
55 def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
56     if not libname in dict[libtype]:
57         done = None
58         while not done:
59             if dict[libtype].has_key(priority):
60                 priority = priority + 1
61             else:
62                 done = True
63         dict[libtype][priority] = libname
64
65 # libtype and priority can both be lists, for defining lib in multiple places
66 def add_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
67     if not dict or not libtype or not libname:
68         print "Passed wrong arg"
69         Exit()
70
71     if type(libtype) is str and type(priority) is int:
72         internal_lib_to_dict(dict, libtype, libname, priority)
73     elif type(libtype) is list and type(priority) is list:
74         if len(libtype)==len(priority):
75             for lt, p in zip(libtype, priority):
76                 internal_lib_to_dict(dict, lt, libname, p)
77         else:
78             print "libtype and priority lists are unequal in length"
79             Exit()
80     else:
81         print "Wrong type combinations for libtype and priority. Only str and int or list and list"
82         Exit()
83
84 def create_blender_liblist(lenv = None, libtype = None):
85     if not lenv or not libtype:
86         print "missing arg"
87
88     lst = []
89     if libtype in possible_types:
90         sortlist = []
91         for k,v in libs[libtype].iteritems():
92             sortlist.append(k)
93         sortlist.sort()
94         curlib = libs[libtype]
95         for sk in sortlist:
96             v = curlib[sk]
97             lst.append('#' + root_build_dir + 'lib/'+lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
98
99     return lst
100
101 ## TODO: static linking
102 def setup_staticlibs(lenv):
103     statlibs = [
104         #here libs for static linking
105     ]
106     libincs = [
107         '/usr/lib',
108         lenv['BF_PYTHON_LIBPATH'],
109         lenv['BF_OPENGL_LIBPATH'],
110         lenv['BF_SDL_LIBPATH'],
111         lenv['BF_JPEG_LIBPATH'],
112         lenv['BF_PNG_LIBPATH'],
113         lenv['BF_ZLIB_LIBPATH'],
114         lenv['BF_ICONV_LIBPATH']
115         ]
116     libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
117
118     if lenv['WITH_BF_INTERNATIONAL']:
119         libincs += Split(lenv['BF_GETTEXT_LIBPATH'])
120         libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
121     if lenv['WITH_BF_OPENAL']:
122         libincs += Split(lenv['BF_OPENAL_LIBPATH'])
123
124     return statlibs, libincs
125
126 def setup_syslibs(lenv):
127     syslibs = [
128         lenv['BF_PYTHON_LIB'],
129         lenv['BF_JPEG_LIB'],
130         lenv['BF_PNG_LIB'],
131         lenv['BF_ZLIB_LIB']
132         ]
133     if lenv['WITH_BF_INTERNATIONAL']:
134         syslibs += Split(lenv['BF_FREETYPE_LIB'])
135         syslibs += Split(lenv['BF_GETTEXT_LIB'])
136     if lenv['WITH_BF_OPENAL']:
137        syslibs += Split(lenv['BF_OPENAL_LIB'])
138     if lenv['OURPLATFORM']=='win32vc':
139         syslibs += Split(lenv['BF_ICONV_LIB'])
140     if lenv['WITH_BF_OPENEXR']:
141         syslibs += Split(lenv['BF_OPENEXR_LIB'])
142     if lenv['WITH_BF_FFMPEG']:
143         syslibs += Split(lenv['BF_FFMPEG_LIB'])
144     syslibs += Split(lenv['BF_SDL_LIB'])
145     syslibs += Split(lenv['BF_OPENGL_LIB'])
146     syslibs += Split(lenv['LLIBS'])
147
148     return syslibs
149
150 def propose_priorities():
151     print bc.OKBLUE+"Priorities:"+bc.ENDC
152     for t in possible_types:
153         print bc.OKGREEN+"\t"+t+bc.ENDC
154         new_priority = 0
155         sortlist = []
156         for k,v in libs[t].iteritems():
157             sortlist.append(k)
158         sortlist.sort()
159         curlib = libs[t]
160         for sk in sortlist:
161             v = curlib[sk]
162             #for p,v in sorted(libs[t].iteritems()):
163             print "\t\t",new_priority, v
164             new_priority += 5
165
166 ## TODO: see if this can be made in an emitter
167 def buildinfo(lenv, build_type):
168     """
169     Generate a buildinfo object
170     """
171     build_date = time.strftime ("%Y-%m-%d")
172     build_time = time.strftime ("%H:%M:%S")
173     obj = []
174     if lenv['BF_BUILDINFO']==1: #user_options_dict['USE_BUILDINFO'] == 1:
175         if sys.platform=='win32':
176             build_info_file = open("source/creator/winbuildinfo.h", 'w')
177             build_info_file.write("char *build_date=\"%s\";\n"%build_date)
178             build_info_file.write("char *build_time=\"%s\";\n"%build_time)
179             build_info_file.write("char *build_platform=\"win32\";\n")
180             build_info_file.write("char *build_type=\"dynamic\";\n")
181             build_info_file.close()
182             lenv.Append (CPPDEFINES = ['NAN_BUILDINFO', 'BUILD_DATE'])
183         else:
184             lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
185                                         'BUILD_DATE=\'"%s"\''%(build_date),
186                                         'BUILD_TYPE=\'"dynamic"\'',
187                                         'NAN_BUILDINFO',
188                                         'BUILD_PLATFORM=\'"%s"\''%(sys.platform)])
189         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
190                         [root_build_dir+'source/creator/buildinfo.c'])]
191     return obj
192
193 ##### END LIB STUFF ############
194
195 ##### ACTION STUFF #############
196
197 def my_compile_print(target, source, env):
198     a = '%s' % (source[0])
199     d, f = os.path.split(a)
200     return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
201
202 def my_moc_print(target, source, env):
203     a = '%s' % (source[0])
204     d, f = os.path.split(a)
205     return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
206
207 def my_linking_print(target, source, env):
208     t = '%s' % (target[0])
209     d, f = os.path.split(t)
210     return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
211
212 def my_program_print(target, source, env):
213     t = '%s' % (target[0])
214     d, f = os.path.split(t)
215     return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
216
217 def msvc_hack(env):
218     static_lib = SCons.Tool.createStaticLibBuilder(env)
219     program = SCons.Tool.createProgBuilder(env)
220     
221     env['BUILDERS']['Library'] = static_lib
222     env['BUILDERS']['StaticLibrary'] = static_lib
223     env['BUILDERS']['Program'] = program
224         
225 def set_quiet_output(env):
226     mycaction = Action("$CCCOM", strfunction=my_compile_print)
227     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
228     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
229     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
230     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
231     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
232
233     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
234     static_ob.add_action('.c', mycaction)
235     static_ob.add_action('.cpp', mycppaction)
236     shared_ob.add_action('.c', myshcaction)
237     shared_ob.add_action('.cpp', myshcppaction)
238
239     static_lib = SCons.Builder.Builder(action = mylibaction,
240                                        emitter = '$LIBEMITTER',
241                                        prefix = '$LIBPREFIX',
242                                        suffix = '$LIBSUFFIX',
243                                        src_suffix = '$OBJSUFFIX',
244                                        src_builder = 'StaticObject')
245
246     program = SCons.Builder.Builder(action = mylinkaction,
247                                     emitter = '$PROGEMITTER',
248                                     prefix = '$PROGPREFIX',
249                                     suffix = '$PROGSUFFIX',
250                                     src_suffix = '$OBJSUFFIX',
251                                     src_builder = 'Object',
252                                     target_scanner = SCons.Defaults.ProgScan)
253
254     env['BUILDERS']['Object'] = static_ob
255     env['BUILDERS']['StaticObject'] = static_ob
256     env['BUILDERS']['StaticLibrary'] = static_lib
257     env['BUILDERS']['Library'] = static_lib
258     env['BUILDERS']['Program'] = program
259
260 def  my_appit_print(target, source, env):
261     a = '%s' % (target[0])
262     d, f = os.path.split(a)
263     return "making bundle for " + f
264
265 def AppIt(target=None, source=None, env=None):
266     import shutil
267     import commands
268     import os.path
269     
270     a = '%s' % (target[0])
271     builddir, b = os.path.split(a)
272     bldroot = env.Dir('.').abspath
273     binary = env['BINARYKIND']
274     
275     sourcedir = bldroot + '/source/darwin/%s.app'%binary
276     sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
277     targetinfo = builddir +'/' + "%s.app/Contents/Info.plist"%binary
278     cmd = builddir + '/' +'%s.app'%binary
279     
280     if os.path.isdir(cmd):
281         shutil.rmtree(cmd)
282     shutil.copytree(sourcedir, cmd)
283     cmd = "cat %s | sed s/VERSION/`cat release/VERSION`/ | sed s/DATE/`date +'%%Y-%%b-%%d'`/ > %s"%(sourceinfo,targetinfo)
284     commands.getoutput(cmd)
285     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,builddir, binary, binary)
286     commands.getoutput(cmd)
287     cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/'%(builddir, binary)
288     print cmd
289     commands.getoutput(cmd)
290     cmd = builddir + '/%s.app/Contents/MacOS/.blender'%binary
291     shutil.copy(bldroot + '/bin/.blender/.bfont.ttf', cmd)
292     shutil.copy(bldroot + '/bin/.blender/.Blanguages', cmd)
293     cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
294     commands.getoutput(cmd) 
295     cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
296     commands.getoutput(cmd) 
297     cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
298     commands.getoutput(cmd)
299     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(builddir,binary, binary)
300     commands.getoutput(cmd)
301     cmd = 'find %s/%s.app -name CVS -prune -exec rm -rf {} \;'%(builddir, binary)
302     commands.getoutput(cmd)
303     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(builddir, binary)
304     commands.getoutput(cmd)
305
306 #### END ACTION STUFF #########
307
308 class BlenderEnvironment(SConsEnvironment):
309
310
311     def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None):
312         if not self or not libname or not sources:
313             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
314             Exit()
315         if libname in quickie or len(quickie)==0:
316             print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
317             lenv = self.Copy()
318             lenv.Append(CPPPATH=includes)
319             lenv.Append(CPPDEFINES=defines)
320             if lenv['WITH_BF_GAMEENGINE']:
321                     lenv.Append(CPPDEFINES=['GAMEBLENDER=1'])
322             if lenv['BF_DEBUG']:
323                     lenv.Append(CFLAGS = lenv['BF_DEBUG_FLAGS'], CCFLAGS = lenv['BF_DEBUG_FLAGS'])
324             else:
325                     lenv.Append(CFLAGS = lenv['REL_CFLAGS'], CCFLAGS = lenv['REL_CCFLAGS'])
326             if lenv['BF_PROFILE']:
327                     lenv.Append(CFLAGS = lenv['BF_PROFILE_FLAGS'], CCFLAGS = lenv['BF_PROFILE_FLAGS'])
328             if compileflags:
329                 lenv.Append(CFLAGS = compileflags)
330                 lenv.Append(CCFLAGS = compileflags)
331             lenv.Append(CFLAGS = Split(lenv['C_WARN']))
332             lenv.Append(CCFLAGS = Split(lenv['CC_WARN']))
333             lib = lenv.Library(target= '#'+root_build_dir+'lib/'+libname, source=sources)
334             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
335         else:
336             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
337         # note: libs is a global
338         add_lib_to_dict(libs, libtype, libname, priority)
339
340     def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''):
341         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
342         lenv = self.Copy()
343         if lenv['OURPLATFORM'] in ['win32-vc', 'cygwin']:
344             lenv.Append(LINKFLAGS = Split(lenv['PLATFORM_LINKFLAGS']))
345         if  lenv['OURPLATFORM']=='darwin':
346             lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
347             lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
348             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
349         lenv.Append(CPPPATH=includes)
350         lenv.Append(LIBPATH=libpath)
351         lenv.Append(LIBS=libs)
352         if lenv['WITH_BF_QUICKTIME']:
353              lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
354              lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
355         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
356         SConsEnvironment.Default(self, prog)
357         program_list.append(prog)
358         if  lenv['OURPLATFORM']=='darwin':
359             lenv['BINARYKIND'] = binarykind
360             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
361
362     def Glob(lenv, pattern):
363         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
364         files = []
365         for i in glob.glob(path + pattern):
366             files.append(string.replace(i, path, ''))
367         return files