CMS 3D CMS Logo

Classes | Functions
condformats_serialization_generate Namespace Reference

Classes

class  SerializationCodeGenerator
 

Functions

def get_basic_type_string (node)
 
def get_clang_version ()
 
def get_default_gcc_search_paths (gcc='g++', language='c++')
 
def get_diagnostics (translation_unit)
 
def get_flags (product_name, flags)
 
def get_serializable_classes_members (node, all_template_types=None, namespace='', only_from_path=None)
 
def get_statement (node)
 
def get_type_string (node)
 
def is_definition_by_loc (node)
 
def is_friend_decl (memkind)
 
def is_serializable_class (node)
 
def is_serializable_class_manual (node)
 
def log_flags (name, flags)
 
def main ()
 
def sanitise (var)
 
def split_path (path)
 

Detailed Description

CMS Conditions DB Serialization generator.

Generates the non-intrusive serialization code required for the classes
marked with the COND_SERIALIZABLE macro.

The code was taken from the prototype that did many other things as well
(finding transients, marking serializable classes, etc.). After removing
everything but what is required to build the serialization, the code was
made more robust and cleaned up a bit to be integrated on the BoostIO IB.
However, the code still needs to be restructured a bit more to improve
readability (e.g. name some constants, use a template engine, ask for
clang's bindings to be installed along clang itself, etc.).

Function Documentation

def condformats_serialization_generate.get_basic_type_string (   node)

Definition at line 121 of file condformats_serialization_generate.py.

Referenced by get_serializable_classes_members(), and get_type_string().

122  typekinds = {
123  clang.cindex.TypeKind.BOOL: 'bool',
124  clang.cindex.TypeKind.INT: 'int',
125  clang.cindex.TypeKind.LONG: 'long',
126  clang.cindex.TypeKind.UINT: 'unsigned int',
127  clang.cindex.TypeKind.ULONG: 'unsigned long',
128  clang.cindex.TypeKind.FLOAT: 'float',
129  clang.cindex.TypeKind.DOUBLE: 'double',
130  }
131 
132  if node.type.kind not in typekinds:
133  raise Exception('Not a known basic type.')
134 
135  return typekinds[node.type.kind]
136 
137 
def condformats_serialization_generate.get_clang_version ( )
Extract clang version and set global clang_version and also return the same value.

Definition at line 347 of file condformats_serialization_generate.py.

References createfilelist.int, split, and digi_MixPreMix_cfi.strip.

Referenced by is_friend_decl().

348  """Extract clang version and set global clang_version and also return the same value."""
349  global clang_version
350  if clang_version is not None:
351  return clang_version
352  command = "clang --version | grep 'clang version' | sed 's/clang version//'"
353  logging.debug("Running: {0}".format(command))
354  (clang_version_major, clang_version_minor, clang_version_patchlevel) = subprocess.check_output(command, shell=True).splitlines()[0].strip().split('.', 3)
355  clang_version = (int(clang_version_major), int(clang_version_minor), int(clang_version_patchlevel))
356  logging.debug("Detected Clang version: {0}".format(clang_version))
357  return clang_version
358 
double split
Definition: MVATrainer.cc:139
def condformats_serialization_generate.get_default_gcc_search_paths (   gcc = 'g++',
  language = 'c++' 
)

Definition at line 385 of file condformats_serialization_generate.py.

385 def get_default_gcc_search_paths(gcc = 'g++', language = 'c++'):
386  command = 'echo "" | %s -x%s -v -E - 2>&1' % (gcc, language)
387  logging.debug('Running: %s', command)
388 
389  paths = []
390  in_list = False
391  for line in subprocess.check_output(command, shell=True).splitlines():
392  if in_list:
393  if line == 'End of search list.':
394  break
395 
396  path = os.path.normpath(line.strip())
397 
398  # Intrinsics not handled by clang
399  # Note that /lib/gcc is found in other paths if not normalized,
400  # so has to go after normpath()
401  if '/lib/gcc/' in path:
402  continue
403 
404  paths.append('-I%s' % path)
405 
406  else:
407  if line == '#include <...> search starts here:':
408  in_list = True
409 
410  if not in_list:
411  raise Exception('Default GCC search paths not found.')
412 
413  return paths
414 
def get_default_gcc_search_paths(gcc='g++', language='c++')
def condformats_serialization_generate.get_diagnostics (   translation_unit)

Definition at line 375 of file condformats_serialization_generate.py.

References genParticles_cff.map.

375 def get_diagnostics(translation_unit):
376  return map(lambda diag: {
377  'severity' : diag.severity,
378  'location' : diag.location,
379  'spelling' : diag.spelling,
380  'ranges' : diag.ranges,
381  'fixits' : diag.fixits,
382  }, translation_unit.diagnostics)
383 
384 
def condformats_serialization_generate.get_flags (   product_name,
  flags 
)

Definition at line 342 of file condformats_serialization_generate.py.

342 def get_flags(product_name, flags):
343  command = "scram b echo_%s_%s | tail -1 | cut -d '=' -f '2-' | xargs -n1" % (product_name, flags)
344  logging.debug('Running: %s', command)
345  return subprocess.check_output(command, shell=True).splitlines()
346 
def condformats_serialization_generate.get_serializable_classes_members (   node,
  all_template_types = None,
  namespace = '',
  only_from_path = None 
)

Definition at line 146 of file condformats_serialization_generate.py.

References get_basic_type_string(), get_statement(), get_type_string(), is_definition_by_loc(), is_friend_decl(), is_serializable_class(), is_serializable_class_manual(), and join().

146 def get_serializable_classes_members(node, all_template_types=None, namespace='', only_from_path=None):
147  if all_template_types is None:
148  all_template_types = []
149 
150  logging.debug('%s', (node.spelling, all_template_types, namespace))
151  results = {}
152  for child in node.get_children():
153  if child.kind == clang.cindex.CursorKind.NAMESPACE:
154  # If we are in the root namespace, let's skip some common, big
155  # namespaces to improve speed and avoid serializing those.
156  if namespace == '':
157  if child.spelling in skip_namespaces:
158  continue
159 
160  # This skips compiler-specific stuff as well (e.g. __gnucxx...)
161  if child.spelling.startswith('_'):
162  continue
163 
164  logging.debug('Going into namespace %s', child.spelling)
165 
166  results.update(get_serializable_classes_members(child, all_template_types, namespace + child.spelling + '::', only_from_path))
167  continue
168 
169  if child.kind in [clang.cindex.CursorKind.CLASS_DECL, clang.cindex.CursorKind.STRUCT_DECL, clang.cindex.CursorKind.CLASS_TEMPLATE] and is_definition_by_loc(child):
170  logging.debug('Found struct/class/template definition: %s', child.spelling if child.spelling else '<anonymous>')
171 
172  if only_from_path is not None \
173  and child.location.file is not None \
174  and not child.location.file.name.startswith(only_from_path):
175  logging.debug('Skipping since it is an external of this package: %s', child.spelling)
176  continue
177 
178  serializable = is_serializable_class(child)
179  if serializable:
180  if child.spelling == '':
181  raise Exception('It is not possible to serialize anonymous/unnamed structs/classes.')
182 
184  logging.info('Found manual serializable struct/class/template: %s', child.spelling)
185  continue
186 
187  logging.info('Found serializable struct/class/template: %s', child.spelling)
188 
189  template_types = []
190  base_objects = []
191  members = []
192  transients = []
193  after_serialize = False
194  after_serialize_count = 0
195  for member in child.get_children():
196  if after_serialize:
197  if after_serialize_count == 2:
198  after_serialize = False
199  else:
200  after_serialize_count = after_serialize_count + 1
201 
202  if not is_friend_decl(member.kind):
203  raise Exception('Expected unexposed declaration (friend) after serialize() but found something else: looks like the COND_SERIALIZABLE macro has been changed without updating the script.')
204 
205  if 'COND_SERIALIZABLE' not in get_statement(member):
206  raise Exception('Could not find COND_SERIALIZABLE in the statement of the expected unexposed declarations (friends) after serialize(). Please fix the script/macro.')
207 
208  logging.debug('Skipping expected unexposed declaration (friend) after serialize().')
209  continue
210 
211  # Template type parameters (e.g. <typename T>)
212  if member.kind == clang.cindex.CursorKind.TEMPLATE_TYPE_PARAMETER:
213  logging.info(' Found template type parameter: %s', member.spelling)
214  template_types.append(('typename', member.spelling))
215 
216  # Template non-type parameters (e.g. <int N>)
217  elif member.kind == clang.cindex.CursorKind.TEMPLATE_NON_TYPE_PARAMETER:
218  type_string = get_type_string(member)
219  if not type_string:
220  type_string = get_basic_type_string(member)
221  logging.info(' Found template non-type parameter: %s %s', type_string, member.spelling)
222  template_types.append((type_string, member.spelling))
223 
224  # Base objects
225  elif member.kind == clang.cindex.CursorKind.CXX_BASE_SPECIFIER:
226  # FIXME: .displayname gives sometimes things like "class mybase"
227  base_object = member.displayname
228  prefix = 'class '
229  if base_object.startswith(prefix):
230  base_object = base_object[len(prefix):]
231  logging.info(' Found base object: %s', base_object)
232  base_objects.append(base_object)
233 
234  # Member variables
235  elif member.kind == clang.cindex.CursorKind.FIELD_DECL and is_definition_by_loc(member):
236  # While clang 3.3 does not ignore unrecognized attributes
237  # (see http://llvm.org/viewvc/llvm-project?revision=165082&view=revision )
238  # for some reason they do not appear in the bindings yet
239  # so we just do it ourselves.
240 
241  # FIXME: To simplify and avoid parsing C++ ourselves, our transient
242  # attribute applies to *all* the variables declared in the same statement.
243  if 'COND_TRANSIENT' not in get_statement(member):
244  logging.info(' Found member variable: %s', member.spelling)
245  members.append(member.spelling)
246  else:
247  if serializable:
248  logging.info(' Found transient member variable: %s', member.spelling)
249  transients.append(member.spelling)
250  else:
251  raise Exception('Transient %s found for non-serializable class %s', member.spelling, child.spelling)
252 
253  elif member.kind == clang.cindex.CursorKind.FUNCTION_TEMPLATE and member.spelling == 'serialize':
254  after_serialize = True
255  logging.debug('Found serialize() method, skipping next two children which must be unexposed declarations.')
256 
257  elif member.kind in frozenset([
258  # For safety, we list all known kinds that we need to skip
259  # and raise in unknown cases (this helps catching problems
260  # with undefined classes)
261  clang.cindex.CursorKind.CONSTRUCTOR,
262  clang.cindex.CursorKind.DESTRUCTOR,
263  clang.cindex.CursorKind.CXX_METHOD,
264  clang.cindex.CursorKind.CXX_ACCESS_SPEC_DECL,
265  clang.cindex.CursorKind.FUNCTION_TEMPLATE,
266  clang.cindex.CursorKind.TYPEDEF_DECL,
267  clang.cindex.CursorKind.CLASS_DECL,
268  clang.cindex.CursorKind.ENUM_DECL,
269  clang.cindex.CursorKind.VAR_DECL,
270  clang.cindex.CursorKind.STRUCT_DECL,
271  clang.cindex.CursorKind.UNION_DECL,
272  clang.cindex.CursorKind.CONVERSION_FUNCTION,
273  clang.cindex.CursorKind.TYPE_REF,
274  clang.cindex.CursorKind.DECL_REF_EXPR,
275  clang.cindex.CursorKind.CLASS_TEMPLATE,
276  clang.cindex.CursorKind.TYPE_ALIAS_DECL,
277  ]):
278  logging.debug('Skipping member: %s %s %s %s', member.displayname, member.spelling, member.kind, member.type.kind)
279 
280  elif is_friend_decl(member.kind):
281  statement = get_statement(member)
282 
283  # Friends are unexposed but they are not data to serialize
284  if 'friend' in statement:
285  # If we know about them, skip the warning
286  if \
287  'friend class ' in statement or \
288  'friend struct ' in statement or \
289  'friend std::ostream& operator<<(' in statement or \
290  'friend std::istream& operator>>(' in statement:
291  logging.debug('Skipping known friend: %s', statement.splitlines()[0])
292  continue
293 
294  # Otherwise warn
295  logging.warning('Unexposed declaration that looks like a friend declaration -- please check: %s %s %s %s %s', member.displayname, member.spelling, member.kind, member.type.kind, statement)
296  continue
297 
298  raise Exception('Unexposed declaration. This probably means (at the time of writing) that an unknown class was found (may happen, for instance, when the compiler does not find the headers for std::vector, i.e. missing -I option): %s %s %s %s %s' % (member.displayname, member.spelling, member.kind, member.type.kind, statement))
299 
300  else:
301  statement = get_statement(member)
302  raise Exception('Unknown kind. Please fix the script: %s %s %s %s %s' % (member.displayname, member.spelling, member.kind, member.type.kind, statement))
303 
304  if template_types:
305  template_use = '%s<%s>' % (child.spelling, ', '.join([template_type_name for (_, template_type_name) in template_types]))
306  else:
307  template_use = child.spelling
308 
309  new_namespace = namespace + template_use
310 
311  new_all_template_types = all_template_types + [template_types]
312 
313  results[new_namespace] = (child, serializable, new_all_template_types, base_objects, members, transients)
314 
315  results.update(get_serializable_classes_members(child, new_all_template_types, new_namespace + '::', only_from_path))
316 
317  for (klass, (node, serializable, all_template_types, base_objects, members, transients)) in results.items():
318  if serializable and len(members) == 0:
319  logging.info('No non-transient members found for serializable class %s', klass)
320 
321  return results
322 
323 
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def get_serializable_classes_members(node, all_template_types=None, namespace='', only_from_path=None)
def condformats_serialization_generate.get_statement (   node)

Definition at line 104 of file condformats_serialization_generate.py.

Referenced by get_serializable_classes_members().

104 def get_statement(node):
105  # For some cursor kinds, their location is empty (e.g. translation units
106  # and attributes); either because of a bug or because they do not have
107  # a meaningful 'start' -- however, the extent is always available
108  if node.extent.start.file is None:
109  return None
110 
111  filename = node.extent.start.file.name
112  start = node.extent.start.offset
113  end = node.extent.end.offset
114 
115  with open(filename, 'rb') as fd:
116  source = fd.read()
117 
118  return source[start:source.find(';', end)]
119 
120 
def condformats_serialization_generate.get_type_string (   node)

Definition at line 138 of file condformats_serialization_generate.py.

References get_basic_type_string().

Referenced by get_serializable_classes_members().

138 def get_type_string(node):
139  spelling = node.type.get_declaration().spelling
140  if spelling is not None:
141  return spelling
142 
143  return get_basic_type_string(node)
144 
145 
def condformats_serialization_generate.is_definition_by_loc (   node)

Definition at line 72 of file condformats_serialization_generate.py.

Referenced by get_serializable_classes_members(), is_serializable_class(), and is_serializable_class_manual().

73  if node.get_definition() is None:
74  return False
75  if node.location is None or node.get_definition().location is None:
76  return False
77  return node.location == node.get_definition().location
78 
def condformats_serialization_generate.is_friend_decl (   memkind)
Check if declaration is a friend

Definition at line 359 of file condformats_serialization_generate.py.

References get_clang_version().

Referenced by get_serializable_classes_members().

359 def is_friend_decl(memkind):
360  """Check if declaration is a friend"""
361  clangv = get_clang_version()
362  if clangv >= (4, 0, 0):
363  return memkind == clang.cindex.CursorKind.FRIEND_DECL
364  else:
365  return memkind == clang.cindex.CursorKind.UNEXPOSED_DECL
366  return false
367 
def condformats_serialization_generate.is_serializable_class (   node)

Definition at line 79 of file condformats_serialization_generate.py.

References is_definition_by_loc().

Referenced by get_serializable_classes_members().

80  for child in node.get_children():
81  if child.spelling != 'serialize' or child.kind != clang.cindex.CursorKind.FUNCTION_TEMPLATE or is_definition_by_loc(child):
82  continue
83 
84  if [(x.spelling, x.kind, is_definition_by_loc(x), x.type.kind) for x in child.get_children()] != [
85  ('Archive', clang.cindex.CursorKind.TEMPLATE_TYPE_PARAMETER, True, clang.cindex.TypeKind.UNEXPOSED),
86  ('ar', clang.cindex.CursorKind.PARM_DECL, True, clang.cindex.TypeKind.LVALUEREFERENCE),
87  ('version', clang.cindex.CursorKind.PARM_DECL, True, clang.cindex.TypeKind.UINT),
88  ]:
89  continue
90 
91  return True
92 
93  return False
94 
95 
def condformats_serialization_generate.is_serializable_class_manual (   node)

Definition at line 96 of file condformats_serialization_generate.py.

References is_definition_by_loc().

Referenced by get_serializable_classes_members().

97  for child in node.get_children():
98  if child.spelling == 'cond_serialization_manual' and child.kind == clang.cindex.CursorKind.CXX_METHOD and not is_definition_by_loc(child):
99  return True
100 
101  return False
102 
103 
def condformats_serialization_generate.log_flags (   name,
  flags 
)

Definition at line 368 of file condformats_serialization_generate.py.

368 def log_flags(name, flags):
369  logging.debug('%s = [', name)
370  for flag in flags:
371  logging.debug(' %s', flag)
372  logging.debug(']')
373 
374 
def condformats_serialization_generate.main ( )

Definition at line 570 of file condformats_serialization_generate.py.

References models.generate().

570 def main():
571  parser = argparse.ArgumentParser(description='CMS Condition DB Serialization generator.')
572  parser.add_argument('--verbose', '-v', action='count', help='Verbosity level. -v reports debugging information.')
573  parser.add_argument('--output' , '-o', action='store', help='Specifies the path to the output file written. Default: src/Serialization.cc')
574  parser.add_argument('--package', '-p', action='store', help='Specifies the path to the package to be processed. Default: the actual package')
575 
576  opts, args = parser.parse_known_args()
577 
578  logLevel = logging.INFO
579  if opts.verbose < 1 and opts.output and opts.package: # assume we're called by scram and reduce logging - but only if no verbose is requested
580  logLevel = logging.WARNING
581 
582  if opts.verbose >= 1:
583  logLevel = logging.DEBUG
584 
585  logging.basicConfig(
586  format = '[%(asctime)s] %(levelname)s: %(message)s',
587  level = logLevel,
588  )
589 
590  if opts.package: # we got a directory name to process, assume it's from scram and remove the last ('/src') dir from the path
591  pkgDir = opts.package
592  if pkgDir.endswith('/src') :
593  pkgDir, srcDir = os.path.split( opts.package )
594  os.chdir( pkgDir )
595  logging.info("Processing package in %s " % pkgDir)
596 
597  if opts.output:
598  logging.info("Writing serialization code to %s " % opts.output)
599 
600  SerializationCodeGenerator( scramFlags=args[1:] ).generate( opts.output )
601 
def generate(map_blobs=False, class_name=None)
Definition: models.py:187
def condformats_serialization_generate.sanitise (   var)

Definition at line 415 of file condformats_serialization_generate.py.

Referenced by condformats_serialization_generate.SerializationCodeGenerator.generate().

415 def sanitise(var):
416  return re.sub('[^a-zA-Z0-9.,-:]', '-', var)
417 
418 
def condformats_serialization_generate.split_path (   path)

Definition at line 324 of file condformats_serialization_generate.py.

324 def split_path(path):
325  folders = []
326 
327  while True:
328  path, folder = os.path.split(path)
329 
330  if folder != '':
331  folders.append(folder)
332  else:
333  if path != '':
334  folders.append(path)
335  break
336 
337  folders.reverse()
338 
339  return folders
340 
341