get the basics of a new scons build system together
[xonotic/netradiant.git] / utils.py
1 # -*- mode: python -*-\r
2 # QuakeZero build scripts\r
3 # TTimo <ttimo@idsoftware.com>\r
4 # http://scons.sourceforge.net\r
5 \r
6 import os, commands, platform, xml.sax, re, string\r
7 \r
8 class vcproj( xml.sax.handler.ContentHandler ):\r
9         def __init__( self, filepath ):\r
10                 self.source_files = []\r
11                 self.misc_files = []\r
12                 self._files = []\r
13                 print 'parse %s' % filepath\r
14                 xml.sax.parse( filepath, self )\r
15 \r
16         def getSourceFiles( self ):\r
17                 return self.source_files\r
18 \r
19         def filterSource( self, expression, filelist = None ):\r
20                 if ( filelist is None ):\r
21                         filelist = self.source_files\r
22                 match = []\r
23                 nomatch = []\r
24                 for s in filelist:\r
25                         if ( re.match( expression, s ) ):\r
26                                 match.append( s )\r
27                         else:\r
28                                 nomatch.append( s )\r
29                 return ( match, nomatch )\r
30 \r
31         def startElement( self, name, attrs ):\r
32                 if ( name == 'File' ):\r
33                         self._files.append( attrs.getValue('RelativePath') )\r
34 \r
35         def endDocument( self ):\r
36                 # split into source and headers, remap path seperator to the platform\r
37                 for f in self._files:\r
38                         if ( platform.system() != 'Windows' ):\r
39                                 f = f.replace( '\\', '/' )\r
40                         if ( f[-2:] == '.c' or f[-4:] == '.cpp' ):\r
41                                 self.source_files.append( f.encode('ascii') )\r
42                         else:\r
43                                 self.misc_files.append( f )\r
44                 print '%d source files' % len( self.source_files )\r
45 \r
46 # action uses LDD to verify that the source doesn't hold unresolved symbols\r
47 # setup as an AddPostAction of a regular SharedLibrary call\r
48 def CheckUnresolved( source, target, env ):\r
49         print 'CheckUnresolved %s' % target[0].abspath\r
50         if ( not os.path.isfile( target[0].abspath ) ):\r
51                 print 'CheckUnresolved: %s does not exist' % target[0]\r
52                 return 1 # fail\r
53         ( status, output ) = commands.getstatusoutput( 'ldd -r %s' % target[0] )\r
54         if ( status != 0 ):\r
55                 print 'CheckUnresolved: ldd command failed (exit code %d)' % status\r
56                 os.system( 'rm %s' % target[ 0 ] )\r
57                 return 1 # fail\r
58         lines = string.split( output, '\n' )\r
59         have_undef = 0\r
60         for i_line in lines:\r
61                 regex = re.compile('undefined symbol: (.*)\t\\((.*)\\)')\r
62                 if ( regex.match( i_line ) ):\r
63                         symbol = regex.sub( '\\1', i_line )\r
64                         try:\r
65                                 env['ALLOWED_SYMBOLS'].index( symbol )\r
66                         except:\r
67                                 have_undef = 1\r
68         if ( have_undef ):\r
69                 print output\r
70                 print "CheckUnresolved: undefined symbols"\r
71                 os.system('rm %s' % target[0])\r
72                 return 1\r
73 \r
74 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413486\r
75 \r
76 def Enum(*names):\r
77    ##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!\r
78 \r
79    class EnumClass(object):\r
80       __slots__ = names\r
81       def __iter__(self):        return iter(constants)\r
82       def __len__(self):         return len(constants)\r
83       def __getitem__(self, i):  return constants[i]\r
84       def __repr__(self):        return 'Enum' + str(names)\r
85       def __str__(self):         return 'enum ' + str(constants)\r
86 \r
87    class EnumValue(object):\r
88       __slots__ = ('__value')\r
89       def __init__(self, value): self.__value = value\r
90       Value = property(lambda self: self.__value)\r
91       EnumType = property(lambda self: EnumType)\r
92       def __hash__(self):        return hash(self.__value)\r
93       def __cmp__(self, other):\r
94          # C fans might want to remove the following assertion\r
95          # to make all enums comparable by ordinal value {;))\r
96          assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"\r
97          return cmp(self.__value, other.__value)\r
98       def __invert__(self):      return constants[maximum - self.__value]\r
99       def __nonzero__(self):     return bool(self.__value)\r
100       def __repr__(self):        return str(names[self.__value])\r
101 \r
102    maximum = len(names) - 1\r
103    constants = [None] * len(names)\r
104    for i, each in enumerate(names):\r
105       val = EnumValue(i)\r
106       setattr(EnumClass, each, val)\r
107       constants[i] = val\r
108    constants = tuple(constants)\r
109    EnumType = EnumClass()\r
110    return EnumType\r
111 \r
112 #if __name__ == '__main__':\r
113 #   print '\n*** Enum Demo ***'\r
114 #   print '--- Days of week ---'\r
115 #   Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')\r
116 #   print Days\r
117 #   print Days.Mo\r
118 #   print Days.Fr\r
119 #   print Days.Mo < Days.Fr\r
120 #   print list(Days)\r
121 #   for each in Days:\r
122 #      print 'Day:', each\r
123 #   print '--- Yes/No ---'\r
124 #   Confirmation = Enum('No', 'Yes')\r
125 #   answer = Confirmation.No\r
126 #   print 'Your answer is not', ~answer\r
127 \r