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