Make "scons clean" remove config files for ffmpeg, x264, xvidcore. Also
[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 = B.arguments.get('BF_CONFIG', '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 # first read platform config. B.arguments will override
161 optfiles = [configfile]
162 if os.path.exists('user-config.py'):
163     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py'
164     optfiles += ['user-config.py']
165 else:
166     print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC
167
168 opts = btools.read_opts(optfiles, B.arguments)
169 opts.Update(env)
170
171 if not env['BF_FANCY']:
172     B.bc.disable()
173
174 # disable elbeem (fluidsim) compilation?
175 if env['BF_NO_ELBEEM'] == 1:
176     env['CPPFLAGS'].append('-DDISABLE_ELBEEM')
177     env['CXXFLAGS'].append('-DDISABLE_ELBEEM')
178     env['CCFLAGS'].append('-DDISABLE_ELBEEM')
179
180 if env['WITH_BF_OPENMP'] == 1:
181         if env['OURPLATFORM']=='win32-vc':
182                 env['CCFLAGS'].append('/openmp')
183                 env['CPPFLAGS'].append('/openmp')
184                 env['CXXFLAGS'].append('/openmp')
185         else:
186             if env['CC'] == 'icc':
187                 env.Append(LINKFLAGS=['-openmp', '-static-intel'])
188                 env['CCFLAGS'].append('-openmp')
189                 env['CPPFLAGS'].append('-openmp')
190                 env['CXXFLAGS'].append('-openmp')
191             else:
192                 env['CCFLAGS'].append('-fopenmp')
193                 env['CPPFLAGS'].append('-fopenmp')
194                 env['CXXFLAGS'].append('-fopenmp')
195
196 #check for additional debug libnames
197
198 if env.has_key('BF_DEBUG_LIBS'):
199     B.quickdebug += env['BF_DEBUG_LIBS']
200
201 printdebug = B.arguments.get('BF_LISTDEBUG', 0)
202
203 # see if this linux distro has libalut
204
205 if env['OURPLATFORM'] == 'linux2' :
206     if env['WITH_BF_OPENAL']:
207         mylib_test_source_file = """
208         #include "AL/alut.h"
209         int main(int argc, char **argv)
210         {
211             alutGetMajorVersion();
212             return 0;
213         }
214         """
215
216         def CheckFreeAlut(context,env):
217             context.Message( B.bc.OKGREEN + "Linux platform detected:\n  checking for FreeAlut... " + B.bc.ENDC )
218             env['LIBS'] = 'alut'
219             result = context.TryLink(mylib_test_source_file, '.c')
220             context.Result(result)
221             return result
222
223         env2 = env.Copy( LIBPATH = env['BF_OPENAL'] ) 
224         sconf_temp = mkdtemp()
225         conf = Configure( env2, {'CheckFreeAlut' : CheckFreeAlut}, sconf_temp, '/dev/null' )
226         if conf.CheckFreeAlut( env2 ):
227             env['BF_OPENAL_LIB'] += ' alut'
228         del env2
229         root = ''
230         for root, dirs, files in os.walk(sconf_temp, topdown=False):
231             for name in files:
232                 os.remove(os.path.join(root, name))
233             for name in dirs:
234                 os.rmdir(os.path.join(root, name))
235         if root: os.rmdir(root)
236
237 if len(B.quickdebug) > 0 and printdebug != 0:
238     print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC
239     for l in B.quickdebug:
240         print "\t" + l
241
242 # check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline
243 if 'blenderplayer' in B.targets:
244     env['WITH_BF_PLAYER'] = True
245
246 if 'blendernogame' in B.targets:
247     env['WITH_BF_GAMEENGINE'] = False
248
249 # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
250 #B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep)
251 B.root_build_dir = env['BF_BUILDDIR']
252 env['BUILDDIR'] = B.root_build_dir
253 if not B.root_build_dir[-1]==os.sep:
254     B.root_build_dir += os.sep
255     
256 # We do a shortcut for clean when no quicklist is given: just delete
257 # builddir without reading in SConscripts
258 do_clean = None
259 if 'clean' in B.targets:
260     do_clean = True
261
262 if not quickie and do_clean:
263     if os.path.exists(B.root_build_dir):
264         print B.bc.HEADER+'Cleaning...'+B.bc.ENDC
265         dirs = os.listdir(B.root_build_dir)
266         for dir in dirs:
267             if os.path.isdir(B.root_build_dir + dir) == 1:
268                 print "clean dir %s"%(B.root_build_dir+dir)
269                 shutil.rmtree(B.root_build_dir+dir)
270         for confile in ['extern/ffmpeg/config.mak', 'extern/x264/config.mak',
271                 'extern/xvidcore/build/generic/platform.inc']:
272             if os.path.exists(confile):
273                 print "clean file %s"%confile
274                 os.remove(confile)
275         print B.bc.OKGREEN+'...done'+B.bc.ENDC
276     else:
277         print B.bc.HEADER+'Already Clean, nothing to do.'+B.bc.ENDC
278     Exit()
279
280 if not os.path.isdir ( B.root_build_dir):
281     os.makedirs ( B.root_build_dir )
282     os.makedirs ( B.root_build_dir + 'source' )
283     os.makedirs ( B.root_build_dir + 'intern' )
284     os.makedirs ( B.root_build_dir + 'extern' )
285     os.makedirs ( B.root_build_dir + 'lib' )
286     os.makedirs ( B.root_build_dir + 'bin' )
287
288 Help(opts.GenerateHelpText(env))
289
290 # default is new quieter output, but if you need to see the 
291 # commands, do 'scons BF_QUIET=0'
292 bf_quietoutput = B.arguments.get('BF_QUIET', '1')
293 if env['BF_QUIET']:
294     B.set_quiet_output(env)
295 else:
296     if toolset=='msvc':
297         B.msvc_hack(env)
298
299 print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir
300 env.SConsignFile(B.root_build_dir+'scons-signatures')
301 B.init_lib_dict()
302
303 ##### END SETUP ##########
304
305 Export('env')
306
307 BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
308 SConscript(B.root_build_dir+'/intern/SConscript')
309 BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
310 SConscript(B.root_build_dir+'/extern/SConscript')
311 BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
312 SConscript(B.root_build_dir+'/source/SConscript')
313
314 # now that we have read all SConscripts, we know what
315 # libraries will be built. Create list of
316 # libraries to give as objects to linking phase
317 mainlist = []
318 for tp in B.possible_types:
319     if not tp == 'player' and not tp == 'player2':
320         mainlist += B.create_blender_liblist(env, tp)
321
322 if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
323     B.propose_priorities()
324
325 dobj = B.buildinfo(env, "dynamic") + B.resources
326 thestatlibs, thelibincs = B.setup_staticlibs(env)
327 thesyslibs = B.setup_syslibs(env)
328
329 env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
330 if env['WITH_BF_PLAYER']:
331     playerlist = B.create_blender_liblist(env, 'player')
332     env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
333
334 ##### Now define some targets
335
336
337 #------------ INSTALL
338
339 #-- binaries
340 blenderinstall = []
341 if  env['OURPLATFORM']=='darwin':
342     for prg in B.program_list:
343         bundle = '%s.app' % prg[0]
344         bundledir = os.path.dirname(bundle)
345         for dp, dn, df in os.walk(bundle):
346             if 'CVS' in dn:
347                 dn.remove('CVS')
348             if '.svn' in dn:
349                 dn.remove('.svn')
350             dir=env['BF_INSTALLDIR']+dp[len(bundledir):]
351             source=[dp+os.sep+f for f in df]
352             blenderinstall.append(env.Install(dir=dir,source=source))
353 else:
354     blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list)
355
356 #-- .blender
357 #- dont do .blender and scripts for darwin, it is already in the bundle
358 dotblendlist = []
359 dottargetlist = []
360 scriptinstall = []
361
362 if  env['OURPLATFORM']!='darwin':
363         for dp, dn, df in os.walk('bin/.blender'):
364             if 'CVS' in dn:
365                 dn.remove('CVS')
366             if '.svn' in dn:
367                 dn.remove('.svn')
368             for f in df:
369                 dotblendlist.append(dp+os.sep+f)
370                 dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f)
371
372         dotblenderinstall = []
373         for targetdir,srcfile in zip(dottargetlist, dotblendlist):
374             td, tf = os.path.split(targetdir)
375             dotblenderinstall.append(env.Install(dir=td, source=srcfile))
376         
377         #-- .blender/scripts    
378         scriptpath='release/scripts'
379         for dp, dn, df in os.walk(scriptpath):
380             if 'CVS' in dn:
381                 dn.remove('CVS')
382             if '.svn' in dn:
383                 dn.remove('.svn')
384             dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):]
385             source=[dp+os.sep+f for f in df]
386             scriptinstall.append(env.Install(dir=dir,source=source))
387
388 #-- plugins
389 pluglist = []
390 plugtargetlist = []
391 for tp, tn, tf in os.walk('release/plugins'):
392     if 'CVS' in tn:
393         tn.remove('CVS')
394     if '.svn' in tn:
395         tn.remove('.svn')
396     for f in tf:
397         pluglist.append(tp+os.sep+f)
398         plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f)
399
400 plugininstall = []
401 for targetdir,srcfile in zip(plugtargetlist, pluglist):
402     td, tf = os.path.split(targetdir)
403     plugininstall.append(env.Install(dir=td, source=srcfile))
404
405 textlist = []
406 texttargetlist = []
407 for tp, tn, tf in os.walk('release/text'):
408     if 'CVS' in tn:
409         tn.remove('CVS')
410     if '.svn' in tn:
411         tn.remove('.svn')
412     for f in tf:
413         textlist.append(tp+os.sep+f)
414
415 textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
416
417 if  env['OURPLATFORM']=='darwin':
418         allinstall = [blenderinstall, plugininstall, textinstall]
419 else:
420         allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall]
421
422 if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
423     dllsources = ['${LCGDIR}/gettext/lib/gnu_gettext.dll',
424                         '${LCGDIR}/png/lib/libpng.dll',
425                         '#release/windows/extra/python25.zip',
426                         '#release/windows/extra/zlib.pyd',
427                         '${LCGDIR}/sdl/lib/SDL.dll',
428                         '${LCGDIR}/zlib/lib/zlib.dll',
429                         '${LCGDIR}/tiff/lib/libtiff.dll']
430     if env['BF_DEBUG']:
431         dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}_d.dll')
432     else:
433         dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}.dll')
434     if env['OURPLATFORM'] == 'win32-mingw':
435         dllsources += ['${LCGDIR}/pthreads/lib/pthreadGC2.dll']
436     else:
437         dllsources += ['${LCGDIR}/pthreads/lib/pthreadVC2.dll']
438     if env['WITH_BF_ICONV']:
439         dllsources += ['${LCGDIR}/iconv/lib/iconv.dll']
440     if env['WITH_BF_FFMPEG']:
441         dllsources += ['${LCGDIR}/ffmpeg/lib/avcodec-51.dll',
442                         '${LCGDIR}/ffmpeg/lib/avformat-52.dll',
443                         '${LCGDIR}/ffmpeg/lib/avdevice-52.dll',
444                         '${LCGDIR}/ffmpeg/lib/avutil-49.dll',
445                         '${LCGDIR}/ffmpeg/lib/libfaad-0.dll',
446                         '${LCGDIR}/ffmpeg/lib/libfaac-0.dll',
447                         '${LCGDIR}/ffmpeg/lib/libmp3lame-0.dll',
448                         '${LCGDIR}/ffmpeg/lib/libx264-59.dll',
449                         '${LCGDIR}/ffmpeg/lib/xvidcore.dll',
450                         '${LCGDIR}/ffmpeg/lib/swscale-0.dll']
451     windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
452     allinstall += windlls
453
454 installtarget = env.Alias('install', allinstall)
455 bininstalltarget = env.Alias('install-bin', blenderinstall)
456
457 nsisaction = env.Action(btools.NSIS_Installer, btools.NSIS_print)
458 nsiscmd = env.Command('nsisinstaller', None, nsisaction)
459 nsisalias = env.Alias('nsis', nsiscmd)
460
461 if env['WITH_BF_PLAYER']:
462     blenderplayer = env.Alias('blenderplayer', B.program_list)
463     Depends(blenderplayer,installtarget)
464
465 if not env['WITH_BF_GAMEENGINE']:
466     blendernogame = env.Alias('blendernogame', B.program_list)
467     Depends(blendernogame,installtarget)
468
469 Depends(nsiscmd, allinstall)
470
471 Default(B.program_list)
472
473 if not env['WITHOUT_BF_INSTALL']:
474         Default(installtarget)
475
476 #------------ RELEASE
477 # TODO: zipup the installation
478
479 #------------ BLENDERPLAYER
480 # TODO: build stubs and link into blenderplayer
481
482 #------------ EPYDOC
483 # TODO: run epydoc
484