1 import sys, traceback, platform, re, commands
3 if __name__ != '__main__':
4 from SCons.Script import *
8 # config = debug release
9 # aliases are going to be very needed here
10 # we have dependency situations too
14 # not used atm, but useful to keep a list in mind
15 # may use them eventually for the 'all' and other aliases expansions?
16 target_choices = utils.Enum( 'radiant' )
17 config_choices = utils.Enum( 'debug', 'release' )
20 # 'all' -> for each choices
21 # 'gamecode' for the targets, 'game' 'cgame' 'ui'
25 self.target_selected = [ 'radiant' ]
26 self.config_selected = [ 'release' ]
27 # those are global to each config
32 return 'config: target=%s config=%s' % ( self.target_selected, self.config_selected )
34 def _processTarget( self, ops ):
35 self.target_selected = ops
37 def _processConfig( self, ops ):
38 self.config_selected = ops
40 def _processCC( self, ops ):
43 def _processCXX( self, ops ):
46 def setupParser( self, operators ):
47 operators['target'] = self._processTarget
48 operators['config'] = self._processConfig
49 operators['cc'] = self._processCC
50 operators['cxx'] = self._processCXX
54 for config_name in self.config_selected:
56 config['name'] = config_name
57 config['shared'] = False
58 Export( 'utils', 'settings', 'config' )
59 build_dir = os.path.join( 'build', config_name )
60 BuildDir( build_dir, '.', duplicate = 0 )
61 # left out jpeg6, splines (FIXME: I think jpeg6 is not used at all, can trash?)
63 for project in [ 'libs/synapse/synapse.vcproj', 'libs/cmdlib/cmdlib.vcproj', 'libs/mathlib/mathlib.vcproj', 'libs/l_net/l_net.vcproj', 'libs/ddslib/ddslib.vcproj', 'libs/picomodel/picomodel.vcproj', 'libs/md5lib/md5lib.vcproj' ]:
65 lib_objects += SConscript( os.path.join( build_dir, 'SConscript.lib' ) )
66 Export( 'lib_objects' )
67 radiant = SConscript( os.path.join( build_dir, 'SConscript.radiant' ) )
68 InstallAs( 'install/radiant.bin', radiant )
70 # PIC versions of the libs for the modules
71 shlib_objects_extra = {}
72 for project in [ 'libs/synapse/synapse.vcproj', 'libs/mathlib/mathlib.vcproj', 'libs/cmdlib/cmdlib.vcproj' ]:
73 ( libpath, libname ) = os.path.split( project )
74 libname = os.path.splitext( libname )[0]
75 config['shared'] = True
76 Export( 'project', 'config' )
77 build_dir = os.path.join( 'build', config_name, 'shobjs' )
78 BuildDir( build_dir, '.', duplicate = 0 )
79 shlib_objects_extra[libname] = SConscript( os.path.join( build_dir, 'SConscript.lib' ) )
81 for project in [ 'plugins/vfspk3/vfspk3.vcproj',
82 'plugins/image/image.vcproj',
83 'plugins/entity/entity.vcproj',
84 'plugins/map/map.vcproj',
85 'plugins/mapxml/mapxml.vcproj',
86 'plugins/shaders/shaders.vcproj',
87 'plugins/surface/surface.vcproj'
89 ( libpath, libname ) = os.path.split( project )
90 libname = os.path.splitext( libname )[0]
91 shlib_objects = shlib_objects_extra['synapse']
92 if ( libname == 'entity' ):
93 shlib_objects += shlib_objects_extra['mathlib']
94 if ( libname == 'map' ):
95 shlib_objects += shlib_objects_extra['cmdlib']
96 Export( 'project', 'shlib_objects' )
97 module = SConscript( os.path.join( build_dir, 'SConscript.module' ) )
98 InstallAs( 'install/modules/%s.so' % libname, module )
100 def SetupEnvironment( self, env, config, useGtk = False, useGtkGL = False, useJPEG = False ):
102 env['CXX'] = self.cxx
103 ( ret, xml2 ) = commands.getstatusoutput( 'xml2-config --cflags' )
105 print 'xml2-config failed'
107 xml2libs = commands.getoutput( 'xml2-config --libs' )
108 env.Append( LINKFLAGS = xml2libs.split( ' ' ) )
109 baseflags = [ '-pipe', '-Wall', '-fmessage-length=0', '-fvisibility=hidden', xml2.split( ' ' ) ]
110 # baseflags += [ '-m32' ]
112 ( ret, gtk2 ) = commands.getstatusoutput( 'pkg-config gtk+-2.0 --cflags' )
114 print 'pkg-config gtk+-2.0 failed'
116 baseflags += gtk2.split( ' ' )
117 gtk2libs = commands.getoutput( 'pkg-config gtk+-2.0 --libs' )
118 env.Append( LINKFLAGS = gtk2libs.split( ' ' ) )
120 # always setup at least glib
121 ( ret, glib ) = commands.getstatusoutput( 'pkg-config glib-2.0 --cflags' )
123 print 'pkg-config glib-2.0 failed'
125 baseflags += glib.split( ' ' )
126 gliblibs = commands.getoutput( 'pkg-config glib-2.0 --libs' )
127 env.Append( LINKFLAGS = gliblibs.split( ' ' ) )
129 ( ret, gtkgl ) = commands.getstatusoutput( 'pkg-config gtkglext-1.0 --cflags' )
131 print 'pkg-config gtkglext-1.0 failed'
133 baseflags += gtkgl.split( ' ' )
134 gtkgllibs = commands.getoutput( 'pkg-config gtkglext-1.0 --libs' )
135 env.Append( LINKFLAGS = gtkgllibs.split( ' ' ) )
137 env.Append( LIBS = 'jpeg' )
139 env.Append( CFLAGS = baseflags )
140 env.Append( CXXFLAGS = baseflags + [ '-fpermissive', '-fvisibility-inlines-hidden' ] )
141 env.Append( CPPPATH = [ 'include', 'libs' ] )
142 env.Append( CPPDEFINES = [ 'Q_NO_STLPORT' ] )
143 if ( config == 'debug' ):
144 env.Append( CFLAGS = [ '-g' ] )
145 env.Append( CPPDEFINES = [ '_DEBUG' ] )
147 env.Append( CFLAGS = [ '-O3', '-Winline', '-ffast-math', '-fno-unsafe-math-optimizations' ] )
148 #env.Append( CFLAGS = [ '-march=pentium3' ] )
150 # env.Append( LINKFLAGS = [ '-m32' ] )
152 # parse the config statement line to produce/update an existing config list
153 # the configs expose a list of keywords and accepted values, which the engine parses out
155 def __init__( self ):
158 def _processOp( self, ops ):
159 assert( len( ops ) == 1 )
161 if ( op == 'clear' ):
163 self.current_config = None
164 elif ( op == 'pop' ):
166 self.current_config = None
167 elif ( op == 'push' ):
168 self.configs.append( self.current_config )
169 self.current_config = Config()
170 self._setupParser( self.current_config )
172 def _setupParser( self, c ):
173 self.operators = { 'op' : self._processOp }
174 c.setupParser( self.operators )
176 def _parseStatement( self, s ):
177 statement_re = re.compile( '(.*)=(.*)' )
178 value_list_re = re.compile( '([^,]*),?' )
179 if ( not statement_re.match( s ) ):
180 print 'syntax error (statement match): %s' % repr( s )
182 statement_split = statement_re.split( s )
183 if ( len( statement_split ) != 4 ):
184 print 'syntax error (statement split): %s' % repr( s )
186 ( foo, name, value, bar ) = statement_split
187 value_split = value_list_re.split( value )
188 if ( len( value_split ) < 2 or len( value_split ) % 2 != 1 ):
189 print 'syntax error (value split): %s' % ( repr( value_split ) )
193 value_split.reverse()
195 while ( len( value_split ) != 0 ):
196 value_array.append( value_split.pop() )
199 print traceback.print_exception( sys.exc_type, sys.exc_value, sys.exc_traceback )
200 print 'syntax error (value to array): %s' % ( repr( value_split ) )
203 return ( name, value_array )
205 def parseStatements( self, _configs, statements ):
206 self.current_config = None
207 self.configs = _configs
208 if ( self.configs is None ):
212 if ( self.current_config is None ):
213 # use a provided config, or create a default one
214 if ( len( self.configs ) > 0 ):
215 self.current_config = self.configs.pop()
217 self.current_config = Config()
218 # setup the operator table for this config
219 # NOTE: have that in self._processOp too
220 self._setupParser( self.current_config )
222 ret = self._parseStatement( s )
224 print 'stop statement parse at %s' % repr( s )
226 ( name, value_array ) = ret
228 processor = self.operators[name]
230 print 'unknown operator %s - stop statement parse at %s' % ( repr( name ), repr( s ) )
232 processor( value_array )
234 if ( not self.current_config is None ):
235 self.configs.append( self.current_config )
236 # make sure there is at least one config
237 if ( len( self.configs ) == 0 ):
238 print 'pushing a default config'
239 self.configs.append( Config() )
244 class TestConfigParse( unittest.TestCase ):
247 self.parser = ConfigParser()
249 def testBasicParse( self ):
250 # test basic config parsing
251 # needs to cleanly stop at the first config statement that is not recognized
252 configs = self.parser.parseStatements( None, [ 'game=missionpack', 'config=qvm', 'foobar' ] )
253 print repr( configs )
255 def testMultiParse( self ):
256 # multiple configs seperated by commas
257 configs = self.parser.parseStatements( None, [ 'target=server,game,cgame' ] )
258 print repr( configs )
261 # test the operator for multiple configs
262 configs = self.parser.parseStatements( None, [ 'target=core', 'config=release', 'op=push', 'target=game,cgame,ui', 'config=debug' ] )
263 print repr( configs )
265 if __name__ == '__main__':