Bugfix for wrong OpenMP flags when using icc (proposed by jensverwiebe via IRC)
[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                 if env['CC'] == 'icc':
189                         env.Append(LINKFLAGS=['-openmp', '-static-intel'])
190                         env['CCFLAGS'].append('-openmp')
191                         env['CPPFLAGS'].append('-openmp')
192                         env['CXXFLAGS'].append('-openmp')
193                 else:
194                         env.Append(LINKFLAGS=['-lgomp'])
195                         env['CCFLAGS'].append('-fopenmp')
196                         env['CPPFLAGS'].append('-fopenmp')
197                         env['CXXFLAGS'].append('-fopenmp')
198
199 #check for additional debug libnames
200
201 if env.has_key('BF_DEBUG_LIBS'):
202     B.quickdebug += env['BF_DEBUG_LIBS']
203
204 printdebug = B.arguments.get('BF_LISTDEBUG', 0)
205
206 # see if this linux distro has libalut
207
208 if env['OURPLATFORM'] == 'linux2' :
209     if env['WITH_BF_OPENAL']:
210         mylib_test_source_file = """
211         #include "AL/alut.h"
212         int main(int argc, char **argv)
213         {
214             alutGetMajorVersion();
215             return 0;
216         }
217         """
218
219         def CheckFreeAlut(context,env):
220             context.Message( B.bc.OKGREEN + "Linux platform detected:\n  checking for FreeAlut... " + B.bc.ENDC )
221             env['LIBS'] = 'alut'
222             result = context.TryLink(mylib_test_source_file, '.c')
223             context.Result(result)
224             return result
225
226         env2 = env.Copy( LIBPATH = env['BF_OPENAL'] ) 
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         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         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 bf_quietoutput=='1':
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 dotblendlist = []
354 dottargetlist = []
355 for dp, dn, df in os.walk('bin/.blender'):
356     if 'CVS' in dn:
357         dn.remove('CVS')
358     if '.svn' in dn:
359         dn.remove('.svn')
360     for f in df:
361         dotblendlist.append(dp+os.sep+f)
362         dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f)
363
364 dotblenderinstall = []
365 for targetdir,srcfile in zip(dottargetlist, dotblendlist):
366     td, tf = os.path.split(targetdir)
367     dotblenderinstall.append(env.Install(dir=td, source=srcfile))
368
369 #-- .blender/scripts
370 scriptinstall = []
371 scriptpath='release/scripts'
372 for dp, dn, df in os.walk(scriptpath):
373     if 'CVS' in dn:
374         dn.remove('CVS')
375     if '.svn' in dn:
376         dn.remove('.svn')
377     dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):]
378     source=[dp+os.sep+f for f in df]
379     scriptinstall.append(env.Install(dir=dir,source=source))
380
381 #-- plugins
382 pluglist = []
383 plugtargetlist = []
384 for tp, tn, tf in os.walk('release/plugins'):
385     if 'CVS' in tn:
386         tn.remove('CVS')
387     if '.svn' in tn:
388         tn.remove('.svn')
389     for f in tf:
390         pluglist.append(tp+os.sep+f)
391         plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f)
392
393 plugininstall = []
394 for targetdir,srcfile in zip(plugtargetlist, pluglist):
395     td, tf = os.path.split(targetdir)
396     plugininstall.append(env.Install(dir=td, source=srcfile))
397
398 textlist = []
399 texttargetlist = []
400 for tp, tn, tf in os.walk('release/text'):
401     if 'CVS' in tn:
402         tn.remove('CVS')
403     if '.svn' in tn:
404         tn.remove('.svn')
405     for f in tf:
406         textlist.append(tp+os.sep+f)
407
408 textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
409
410 allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall]
411
412 if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
413     dllsources = ['${LCGDIR}/gettext/lib/gnu_gettext.dll',
414                         '${LCGDIR}/png/lib/libpng.dll',
415                         '#release/windows/extra/python25.zip',
416                         '#release/windows/extra/zlib.pyd',
417                         '${LCGDIR}/sdl/lib/SDL.dll',
418                         '${LCGDIR}/zlib/lib/zlib.dll',
419                         '${LCGDIR}/tiff/lib/libtiff.dll']
420     if env['BF_DEBUG']:
421         dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}_d.dll')
422     else:
423         dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}.dll')
424     if env['OURPLATFORM'] == 'win32-mingw':
425         dllsources += ['${LCGDIR}/pthreads/lib/pthreadGC2.dll']
426     else:
427         dllsources += ['${LCGDIR}/pthreads/lib/pthreadVC2.dll']
428     if env['WITH_BF_ICONV']:
429         dllsources += ['${LCGDIR}/iconv/lib/iconv.dll']
430 #    if env['WITH_BF_FFMPEG']:
431 #        dllsources += ['${LCGDIR}/ffmpeg/lib/avcodec-51.dll',
432 #                        '${LCGDIR}/ffmpeg/lib/avformat-51.dll',
433 #                        '${LCGDIR}/ffmpeg/lib/avutil-49.dll']
434     windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
435     allinstall += windlls
436
437 installtarget = env.Alias('install', allinstall)
438 bininstalltarget = env.Alias('install-bin', blenderinstall)
439
440 nsisaction = env.Action(btools.NSIS_Installer, btools.NSIS_print)
441 nsiscmd = env.Command('nsisinstaller', None, nsisaction)
442 nsisalias = env.Alias('nsis', nsiscmd)
443
444 if env['WITH_BF_PLAYER']:
445     blenderplayer = env.Alias('blenderplayer', B.program_list)
446     Depends(blenderplayer,installtarget)
447
448 if not env['WITH_BF_GAMEENGINE']:
449     blendernogame = env.Alias('blendernogame', B.program_list)
450     Depends(blendernogame,installtarget)
451
452 Depends(nsiscmd, allinstall)
453
454 Default(B.program_list)
455
456 if not env['WITHOUT_BF_INSTALL']:
457         Default(installtarget)
458
459 #------------ RELEASE
460 # TODO: zipup the installation
461
462 #------------ BLENDERPLAYER
463 # TODO: build stubs and link into blenderplayer
464
465 #------------ EPYDOC
466 # TODO: run epydoc
467