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