==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) 2001-2002 by NaN Holding BV.
23 # All rights reserved.
24 #
25 # The Original Code is: none 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
42 import tools.Blender
43 import tools.btools
44 import tools.bcolors
45
46 BlenderEnvironment = tools.Blender.BlenderEnvironment
47 btools = tools.btools
48 B = tools.Blender
49
50 ### globals ###
51 platform = sys.platform
52 quickie = None
53
54 ##### BEGIN SETUP #####
55
56 B.possible_types = ['core', 'common', 'blender', 'intern',
57                     'international', 'game', 'game2',
58                     'player', 'player2', 'system']
59
60 B.binarykind = ['blender' , 'blenderplayer']
61 ##################################
62 # target and argument validation #
63 ##################################
64 # XX cheating for BF_FANCY, we check for BF_FANCY before args are validated
65 use_color = ARGUMENTS.get('BF_FANCY', '1')
66 if platform=='win32':
67     use_color = None
68
69 if not use_color=='1':
70     B.bc.disable()
71
72 # arguments
73 print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC
74 B.arguments = btools.validate_arguments(ARGUMENTS, B.bc)
75 btools.print_arguments(B.arguments, B.bc)
76
77 # targets
78 print B.bc.HEADER+'Command-line targets'+B.bc.ENDC
79 B.targets = btools.validate_targets(COMMAND_LINE_TARGETS, B.bc)
80 btools.print_targets(B.targets, B.bc)
81
82 ##########################
83 # setting up environment #
84 ##########################
85
86 # handling cmd line arguments & config file
87
88 # first check cmdline for toolset and we create env to work on
89 quickie = B.arguments.get('BF_QUICK', None)
90 if quickie:
91     B.quickie=string.split(quickie,',')
92 else:
93     B.quickie=[]
94
95 toolset = B.arguments.get('BF_TOOLSET', None)
96 if toolset:
97     print "Using " + toolset
98     if toolset=='mstoolkit':
99         env = BlenderEnvironment(ENV = os.environ)
100         env.Tool('mstoolkit', ['tools'])
101     else:
102         env = BlenderEnvironment(tools=[toolset], ENV = os.environ)
103 else:
104     env = BlenderEnvironment(ENV = os.environ)
105
106 if not env:
107     print "Could not create a build environment"
108     Exit()
109
110 if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32':
111     platform = 'win32-vc'
112 elif env['CC'] in ['gcc'] and sys.platform=='win32':
113     platform = 'win32-mingw'
114
115 crossbuild = B.arguments.get('BF_CROSS', None)
116 if crossbuild and platform!='win32':
117     platform = 'linuxcross'
118
119 env['OURPLATFORM'] = platform
120
121 configfile = B.arguments.get('BF_CONFIG', 'config'+os.sep+platform+'-config.py')
122
123 if os.path.exists(configfile):
124     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile
125 else:
126     print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC
127
128 if crossbuild and env['PLATFORM'] != 'win32':
129     print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC
130     env.Tool('crossmingw', ['tools'])
131     # todo: determine proper libs/includes etc.
132     # Needed for gui programs, console programs should do without it
133     env.Append(LINKFLAGS=['-mwindows'])
134
135 # first read platform config. B.arguments will override
136 optfiles = [configfile]
137 if os.path.exists('user-config.py'):
138     print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py'
139     optfiles += ['user-config.py']
140 else:
141     print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC
142
143 opts = btools.read_opts(optfiles, B.arguments)
144 opts.Update(env)
145
146 # check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline
147 if 'blenderplayer' in B.targets:
148     env['WITH_BF_PLAYER'] = True
149
150 if 'blendernogame' in B.targets:
151     env['WITH_BF_GAMEENGINE'] = False
152
153 # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
154 #B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep)
155 B.root_build_dir = env['BF_BUILDDIR']
156 env['BUILDDIR'] = B.root_build_dir
157 if not B.root_build_dir[-1]==os.sep:
158     B.root_build_dir += os.sep
159
160 # We do a shortcut for clean when no quicklist is given: just delete
161 # builddir without reading in SConscripts
162 do_clean = None
163 if 'clean' in B.targets:
164     do_clean = True
165
166 if not quickie and do_clean:
167     print B.bc.HEADER+'Cleaning...'+B.bc.ENDC
168     dirs = os.listdir(B.root_build_dir)
169     for dir in dirs:
170         if os.path.isdir(B.root_build_dir + dir) == 1:
171             print "clean dir %s"%(B.root_build_dir+dir)
172             shutil.rmtree(B.root_build_dir+dir)
173     print B.bc.OKGREEN+'...done'+B.bc.ENDC
174     Exit()
175
176 if not os.path.isdir ( B.root_build_dir):
177     os.makedirs ( B.root_build_dir )
178     os.makedirs ( B.root_build_dir + 'source' )
179     os.makedirs ( B.root_build_dir + 'intern' )
180     os.makedirs ( B.root_build_dir + 'extern' )
181     os.makedirs ( B.root_build_dir + 'lib' )
182     os.makedirs ( B.root_build_dir + 'bin' )
183
184 Help(opts.GenerateHelpText(env))
185
186 # default is new quieter output, but if you need to see the 
187 # commands, do 'scons BF_QUIET=0'
188 bf_quietoutput = B.arguments.get('BF_QUIET', '1')
189 if bf_quietoutput=='1':
190     B.set_quiet_output(env)
191 else:
192     if toolset=='msvc':
193         B.msvc_hack(env)
194
195 print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir
196 env.SConsignFile(B.root_build_dir+'scons-signatures')
197 B.init_lib_dict()
198
199 ##### END SETUP ##########
200
201 Export('env')
202 #Export('root_build_dir') # this one is still needed for makesdna
203 ##TODO: improve makesdna usage
204
205 BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
206 SConscript(B.root_build_dir+'/intern/SConscript')
207 BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
208 SConscript(B.root_build_dir+'/extern/SConscript')
209 BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
210 SConscript(B.root_build_dir+'/source/SConscript')
211
212 # now that we have read all SConscripts, we know what
213 # libraries will be built. Create list of
214 # libraries to give as objects to linking phase
215 mainlist = []
216 for tp in B.possible_types:
217     if not tp == 'player' and not tp == 'player2':
218         mainlist += B.create_blender_liblist(env, tp)
219
220 if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
221     B.propose_priorities()
222
223 dobj = B.buildinfo(env, "dynamic")
224 thestatlibs, thelibincs = B.setup_staticlibs(env)
225 thesyslibs = B.setup_syslibs(env)
226
227 env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
228 if env['WITH_BF_PLAYER']:
229     playerlist = B.create_blender_liblist(env, 'player')
230     playerlist += B.create_blender_liblist(env, 'core')
231     playerlist += B.create_blender_liblist(env, 'common')
232     playerlist += B.create_blender_liblist(env, 'intern')
233     playerlist += B.create_blender_liblist(env, 'international')
234     playerlist += B.create_blender_liblist(env, 'game')
235     playerlist += B.create_blender_liblist(env, 'game2')
236     playerlist += B.create_blender_liblist(env, 'player2')
237     env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
238
239 ##### Now define some targets
240
241
242 #------------ INSTALL
243
244 blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list)
245
246 #-- .blender
247 dotblendlist = []
248 dottargetlist = []
249 for dp, dn, df in os.walk('bin/.blender'):
250     if 'CVS' in dn:
251         dn.remove('CVS')
252     for f in df:
253         dotblendlist.append(dp+os.sep+f)
254         dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f)
255
256 dotblenderinstall = []
257 for targetdir,srcfile in zip(dottargetlist, dotblendlist):
258     td, tf = os.path.split(targetdir)
259     dotblenderinstall.append(env.Install(dir=td, source=srcfile))
260
261 #-- .blender/scripts
262 scriptlist = glob.glob('release/scripts/*.py')
263 scriptinstall = env.Install(dir=env['BF_INSTALLDIR']+'/.blender/scripts', source=scriptlist)
264
265 #-- plugins
266 pluglist = []
267 plugtargetlist = []
268 for tp, tn, tf in os.walk('release/plugins'):
269     if 'CVS' in tn:
270         tn.remove('CVS')
271     for f in tf:
272         pluglist.append(tp+os.sep+f)
273         plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f)
274
275 plugininstall = []
276 for targetdir,srcfile in zip(plugtargetlist, pluglist):
277     td, tf = os.path.split(targetdir)
278     plugininstall.append(env.Install(dir=td, source=srcfile))
279
280 textlist = []
281 texttargetlist = []
282 for tp, tn, tf in os.walk('release/text'):
283     if 'CVS' in tn:
284         tn.remove('CVS')
285     for f in tf:
286         textlist.append(tp+os.sep+f)
287
288 textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
289
290 allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall]
291
292 if sys.platform=='win32':
293     # TODO: gather all needed dlls from lib/windows for inclusion in install
294     windlls = []
295     allinstall += windlls
296
297 installtarget = env.Alias('install', allinstall)
298 bininstalltarget = env.Alias('install-bin', blenderinstall)
299
300 if env['WITH_BF_PLAYER']:
301     blenderplayer = env.Alias('blenderplayer', B.program_list)
302
303 if not env['WITH_BF_GAMEENGINE']:
304     blendernogame = env.Alias('blendernogame', B.program_list)
305
306 Default(B.program_list)
307 Default(installtarget)
308
309 #------------ RELEASE
310 # TODO: zipup the installation
311
312 #------------ BLENDERPLAYER
313 # TODO: build stubs and link into blenderplayer
314
315 #------------ EPYDOC
316 # TODO: run epydoc
317