Patch to change license to GPL only, from GSR.
[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
40 import tools.Blender
41 import tools.btools
42 import tools.bcolors
43
44 BlenderEnvironment = tools.Blender.BlenderEnvironment
45 btools = tools.btools
46 B = tools.Blender
47
48 ### globals ###
49 platform = sys.platform
50 quickie = None
51 quickdebug = None
52 nsis_build = None
53
54 ##### BEGIN SETUP #####
55
56 B.possible_types = ['core', 'common', 'blender', 'intern',
57                     'international', 'game', 'game2',
58                     'player', 'player2', 'system']
59
60 B.binarykind = ['blender' , 'blenderplayer']
61 ##################################
62 # target and argument validation #
63 ##################################
64 # XX cheating for BF_FANCY, we check for BF_FANCY before args are validated
65 use_color = ARGUMENTS.get('BF_FANCY', '1')
66 if platform=='win32':
67     use_color = None
68
69 if not use_color=='1':
70     B.bc.disable()
71     
72  #on defaut white Os X terminal, some colors are totally unlegible
73 if platform=='darwin':
74     B.bc.OKGREEN = '\033[34m'
75     B.bc.WARNING = '\033[36m'
76
77 # arguments
78 print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC
79 B.arguments = btools.validate_arguments(ARGUMENTS, B.bc)
80 btools.print_arguments(B.arguments, B.bc)
81
82 # targets
83 print B.bc.HEADER+'Command-line targets'+B.bc.ENDC
84 B.targets = btools.validate_targets(COMMAND_LINE_TARGETS, B.bc)
85 btools.print_targets(B.targets, B.bc)
86
87 ##########################
88 # setting up environment #
89 ##########################
90
91 # handling cmd line arguments & config file
92
93 # first check cmdline for toolset and we create env to work on
94 quickie = B.arguments.get('BF_QUICK', None)
95 quickdebug = B.arguments.get('BF_QUICKDEBUG', None)
96
97 if quickdebug:
98     B.quickdebug=string.split(quickdebug, ',')
99 else:
100     B.quickdebug=[]
101
102 if quickie:
103     B.quickie=string.split(quickie,',')
104 else:
105     B.quickie=[]
106     
107 toolset = B.arguments.get('BF_TOOLSET', None)
108 if toolset:
109     print "Using " + toolset
110     if toolset=='mstoolkit':
111         env = BlenderEnvironment(ENV = os.environ)
112         env.Tool('mstoolkit', ['tools'])
113     else:
114         env = BlenderEnvironment(tools=[toolset], ENV = os.environ)
115         if env:
116             btools.SetupSpawn(env)
117 else:
118     env = BlenderEnvironment(ENV = os.environ)
119
120 if not env:
121     print "Could not create a build environment"
122     Exit()
123
124
125 cc = B.arguments.get('CC', None)
126 cxx = B.arguments.get('CXX', None)
127 if cc:
128     env['CC'] = cc
129 if cxx:
130     env['CXX'] = cxx
131
132 if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32':
133     platform = 'win32-vc'
134 elif env['CC'] in ['gcc'] and sys.platform=='win32':
135     platform = 'win32-mingw'
136
137 env.SConscriptChdir(0)
138
139 crossbuild = B.arguments.get('BF_CROSS', None)
140 if crossbuild and platform!='win32':
141     platform = 'linuxcross'
142
143 env['OURPLATFORM'] = platform
144
145 configfile = B.arguments.get('BF_CONFIG', 'config'+os.sep+platform+'-config.py')
146
147 if os.path.exists(configfile):
148     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile
149 else:
150     print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC
151
152 if crossbuild and env['PLATFORM'] != 'win32':
153     print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC
154     env.Tool('crossmingw', ['tools'])
155     # todo: determine proper libs/includes etc.
156     # Needed for gui programs, console programs should do without it
157     env.Append(LINKFLAGS=['-mwindows'])
158
159 # first read platform config. B.arguments will override
160 optfiles = [configfile]
161 if os.path.exists('user-config.py'):
162     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py'
163     optfiles += ['user-config.py']
164 else:
165     print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC
166
167 opts = btools.read_opts(optfiles, B.arguments)
168 opts.Update(env)
169
170 if not env['BF_FANCY']:
171     B.bc.disable()
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