==SCons==
[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 cc = B.arguments.get('CC', None)
120 cxx = B.arguments.get('CXX', None)
121 if cc:
122         env['CC'] = cc
123 if cxx:
124         env['CXX'] = cxx
125
126 if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32':
127     platform = 'win32-vc'
128 elif env['CC'] in ['gcc'] and sys.platform=='win32':
129     platform = 'win32-mingw'
130
131 crossbuild = B.arguments.get('BF_CROSS', None)
132 if crossbuild and platform!='win32':
133     platform = 'linuxcross'
134
135 env['OURPLATFORM'] = platform
136
137 configfile = B.arguments.get('BF_CONFIG', 'config'+os.sep+platform+'-config.py')
138
139 if os.path.exists(configfile):
140     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile
141 else:
142     print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC
143
144 if crossbuild and env['PLATFORM'] != 'win32':
145     print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC
146     env.Tool('crossmingw', ['tools'])
147     # todo: determine proper libs/includes etc.
148     # Needed for gui programs, console programs should do without it
149     env.Append(LINKFLAGS=['-mwindows'])
150
151 # first read platform config. B.arguments will override
152 optfiles = [configfile]
153 if os.path.exists('user-config.py'):
154     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py'
155     optfiles += ['user-config.py']
156 else:
157     print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC
158
159 opts = btools.read_opts(optfiles, B.arguments)
160 opts.Update(env)
161
162 #check for additional debug libnames
163
164 if env.has_key('BF_DEBUG_LIBS'):
165         B.quickdebug += env['BF_DEBUG_LIBS']
166
167 printdebug = B.arguments.get('BF_LISTDEBUG', 0)
168
169 if len(B.quickdebug) > 0 and printdebug != 0:
170         print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC
171         for l in B.quickdebug:
172                 print "\t" + l
173
174 # check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline
175 if 'blenderplayer' in B.targets:
176     env['WITH_BF_PLAYER'] = True
177
178 if 'blendernogame' in B.targets:
179     env['WITH_BF_GAMEENGINE'] = False
180
181 # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
182 #B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep)
183 B.root_build_dir = env['BF_BUILDDIR']
184 env['BUILDDIR'] = B.root_build_dir
185 if not B.root_build_dir[-1]==os.sep:
186     B.root_build_dir += os.sep
187
188 # We do a shortcut for clean when no quicklist is given: just delete
189 # builddir without reading in SConscripts
190 do_clean = None
191 if 'clean' in B.targets:
192     do_clean = True
193
194 if not quickie and do_clean:
195     print B.bc.HEADER+'Cleaning...'+B.bc.ENDC
196     dirs = os.listdir(B.root_build_dir)
197     for dir in dirs:
198         if os.path.isdir(B.root_build_dir + dir) == 1:
199             print "clean dir %s"%(B.root_build_dir+dir)
200             shutil.rmtree(B.root_build_dir+dir)
201     print B.bc.OKGREEN+'...done'+B.bc.ENDC
202     Exit()
203
204 if not os.path.isdir ( B.root_build_dir):
205     os.makedirs ( B.root_build_dir )
206     os.makedirs ( B.root_build_dir + 'source' )
207     os.makedirs ( B.root_build_dir + 'intern' )
208     os.makedirs ( B.root_build_dir + 'extern' )
209     os.makedirs ( B.root_build_dir + 'lib' )
210     os.makedirs ( B.root_build_dir + 'bin' )
211
212 Help(opts.GenerateHelpText(env))
213
214 # default is new quieter output, but if you need to see the 
215 # commands, do 'scons BF_QUIET=0'
216 bf_quietoutput = B.arguments.get('BF_QUIET', '1')
217 if bf_quietoutput=='1':
218     B.set_quiet_output(env)
219 else:
220     if toolset=='msvc':
221         B.msvc_hack(env)
222
223 print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir
224 env.SConsignFile(B.root_build_dir+'scons-signatures')
225 B.init_lib_dict()
226
227 ##### END SETUP ##########
228
229 Export('env')
230 #Export('root_build_dir') # this one is still needed for makesdna
231 ##TODO: improve makesdna usage
232
233 BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
234 SConscript(B.root_build_dir+'/intern/SConscript')
235 BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
236 SConscript(B.root_build_dir+'/extern/SConscript')
237 BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
238 SConscript(B.root_build_dir+'/source/SConscript')
239
240 # now that we have read all SConscripts, we know what
241 # libraries will be built. Create list of
242 # libraries to give as objects to linking phase
243 mainlist = []
244 for tp in B.possible_types:
245     if not tp == 'player' and not tp == 'player2':
246         mainlist += B.create_blender_liblist(env, tp)
247
248 if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
249     B.propose_priorities()
250
251 dobj = B.buildinfo(env, "dynamic") + B.resources
252 thestatlibs, thelibincs = B.setup_staticlibs(env)
253 thesyslibs = B.setup_syslibs(env)
254
255 env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
256 if env['WITH_BF_PLAYER']:
257     playerlist = B.create_blender_liblist(env, 'player')
258     env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
259
260 ##### Now define some targets
261
262
263 #------------ INSTALL
264
265 blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list)
266
267 #-- .blender
268 dotblendlist = []
269 dottargetlist = []
270 for dp, dn, df in os.walk('bin/.blender'):
271     if 'CVS' in dn:
272         dn.remove('CVS')
273     for f in df:
274         dotblendlist.append(dp+os.sep+f)
275         dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f)
276
277 dotblenderinstall = []
278 for targetdir,srcfile in zip(dottargetlist, dotblendlist):
279     td, tf = os.path.split(targetdir)
280     dotblenderinstall.append(env.Install(dir=td, source=srcfile))
281
282 #-- .blender/scripts
283 scriptlist = glob.glob('release/scripts/*.py')
284 scriptinstall = env.Install(dir=env['BF_INSTALLDIR']+'/.blender/scripts', source=scriptlist)
285
286 #-- plugins
287 pluglist = []
288 plugtargetlist = []
289 for tp, tn, tf in os.walk('release/plugins'):
290     if 'CVS' in tn:
291         tn.remove('CVS')
292     for f in tf:
293         pluglist.append(tp+os.sep+f)
294         plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f)
295
296 plugininstall = []
297 for targetdir,srcfile in zip(plugtargetlist, pluglist):
298     td, tf = os.path.split(targetdir)
299     plugininstall.append(env.Install(dir=td, source=srcfile))
300
301 textlist = []
302 texttargetlist = []
303 for tp, tn, tf in os.walk('release/text'):
304     if 'CVS' in tn:
305         tn.remove('CVS')
306     for f in tf:
307         textlist.append(tp+os.sep+f)
308
309 textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
310
311 allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall]
312
313 if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
314     dllsources = ['#../lib/windows/gettext/lib/gnu_gettext.dll',
315                         '#../lib/windows/png/lib/libpng.dll',
316                         '#../lib/windows/python/lib/python24.dll',
317                         '#../lib/windows/sdl/lib/SDL.dll',
318                         '#../lib/windows/zlib/lib/zlib.dll']
319     if env['OURPLATFORM'] == 'win32-mingw':
320         dllsources += ['#../lib/windows/pthreads/lib/pthreadGC2.dll']
321     else:
322         dllsources += ['#../lib/windows/pthreads/lib/pthreadVC2.dll']
323     windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
324     allinstall += windlls
325
326 installtarget = env.Alias('install', allinstall)
327 bininstalltarget = env.Alias('install-bin', blenderinstall)
328
329 if env['WITH_BF_PLAYER']:
330     blenderplayer = env.Alias('blenderplayer', B.program_list)
331     Depends(blenderplayer,installtarget)
332
333 if not env['WITH_BF_GAMEENGINE']:
334     blendernogame = env.Alias('blendernogame', B.program_list)
335     Depends(blendernogame,installtarget)
336
337
338 Default(B.program_list)
339 Default(installtarget)
340
341 #------------ RELEASE
342 # TODO: zipup the installation
343
344 #------------ BLENDERPLAYER
345 # TODO: build stubs and link into blenderplayer
346
347 #------------ EPYDOC
348 # TODO: run epydoc
349