3 # TTimo <ttimo@idsoftware.com>
4 # http://scons.sourceforge.net
6 import sys, os, time, commands, re, pickle, StringIO, popen2, commands, pdb, zipfile, string
9 sys.path.append( 'sys/scons' )
12 conf_filename='site.conf'
13 # choose configuration variables which should be saved between runs
14 # ( we handle all those as strings )
15 serialized=['CC', 'CXX', 'JOBS', 'BUILD', 'IDNET_HOST', 'GL_HARDLINK', 'DEDICATED',
16 'DEBUG_MEMORY', 'LIBC_MALLOC', 'ID_NOLANADDRESS', 'ID_MCHECK', 'ALSA',
17 'TARGET_CORE', 'TARGET_GAME', 'TARGET_D3XP', 'TARGET_MONO', 'TARGET_DEMO', 'NOCURL',
18 'BUILD_ROOT', 'BUILD_GAMEPAK', 'BASEFLAGS', 'SILENT' ]
20 # global build mode ------------------------------
22 g_sdk = not os.path.exists( 'sys/scons/SConscript.core' )
24 # ------------------------------------------------
26 # help -------------------------------------------
29 Usage: scons [OPTIONS] [TARGET] [CONFIG]
31 [OPTIONS] and [TARGET] are covered in command line options, use scons -H
33 [CONFIG]: KEY="VALUE" [...]
34 a number of configuration options saved between runs in the """ + conf_filename + """ file
35 erase """ + conf_filename + """ to start with default settings again
39 Specify C and C++ compilers (defaults gcc and g++)
41 You can use ccache and distcc, for instance:
42 CC="ccache distcc gcc" CXX="ccache distcc g++"
48 Use debug-all/debug/release to select build settings
50 debug-all: no optimisations, debugging symbols
52 release: all optimisations, including CPU target etc.
54 BUILD_ROOT (default 'build')
55 change the build root directory
57 TARGET_GAME (default 1)
58 Build the base game code
60 TARGET_D3XP (default 1)
61 Build the d3xp game code
63 BUILD_GAMEPAK (default 0)
66 BASEFLAGS (default '')
69 NOCONF (default 0, not saved)
70 ignore site configuration and use defaults + command line only
72 SILENT ( default 0, saved )
73 hide the compiler output, unless error
79 Control regular / dedicated type of build:
84 TARGET_CORE (default 1)
87 TARGET_MONO (default 0)
88 Build a monolithic binary
90 TARGET_DEMO (default 0)
91 Build demo client ( both a core and game, no mono )
92 NOTE: if you *only* want the demo client, set TARGET_CORE and TARGET_GAME to 0
94 IDNET_HOST (default to source hardcoded)
95 Override builtin IDNET_HOST with your own settings
97 GL_HARDLINK (default 0)
98 Instead of dynamically loading the OpenGL libraries, use implicit dependencies
99 NOTE: no GL logging capability and no r_glDriver with GL_HARDLINK 1
101 DEBUG_MEMORY (default 0)
102 Enables memory logging to file
104 LIBC_MALLOC (default 1)
105 Toggle idHeap memory / libc malloc usage
106 When libc malloc is on, memory size statistics are wrong ( no _msize )
108 ID_NOLANADDRESS (default 0)
109 Don't recognize any IP as LAN address. This is useful when debugging network
110 code where LAN / not LAN influences application behaviour
112 ID_MCHECK (default 2)
113 Perform heap consistency checking
114 0: on in Debug / off in Release
115 1 forces on, 2 forces off
116 note that Doom has it's own block allocator/checking
117 this should not be considered a replacement, but an additional tool
120 enable ALSA sound backend support
122 SETUP (default 0, not saved)
123 build a setup. implies release build
125 SDK (default 0, not saved)
129 set to 1 to disable usage of libcurl and http/ftp downloads feature
134 # end help ---------------------------------------
136 # sanity -----------------------------------------
138 EnsureSConsVersion( 0, 96 )
140 # end sanity -------------------------------------
142 # system detection -------------------------------
145 cpu = commands.getoutput('uname -m')
146 exp = re.compile('.*i?86.*')
150 cpu = commands.getoutput('uname -p')
151 if ( cpu == 'powerpc' ):
157 # end system detection ---------------------------
159 # default settings -------------------------------
175 ID_NOLANADDRESS = '0'
187 # end default settings ---------------------------
189 # site settings ----------------------------------
191 if ( not ARGUMENTS.has_key( 'NOCONF' ) or ARGUMENTS['NOCONF'] != '1' ):
193 if (os.path.exists(conf_filename)):
194 site_file = open(conf_filename, 'r')
195 p = pickle.Unpickler(site_file)
197 print 'Loading build configuration from ' + conf_filename + ':'
198 for k, v in site_dict.items():
199 exec_cmd = k + '=\'' + v + '\''
203 print 'Site settings ignored'
205 # end site settings ------------------------------
207 # command line settings --------------------------
209 for k in ARGUMENTS.keys():
210 exec_cmd = k + '=\'' + ARGUMENTS[k] + '\''
211 print 'Command line: ' + exec_cmd
214 # end command line settings ----------------------
216 # save site configuration ----------------------
218 if ( not ARGUMENTS.has_key( 'NOCONF' ) or ARGUMENTS['NOCONF'] != '1' ):
220 exec_cmd = 'site_dict[\'' + k + '\'] = ' + k
223 site_file = open(conf_filename, 'w')
224 p = pickle.Pickler(site_file)
228 # end save site configuration ------------------
230 # configuration rules --------------------------
236 if ( g_sdk or SDK != '0' ):
243 # end configuration rules ----------------------
245 # general configuration, target selection --------
247 g_build = BUILD_ROOT + '/' + BUILD
249 SConsignFile( 'scons.signatures' )
251 if ( GL_HARDLINK != '0' ):
252 g_build += '-hardlink'
254 if ( DEBUG_MEMORY != '0' ):
255 g_build += '-debugmem'
257 if ( LIBC_MALLOC != '1' ):
258 g_build += '-nolibcmalloc'
260 SetOption('num_jobs', JOBS)
265 # BASE + CORE + OPT for engine
266 # BASE + GAME + OPT for game
267 # _noopt versions of the environements are built without the OPT
277 # for release build, further optimisations that may not work on all files
280 BASECPPFLAGS.append( BASEFLAGS )
281 BASECPPFLAGS.append( '-pipe' )
283 BASECPPFLAGS.append( '-Wall' )
284 BASECPPFLAGS.append( '-Wno-unknown-pragmas' )
285 # this define is necessary to make sure threading support is enabled in X
286 CORECPPFLAGS.append( '-DXTHREADS' )
287 # don't wrap gcc messages
288 BASECPPFLAGS.append( '-fmessage-length=0' )
290 BASECPPFLAGS.append( '-fpermissive' )
292 if ( g_os == 'Linux' ):
293 # gcc 4.x option only - only export what we mean to from the game SO
294 BASECPPFLAGS.append( '-fvisibility=hidden' )
295 # get the 64 bits machine on the distcc array to produce 32 bit binaries :)
296 BASECPPFLAGS.append( '-m32' )
297 BASELINKFLAGS.append( '-m32' )
299 if ( g_sdk or SDK != '0' ):
300 BASECPPFLAGS.append( '-D_D3SDK' )
302 if ( BUILD == 'debug-all' ):
303 OPTCPPFLAGS = [ '-g', '-D_DEBUG' ]
304 if ( ID_MCHECK == '0' ):
306 elif ( BUILD == 'debug' ):
307 OPTCPPFLAGS = [ '-g', '-O1', '-D_DEBUG' ]
308 if ( ID_MCHECK == '0' ):
310 elif ( BUILD == 'release' ):
311 # -fomit-frame-pointer: "-O also turns on -fomit-frame-pointer on machines where doing so does not interfere with debugging."
312 # on x86 have to set it explicitely
313 # -finline-functions: implicit at -O3
314 # -fschedule-insns2: implicit at -O2
315 # no-unsafe-math-optimizations: that should be on by default really. hit some wonko bugs in physics code because of that
316 OPTCPPFLAGS = [ '-O3', '-march=pentium3', '-Winline', '-ffast-math', '-fno-unsafe-math-optimizations', '-fomit-frame-pointer' ]
317 if ( ID_MCHECK == '0' ):
320 print 'Unknown build configuration ' + BUILD
323 if ( GL_HARDLINK != '0' ):
324 CORECPPFLAGS.append( '-DID_GL_HARDLINK' )
326 if ( DEBUG_MEMORY != '0' ):
327 BASECPPFLAGS += [ '-DID_DEBUG_MEMORY', '-DID_REDIRECT_NEWDELETE' ]
329 if ( LIBC_MALLOC != '1' ):
330 BASECPPFLAGS.append( '-DUSE_LIBC_MALLOC=0' )
332 if ( len( IDNET_HOST ) ):
333 CORECPPFLAGS.append( '-DIDNET_HOST=\\"%s\\"' % IDNET_HOST)
335 if ( ID_NOLANADDRESS != '0' ):
336 CORECPPFLAGS.append( '-DID_NOLANADDRESS' )
338 if ( ID_MCHECK == '1' ):
339 BASECPPFLAGS.append( '-DID_MCHECK' )
341 # create the build environements
342 g_base_env = Environment( ENV = os.environ, CC = CC, CXX = CXX, LINK = LINK, CPPFLAGS = BASECPPFLAGS, LINKFLAGS = BASELINKFLAGS, CPPPATH = CORECPPPATH, LIBPATH = CORELIBPATH )
343 scons_utils.SetupUtils( g_base_env )
345 g_env = g_base_env.Clone()
347 g_env['CPPFLAGS'] += OPTCPPFLAGS
348 g_env['CPPFLAGS'] += CORECPPFLAGS
349 g_env['LINKFLAGS'] += CORELINKFLAGS
351 g_env_noopt = g_base_env.Clone()
352 g_env_noopt['CPPFLAGS'] += CORECPPFLAGS
354 g_game_env = g_base_env.Clone()
355 g_game_env['CPPFLAGS'] += OPTCPPFLAGS
356 g_game_env['CPPFLAGS'] += GAMECPPFLAGS
358 # maintain this dangerous optimization off at all times
359 g_env.Append( CPPFLAGS = '-fno-strict-aliasing' )
360 g_env_noopt.Append( CPPFLAGS = '-fno-strict-aliasing' )
361 g_game_env.Append( CPPFLAGS = '-fno-strict-aliasing' )
363 if ( int(JOBS) > 1 ):
364 print 'Using buffered process output'
366 if ( SILENT == '1' ):
368 scons_utils.SetupBufferedOutput( g_env, silent )
369 scons_utils.SetupBufferedOutput( g_game_env, silent )
374 # 0 for monolithic build
376 # carry around rather than using .a, avoids binutils bugs
380 # curl usage. there is a global toggle flag
383 # if idlib should produce PIC objects ( depending on core or game inclusion )
385 # switch between base game build and d3xp game build
388 GLOBALS = 'g_env g_env_noopt g_game_env g_os ID_MCHECK ALSA idlib_objects game_objects local_dedicated local_gamedll local_demo local_idlibpic curl_lib local_curl local_d3xp OPTCPPFLAGS'
390 # end general configuration ----------------------
392 # targets ----------------------------------------
394 Export( 'GLOBALS ' + GLOBALS )
403 # build curl if needed
404 if ( NOCURL == '0' and ( TARGET_CORE == '1' or TARGET_MONO == '1' ) ):
405 # 1: debug, 2: release
406 if ( BUILD == 'release' ):
410 Export( 'GLOBALS ' + GLOBALS )
411 curl_lib = SConscript( 'sys/scons/SConscript.curl' )
413 if ( TARGET_CORE == '1' ):
417 if ( DEDICATED == '0' or DEDICATED == '2' ):
419 Export( 'GLOBALS ' + GLOBALS )
421 VariantDir( g_build + '/core/glimp', '.', duplicate = 1 )
422 SConscript( g_build + '/core/glimp/sys/scons/SConscript.gl' )
423 VariantDir( g_build + '/core', '.', duplicate = 0 )
424 idlib_objects = SConscript( g_build + '/core/sys/scons/SConscript.idlib' )
425 Export( 'GLOBALS ' + GLOBALS ) # update idlib_objects
426 doom = SConscript( g_build + '/core/sys/scons/SConscript.core' )
428 InstallAs( '#doom.' + cpu, doom )
430 if ( DEDICATED == '1' or DEDICATED == '2' ):
432 Export( 'GLOBALS ' + GLOBALS )
434 VariantDir( g_build + '/dedicated/glimp', '.', duplicate = 1 )
435 SConscript( g_build + '/dedicated/glimp/sys/scons/SConscript.gl' )
436 VariantDir( g_build + '/dedicated', '.', duplicate = 0 )
437 idlib_objects = SConscript( g_build + '/dedicated/sys/scons/SConscript.idlib' )
438 Export( 'GLOBALS ' + GLOBALS )
439 doomded = SConscript( g_build + '/dedicated/sys/scons/SConscript.core' )
441 InstallAs( '#doomded.' + cpu, doomded )
443 if ( TARGET_GAME == '1' or TARGET_D3XP == '1' ):
448 Export( 'GLOBALS ' + GLOBALS )
451 # building an SDK, use scons for dependencies walking
452 # clear the build directory to be safe
453 g_env.PreBuildSDK( [ g_build + '/game', g_build + '/d3xp' ] )
455 VariantDir( g_build + '/game', '.', duplicate = dupe )
456 idlib_objects = SConscript( g_build + '/game/sys/scons/SConscript.idlib' )
457 if ( TARGET_GAME == '1' ):
459 Export( 'GLOBALS ' + GLOBALS )
460 game = SConscript( g_build + '/game/sys/scons/SConscript.game' )
461 game_base = InstallAs( '#game%s-base.so' % cpu, game )
462 if ( BUILD_GAMEPAK == '1' ):
463 Command( '#game01-base.pk4', [ game_base, game ], Action( g_env.BuildGamePak ) )
464 if ( TARGET_D3XP == '1' ):
465 # uses idlib as compiled for game/
467 VariantDir( g_build + '/d3xp', '.', duplicate = dupe )
468 Export( 'GLOBALS ' + GLOBALS )
469 d3xp = SConscript( g_build + '/d3xp/sys/scons/SConscript.game' )
470 game_d3xp = InstallAs( '#game%s-d3xp.so' % cpu, d3xp )
471 if ( BUILD_GAMEPAK == '1' ):
472 Command( '#game01-d3xp.pk4', [ game_d3xp, d3xp ], Action( g_env.BuildGamePak ) )
474 if ( TARGET_MONO == '1' ):
475 # NOTE: no D3XP atm. add a TARGET_MONO_D3XP
481 Export( 'GLOBALS ' + GLOBALS )
482 VariantDir( g_build + '/mono/glimp', '.', duplicate = 1 )
483 SConscript( g_build + '/mono/glimp/sys/scons/SConscript.gl' )
484 VariantDir( g_build + '/mono', '.', duplicate = 0 )
485 idlib_objects = SConscript( g_build + '/mono/sys/scons/SConscript.idlib' )
486 game_objects = SConscript( g_build + '/mono/sys/scons/SConscript.game' )
487 Export( 'GLOBALS ' + GLOBALS )
488 doom_mono = SConscript( g_build + '/mono/sys/scons/SConscript.core' )
489 InstallAs( '#doom-mon.' + cpu, doom_mono )
491 if ( TARGET_DEMO == '1' ):
492 # NOTE: no D3XP atm. add a TARGET_DEMO_D3XP
500 Export( 'GLOBALS ' + GLOBALS )
501 VariantDir( g_build + '/demo/glimp', '.', duplicate = 1 )
502 SConscript( g_build + '/demo/glimp/sys/scons/SConscript.gl' )
503 VariantDir( g_build + '/demo', '.', duplicate = 0 )
504 idlib_objects = SConscript( g_build + '/demo/sys/scons/SConscript.idlib' )
505 Export( 'GLOBALS ' + GLOBALS )
506 doom_demo = SConscript( g_build + '/demo/sys/scons/SConscript.core' )
508 InstallAs( '#doom-demo.' + cpu, doom_demo )
511 Export( 'GLOBALS ' + GLOBALS )
512 VariantDir( g_build + '/demo/game', '.', duplicate = 0 )
513 idlib_objects = SConscript( g_build + '/demo/game/sys/scons/SConscript.idlib' )
514 Export( 'GLOBALS ' + GLOBALS )
515 game_demo = SConscript( g_build + '/demo/game/sys/scons/SConscript.game' )
517 InstallAs( '#game%s-demo.so' % cpu, game_demo )
520 brandelf = Program( 'brandelf', 'sys/linux/setup/brandelf.c' )
521 if ( TARGET_CORE == '1' and TARGET_GAME == '1' and TARGET_D3XP == '1' ):
522 setup = Command( 'setup', [ brandelf, doom, doomded, game, d3xp ], Action( g_env.BuildSetup ) )
524 print 'Skipping main setup: TARGET_CORE == 0 or TARGET_GAME == 0'
525 if ( TARGET_DEMO == '1' ):
526 setup_demo = Command( 'setup-demo', [ brandelf, doom_demo, game_demo ], Action( g_env.BuildSetup ) )
527 # if building two setups, make sure JOBS doesn't parallelize them
529 g_env.Depends( setup_demo, setup )
533 print 'Skipping demo setup ( TARGET_DEMO == 0 )'
536 setup_sdk = Command( 'sdk', [ ], Action( g_env.BuildSDK ) )
537 g_env.Depends( setup_sdk, [ game, d3xp ] )
539 # end targets ------------------------------------