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