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