Patch from GSR that a) fixes a whole bunch of GPL/BL license
[blender-staging.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 = B.arguments.get('BF_CONFIG', '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 # first read platform config. B.arguments will override
161 optfiles = [configfile]
162 if os.path.exists('user-config.py'):
163     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py'
164     optfiles += ['user-config.py']
165 else:
166     print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC
167
168 opts = btools.read_opts(optfiles, B.arguments)
169 opts.Update(env)
170
171 if not env['BF_FANCY']:
172     B.bc.disable()
173
174 # disable elbeem (fluidsim) compilation?
175 if env['BF_NO_ELBEEM'] == 1:
176     env['CPPFLAGS'].append('-DDISABLE_ELBEEM')
177     env['CXXFLAGS'].append('-DDISABLE_ELBEEM')
178     env['CCFLAGS'].append('-DDISABLE_ELBEEM')
179
180 if env['WITH_BF_OPENMP'] == 1:
181         if env['OURPLATFORM']=='win32-vc':
182                 env['CCFLAGS'].append('/openmp')
183                 env['CPPFLAGS'].append('/openmp')
184                 env['CXXFLAGS'].append('/openmp')
185         else:
186                 if env['CC'] == 'icc':
187                         env.Append(LINKFLAGS=['-openmp', '-static-intel'])
188                         env['CCFLAGS'].append('-openmp')
189                         env['CPPFLAGS'].append('-openmp')
190                         env['CXXFLAGS'].append('-openmp')
191                 else:
192                         env.Append(LINKFLAGS=['-lgomp'])
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         print B.bc.OKGREEN+'...done'+B.bc.ENDC
272     else:
273         print B.bc.HEADER+'Already Clean, nothing to do.'+B.bc.ENDC
274     Exit()
275
276 if not os.path.isdir ( B.root_build_dir):
277     os.makedirs ( B.root_build_dir )
278     os.makedirs ( B.root_build_dir + 'source' )
279     os.makedirs ( B.root_build_dir + 'intern' )
280     os.makedirs ( B.root_build_dir + 'extern' )
281     os.makedirs ( B.root_build_dir + 'lib' )
282     os.makedirs ( B.root_build_dir + 'bin' )
283
284 Help(opts.GenerateHelpText(env))
285
286 # default is new quieter output, but if you need to see the 
287 # commands, do 'scons BF_QUIET=0'
288 bf_quietoutput = B.arguments.get('BF_QUIET', '1')
289 if env['BF_QUIET']:
290     B.set_quiet_output(env)
291 else:
292     if toolset=='msvc':
293         B.msvc_hack(env)
294
295 print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir
296 env.SConsignFile(B.root_build_dir+'scons-signatures')
297 B.init_lib_dict()
298
299 ##### END SETUP ##########
300
301 Export('env')
302
303 BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
304 SConscript(B.root_build_dir+'/intern/SConscript')
305 BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
306 SConscript(B.root_build_dir+'/extern/SConscript')
307 BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
308 SConscript(B.root_build_dir+'/source/SConscript')
309
310 # now that we have read all SConscripts, we know what
311 # libraries will be built. Create list of
312 # libraries to give as objects to linking phase
313 mainlist = []
314 for tp in B.possible_types:
315     if not tp == 'player' and not tp == 'player2':
316         mainlist += B.create_blender_liblist(env, tp)
317
318 if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
319     B.propose_priorities()
320
321 dobj = B.buildinfo(env, "dynamic") + B.resources
322 thestatlibs, thelibincs = B.setup_staticlibs(env)
323 thesyslibs = B.setup_syslibs(env)
324
325 env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
326 if env['WITH_BF_PLAYER']:
327     playerlist = B.create_blender_liblist(env, 'player')
328     env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
329
330 ##### Now define some targets
331
332
333 #------------ INSTALL
334
335 #-- binaries
336 blenderinstall = []
337 if  env['OURPLATFORM']=='darwin':
338     for prg in B.program_list:
339         bundle = '%s.app' % prg[0]
340         bundledir = os.path.dirname(bundle)
341         for dp, dn, df in os.walk(bundle):
342             if 'CVS' in dn:
343                 dn.remove('CVS')
344             if '.svn' in dn:
345                 dn.remove('.svn')
346             dir=env['BF_INSTALLDIR']+dp[len(bundledir):]
347             source=[dp+os.sep+f for f in df]
348             blenderinstall.append(env.Install(dir=dir,source=source))
349 else:
350     blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list)
351
352 #-- .blender
353 #- dont do .blender and scripts for darwin, it is already in the bundle
354 dotblendlist = []
355 dottargetlist = []
356 scriptinstall = []
357
358 if  env['OURPLATFORM']!='darwin':
359         for dp, dn, df in os.walk('bin/.blender'):
360             if 'CVS' in dn:
361                 dn.remove('CVS')
362             if '.svn' in dn:
363                 dn.remove('.svn')
364             for f in df:
365                 dotblendlist.append(dp+os.sep+f)
366                 dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f)
367
368         dotblenderinstall = []
369         for targetdir,srcfile in zip(dottargetlist, dotblendlist):
370             td, tf = os.path.split(targetdir)
371             dotblenderinstall.append(env.Install(dir=td, source=srcfile))
372         
373         #-- .blender/scripts    
374         scriptpath='release/scripts'
375         for dp, dn, df in os.walk(scriptpath):
376             if 'CVS' in dn:
377                 dn.remove('CVS')
378             if '.svn' in dn:
379                 dn.remove('.svn')
380             dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):]
381             source=[dp+os.sep+f for f in df]
382             scriptinstall.append(env.Install(dir=dir,source=source))
383
384 #-- plugins
385 pluglist = []
386 plugtargetlist = []
387 for tp, tn, tf in os.walk('release/plugins'):
388     if 'CVS' in tn:
389         tn.remove('CVS')
390     if '.svn' in tn:
391         tn.remove('.svn')
392     for f in tf:
393         pluglist.append(tp+os.sep+f)
394         plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f)
395
396 plugininstall = []
397 for targetdir,srcfile in zip(plugtargetlist, pluglist):
398     td, tf = os.path.split(targetdir)
399     plugininstall.append(env.Install(dir=td, source=srcfile))
400
401 textlist = []
402 texttargetlist = []
403 for tp, tn, tf in os.walk('release/text'):
404     if 'CVS' in tn:
405         tn.remove('CVS')
406     if '.svn' in tn:
407         tn.remove('.svn')
408     for f in tf:
409         textlist.append(tp+os.sep+f)
410
411 textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
412
413 if  env['OURPLATFORM']=='darwin':
414         allinstall = [blenderinstall, plugininstall, textinstall]
415 else:
416         allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall]
417
418 if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
419     dllsources = ['${LCGDIR}/gettext/lib/gnu_gettext.dll',
420                         '${LCGDIR}/png/lib/libpng.dll',
421                         '#release/windows/extra/python25.zip',
422                         '#release/windows/extra/zlib.pyd',
423                         '${LCGDIR}/sdl/lib/SDL.dll',
424                         '${LCGDIR}/zlib/lib/zlib.dll',
425                         '${LCGDIR}/tiff/lib/libtiff.dll']
426     if env['BF_DEBUG']:
427         dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}_d.dll')
428     else:
429         dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}.dll')
430     if env['OURPLATFORM'] == 'win32-mingw':
431         dllsources += ['${LCGDIR}/pthreads/lib/pthreadGC2.dll']
432     else:
433         dllsources += ['${LCGDIR}/pthreads/lib/pthreadVC2.dll']
434     if env['WITH_BF_ICONV']:
435         dllsources += ['${LCGDIR}/iconv/lib/iconv.dll']
436 #    if env['WITH_BF_FFMPEG']:
437 #        dllsources += ['${LCGDIR}/ffmpeg/lib/avcodec-51.dll',
438 #                        '${LCGDIR}/ffmpeg/lib/avformat-51.dll',
439 #                        '${LCGDIR}/ffmpeg/lib/avutil-49.dll']
440     windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
441     allinstall += windlls
442
443 installtarget = env.Alias('install', allinstall)
444 bininstalltarget = env.Alias('install-bin', blenderinstall)
445
446 nsisaction = env.Action(btools.NSIS_Installer, btools.NSIS_print)
447 nsiscmd = env.Command('nsisinstaller', None, nsisaction)
448 nsisalias = env.Alias('nsis', nsiscmd)
449
450 if env['WITH_BF_PLAYER']:
451     blenderplayer = env.Alias('blenderplayer', B.program_list)
452     Depends(blenderplayer,installtarget)
453
454 if not env['WITH_BF_GAMEENGINE']:
455     blendernogame = env.Alias('blendernogame', B.program_list)
456     Depends(blendernogame,installtarget)
457
458 Depends(nsiscmd, allinstall)
459
460 Default(B.program_list)
461
462 if not env['WITHOUT_BF_INSTALL']:
463         Default(installtarget)
464
465 #------------ RELEASE
466 # TODO: zipup the installation
467
468 #------------ BLENDERPLAYER
469 # TODO: build stubs and link into blenderplayer
470
471 #------------ EPYDOC
472 # TODO: run epydoc
473