2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
24 from .libtoolimporter import LibtoolImporter
25 from .message import Position
26 from .ccompiler import CCompiler
27 from .utils import have_debug_flag
29 with LibtoolImporter(None, None):
30 if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
31 from _giscanner import SourceScanner as CSourceScanner
33 from giscanner._giscanner import SourceScanner as CSourceScanner
35 HEADER_EXTS = ['.h', '.hpp', '.hxx']
36 SOURCE_EXTS = ['.c', '.cpp', '.cc', '.cxx']
37 ALL_EXTS = SOURCE_EXTS + HEADER_EXTS
39 (CSYMBOL_TYPE_INVALID,
40 CSYMBOL_TYPE_ELLIPSIS,
43 CSYMBOL_TYPE_FUNCTION,
44 CSYMBOL_TYPE_FUNCTION_MACRO,
49 CSYMBOL_TYPE_MEMBER) = range(11)
60 CTYPE_FUNCTION) = range(10)
62 STORAGE_CLASS_NONE = 0
63 STORAGE_CLASS_TYPEDEF = 1 << 1
64 STORAGE_CLASS_EXTERN = 1 << 2
65 STORAGE_CLASS_STATIC = 1 << 3
66 STORAGE_CLASS_AUTO = 1 << 4
67 STORAGE_CLASS_REGISTER = 1 << 5
68 STORAGE_CLASS_THREAD_LOCAL = 1 << 6
70 TYPE_QUALIFIER_NONE = 0
71 TYPE_QUALIFIER_CONST = 1 << 1
72 TYPE_QUALIFIER_RESTRICT = 1 << 2
73 TYPE_QUALIFIER_VOLATILE = 1 << 3
74 TYPE_QUALIFIER_EXTENSION = 1 << 4
77 FUNCTION_INLINE = 1 << 1
80 UNARY_POINTER_INDIRECTION,
83 UNARY_BITWISE_COMPLEMENT,
84 UNARY_LOGICAL_NEGATION) = range(6)
87 def symbol_type_name(symbol_type):
89 CSYMBOL_TYPE_INVALID: 'invalid',
90 CSYMBOL_TYPE_ELLIPSIS: 'ellipsis',
91 CSYMBOL_TYPE_CONST: 'const',
92 CSYMBOL_TYPE_OBJECT: 'object',
93 CSYMBOL_TYPE_FUNCTION: 'function',
94 CSYMBOL_TYPE_FUNCTION_MACRO: 'function_macro',
95 CSYMBOL_TYPE_STRUCT: 'struct',
96 CSYMBOL_TYPE_UNION: 'union',
97 CSYMBOL_TYPE_ENUM: 'enum',
98 CSYMBOL_TYPE_TYPEDEF: 'typedef',
99 CSYMBOL_TYPE_MEMBER: 'member'}.get(symbol_type)
102 def ctype_name(ctype):
104 CTYPE_INVALID: 'invalid',
106 CTYPE_BASIC_TYPE: 'basic',
107 CTYPE_TYPEDEF: 'typedef',
108 CTYPE_STRUCT: 'struct',
109 CTYPE_UNION: 'union',
111 CTYPE_POINTER: 'pointer',
112 CTYPE_ARRAY: 'array',
113 CTYPE_FUNCTION: 'function'}.get(ctype)
116 class SourceType(object):
117 __members__ = ['type', 'base_type', 'name', 'type_qualifier',
118 'child_list', 'is_bitfield']
120 def __init__(self, scanner, stype):
121 self._scanner = scanner
125 return "<%s type='%s' name='%s'>" % (
126 self.__class__.__name__,
127 ctype_name(self.type),
132 return self._stype.type
136 if self._stype.base_type is not None:
137 return SourceType(self._scanner, self._stype.base_type)
141 return self._stype.name
144 def type_qualifier(self):
145 return self._stype.type_qualifier
148 def child_list(self):
149 for symbol in self._stype.child_list:
152 yield SourceSymbol(self._scanner, symbol)
155 def is_bitfield(self):
156 return self._stype.is_bitfield
159 class SourceSymbol(object):
160 __members__ = ['const_int', 'const_double', 'const_string', 'const_boolean',
161 'ident', 'type', 'base_type']
163 def __init__(self, scanner, symbol):
164 self._scanner = scanner
165 self._symbol = symbol
168 src = self.source_filename
172 src += ":'%s'" % (line, )
173 return "<%s type='%s' ident='%s' src='%s'>" % (
174 self.__class__.__name__,
175 symbol_type_name(self.type),
181 return self._symbol.const_int
184 def const_double(self):
185 return self._symbol.const_double
188 def const_string(self):
189 return self._symbol.const_string
192 def const_boolean(self):
193 return self._symbol.const_boolean
197 return self._symbol.ident
201 return self._symbol.type
205 if self._symbol.base_type is not None:
206 return SourceType(self._scanner, self._symbol.base_type)
209 def source_filename(self):
210 return self._symbol.source_filename
214 return self._symbol.line
218 return self._symbol.private
222 return Position(self._symbol.source_filename,
226 class SourceScanner(object):
229 self._scanner = CSourceScanner()
231 self._cpp_options = []
235 def set_cpp_options(self, includes, defines, undefines, cflags=[]):
236 self._cpp_options.extend(cflags)
237 for prefix, args in [('-I', [os.path.realpath(f) for f in includes]),
240 for arg in (args or []):
242 if opt not in self._cpp_options:
243 self._cpp_options.append(opt)
245 def parse_files(self, filenames):
246 for filename in filenames:
247 # self._scanner expects file names to be canonicalized and symlinks to be resolved
248 filename = os.path.realpath(filename)
249 self._scanner.append_filename(filename)
250 self._filenames.append(filename)
253 for filename in self._filenames:
254 if os.path.splitext(filename)[1] in SOURCE_EXTS:
255 self._scanner.lex_filename(filename)
257 headers.append(filename)
261 def parse_macros(self, filenames):
262 self._scanner.set_macro_scan(True)
263 # self._scanner expects file names to be canonicalized and symlinks to be resolved
264 self._scanner.parse_macros([os.path.realpath(f) for f in filenames])
265 self._scanner.set_macro_scan(False)
267 def get_symbols(self):
268 for symbol in self._scanner.get_symbols():
269 yield SourceSymbol(self._scanner, symbol)
271 def get_comments(self):
272 return self._scanner.get_comments()
274 def get_errors(self):
275 return self._scanner.get_errors()
279 for symbol in self._scanner.get_symbols():
280 print(symbol.ident, symbol.base_type.name, symbol.type)
284 def _parse(self, filenames):
288 defines = ['__GI_SCANNER__']
293 tmp_fd_cpp, tmp_name_cpp = tempfile.mkstemp(prefix='g-ir-cpp-',
296 with os.fdopen(tmp_fd_cpp, 'wb') as fp_cpp:
297 self._write_preprocess_src(fp_cpp, defines, undefs, filenames)
299 tmpfile_basename = os.path.basename(os.path.splitext(tmp_name_cpp)[0])
301 # Output file name of the preprocessor, only really used on non-MSVC,
302 # so we want the name to match the output file name of the MSVC preprocessor
303 tmpfile_output = tmpfile_basename + '.i'
305 cc.preprocess(tmp_name_cpp,
309 if not have_debug_flag('save-temps'):
310 os.unlink(tmp_name_cpp)
311 self._scanner.parse_file(tmpfile_output)
312 if not have_debug_flag('save-temps'):
313 os.unlink(tmpfile_output)
315 def _write_preprocess_src(self, fp, defines, undefs, filenames):
316 # Write to the temp file for feeding into the preprocessor
317 for define in defines:
318 fp.write(('#ifndef %s\n' % (define, )).encode())
319 fp.write(('# define %s\n' % (define, )).encode())
320 fp.write('#endif\n'.encode())
322 fp.write(('#undef %s\n' % (undef, )).encode())
323 for filename in filenames:
324 fp.write(('#include <%s>\n' % (filename, )).encode())