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