==== MSVC Projectfiles ====
[blender-staging.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
56 ##### BEGIN SETUP #####
57
58 B.possible_types = ['core', 'common', 'blender', 'intern',
59                     'international', 'game', 'game2',
60                     'player', 'player2', 'system']
61
62 B.binarykind = ['blender' , 'blenderplayer']
63 ##################################
64 # target and argument validation #
65 ##################################
66 # XX cheating for BF_FANCY, we check for BF_FANCY before args are validated
67 use_color = ARGUMENTS.get('BF_FANCY', '1')
68 if platform=='win32':
69     use_color = None
70
71 if not use_color=='1':
72     B.bc.disable()
73
74 # arguments
75 print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC
76 B.arguments = btools.validate_arguments(ARGUMENTS, B.bc)
77 btools.print_arguments(B.arguments, B.bc)
78
79 # targets
80 print B.bc.HEADER+'Command-line targets'+B.bc.ENDC
81 B.targets = btools.validate_targets(COMMAND_LINE_TARGETS, B.bc)
82 btools.print_targets(B.targets, B.bc)
83
84 ##########################
85 # setting up environment #
86 ##########################
87
88 # handling cmd line arguments & config file
89
90 # first check cmdline for toolset and we create env to work on
91 quickie = B.arguments.get('BF_QUICK', None)
92 quickdebug = B.arguments.get('BF_QUICKDEBUG', None)
93
94 if quickdebug:
95     B.quickdebug=string.split(quickdebug, ',')
96 else:
97     B.quickdebug=[]
98
99 if quickie:
100     B.quickie=string.split(quickie,',')
101 else:
102     B.quickie=[]
103
104 toolset = B.arguments.get('BF_TOOLSET', None)
105 if toolset:
106     print "Using " + toolset
107     if toolset=='mstoolkit':
108         env = BlenderEnvironment(ENV = os.environ)
109         env.Tool('mstoolkit', ['tools'])
110     else:
111         env = BlenderEnvironment(tools=[toolset], ENV = os.environ)
112 else:
113     env = BlenderEnvironment(ENV = os.environ)
114
115 if not env:
116     print "Could not create a build environment"
117     Exit()
118
119 env.SConscriptChdir(0)
120 cc = B.arguments.get('CC', None)
121 cxx = B.arguments.get('CXX', None)
122 if cc:
123     env['CC'] = cc
124 if cxx:
125     env['CXX'] = cxx
126
127 if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32':
128     platform = 'win32-vc'
129 elif env['CC'] in ['gcc'] and sys.platform=='win32':
130     platform = 'win32-mingw'
131
132 if platform == 'win32-mingw':
133     try:
134         import win32file
135         import win32event
136         import win32process
137         import win32security
138         import string
139
140         slash= re.compile(r"\\")
141
142         def myesc(b):
143             if b[0]!= "-":
144                 b = slash.sub(r"\\\\", b[1:-1])
145                 return "\"" + b + "\""
146             else:
147                 return b
148
149         def my_spawn(sh, escape, cmd, args, spawnenv):
150             for var in spawnenv:
151                 spawnenv[var] = spawnenv[var].encode('ascii', 'replace')
152
153             sAttrs = win32security.SECURITY_ATTRIBUTES()
154             StartupInfo = win32process.STARTUPINFO()
155             if cmd=='ar' and args[1]=='r':
156                 args[1] = '-r'
157             newargs = string.join(map(myesc, args[1:]), ' ')
158             cmdline = cmd + " " + newargs
159
160             # check for any special operating system commands
161             if cmd == 'del':
162                 for arg in args[1:]:
163                     win32file.DeleteFile(arg)
164                 exit_code = 0
165             else:
166                 # otherwise execute the command.
167                 hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo)
168                 win32event.WaitForSingleObject(hProcess, win32event.INFINITE)
169                 exit_code = win32process.GetExitCodeProcess(hProcess)
170                 win32file.CloseHandle(hProcess);
171                 win32file.CloseHandle(hThread);
172             return exit_code
173
174         env['SPAWN'] = my_spawn
175     except:
176         print "install win32all from http://sourceforge.net/project/showfiles.php?group_id=78018"
177
178 crossbuild = B.arguments.get('BF_CROSS', None)
179 if crossbuild and platform!='win32':
180     platform = 'linuxcross'
181
182 env['OURPLATFORM'] = platform
183
184 configfile = B.arguments.get('BF_CONFIG', 'config'+os.sep+platform+'-config.py')
185
186 if os.path.exists(configfile):
187     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile
188 else:
189     print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC
190
191 if crossbuild and env['PLATFORM'] != 'win32':
192     print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC
193     env.Tool('crossmingw', ['tools'])
194     # todo: determine proper libs/includes etc.
195     # Needed for gui programs, console programs should do without it
196     env.Append(LINKFLAGS=['-mwindows'])
197
198 # first read platform config. B.arguments will override
199 optfiles = [configfile]
200 if os.path.exists('user-config.py'):
201     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py'
202     optfiles += ['user-config.py']
203 else:
204     print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC
205
206 opts = btools.read_opts(optfiles, B.arguments)
207 opts.Update(env)
208
209 # disable elbeem (fluidsim) compilation?
210 if env['BF_NO_ELBEEM'] == 1:
211     env['CPPFLAGS'].append('-DDISABLE_ELBEEM')
212     env['CXXFLAGS'].append('-DDISABLE_ELBEEM')
213     env['CCFLAGS'].append('-DDISABLE_ELBEEM')
214
215 #check for additional debug libnames
216
217 if env.has_key('BF_DEBUG_LIBS'):
218     B.quickdebug += env['BF_DEBUG_LIBS']
219
220 printdebug = B.arguments.get('BF_LISTDEBUG', 0)
221
222 # see if this linux distro has libalut
223
224 if env['OURPLATFORM'] == 'linux2' :
225     if env['WITH_BF_OPENAL']:
226         mylib_test_source_file = """
227         #include "AL/alut.h"
228         int main(int argc, char **argv)
229         {
230             alutGetMajorVersion();
231             return 0;
232         }
233         """
234
235         def CheckFreeAlut(context,env):
236             context.Message( B.bc.OKGREEN + "Linux platform detected:\n  checking for FreeAlut... " + B.bc.ENDC )
237             env['LIBS'] = 'alut'
238             result = context.TryLink(mylib_test_source_file, '.c')
239             context.Result(result)
240             return result
241
242         env2 = env.Copy( LIBPATH = env['BF_OPENAL'] ) 
243         conf = Configure( env2, {'CheckFreeAlut' : CheckFreeAlut}, '.sconf_temp', '/dev/null' )
244         if conf.CheckFreeAlut( env2 ):
245             env['BF_OPENAL_LIB'] += ' alut'
246         del env2
247         for root, dirs, files in os.walk('.sconf_temp', topdown=False):
248             for name in files:
249                 os.remove(os.path.join(root, name))
250             for name in dirs:
251                 os.rmdir(os.path.join(root, name))
252         os.rmdir(root)
253
254 if len(B.quickdebug) > 0 and printdebug != 0:
255     print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC
256     for l in B.quickdebug:
257         print "\t" + l
258
259 # check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline
260 if 'blenderplayer' in B.targets:
261     env['WITH_BF_PLAYER'] = True
262
263 if 'blendernogame' in B.targets:
264     env['WITH_BF_GAMEENGINE'] = False
265
266 # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
267 #B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep)
268 B.root_build_dir = env['BF_BUILDDIR']
269 env['BUILDDIR'] = B.root_build_dir
270 if not B.root_build_dir[-1]==os.sep:
271     B.root_build_dir += os.sep
272
273 # We do a shortcut for clean when no quicklist is given: just delete
274 # builddir without reading in SConscripts
275 do_clean = None
276 if 'clean' in B.targets:
277     do_clean = True
278
279 if not quickie and do_clean:
280     print B.bc.HEADER+'Cleaning...'+B.bc.ENDC
281     dirs = os.listdir(B.root_build_dir)
282     for dir in dirs:
283         if os.path.isdir(B.root_build_dir + dir) == 1:
284             print "clean dir %s"%(B.root_build_dir+dir)
285             shutil.rmtree(B.root_build_dir+dir)
286     print B.bc.OKGREEN+'...done'+B.bc.ENDC
287     Exit()
288
289 if not os.path.isdir ( B.root_build_dir):
290     os.makedirs ( B.root_build_dir )
291     os.makedirs ( B.root_build_dir + 'source' )
292     os.makedirs ( B.root_build_dir + 'intern' )
293     os.makedirs ( B.root_build_dir + 'extern' )
294     os.makedirs ( B.root_build_dir + 'lib' )
295     os.makedirs ( B.root_build_dir + 'bin' )
296
297 Help(opts.GenerateHelpText(env))
298
299 # default is new quieter output, but if you need to see the 
300 # commands, do 'scons BF_QUIET=0'
301 bf_quietoutput = B.arguments.get('BF_QUIET', '1')
302 if bf_quietoutput=='1':
303     B.set_quiet_output(env)
304 else:
305     if toolset=='msvc':
306         B.msvc_hack(env)
307
308 print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir
309 env.SConsignFile(B.root_build_dir+'scons-signatures')
310 B.init_lib_dict()
311
312 ##### END SETUP ##########
313
314 Export('env')
315 #Export('root_build_dir') # this one is still needed for makesdna
316 ##TODO: improve makesdna usage
317
318 BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
319 SConscript(B.root_build_dir+'/intern/SConscript')
320 BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
321 SConscript(B.root_build_dir+'/extern/SConscript')
322 BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
323 SConscript(B.root_build_dir+'/source/SConscript')
324
325 # now that we have read all SConscripts, we know what
326 # libraries will be built. Create list of
327 # libraries to give as objects to linking phase
328 mainlist = []
329 for tp in B.possible_types:
330     if not tp == 'player' and not tp == 'player2':
331         mainlist += B.create_blender_liblist(env, tp)
332
333 if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
334     B.propose_priorities()
335
336 dobj = B.buildinfo(env, "dynamic") + B.resources
337 thestatlibs, thelibincs = B.setup_staticlibs(env)
338 thesyslibs = B.setup_syslibs(env)
339
340 env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
341 if env['WITH_BF_PLAYER']:
342     playerlist = B.create_blender_liblist(env, 'player')
343     env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
344
345 ##### Now define some targets
346
347
348 #------------ INSTALL
349
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     for f in df:
359         dotblendlist.append(dp+os.sep+f)
360         dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f)
361
362 dotblenderinstall = []
363 for targetdir,srcfile in zip(dottargetlist, dotblendlist):
364     td, tf = os.path.split(targetdir)
365     dotblenderinstall.append(env.Install(dir=td, source=srcfile))
366
367 #-- .blender/scripts
368 scriptinstall = []
369 scriptpath='release/scripts'
370 for dp, dn, df in os.walk(scriptpath):
371     if 'CVS' in dn:
372         dn.remove('CVS')
373     dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):]
374     source=[dp+os.sep+f for f in df]
375     scriptinstall.append(env.Install(dir=dir,source=source))
376
377 #-- plugins
378 pluglist = []
379 plugtargetlist = []
380 for tp, tn, tf in os.walk('release/plugins'):
381     if 'CVS' in tn:
382         tn.remove('CVS')
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     for f in tf:
398         textlist.append(tp+os.sep+f)
399
400 textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
401
402 allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall]
403
404 if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
405     dllsources = ['${LCGDIR}/gettext/lib/gnu_gettext.dll',
406                         '${LCGDIR}/png/lib/libpng.dll',
407                         '#release/windows/extra/python24.zip',
408                         '#release/windows/extra/zlib.pyd',
409                         '${LCGDIR}/sdl/lib/SDL.dll',
410                         '${LCGDIR}/zlib/lib/zlib.dll',
411                         '${LCGDIR}/tiff/lib/libtiff.dll']
412     if env['BF_DEBUG']:
413         dllsources.append('${LCGDIR}/python/lib/python24_d.dll')
414     else:
415         dllsources.append('${LCGDIR}/python/lib/python24.dll')
416     if env['OURPLATFORM'] == 'win32-mingw':
417         dllsources += ['${LCGDIR}/pthreads/lib/pthreadGC2.dll']
418     else:
419         dllsources += ['${LCGDIR}/pthreads/lib/pthreadVC2.dll']
420     if env['WITH_BF_ICONV']:
421         dllsources += ['${LCGDIR}/iconv/lib/iconv.dll']
422     if env['WITH_BF_FFMPEG']:
423         dllsources += ['${LCGDIR}/ffmpeg/lib/avcodec-51.dll',
424                         '${LCGDIR}/ffmpeg/lib/avformat-51.dll',
425                         '${LCGDIR}/ffmpeg/lib/avutil-49.dll',
426                         '${LCGDIR}/ffmpeg/lib/libdts.dll',
427                         '${LCGDIR}/ffmpeg/lib/libfaac.dll',
428                         '${LCGDIR}/ffmpeg/lib/libfaad.dll',
429                         '${LCGDIR}/ffmpeg/lib/libgsm.dll',
430                         '${LCGDIR}/ffmpeg/lib/libmp3lame-0.dll',
431                         '${LCGDIR}/ffmpeg/lib/libogg-0.dll',
432                         '${LCGDIR}/ffmpeg/lib/libvorbis-0.dll',
433                         '${LCGDIR}/ffmpeg/lib/libvorbisenc-2.dll',
434                         '${LCGDIR}/ffmpeg/lib/libx264-54.dll',
435                         '${LCGDIR}/ffmpeg/lib/postproc-51.dll',
436                         '${LCGDIR}/ffmpeg/lib/xvidcore.dll']
437     windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
438     allinstall += windlls
439
440 installtarget = env.Alias('install', allinstall)
441 bininstalltarget = env.Alias('install-bin', blenderinstall)
442
443 if env['WITH_BF_PLAYER']:
444     blenderplayer = env.Alias('blenderplayer', B.program_list)
445     Depends(blenderplayer,installtarget)
446
447 if not env['WITH_BF_GAMEENGINE']:
448     blendernogame = env.Alias('blendernogame', B.program_list)
449     Depends(blendernogame,installtarget)
450
451 Default(B.program_list)
452 Default(installtarget)
453
454 #------------ RELEASE
455 # TODO: zipup the installation
456
457 #------------ BLENDERPLAYER
458 # TODO: build stubs and link into blenderplayer
459
460 #------------ EPYDOC
461 # TODO: run epydoc
462