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