Added WITH_BF_NOBLENDER to scons so that blenderplayer can be compiler by itself...
[blender.git] / SConstruct
1 #!/usr/bin/env python
2 # $Id$
3 # ***** BEGIN GPL LICENSE BLOCK *****
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 #
19 # The Original Code is Copyright (C) 2006, Blender Foundation
20 # All rights reserved.
21 #
22 # The Original Code is: all of this file.
23 #
24 # Contributor(s): Nathan Letwory.
25 #
26 # ***** END GPL LICENSE BLOCK *****
27 #
28 # Main entry-point for the SCons building system
29 # Set up some custom actions and target/argument handling
30 # Then read all SConscripts and build
31
32 import sys
33 import os
34 import os.path
35 import string
36 import shutil
37 import glob
38 import re
39 from tempfile import mkdtemp
40
41 import tools.Blender
42 import tools.btools
43 import tools.bcolors
44
45 BlenderEnvironment = tools.Blender.BlenderEnvironment
46 btools = tools.btools
47 B = tools.Blender
48
49 ### globals ###
50 platform = sys.platform
51 quickie = None
52 quickdebug = None
53 nsis_build = None
54
55 ##### BEGIN SETUP #####
56
57 B.possible_types = ['core', 'common', 'blender', 'intern',
58                     'international', 'game', 'game2',
59                     'player', 'player2', 'system']
60
61 B.binarykind = ['blender' , 'blenderplayer']
62 ##################################
63 # target and argument validation #
64 ##################################
65 # XX cheating for BF_FANCY, we check for BF_FANCY before args are validated
66 use_color = ARGUMENTS.get('BF_FANCY', '1')
67 if platform=='win32':
68     use_color = None
69
70 if not use_color=='1':
71     B.bc.disable()
72     
73  #on defaut white Os X terminal, some colors are totally unlegible
74 if platform=='darwin':
75     B.bc.OKGREEN = '\033[34m'
76     B.bc.WARNING = '\033[36m'
77
78 # arguments
79 print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC
80 B.arguments = btools.validate_arguments(ARGUMENTS, B.bc)
81 btools.print_arguments(B.arguments, B.bc)
82
83 # targets
84 print B.bc.HEADER+'Command-line targets'+B.bc.ENDC
85 B.targets = btools.validate_targets(COMMAND_LINE_TARGETS, B.bc)
86 btools.print_targets(B.targets, B.bc)
87
88 ##########################
89 # setting up environment #
90 ##########################
91
92 # handling cmd line arguments & config file
93
94 # first check cmdline for toolset and we create env to work on
95 quickie = B.arguments.get('BF_QUICK', None)
96 quickdebug = B.arguments.get('BF_QUICKDEBUG', None)
97
98 if quickdebug:
99     B.quickdebug=string.split(quickdebug, ',')
100 else:
101     B.quickdebug=[]
102
103 if quickie:
104     B.quickie=string.split(quickie,',')
105 else:
106     B.quickie=[]
107     
108 toolset = B.arguments.get('BF_TOOLSET', None)
109 if toolset:
110     print "Using " + toolset
111     if toolset=='mstoolkit':
112         env = BlenderEnvironment(ENV = os.environ)
113         env.Tool('mstoolkit', ['tools'])
114     else:
115         env = BlenderEnvironment(tools=[toolset], ENV = os.environ)
116         if env:
117             btools.SetupSpawn(env)
118 else:
119     env = BlenderEnvironment(ENV = os.environ)
120
121 if not env:
122     print "Could not create a build environment"
123     Exit()
124
125
126 cc = B.arguments.get('CC', None)
127 cxx = B.arguments.get('CXX', None)
128 if cc:
129     env['CC'] = cc
130 if cxx:
131     env['CXX'] = cxx
132
133 if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32':
134     platform = 'win32-vc'
135 elif env['CC'] in ['gcc'] and sys.platform=='win32':
136     platform = 'win32-mingw'
137
138 env.SConscriptChdir(0)
139
140 crossbuild = B.arguments.get('BF_CROSS', None)
141 if crossbuild and platform!='win32':
142     platform = 'linuxcross'
143
144 env['OURPLATFORM'] = platform
145
146 configfile = 'config'+os.sep+platform+'-config.py'
147
148 if os.path.exists(configfile):
149     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile
150 else:
151     print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC
152
153 if crossbuild and env['PLATFORM'] != 'win32':
154     print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC
155     env.Tool('crossmingw', ['tools'])
156     # todo: determine proper libs/includes etc.
157     # Needed for gui programs, console programs should do without it
158     env.Append(LINKFLAGS=['-mwindows'])
159
160 userconfig = B.arguments.get('BF_CONFIG', 'user-config.py')
161 # first read platform config. B.arguments will override
162 optfiles = [configfile]
163 if os.path.exists(userconfig):
164     print B.bc.OKGREEN + "Using user-config file: " + B.bc.ENDC + userconfig
165     optfiles += [userconfig]
166 else:
167     print B.bc.WARNING + userconfig + " not found, no user overrides" + B.bc.ENDC
168
169 opts = btools.read_opts(optfiles, B.arguments)
170 opts.Update(env)
171
172 if not env['BF_FANCY']:
173     B.bc.disable()
174
175 # disable elbeem (fluidsim) compilation?
176 if env['BF_NO_ELBEEM'] == 1:
177     env['CPPFLAGS'].append('-DDISABLE_ELBEEM')
178     env['CXXFLAGS'].append('-DDISABLE_ELBEEM')
179     env['CCFLAGS'].append('-DDISABLE_ELBEEM')
180
181 if env['WITH_BF_OPENMP'] == 1:
182         if env['OURPLATFORM']=='win32-vc':
183                 env['CCFLAGS'].append('/openmp')
184                 env['CPPFLAGS'].append('/openmp')
185                 env['CXXFLAGS'].append('/openmp')
186         else:
187             if env['CC'][-3:] == 'icc': # to be able to handle CC=/opt/bla/icc case
188                 env.Append(LINKFLAGS=['-openmp', '-static-intel'])
189                 env['CCFLAGS'].append('-openmp')
190                 env['CPPFLAGS'].append('-openmp')
191                 env['CXXFLAGS'].append('-openmp')
192             else:
193                 env.Append(CCFLAGS=['-fopenmp']) 
194                 env.Append(CPPFLAGS=['-fopenmp'])
195                 env.Append(CXXFLAGS=['-fopenmp'])
196                 # env.Append(LINKFLAGS=['-fprofile-generate'])
197
198 #check for additional debug libnames
199
200 if env.has_key('BF_DEBUG_LIBS'):
201     B.quickdebug += env['BF_DEBUG_LIBS']
202
203 printdebug = B.arguments.get('BF_LISTDEBUG', 0)
204
205 # see if this linux distro has libalut
206
207 if env['OURPLATFORM'] == 'linux2' :
208     if env['WITH_BF_OPENAL']:
209         mylib_test_source_file = """
210         #include "AL/alut.h"
211         int main(int argc, char **argv)
212         {
213             alutGetMajorVersion();
214             return 0;
215         }
216         """
217
218         def CheckFreeAlut(context,env):
219             context.Message( B.bc.OKGREEN + "Linux platform detected:\n  checking for FreeAlut... " + B.bc.ENDC )
220             env['LIBS'] = 'alut'
221             result = context.TryLink(mylib_test_source_file, '.c')
222             context.Result(result)
223             return result
224
225         env2 = env.Copy( LIBPATH = env['BF_OPENAL'] ) 
226         sconf_temp = mkdtemp()
227         conf = Configure( env2, {'CheckFreeAlut' : CheckFreeAlut}, sconf_temp, '/dev/null' )
228         if conf.CheckFreeAlut( env2 ):
229             env['BF_OPENAL_LIB'] += ' alut'
230         del env2
231         root = ''
232         for root, dirs, files in os.walk(sconf_temp, topdown=False):
233             for name in files:
234                 os.remove(os.path.join(root, name))
235             for name in dirs:
236                 os.rmdir(os.path.join(root, name))
237         if root: os.rmdir(root)
238
239 if len(B.quickdebug) > 0 and printdebug != 0:
240     print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC
241     for l in B.quickdebug:
242         print "\t" + l
243
244 # remove stdc++ from LLIBS if we are building a statc linked CXXFLAGS
245 if env['WITH_BF_STATICCXX']:
246     if 'stdc++' in env['LLIBS']:
247         env['LLIBS'] = env['LLIBS'].replace('stdc++', ' ')
248     else:
249         print '\tcould not remove stdc++ library from LLIBS, WITH_BF_STATICCXX may not work for your platform'
250
251 # check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline
252 if 'blenderplayer' in B.targets:
253     env['WITH_BF_PLAYER'] = True
254
255 if 'blendernogame' in B.targets:
256     env['WITH_BF_GAMEENGINE'] = False
257
258 if 'blenderlite' in B.targets:
259     env['WITH_BF_GAMEENGINE'] = False
260     env['WITH_BF_OPENAL'] = False
261     env['WITH_BF_OPENEXR'] = False
262     env['WITH_BF_ICONV'] = False
263     env['WITH_BF_INTERNATIONAL'] = False
264     env['WITH_BF_OPENJPEG'] = False
265     env['WITH_BF_FFMPEG'] = False
266     env['WITH_BF_QUICKTIME'] = False
267     env['WITH_BF_YAFRAY'] = False
268     env['WITH_BF_REDCODE'] = False
269     env['WITH_BF_FTGL'] = False
270     env['WITH_BF_DDS'] = False
271     env['WITH_BF_ZLIB'] = False
272     env['WITH_BF_SDL'] = False
273     env['WITH_BF_JPEG'] = False
274     env['WITH_BF_PNG'] = False
275     env['WITH_BF_ODE'] = False
276     env['WITH_BF_BULLET'] = False
277     env['WITH_BF_BINRELOC'] = False
278     env['BF_BUILDINFO'] = False
279     env['BF_NO_ELBEEM'] = True
280     
281
282
283 # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
284 #B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep)
285 B.root_build_dir = env['BF_BUILDDIR']
286 env['BUILDDIR'] = B.root_build_dir
287 if not B.root_build_dir[-1]==os.sep:
288     B.root_build_dir += os.sep
289     
290 # We do a shortcut for clean when no quicklist is given: just delete
291 # builddir without reading in SConscripts
292 do_clean = None
293 if 'clean' in B.targets:
294     do_clean = True
295
296 if not quickie and do_clean:
297     if os.path.exists(B.root_build_dir):
298         print B.bc.HEADER+'Cleaning...'+B.bc.ENDC
299         dirs = os.listdir(B.root_build_dir)
300         for entry in dirs:
301             if os.path.isdir(B.root_build_dir + entry) == 1:
302                 print "clean dir %s"%(B.root_build_dir+entry)
303                 shutil.rmtree(B.root_build_dir+entry)
304             else: # remove file
305                 print "remove file %s"%(B.root_build_dir+entry)
306                 os.remove(B.root_build_dir+entry)
307         for confile in ['extern/ffmpeg/config.mak', 'extern/x264/config.mak',
308                 'extern/xvidcore/build/generic/platform.inc']:
309             if os.path.exists(confile):
310                 print "clean file %s"%confile
311                 os.remove(confile)
312         print B.bc.OKGREEN+'...done'+B.bc.ENDC
313     else:
314         print B.bc.HEADER+'Already Clean, nothing to do.'+B.bc.ENDC
315     Exit()
316
317 if not os.path.isdir ( B.root_build_dir):
318     os.makedirs ( B.root_build_dir )
319     os.makedirs ( B.root_build_dir + 'source' )
320     os.makedirs ( B.root_build_dir + 'intern' )
321     os.makedirs ( B.root_build_dir + 'extern' )
322     os.makedirs ( B.root_build_dir + 'lib' )
323     os.makedirs ( B.root_build_dir + 'bin' )
324
325 Help(opts.GenerateHelpText(env))
326
327 # default is new quieter output, but if you need to see the 
328 # commands, do 'scons BF_QUIET=0'
329 bf_quietoutput = B.arguments.get('BF_QUIET', '1')
330 if env['BF_QUIET']:
331     B.set_quiet_output(env)
332 else:
333     if toolset=='msvc':
334         B.msvc_hack(env)
335
336 print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir
337 env.SConsignFile(B.root_build_dir+'scons-signatures')
338 B.init_lib_dict()
339
340 ##### END SETUP ##########
341
342 Export('env')
343
344 BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
345 SConscript(B.root_build_dir+'/intern/SConscript')
346 BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
347 SConscript(B.root_build_dir+'/extern/SConscript')
348 BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
349 SConscript(B.root_build_dir+'/source/SConscript')
350
351 # now that we have read all SConscripts, we know what
352 # libraries will be built. Create list of
353 # libraries to give as objects to linking phase
354 mainlist = []
355 for tp in B.possible_types:
356     if not tp == 'player' and not tp == 'player2':
357         mainlist += B.create_blender_liblist(env, tp)
358
359 if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
360     B.propose_priorities()
361
362 dobj = B.buildinfo(env, "dynamic") + B.resources
363 thestatlibs, thelibincs = B.setup_staticlibs(env)
364 thesyslibs = B.setup_syslibs(env)
365
366 if 'blender' in B.targets or not env['WITH_BF_NOBLENDER']:
367     env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
368 if env['WITH_BF_PLAYER']:
369     playerlist = B.create_blender_liblist(env, 'player')
370     env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
371
372 ##### Now define some targets
373
374
375 #------------ INSTALL
376
377 #-- binaries
378 blenderinstall = []
379 if  env['OURPLATFORM']=='darwin':
380     for prg in B.program_list:
381         bundle = '%s.app' % prg[0]
382         bundledir = os.path.dirname(bundle)
383         for dp, dn, df in os.walk(bundle):
384             if 'CVS' in dn:
385                 dn.remove('CVS')
386             if '.svn' in dn:
387                 dn.remove('.svn')
388             dir=env['BF_INSTALLDIR']+dp[len(bundledir):]
389             source=[dp+os.sep+f for f in df]
390             blenderinstall.append(env.Install(dir=dir,source=source))
391 else:
392     blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list)
393
394 #-- .blender
395 #- dont do .blender and scripts for darwin, it is already in the bundle
396 dotblendlist = []
397 dottargetlist = []
398 scriptinstall = []
399
400 if  env['OURPLATFORM']!='darwin':
401         for dp, dn, df in os.walk('bin/.blender'):
402             if 'CVS' in dn:
403                 dn.remove('CVS')
404             if '.svn' in dn:
405                 dn.remove('.svn')
406             for f in df:
407                 dotblendlist.append(dp+os.sep+f)
408                 dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f)
409
410         dotblenderinstall = []
411         for targetdir,srcfile in zip(dottargetlist, dotblendlist):
412             td, tf = os.path.split(targetdir)
413             dotblenderinstall.append(env.Install(dir=td, source=srcfile))
414         
415         #-- .blender/scripts    
416         scriptpath='release/scripts'
417         for dp, dn, df in os.walk(scriptpath):
418             if 'CVS' in dn:
419                 dn.remove('CVS')
420             if '.svn' in dn:
421                 dn.remove('.svn')
422             dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):]
423             source=[dp+os.sep+f for f in df]
424             scriptinstall.append(env.Install(dir=dir,source=source))
425
426 #-- icons
427 if env['OURPLATFORM']=='linux2':
428         iconlist = []
429         icontargetlist = []
430
431         for tp, tn, tf in os.walk('release/freedesktop/icons'):
432                 if 'CVS' in tn:
433                         tn.remove('CVS')
434                 if '.svn' in tn:
435                         tn.remove('.svn')
436                 for f in tf:
437                         print ">>>", env['BF_INSTALLDIR'], tp, f
438                         iconlist.append(tp+os.sep+f)
439                         icontargetlist.append(env['BF_INSTALLDIR']+tp[19:]+os.sep+f)
440
441         iconinstall = []
442         for targetdir,srcfile in zip(icontargetlist, iconlist):
443                 td, tf = os.path.split(targetdir)
444                 iconinstall.append(env.Install(dir=td, source=srcfile))
445
446 #-- plugins
447 pluglist = []
448 plugtargetlist = []
449 for tp, tn, tf in os.walk('release/plugins'):
450     if 'CVS' in tn:
451         tn.remove('CVS')
452     if '.svn' in tn:
453         tn.remove('.svn')
454     for f in tf:
455         print ">>>", env['BF_INSTALLDIR'], tp, f
456         pluglist.append(tp+os.sep+f)
457         plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f)
458
459 # header files for plugins
460 pluglist.append('source/blender/blenpluginapi/documentation.h')
461 plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'documentation.h')
462 pluglist.append('source/blender/blenpluginapi/externdef.h')
463 plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'externdef.h')
464 pluglist.append('source/blender/blenpluginapi/floatpatch.h')
465 plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'floatpatch.h')
466 pluglist.append('source/blender/blenpluginapi/iff.h')
467 plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'iff.h')
468 pluglist.append('source/blender/blenpluginapi/plugin.h')
469 plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'plugin.h')
470 pluglist.append('source/blender/blenpluginapi/util.h')
471 plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'util.h')
472 pluglist.append('source/blender/blenpluginapi/plugin.DEF')
473 plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep + 'plugin.def')
474
475 plugininstall = []
476 for targetdir,srcfile in zip(plugtargetlist, pluglist):
477     td, tf = os.path.split(targetdir)
478     plugininstall.append(env.Install(dir=td, source=srcfile))
479
480 textlist = []
481 texttargetlist = []
482 for tp, tn, tf in os.walk('release/text'):
483     if 'CVS' in tn:
484         tn.remove('CVS')
485     if '.svn' in tn:
486         tn.remove('.svn')
487     for f in tf:
488         textlist.append(tp+os.sep+f)
489
490 textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
491
492 if  env['OURPLATFORM']=='darwin':
493         allinstall = [blenderinstall, plugininstall, textinstall]
494 elif env['OURPLATFORM']=='linux2':
495         allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall, iconinstall]
496 else:
497         allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall]
498
499 if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
500     dllsources = ['${LCGDIR}/gettext/lib/gnu_gettext.dll',
501                         '${LCGDIR}/png/lib/libpng.dll',
502                         '#release/windows/extra/python25.zip',
503                         '#release/windows/extra/zlib.pyd',
504                         '${LCGDIR}/sdl/lib/SDL.dll',
505                         '${LCGDIR}/zlib/lib/zlib.dll',
506                         '${LCGDIR}/tiff/lib/libtiff.dll']
507     if env['BF_DEBUG']:
508         dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}_d.dll')
509     else:
510         dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}.dll')
511     if env['OURPLATFORM'] == 'win32-mingw':
512         dllsources += ['${LCGDIR}/pthreads/lib/pthreadGC2.dll']
513     else:
514         dllsources += ['${LCGDIR}/pthreads/lib/pthreadVC2.dll']
515     if env['WITH_BF_ICONV']:
516         dllsources += ['${LCGDIR}/iconv/lib/iconv.dll']
517     if env['WITH_BF_FFMPEG']:
518         dllsources += ['${LCGDIR}/ffmpeg/lib/avcodec-51.dll',
519                         '${LCGDIR}/ffmpeg/lib/avformat-52.dll',
520                         '${LCGDIR}/ffmpeg/lib/avdevice-52.dll',
521                         '${LCGDIR}/ffmpeg/lib/avutil-49.dll',
522                         '${LCGDIR}/ffmpeg/lib/libfaad-0.dll',
523                         '${LCGDIR}/ffmpeg/lib/libfaac-0.dll',
524                         '${LCGDIR}/ffmpeg/lib/libmp3lame-0.dll',
525                         '${LCGDIR}/ffmpeg/lib/libx264-59.dll',
526                         '${LCGDIR}/ffmpeg/lib/xvidcore.dll',
527                         '${LCGDIR}/ffmpeg/lib/swscale-0.dll']
528     windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
529     allinstall += windlls
530
531 installtarget = env.Alias('install', allinstall)
532 bininstalltarget = env.Alias('install-bin', blenderinstall)
533
534 nsisaction = env.Action(btools.NSIS_Installer, btools.NSIS_print)
535 nsiscmd = env.Command('nsisinstaller', None, nsisaction)
536 nsisalias = env.Alias('nsis', nsiscmd)
537
538 if 'blender' in B.targets:
539         blenderexe= env.Alias('blender', B.program_list)
540         Depends(blenderexe,installtarget)
541
542 if env['WITH_BF_PLAYER']:
543     blenderplayer = env.Alias('blenderplayer', B.program_list)
544     Depends(blenderplayer,installtarget)
545
546 if not env['WITH_BF_GAMEENGINE']:
547     blendernogame = env.Alias('blendernogame', B.program_list)
548     Depends(blendernogame,installtarget)
549
550 if 'blenderlite' in B.targets:
551         blenderlite = env.Alias('blenderlite', B.program_list)
552         Depends(blenderlite,installtarget)
553
554 Depends(nsiscmd, allinstall)
555
556 Default(B.program_list)
557
558 if not env['WITHOUT_BF_INSTALL']:
559         Default(installtarget)
560
561 #------------ RELEASE
562 # TODO: zipup the installation
563
564 #------------ BLENDERPLAYER
565 # TODO: build stubs and link into blenderplayer
566
567 #------------ EPYDOC
568 # TODO: run epydoc
569