SConstruct 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. # -*- mode: python -*-
  2. # DOOM build script
  3. # TTimo <ttimo@idsoftware.com>
  4. # http://scons.sourceforge.net
  5. import sys, os, time, commands, re, pickle, StringIO, popen2, commands, pdb, zipfile, string
  6. import SCons
  7. sys.path.append( 'sys/scons' )
  8. import scons_utils
  9. conf_filename='site.conf'
  10. # choose configuration variables which should be saved between runs
  11. # ( we handle all those as strings )
  12. serialized=['CC', 'CXX', 'JOBS', 'BUILD', 'IDNET_HOST', 'GL_HARDLINK', 'DEDICATED',
  13. 'DEBUG_MEMORY', 'LIBC_MALLOC', 'ID_NOLANADDRESS', 'ID_MCHECK', 'ALSA',
  14. 'TARGET_CORE', 'TARGET_GAME', 'TARGET_D3XP', 'TARGET_MONO', 'TARGET_DEMO', 'NOCURL',
  15. 'BUILD_ROOT', 'BUILD_GAMEPAK', 'BASEFLAGS', 'SILENT' ]
  16. # global build mode ------------------------------
  17. g_sdk = not os.path.exists( 'sys/scons/SConscript.core' )
  18. # ------------------------------------------------
  19. # help -------------------------------------------
  20. help_string = """
  21. Usage: scons [OPTIONS] [TARGET] [CONFIG]
  22. [OPTIONS] and [TARGET] are covered in command line options, use scons -H
  23. [CONFIG]: KEY="VALUE" [...]
  24. a number of configuration options saved between runs in the """ + conf_filename + """ file
  25. erase """ + conf_filename + """ to start with default settings again
  26. CC (default gcc)
  27. CXX (default g++)
  28. Specify C and C++ compilers (defaults gcc and g++)
  29. ex: CC="gcc-3.3"
  30. You can use ccache and distcc, for instance:
  31. CC="ccache distcc gcc" CXX="ccache distcc g++"
  32. JOBS (default 1)
  33. Parallel build
  34. BUILD (default debug)
  35. Use debug-all/debug/release to select build settings
  36. ex: BUILD="release"
  37. debug-all: no optimisations, debugging symbols
  38. debug: -O -g
  39. release: all optimisations, including CPU target etc.
  40. BUILD_ROOT (default 'build')
  41. change the build root directory
  42. TARGET_GAME (default 1)
  43. Build the base game code
  44. TARGET_D3XP (default 1)
  45. Build the d3xp game code
  46. BUILD_GAMEPAK (default 0)
  47. Build a game pak
  48. BASEFLAGS (default '')
  49. Add compile flags
  50. NOCONF (default 0, not saved)
  51. ignore site configuration and use defaults + command line only
  52. SILENT ( default 0, saved )
  53. hide the compiler output, unless error
  54. """
  55. if ( not g_sdk ):
  56. help_string += """
  57. DEDICATED (default 0)
  58. Control regular / dedicated type of build:
  59. 0 - client
  60. 1 - dedicated server
  61. 2 - both
  62. TARGET_CORE (default 1)
  63. Build the core
  64. TARGET_MONO (default 0)
  65. Build a monolithic binary
  66. TARGET_DEMO (default 0)
  67. Build demo client ( both a core and game, no mono )
  68. NOTE: if you *only* want the demo client, set TARGET_CORE and TARGET_GAME to 0
  69. IDNET_HOST (default to source hardcoded)
  70. Override builtin IDNET_HOST with your own settings
  71. GL_HARDLINK (default 0)
  72. Instead of dynamically loading the OpenGL libraries, use implicit dependencies
  73. NOTE: no GL logging capability and no r_glDriver with GL_HARDLINK 1
  74. DEBUG_MEMORY (default 0)
  75. Enables memory logging to file
  76. LIBC_MALLOC (default 1)
  77. Toggle idHeap memory / libc malloc usage
  78. When libc malloc is on, memory size statistics are wrong ( no _msize )
  79. ID_NOLANADDRESS (default 0)
  80. Don't recognize any IP as LAN address. This is useful when debugging network
  81. code where LAN / not LAN influences application behaviour
  82. ID_MCHECK (default 2)
  83. Perform heap consistency checking
  84. 0: on in Debug / off in Release
  85. 1 forces on, 2 forces off
  86. note that Doom has it's own block allocator/checking
  87. this should not be considered a replacement, but an additional tool
  88. ALSA (default 1)
  89. enable ALSA sound backend support
  90. SETUP (default 0, not saved)
  91. build a setup. implies release build
  92. SDK (default 0, not saved)
  93. build an SDK release
  94. NOCURL (default 0)
  95. set to 1 to disable usage of libcurl and http/ftp downloads feature
  96. """
  97. Help( help_string )
  98. # end help ---------------------------------------
  99. # sanity -----------------------------------------
  100. EnsureSConsVersion( 0, 96 )
  101. # end sanity -------------------------------------
  102. # system detection -------------------------------
  103. # CPU type
  104. cpu = commands.getoutput('uname -m')
  105. exp = re.compile('.*i?86.*')
  106. if exp.match(cpu):
  107. cpu = 'x86'
  108. else:
  109. cpu = commands.getoutput('uname -p')
  110. if ( cpu == 'powerpc' ):
  111. cpu = 'ppc'
  112. else:
  113. cpu = 'cpu'
  114. g_os = 'Linux'
  115. # end system detection ---------------------------
  116. # default settings -------------------------------
  117. CC = 'gcc'
  118. CXX = 'g++'
  119. JOBS = '1'
  120. BUILD = 'debug'
  121. DEDICATED = '0'
  122. TARGET_CORE = '1'
  123. TARGET_GAME = '1'
  124. TARGET_D3XP = '1'
  125. TARGET_MONO = '0'
  126. TARGET_DEMO = '0'
  127. IDNET_HOST = ''
  128. GL_HARDLINK = '0'
  129. DEBUG_MEMORY = '0'
  130. LIBC_MALLOC = '1'
  131. ID_NOLANADDRESS = '0'
  132. ID_MCHECK = '2'
  133. BUILD_ROOT = 'build'
  134. ALSA = '1'
  135. SETUP = '0'
  136. SDK = '0'
  137. NOCONF = '0'
  138. NOCURL = '0'
  139. BUILD_GAMEPAK = '0'
  140. BASEFLAGS = ''
  141. SILENT = '0'
  142. # end default settings ---------------------------
  143. # site settings ----------------------------------
  144. if ( not ARGUMENTS.has_key( 'NOCONF' ) or ARGUMENTS['NOCONF'] != '1' ):
  145. site_dict = {}
  146. if (os.path.exists(conf_filename)):
  147. site_file = open(conf_filename, 'r')
  148. p = pickle.Unpickler(site_file)
  149. site_dict = p.load()
  150. print 'Loading build configuration from ' + conf_filename + ':'
  151. for k, v in site_dict.items():
  152. exec_cmd = k + '=\'' + v + '\''
  153. print ' ' + exec_cmd
  154. exec(exec_cmd)
  155. else:
  156. print 'Site settings ignored'
  157. # end site settings ------------------------------
  158. # command line settings --------------------------
  159. for k in ARGUMENTS.keys():
  160. exec_cmd = k + '=\'' + ARGUMENTS[k] + '\''
  161. print 'Command line: ' + exec_cmd
  162. exec( exec_cmd )
  163. # end command line settings ----------------------
  164. # save site configuration ----------------------
  165. if ( not ARGUMENTS.has_key( 'NOCONF' ) or ARGUMENTS['NOCONF'] != '1' ):
  166. for k in serialized:
  167. exec_cmd = 'site_dict[\'' + k + '\'] = ' + k
  168. exec(exec_cmd)
  169. site_file = open(conf_filename, 'w')
  170. p = pickle.Pickler(site_file)
  171. p.dump(site_dict)
  172. site_file.close()
  173. # end save site configuration ------------------
  174. # configuration rules --------------------------
  175. if ( SETUP != '0' ):
  176. DEDICATED = '2'
  177. BUILD = 'release'
  178. if ( g_sdk or SDK != '0' ):
  179. TARGET_CORE = '0'
  180. TARGET_GAME = '1'
  181. TARGET_D3XP = '1'
  182. TARGET_MONO = '0'
  183. TARGET_DEMO = '0'
  184. # end configuration rules ----------------------
  185. # general configuration, target selection --------
  186. g_build = BUILD_ROOT + '/' + BUILD
  187. SConsignFile( 'scons.signatures' )
  188. if ( GL_HARDLINK != '0' ):
  189. g_build += '-hardlink'
  190. if ( DEBUG_MEMORY != '0' ):
  191. g_build += '-debugmem'
  192. if ( LIBC_MALLOC != '1' ):
  193. g_build += '-nolibcmalloc'
  194. SetOption('num_jobs', JOBS)
  195. LINK = CXX
  196. # common flags
  197. # BASE + CORE + OPT for engine
  198. # BASE + GAME + OPT for game
  199. # _noopt versions of the environements are built without the OPT
  200. BASECPPFLAGS = [ ]
  201. CORECPPPATH = [ ]
  202. CORELIBPATH = [ ]
  203. CORECPPFLAGS = [ ]
  204. GAMECPPFLAGS = [ ]
  205. BASELINKFLAGS = [ ]
  206. CORELINKFLAGS = [ ]
  207. # for release build, further optimisations that may not work on all files
  208. OPTCPPFLAGS = [ ]
  209. BASECPPFLAGS.append( BASEFLAGS )
  210. BASECPPFLAGS.append( '-pipe' )
  211. # warn all
  212. BASECPPFLAGS.append( '-Wall' )
  213. BASECPPFLAGS.append( '-Wno-unknown-pragmas' )
  214. # this define is necessary to make sure threading support is enabled in X
  215. CORECPPFLAGS.append( '-DXTHREADS' )
  216. # don't wrap gcc messages
  217. BASECPPFLAGS.append( '-fmessage-length=0' )
  218. # gcc 4.0
  219. BASECPPFLAGS.append( '-fpermissive' )
  220. if ( g_os == 'Linux' ):
  221. # gcc 4.x option only - only export what we mean to from the game SO
  222. BASECPPFLAGS.append( '-fvisibility=hidden' )
  223. # get the 64 bits machine on the distcc array to produce 32 bit binaries :)
  224. BASECPPFLAGS.append( '-m32' )
  225. BASELINKFLAGS.append( '-m32' )
  226. if ( g_sdk or SDK != '0' ):
  227. BASECPPFLAGS.append( '-D_D3SDK' )
  228. if ( BUILD == 'debug-all' ):
  229. OPTCPPFLAGS = [ '-g', '-D_DEBUG' ]
  230. if ( ID_MCHECK == '0' ):
  231. ID_MCHECK = '1'
  232. elif ( BUILD == 'debug' ):
  233. OPTCPPFLAGS = [ '-g', '-O1', '-D_DEBUG' ]
  234. if ( ID_MCHECK == '0' ):
  235. ID_MCHECK = '1'
  236. elif ( BUILD == 'release' ):
  237. # -fomit-frame-pointer: "-O also turns on -fomit-frame-pointer on machines where doing so does not interfere with debugging."
  238. # on x86 have to set it explicitely
  239. # -finline-functions: implicit at -O3
  240. # -fschedule-insns2: implicit at -O2
  241. # no-unsafe-math-optimizations: that should be on by default really. hit some wonko bugs in physics code because of that
  242. OPTCPPFLAGS = [ '-O3', '-march=pentium3', '-Winline', '-ffast-math', '-fno-unsafe-math-optimizations', '-fomit-frame-pointer' ]
  243. if ( ID_MCHECK == '0' ):
  244. ID_MCHECK = '2'
  245. else:
  246. print 'Unknown build configuration ' + BUILD
  247. sys.exit(0)
  248. if ( GL_HARDLINK != '0' ):
  249. CORECPPFLAGS.append( '-DID_GL_HARDLINK' )
  250. if ( DEBUG_MEMORY != '0' ):
  251. BASECPPFLAGS += [ '-DID_DEBUG_MEMORY', '-DID_REDIRECT_NEWDELETE' ]
  252. if ( LIBC_MALLOC != '1' ):
  253. BASECPPFLAGS.append( '-DUSE_LIBC_MALLOC=0' )
  254. if ( len( IDNET_HOST ) ):
  255. CORECPPFLAGS.append( '-DIDNET_HOST=\\"%s\\"' % IDNET_HOST)
  256. if ( ID_NOLANADDRESS != '0' ):
  257. CORECPPFLAGS.append( '-DID_NOLANADDRESS' )
  258. if ( ID_MCHECK == '1' ):
  259. BASECPPFLAGS.append( '-DID_MCHECK' )
  260. # create the build environements
  261. g_base_env = Environment( ENV = os.environ, CC = CC, CXX = CXX, LINK = LINK, CPPFLAGS = BASECPPFLAGS, LINKFLAGS = BASELINKFLAGS, CPPPATH = CORECPPPATH, LIBPATH = CORELIBPATH )
  262. scons_utils.SetupUtils( g_base_env )
  263. g_env = g_base_env.Clone()
  264. g_env['CPPFLAGS'] += OPTCPPFLAGS
  265. g_env['CPPFLAGS'] += CORECPPFLAGS
  266. g_env['LINKFLAGS'] += CORELINKFLAGS
  267. g_env_noopt = g_base_env.Clone()
  268. g_env_noopt['CPPFLAGS'] += CORECPPFLAGS
  269. g_game_env = g_base_env.Clone()
  270. g_game_env['CPPFLAGS'] += OPTCPPFLAGS
  271. g_game_env['CPPFLAGS'] += GAMECPPFLAGS
  272. # maintain this dangerous optimization off at all times
  273. g_env.Append( CPPFLAGS = '-fno-strict-aliasing' )
  274. g_env_noopt.Append( CPPFLAGS = '-fno-strict-aliasing' )
  275. g_game_env.Append( CPPFLAGS = '-fno-strict-aliasing' )
  276. if ( int(JOBS) > 1 ):
  277. print 'Using buffered process output'
  278. silent = False
  279. if ( SILENT == '1' ):
  280. silent = True
  281. scons_utils.SetupBufferedOutput( g_env, silent )
  282. scons_utils.SetupBufferedOutput( g_game_env, silent )
  283. # mark the globals
  284. local_dedicated = 0
  285. # 0 for monolithic build
  286. local_gamedll = 1
  287. # carry around rather than using .a, avoids binutils bugs
  288. idlib_objects = []
  289. game_objects = []
  290. local_demo = 0
  291. # curl usage. there is a global toggle flag
  292. local_curl = 0
  293. curl_lib = []
  294. # if idlib should produce PIC objects ( depending on core or game inclusion )
  295. local_idlibpic = 0
  296. # switch between base game build and d3xp game build
  297. local_d3xp = 0
  298. 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'
  299. # end general configuration ----------------------
  300. # targets ----------------------------------------
  301. Export( 'GLOBALS ' + GLOBALS )
  302. doom = None
  303. doomded = None
  304. game = None
  305. doom_mono = None
  306. doom_demo = None
  307. game_demo = None
  308. # build curl if needed
  309. if ( NOCURL == '0' and ( TARGET_CORE == '1' or TARGET_MONO == '1' ) ):
  310. # 1: debug, 2: release
  311. if ( BUILD == 'release' ):
  312. local_curl = 2
  313. else:
  314. local_curl = 1
  315. Export( 'GLOBALS ' + GLOBALS )
  316. curl_lib = SConscript( 'sys/scons/SConscript.curl' )
  317. if ( TARGET_CORE == '1' ):
  318. local_gamedll = 1
  319. local_demo = 0
  320. local_idlibpic = 0
  321. if ( DEDICATED == '0' or DEDICATED == '2' ):
  322. local_dedicated = 0
  323. Export( 'GLOBALS ' + GLOBALS )
  324. VariantDir( g_build + '/core/glimp', '.', duplicate = 1 )
  325. SConscript( g_build + '/core/glimp/sys/scons/SConscript.gl' )
  326. VariantDir( g_build + '/core', '.', duplicate = 0 )
  327. idlib_objects = SConscript( g_build + '/core/sys/scons/SConscript.idlib' )
  328. Export( 'GLOBALS ' + GLOBALS ) # update idlib_objects
  329. doom = SConscript( g_build + '/core/sys/scons/SConscript.core' )
  330. InstallAs( '#doom.' + cpu, doom )
  331. if ( DEDICATED == '1' or DEDICATED == '2' ):
  332. local_dedicated = 1
  333. Export( 'GLOBALS ' + GLOBALS )
  334. VariantDir( g_build + '/dedicated/glimp', '.', duplicate = 1 )
  335. SConscript( g_build + '/dedicated/glimp/sys/scons/SConscript.gl' )
  336. VariantDir( g_build + '/dedicated', '.', duplicate = 0 )
  337. idlib_objects = SConscript( g_build + '/dedicated/sys/scons/SConscript.idlib' )
  338. Export( 'GLOBALS ' + GLOBALS )
  339. doomded = SConscript( g_build + '/dedicated/sys/scons/SConscript.core' )
  340. InstallAs( '#doomded.' + cpu, doomded )
  341. if ( TARGET_GAME == '1' or TARGET_D3XP == '1' ):
  342. local_gamedll = 1
  343. local_demo = 0
  344. local_dedicated = 0
  345. local_idlibpic = 1
  346. Export( 'GLOBALS ' + GLOBALS )
  347. dupe = 0
  348. if ( SDK == '1' ):
  349. # building an SDK, use scons for dependencies walking
  350. # clear the build directory to be safe
  351. g_env.PreBuildSDK( [ g_build + '/game', g_build + '/d3xp' ] )
  352. dupe = 1
  353. VariantDir( g_build + '/game', '.', duplicate = dupe )
  354. idlib_objects = SConscript( g_build + '/game/sys/scons/SConscript.idlib' )
  355. if ( TARGET_GAME == '1' ):
  356. local_d3xp = 0
  357. Export( 'GLOBALS ' + GLOBALS )
  358. game = SConscript( g_build + '/game/sys/scons/SConscript.game' )
  359. game_base = InstallAs( '#game%s-base.so' % cpu, game )
  360. if ( BUILD_GAMEPAK == '1' ):
  361. Command( '#game01-base.pk4', [ game_base, game ], Action( g_env.BuildGamePak ) )
  362. if ( TARGET_D3XP == '1' ):
  363. # uses idlib as compiled for game/
  364. local_d3xp = 1
  365. VariantDir( g_build + '/d3xp', '.', duplicate = dupe )
  366. Export( 'GLOBALS ' + GLOBALS )
  367. d3xp = SConscript( g_build + '/d3xp/sys/scons/SConscript.game' )
  368. game_d3xp = InstallAs( '#game%s-d3xp.so' % cpu, d3xp )
  369. if ( BUILD_GAMEPAK == '1' ):
  370. Command( '#game01-d3xp.pk4', [ game_d3xp, d3xp ], Action( g_env.BuildGamePak ) )
  371. if ( TARGET_MONO == '1' ):
  372. # NOTE: no D3XP atm. add a TARGET_MONO_D3XP
  373. local_gamedll = 0
  374. local_dedicated = 0
  375. local_demo = 0
  376. local_idlibpic = 0
  377. local_d3xp = 0
  378. Export( 'GLOBALS ' + GLOBALS )
  379. VariantDir( g_build + '/mono/glimp', '.', duplicate = 1 )
  380. SConscript( g_build + '/mono/glimp/sys/scons/SConscript.gl' )
  381. VariantDir( g_build + '/mono', '.', duplicate = 0 )
  382. idlib_objects = SConscript( g_build + '/mono/sys/scons/SConscript.idlib' )
  383. game_objects = SConscript( g_build + '/mono/sys/scons/SConscript.game' )
  384. Export( 'GLOBALS ' + GLOBALS )
  385. doom_mono = SConscript( g_build + '/mono/sys/scons/SConscript.core' )
  386. InstallAs( '#doom-mon.' + cpu, doom_mono )
  387. if ( TARGET_DEMO == '1' ):
  388. # NOTE: no D3XP atm. add a TARGET_DEMO_D3XP
  389. local_demo = 1
  390. local_dedicated = 0
  391. local_gamedll = 1
  392. local_idlibpic = 0
  393. local_curl = 0
  394. local_d3xp = 0
  395. curl_lib = []
  396. Export( 'GLOBALS ' + GLOBALS )
  397. VariantDir( g_build + '/demo/glimp', '.', duplicate = 1 )
  398. SConscript( g_build + '/demo/glimp/sys/scons/SConscript.gl' )
  399. VariantDir( g_build + '/demo', '.', duplicate = 0 )
  400. idlib_objects = SConscript( g_build + '/demo/sys/scons/SConscript.idlib' )
  401. Export( 'GLOBALS ' + GLOBALS )
  402. doom_demo = SConscript( g_build + '/demo/sys/scons/SConscript.core' )
  403. InstallAs( '#doom-demo.' + cpu, doom_demo )
  404. local_idlibpic = 1
  405. Export( 'GLOBALS ' + GLOBALS )
  406. VariantDir( g_build + '/demo/game', '.', duplicate = 0 )
  407. idlib_objects = SConscript( g_build + '/demo/game/sys/scons/SConscript.idlib' )
  408. Export( 'GLOBALS ' + GLOBALS )
  409. game_demo = SConscript( g_build + '/demo/game/sys/scons/SConscript.game' )
  410. InstallAs( '#game%s-demo.so' % cpu, game_demo )
  411. if ( SETUP != '0' ):
  412. brandelf = Program( 'brandelf', 'sys/linux/setup/brandelf.c' )
  413. if ( TARGET_CORE == '1' and TARGET_GAME == '1' and TARGET_D3XP == '1' ):
  414. setup = Command( 'setup', [ brandelf, doom, doomded, game, d3xp ], Action( g_env.BuildSetup ) )
  415. else:
  416. print 'Skipping main setup: TARGET_CORE == 0 or TARGET_GAME == 0'
  417. if ( TARGET_DEMO == '1' ):
  418. setup_demo = Command( 'setup-demo', [ brandelf, doom_demo, game_demo ], Action( g_env.BuildSetup ) )
  419. # if building two setups, make sure JOBS doesn't parallelize them
  420. try:
  421. g_env.Depends( setup_demo, setup )
  422. except:
  423. pass
  424. else:
  425. print 'Skipping demo setup ( TARGET_DEMO == 0 )'
  426. if ( SDK != '0' ):
  427. setup_sdk = Command( 'sdk', [ ], Action( g_env.BuildSDK ) )
  428. g_env.Depends( setup_sdk, [ game, d3xp ] )
  429. # end targets ------------------------------------