==SCons==
[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
56 ##### BEGIN SETUP #####
57
58 B.possible_types = ['core', 'common', 'blender', 'intern',
59                     'international', 'game', 'game2',
60                     'player', 'player2', 'system']
61
62 B.binarykind = ['blender' , 'blenderplayer']
63 ##################################
64 # target and argument validation #
65 ##################################
66 # XX cheating for BF_FANCY, we check for BF_FANCY before args are validated
67 use_color = ARGUMENTS.get('BF_FANCY', '1')
68 if platform=='win32':
69     use_color = None
70
71 if not use_color=='1':
72     B.bc.disable()
73
74 # arguments
75 print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC
76 B.arguments = btools.validate_arguments(ARGUMENTS, B.bc)
77 btools.print_arguments(B.arguments, B.bc)
78
79 # targets
80 print B.bc.HEADER+'Command-line targets'+B.bc.ENDC
81 B.targets = btools.validate_targets(COMMAND_LINE_TARGETS, B.bc)
82 btools.print_targets(B.targets, B.bc)
83
84 ##########################
85 # setting up environment #
86 ##########################
87
88 # handling cmd line arguments & config file
89
90 # first check cmdline for toolset and we create env to work on
91 quickie = B.arguments.get('BF_QUICK', None)
92 quickdebug = B.arguments.get('BF_QUICKDEBUG', None)
93
94 if quickdebug:
95     B.quickdebug=string.split(quickdebug, ',')
96 else:
97     B.quickdebug=[]
98
99 if quickie:
100     B.quickie=string.split(quickie,',')
101 else:
102     B.quickie=[]
103
104 toolset = B.arguments.get('BF_TOOLSET', None)
105 if toolset:
106     print "Using " + toolset
107     if toolset=='mstoolkit':
108         env = BlenderEnvironment(ENV = os.environ)
109         env.Tool('mstoolkit', ['tools'])
110     else:
111         env = BlenderEnvironment(tools=[toolset], ENV = os.environ)
112 else:
113     env = BlenderEnvironment(ENV = os.environ)
114
115 if not env:
116     print "Could not create a build environment"
117     Exit()
118
119 env.SConscriptChdir(0)
120 cc = B.arguments.get('CC', None)
121 cxx = B.arguments.get('CXX', None)
122 if cc:
123     env['CC'] = cc
124 if cxx:
125     env['CXX'] = cxx
126
127 if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32':
128     platform = 'win32-vc'
129 elif env['CC'] in ['gcc'] and sys.platform=='win32':
130     platform = 'win32-mingw'
131
132 crossbuild = B.arguments.get('BF_CROSS', None)
133 if crossbuild and platform!='win32':
134     platform = 'linuxcross'
135
136 env['OURPLATFORM'] = platform
137
138 configfile = B.arguments.get('BF_CONFIG', 'config'+os.sep+platform+'-config.py')
139
140 if os.path.exists(configfile):
141     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile
142 else:
143     print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC
144
145 if crossbuild and env['PLATFORM'] != 'win32':
146     print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC
147     env.Tool('crossmingw', ['tools'])
148     # todo: determine proper libs/includes etc.
149     # Needed for gui programs, console programs should do without it
150     env.Append(LINKFLAGS=['-mwindows'])
151
152 # first read platform config. B.arguments will override
153 optfiles = [configfile]
154 if os.path.exists('user-config.py'):
155     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py'
156     optfiles += ['user-config.py']
157 else:
158     print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC
159
160 opts = btools.read_opts(optfiles, B.arguments)
161 opts.Update(env)
162
163 # disable elbeem (fluidsim) compilation?
164 if env['BF_NO_ELBEEM'] == 1:
165     env['CPPFLAGS'].append('-DDISABLE_ELBEEM')
166     env['CXXFLAGS'].append('-DDISABLE_ELBEEM')
167     env['CCFLAGS'].append('-DDISABLE_ELBEEM')
168
169 #check for additional debug libnames
170
171 if env.has_key('BF_DEBUG_LIBS'):
172     B.quickdebug += env['BF_DEBUG_LIBS']
173
174 printdebug = B.arguments.get('BF_LISTDEBUG', 0)
175
176 # see if this linux distro has libalut
177
178 if env['OURPLATFORM'] == 'linux2' :
179     if env['WITH_BF_OPENAL']:
180         mylib_test_source_file = """
181         #include "AL/alut.h"
182         int main(int argc, char **argv)
183         {
184             alutGetMajorVersion();
185             return 0;
186         }
187         """
188
189         def CheckFreeAlut(context,env):
190             context.Message( B.bc.OKGREEN + "Linux platform detected:\n  checking for FreeAlut... " + B.bc.ENDC )
191             env['LIBS'] = 'alut'
192             result = context.TryLink(mylib_test_source_file, '.c')
193             context.Result(result)
194             return result
195
196         env2 = env.Copy( LIBPATH = env['BF_OPENAL'] ) 
197         conf = Configure( env2, {'CheckFreeAlut' : CheckFreeAlut}, '.sconf_temp', '/dev/null' )
198         if conf.CheckFreeAlut( env2 ):
199             env['BF_OPENAL_LIB'] += ' alut'
200         del env2
201         for root, dirs, files in os.walk('.sconf_temp', topdown=False):
202             for name in files:
203                 os.remove(os.path.join(root, name))
204             for name in dirs:
205                 os.rmdir(os.path.join(root, name))
206         os.rmdir(root)
207
208 if len(B.quickdebug) > 0 and printdebug != 0:
209     print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC
210     for l in B.quickdebug:
211         print "\t" + l
212
213 # check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline
214 if 'blenderplayer' in B.targets:
215     env['WITH_BF_PLAYER'] = True
216
217 if 'blendernogame' in B.targets:
218     env['WITH_BF_GAMEENGINE'] = False
219
220 # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
221 #B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep)
222 B.root_build_dir = env['BF_BUILDDIR']
223 env['BUILDDIR'] = B.root_build_dir
224 if not B.root_build_dir[-1]==os.sep:
225     B.root_build_dir += os.sep
226
227 # We do a shortcut for clean when no quicklist is given: just delete
228 # builddir without reading in SConscripts
229 do_clean = None
230 if 'clean' in B.targets:
231     do_clean = True
232
233 if not quickie and do_clean:
234     print B.bc.HEADER+'Cleaning...'+B.bc.ENDC
235     dirs = os.listdir(B.root_build_dir)
236     for dir in dirs:
237         if os.path.isdir(B.root_build_dir + dir) == 1:
238             print "clean dir %s"%(B.root_build_dir+dir)
239             shutil.rmtree(B.root_build_dir+dir)
240     print B.bc.OKGREEN+'...done'+B.bc.ENDC
241     Exit()
242
243 if not os.path.isdir ( B.root_build_dir):
244     os.makedirs ( B.root_build_dir )
245     os.makedirs ( B.root_build_dir + 'source' )
246     os.makedirs ( B.root_build_dir + 'intern' )
247     os.makedirs ( B.root_build_dir + 'extern' )
248     os.makedirs ( B.root_build_dir + 'lib' )
249     os.makedirs ( B.root_build_dir + 'bin' )
250
251 Help(opts.GenerateHelpText(env))
252
253 # default is new quieter output, but if you need to see the 
254 # commands, do 'scons BF_QUIET=0'
255 bf_quietoutput = B.arguments.get('BF_QUIET', '1')
256 if bf_quietoutput=='1':
257     B.set_quiet_output(env)
258 else:
259     if toolset=='msvc':
260         B.msvc_hack(env)
261
262 print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir
263 env.SConsignFile(B.root_build_dir+'scons-signatures')
264 B.init_lib_dict()
265
266 ##### END SETUP ##########
267
268 Export('env')
269 #Export('root_build_dir') # this one is still needed for makesdna
270 ##TODO: improve makesdna usage
271
272 BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
273 SConscript(B.root_build_dir+'/intern/SConscript')
274 BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
275 SConscript(B.root_build_dir+'/extern/SConscript')
276 BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
277 SConscript(B.root_build_dir+'/source/SConscript')
278
279 # now that we have read all SConscripts, we know what
280 # libraries will be built. Create list of
281 # libraries to give as objects to linking phase
282 mainlist = []
283 for tp in B.possible_types:
284     if not tp == 'player' and not tp == 'player2':
285         mainlist += B.create_blender_liblist(env, tp)
286
287 if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
288     B.propose_priorities()
289
290 dobj = B.buildinfo(env, "dynamic") + B.resources
291 thestatlibs, thelibincs = B.setup_staticlibs(env)
292 thesyslibs = B.setup_syslibs(env)
293
294 env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
295 if env['WITH_BF_PLAYER']:
296     playerlist = B.create_blender_liblist(env, 'player')
297     env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
298
299 ##### Now define some targets
300
301
302 #------------ INSTALL
303
304 blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list)
305
306 #-- .blender
307 dotblendlist = []
308 dottargetlist = []
309 for dp, dn, df in os.walk('bin/.blender'):
310     if 'CVS' in dn:
311         dn.remove('CVS')
312     for f in df:
313         dotblendlist.append(dp+os.sep+f)
314         dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f)
315
316 dotblenderinstall = []
317 for targetdir,srcfile in zip(dottargetlist, dotblendlist):
318     td, tf = os.path.split(targetdir)
319     dotblenderinstall.append(env.Install(dir=td, source=srcfile))
320
321 #-- .blender/scripts
322 scriptinstall = []
323 scriptpath='release/scripts'
324 for dp, dn, df in os.walk(scriptpath):
325     if 'CVS' in dn:
326         dn.remove('CVS')
327     dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):]
328     source=[dp+os.sep+f for f in df]
329     scriptinstall.append(env.Install(dir=dir,source=source))
330
331 #-- plugins
332 pluglist = []
333 plugtargetlist = []
334 for tp, tn, tf in os.walk('release/plugins'):
335     if 'CVS' in tn:
336         tn.remove('CVS')
337     for f in tf:
338         pluglist.append(tp+os.sep+f)
339         plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f)
340
341 plugininstall = []
342 for targetdir,srcfile in zip(plugtargetlist, pluglist):
343     td, tf = os.path.split(targetdir)
344     plugininstall.append(env.Install(dir=td, source=srcfile))
345
346 textlist = []
347 texttargetlist = []
348 for tp, tn, tf in os.walk('release/text'):
349     if 'CVS' in tn:
350         tn.remove('CVS')
351     for f in tf:
352         textlist.append(tp+os.sep+f)
353
354 textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
355
356 allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall]
357
358 if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
359     dllsources = ['${LCGDIR}/gettext/lib/gnu_gettext.dll',
360                         '${LCGDIR}/png/lib/libpng.dll',
361                         '#release/windows/extra/python24.zip',
362                         '#release/windows/extra/zlib.pyd',
363                         '${LCGDIR}/sdl/lib/SDL.dll',
364                         '${LCGDIR}/zlib/lib/zlib.dll',
365                         '${LCGDIR}/tiff/lib/libtiff.dll']
366     if env['BF_DEBUG']:
367         dllsources.append('${LCGDIR}/python/lib/python24_d.dll')
368     else:
369         dllsources.append('${LCGDIR}/python/lib/python24.dll')
370     if env['OURPLATFORM'] == 'win32-mingw':
371         dllsources += ['${LCGDIR}/pthreads/lib/pthreadGC2.dll']
372     else:
373         dllsources += ['${LCGDIR}/pthreads/lib/pthreadVC2.dll']
374     if env['WITH_BF_ICONV']:
375         dllsources += ['${LCGDIR}/iconv/lib/iconv.dll']
376     if env['WITH_BF_FFMPEG']:
377         dllsources += ['${LCGDIR}/ffmpeg/lib/avcodec-51.dll',
378                         '${LCGDIR}/ffmpeg/lib/avformat-51.dll',
379                         '${LCGDIR}/ffmpeg/lib/avutil-49.dll',
380                         '${LCGDIR}/ffmpeg/lib/libdts.dll',
381                         '${LCGDIR}/ffmpeg/lib/libfaac.dll',
382                         '${LCGDIR}/ffmpeg/lib/libfaad.dll',
383                         '${LCGDIR}/ffmpeg/lib/libgsm.dll',
384                         '${LCGDIR}/ffmpeg/lib/libmp3lame-0.dll',
385                         '${LCGDIR}/ffmpeg/lib/libogg-0.dll',
386                         '${LCGDIR}/ffmpeg/lib/libvorbis-0.dll',
387                         '${LCGDIR}/ffmpeg/lib/libvorbisenc-2.dll',
388                         '${LCGDIR}/ffmpeg/lib/libx264-54.dll',
389                         '${LCGDIR}/ffmpeg/lib/postproc-51.dll',
390                         '${LCGDIR}/ffmpeg/lib/xvidcore.dll']
391     windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
392     allinstall += windlls
393
394 installtarget = env.Alias('install', allinstall)
395 bininstalltarget = env.Alias('install-bin', blenderinstall)
396
397 if env['WITH_BF_PLAYER']:
398     blenderplayer = env.Alias('blenderplayer', B.program_list)
399     Depends(blenderplayer,installtarget)
400
401 if not env['WITH_BF_GAMEENGINE']:
402     blendernogame = env.Alias('blendernogame', B.program_list)
403     Depends(blendernogame,installtarget)
404
405 Default(B.program_list)
406 Default(installtarget)
407
408 #------------ RELEASE
409 # TODO: zipup the installation
410
411 #------------ BLENDERPLAYER
412 # TODO: build stubs and link into blenderplayer
413
414 #------------ EPYDOC
415 # TODO: run epydoc
416