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