= translation =
[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
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 # Fix me!
133 #if platform == 'win32-mingw':
134 if 0:
135     try:
136         import win32file
137         import win32event
138         import win32process
139         import win32security
140         import string
141
142         slash= re.compile(r"\\")
143
144         def myesc(b):
145             if b[0]!= "-":
146                 b = slash.sub(r"\\\\", b[1:-1])
147                 return "\"" + b + "\""
148             else:
149                 return b
150
151         def my_spawn(sh, escape, cmd, args, spawnenv):
152             for var in spawnenv:
153                 spawnenv[var] = spawnenv[var].encode('ascii', 'replace')
154
155             sAttrs = win32security.SECURITY_ATTRIBUTES()
156             StartupInfo = win32process.STARTUPINFO()
157             if cmd=='ar' and args[1]=='r':
158                 args[1] = '-r'
159             newargs = string.join(map(myesc, args[1:]), ' ')
160             cmdline = cmd + " " + newargs
161
162             # check for any special operating system commands
163             if cmd == 'del':
164                 for arg in args[1:]:
165                     win32file.DeleteFile(arg)
166                 exit_code = 0
167             else:
168                 # otherwise execute the command.
169                 hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo)
170                 win32event.WaitForSingleObject(hProcess, win32event.INFINITE)
171                 exit_code = win32process.GetExitCodeProcess(hProcess)
172                 win32file.CloseHandle(hProcess);
173                 win32file.CloseHandle(hThread);
174             return exit_code
175
176         env['SPAWN'] = my_spawn
177     except:
178         print "install win32all from http://sourceforge.net/project/showfiles.php?group_id=78018"
179
180 crossbuild = B.arguments.get('BF_CROSS', None)
181 if crossbuild and platform!='win32':
182     platform = 'linuxcross'
183
184 env['OURPLATFORM'] = platform
185
186 configfile = B.arguments.get('BF_CONFIG', 'config'+os.sep+platform+'-config.py')
187
188 if os.path.exists(configfile):
189     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile
190 else:
191     print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC
192
193 if crossbuild and env['PLATFORM'] != 'win32':
194     print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC
195     env.Tool('crossmingw', ['tools'])
196     # todo: determine proper libs/includes etc.
197     # Needed for gui programs, console programs should do without it
198     env.Append(LINKFLAGS=['-mwindows'])
199
200 # first read platform config. B.arguments will override
201 optfiles = [configfile]
202 if os.path.exists('user-config.py'):
203     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py'
204     optfiles += ['user-config.py']
205 else:
206     print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC
207
208 opts = btools.read_opts(optfiles, B.arguments)
209 opts.Update(env)
210
211 # disable elbeem (fluidsim) compilation?
212 if env['BF_NO_ELBEEM'] == 1:
213     env['CPPFLAGS'].append('-DDISABLE_ELBEEM')
214     env['CXXFLAGS'].append('-DDISABLE_ELBEEM')
215     env['CCFLAGS'].append('-DDISABLE_ELBEEM')
216
217 #check for additional debug libnames
218
219 if env.has_key('BF_DEBUG_LIBS'):
220     B.quickdebug += env['BF_DEBUG_LIBS']
221
222 printdebug = B.arguments.get('BF_LISTDEBUG', 0)
223
224 # see if this linux distro has libalut
225
226 if env['OURPLATFORM'] == 'linux2' :
227     if env['WITH_BF_OPENAL']:
228         mylib_test_source_file = """
229         #include "AL/alut.h"
230         int main(int argc, char **argv)
231         {
232             alutGetMajorVersion();
233             return 0;
234         }
235         """
236
237         def CheckFreeAlut(context,env):
238             context.Message( B.bc.OKGREEN + "Linux platform detected:\n  checking for FreeAlut... " + B.bc.ENDC )
239             env['LIBS'] = 'alut'
240             result = context.TryLink(mylib_test_source_file, '.c')
241             context.Result(result)
242             return result
243
244         env2 = env.Copy( LIBPATH = env['BF_OPENAL'] ) 
245         conf = Configure( env2, {'CheckFreeAlut' : CheckFreeAlut}, '.sconf_temp', '/dev/null' )
246         if conf.CheckFreeAlut( env2 ):
247             env['BF_OPENAL_LIB'] += ' alut'
248         del env2
249         for root, dirs, files in os.walk('.sconf_temp', topdown=False):
250             for name in files:
251                 os.remove(os.path.join(root, name))
252             for name in dirs:
253                 os.rmdir(os.path.join(root, name))
254         os.rmdir(root)
255
256 if len(B.quickdebug) > 0 and printdebug != 0:
257     print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC
258     for l in B.quickdebug:
259         print "\t" + l
260
261 # check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline
262 if 'blenderplayer' in B.targets:
263     env['WITH_BF_PLAYER'] = True
264
265 if 'blendernogame' in B.targets:
266     env['WITH_BF_GAMEENGINE'] = False
267
268 # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
269 #B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep)
270 B.root_build_dir = env['BF_BUILDDIR']
271 env['BUILDDIR'] = B.root_build_dir
272 if not B.root_build_dir[-1]==os.sep:
273     B.root_build_dir += os.sep
274
275 # We do a shortcut for clean when no quicklist is given: just delete
276 # builddir without reading in SConscripts
277 do_clean = None
278 if 'clean' in B.targets:
279     do_clean = True
280
281 if not quickie and do_clean:
282     print B.bc.HEADER+'Cleaning...'+B.bc.ENDC
283     dirs = os.listdir(B.root_build_dir)
284     for dir in dirs:
285         if os.path.isdir(B.root_build_dir + dir) == 1:
286             print "clean dir %s"%(B.root_build_dir+dir)
287             shutil.rmtree(B.root_build_dir+dir)
288     print B.bc.OKGREEN+'...done'+B.bc.ENDC
289     Exit()
290
291 if not os.path.isdir ( B.root_build_dir):
292     os.makedirs ( B.root_build_dir )
293     os.makedirs ( B.root_build_dir + 'source' )
294     os.makedirs ( B.root_build_dir + 'intern' )
295     os.makedirs ( B.root_build_dir + 'extern' )
296     os.makedirs ( B.root_build_dir + 'lib' )
297     os.makedirs ( B.root_build_dir + 'bin' )
298
299 Help(opts.GenerateHelpText(env))
300
301 # default is new quieter output, but if you need to see the 
302 # commands, do 'scons BF_QUIET=0'
303 bf_quietoutput = B.arguments.get('BF_QUIET', '1')
304 if bf_quietoutput=='1':
305     B.set_quiet_output(env)
306 else:
307     if toolset=='msvc':
308         B.msvc_hack(env)
309
310 print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir
311 env.SConsignFile(B.root_build_dir+'scons-signatures')
312 B.init_lib_dict()
313
314 ##### END SETUP ##########
315
316 Export('env')
317 #Export('root_build_dir') # this one is still needed for makesdna
318 ##TODO: improve makesdna usage
319
320 BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
321 SConscript(B.root_build_dir+'/intern/SConscript')
322 BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
323 SConscript(B.root_build_dir+'/extern/SConscript')
324 BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
325 SConscript(B.root_build_dir+'/source/SConscript')
326
327 # now that we have read all SConscripts, we know what
328 # libraries will be built. Create list of
329 # libraries to give as objects to linking phase
330 mainlist = []
331 for tp in B.possible_types:
332     if not tp == 'player' and not tp == 'player2':
333         mainlist += B.create_blender_liblist(env, tp)
334
335 if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
336     B.propose_priorities()
337
338 dobj = B.buildinfo(env, "dynamic") + B.resources
339 thestatlibs, thelibincs = B.setup_staticlibs(env)
340 thesyslibs = B.setup_syslibs(env)
341
342 env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
343 if env['WITH_BF_PLAYER']:
344     playerlist = B.create_blender_liblist(env, 'player')
345     env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
346
347 ##### Now define some targets
348
349
350 #------------ INSTALL
351
352 blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list)
353
354 #-- .blender
355 dotblendlist = []
356 dottargetlist = []
357 for dp, dn, df in os.walk('bin/.blender'):
358     if 'CVS' in dn:
359         dn.remove('CVS')
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     dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):]
376     source=[dp+os.sep+f for f in df]
377     scriptinstall.append(env.Install(dir=dir,source=source))
378
379 #-- plugins
380 pluglist = []
381 plugtargetlist = []
382 for tp, tn, tf in os.walk('release/plugins'):
383     if 'CVS' in tn:
384         tn.remove('CVS')
385     for f in tf:
386         pluglist.append(tp+os.sep+f)
387         plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f)
388
389 plugininstall = []
390 for targetdir,srcfile in zip(plugtargetlist, pluglist):
391     td, tf = os.path.split(targetdir)
392     plugininstall.append(env.Install(dir=td, source=srcfile))
393
394 textlist = []
395 texttargetlist = []
396 for tp, tn, tf in os.walk('release/text'):
397     if 'CVS' in tn:
398         tn.remove('CVS')
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/python24.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/python24_d.dll')
416     else:
417         dllsources.append('${LCGDIR}/python/lib/python24.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                         '${LCGDIR}/ffmpeg/lib/libdts.dll',
429                         '${LCGDIR}/ffmpeg/lib/libfaac.dll',
430                         '${LCGDIR}/ffmpeg/lib/libfaad.dll',
431                         '${LCGDIR}/ffmpeg/lib/libgsm.dll',
432                         '${LCGDIR}/ffmpeg/lib/libmp3lame-0.dll',
433                         '${LCGDIR}/ffmpeg/lib/libogg-0.dll',
434                         '${LCGDIR}/ffmpeg/lib/libvorbis-0.dll',
435                         '${LCGDIR}/ffmpeg/lib/libvorbisenc-2.dll',
436                         '${LCGDIR}/ffmpeg/lib/libx264-54.dll',
437                         '${LCGDIR}/ffmpeg/lib/postproc-51.dll',
438                         '${LCGDIR}/ffmpeg/lib/xvidcore.dll']
439     windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
440     allinstall += windlls
441
442 installtarget = env.Alias('install', allinstall)
443 bininstalltarget = env.Alias('install-bin', blenderinstall)
444
445 if env['WITH_BF_PLAYER']:
446     blenderplayer = env.Alias('blenderplayer', B.program_list)
447     Depends(blenderplayer,installtarget)
448
449 if not env['WITH_BF_GAMEENGINE']:
450     blendernogame = env.Alias('blendernogame', B.program_list)
451     Depends(blendernogame,installtarget)
452
453 Default(B.program_list)
454 Default(installtarget)
455
456 #------------ RELEASE
457 # TODO: zipup the installation
458
459 #------------ BLENDERPLAYER
460 # TODO: build stubs and link into blenderplayer
461
462 #------------ EPYDOC
463 # TODO: run epydoc
464