Gaudi Framework, version v23r4

Home   Generated: Mon Sep 17 2012
Public Member Functions | Public Attributes | Private Member Functions

cmt2cmake::Package Class Reference

Inheritance diagram for cmt2cmake::Package:
Inheritance graph
[legend]

List of all members.

Public Member Functions

def __init__
def generate
def process

Public Attributes

 path
 name
 requirements
 project
 uses
 version
 libraries
 applications
 documents
 macros
 singleton_patterns
 install_more_includes
 install_python_modules
 install_scripts
 QMTest
 god_headers
 god_dictionary
 PyQtResource
 PyQtUIC
 multi_patterns
 reflex_dictionary
 component_library
 linker_library
 reflex_dictionaries
 component_libraries
 linker_libraries
 log

Private Member Functions

def _parseRequirements

Detailed Description

Definition at line 116 of file cmt2cmake.py.


Constructor & Destructor Documentation

def cmt2cmake::Package::__init__ (   self,
  path,
  project = None 
)

Definition at line 117 of file cmt2cmake.py.

00118                                           :
00119         self.path = os.path.realpath(path)
00120         if not isPackage(self.path):
00121             raise ValueError("%s is not a package" % self.path)
00122 
00123         self.name = os.path.basename(self.path)
00124         self.requirements = os.path.join(self.path, "cmt", "requirements")
00125         self.project = project
00126 
00127         # prepare attributes filled during parsing of requirements
00128         self.uses = {}
00129         self.version = None
00130         self.libraries = []
00131         self.applications = []
00132         self.documents = []
00133         self.macros = {}
00134 
00135         self.singleton_patterns = set(["QMTest", "install_python_modules", "install_scripts",
00136                                        "install_more_includes", "god_headers", "god_dictionary",
00137                                        "PyQtResource", "PyQtUIC"])
00138         self.install_more_includes = {}
00139         self.install_python_modules = self.install_scripts = self.QMTest = False
00140         self.god_headers = {}
00141         self.god_dictionary = {}
00142         self.PyQtResource = {}
00143         self.PyQtUIC = {}
00144 
00145         self.multi_patterns = set(["reflex_dictionary", 'component_library', 'linker_library'])
00146         self.reflex_dictionary = []
00147         self.component_library = []
00148         self.linker_library = []
00149 
00150         self.reflex_dictionaries = {}
00151         self.component_libraries = set()
00152         self.linker_libraries = set()
00153 
00154         self.log = logging.getLogger('Package(%s)' % self.name)
00155         try:
00156             self._parseRequirements()
00157         except:
00158             print "Processing %s" % self.requirements
00159             raise
00160         # update the known subdirs
00161         known_subdirs[self.name] = {# list of linker libraries provided by the package
00162                                     'libraries': list(self.linker_libraries),
00163                                     # true if it's a headers-only package
00164                                     'includes': bool(self.install_more_includes and
00165                                                      not self.linker_libraries)}


Member Function Documentation

def cmt2cmake::Package::_parseRequirements (   self ) [private]

Definition at line 442 of file cmt2cmake.py.

00443                                 :
00444         def requirements():
00445             statement = ""
00446             for l in open(self.requirements):
00447                 if '#' in l:
00448                     l = l[:l.find('#')]
00449                 l = l.strip()
00450                 if l:
00451                     statement += l
00452                     if statement.endswith('\\'):
00453                         statement = statement[:-1] + ' '
00454                         continue
00455                     else:
00456                         try:
00457                             yield list(CMTParser.parseString(statement))
00458                         except:
00459                             # ignore not know statements
00460                             self.log.debug("Failed to parse statement: %r", statement)
00461                         statement = ""
00462 
00463         for args in requirements():
00464             cmd = args.pop(0)
00465             if cmd == 'version':
00466                 self.version = args[0]
00467             elif cmd == "use":
00468                 if "-no_auto_imports" in args:
00469                     imp = False
00470                     args.remove("-no_auto_imports")
00471                 else:
00472                     imp = True
00473                 if len(args) > 1: # only one argument means usually a conditional use
00474                     if len(args) > 2:
00475                         name = "%s/%s" % (args[2], args[0])
00476                     else:
00477                         name = args[0]
00478                     self.uses[name] = (args[1], imp)
00479 
00480             elif cmd == "apply_pattern":
00481                 pattern = args.pop(0)
00482                 args = dict([x.split('=', 1) for x in args])
00483                 if pattern in self.singleton_patterns:
00484                     setattr(self, pattern, args or True)
00485                 elif pattern in self.multi_patterns:
00486                     getattr(self, pattern).append(args)
00487 
00488             elif cmd == 'library':
00489                 name = args.pop(0)
00490                 # digest arguments (options, variables, sources)
00491                 imports = []
00492                 group = None
00493                 sources = []
00494                 for a in args:
00495                     if a.startswith('-'): # options
00496                         if a.startswith('-import='):
00497                             imports.append(a[8:])
00498                         elif a.startswith('-group='):
00499                             group = a[7:]
00500                     elif '=' in a: # variable
00501                         pass
00502                     else: # source
00503                         sources.append(a)
00504                 self.libraries.append((name, sources, group, imports))
00505 
00506             elif cmd == 'application':
00507                 name = args.pop(0)
00508                 # digest arguments (options, variables, sources)
00509                 imports = []
00510                 group = None
00511                 sources = []
00512                 for a in args:
00513                     if a.startswith('-'): # options
00514                         if a.startswith('-import='):
00515                             imports.append(a[8:])
00516                         elif a.startswith('-group='):
00517                             group = a[7:]
00518                         elif a == '-check': # used for test applications
00519                             group = 'tests'
00520                     elif '=' in a: # variable
00521                         pass
00522                     else: # source
00523                         sources.append(a)
00524                 if 'test' in name.lower() or [s for s in sources if 'test' in s.lower()]:
00525                     # usually, developers do not put tests in the right group
00526                     group = 'tests'
00527                 self.applications.append((name, sources, group, imports))
00528 
00529             elif cmd == 'document':
00530                 name = args.pop(0)
00531                 constituent = args.pop(0)
00532                 sources = args
00533                 self.documents.append((name, constituent, sources))
00534 
00535             elif cmd == 'macro':
00536                 # FIXME: should handle macro tags
00537                 name = args.pop(0)
00538                 value = args[0].strip('"').strip("'")
00539                 self.macros[name] = value
00540 
00541             elif cmd == 'macro_append':
00542                 # FIXME: should handle macro tags
00543                 name = args.pop(0)
00544                 value = args[0].strip('"').strip("'")
00545                 self.macros[name] = self.macros.get(name, "") + value
00546 
00547 
00548         # classification of libraries in the package
00549         unquote = lambda x: x.strip('"').strip("'")
00550         self.component_libraries = set([unquote(l['library']) for l in self.component_library])
00551         self.linker_libraries = set([unquote(l['library']) for l in self.linker_library])
00552         self.reflex_dictionaries = dict([(unquote(l['dictionary']), l.get('options', ''))
00553                                          for l in self.reflex_dictionary])

def cmt2cmake::Package::generate (   self )

Definition at line 166 of file cmt2cmake.py.

00167                       :
00168         # header
00169         data = ["#" * 80,
00170                 "# Package: %s" % self.name,
00171                 "#" * 80,
00172                 "gaudi_subdir(%s %s)" % (self.name, self.version),
00173                 ""]
00174         # dependencies
00175         #  subdirectories (excluding specials)
00176         subdirs = [n for n in sorted(self.uses)
00177                    if not n.startswith("LCG_Interfaces/")
00178                       and n not in ignore_dep_on_subdirs]
00179 
00180         inc_dirs = []
00181         if subdirs:
00182             # check if we are missing info for a subdir
00183             missing_subdirs = set([s.rsplit('/')[-1] for s in subdirs]) - set(known_subdirs)
00184             if missing_subdirs:
00185                 self.log.warning('Missing info cache for subdirs %s', ' '.join(sorted(missing_subdirs)))
00186             # declare inclusion order
00187             data.append(callStringWithIndent('gaudi_depends_on_subdirs', subdirs))
00188             data.append('')
00189             # consider header-only subdirs
00190             #  for each required subdir that comes with only headers, add its
00191             #  location to the call to 'include_directories'
00192             inc_only = lambda s: known_subdirs.get(s.rsplit('/')[-1], {}).get('includes')
00193             inc_dirs = filter(inc_only, subdirs)
00194 
00195 
00196         #  externals (excluding specials)
00197         #  - Python needs to be treated in a special way
00198         find_packages = {}
00199         for n in sorted(self.uses):
00200             if n.startswith("LCG_Interfaces/"):
00201                 n = extName(n[15:])
00202                 # FIXME: find a general way to treat these special cases
00203                 if n == "PythonLibs":
00204                     if self.name not in needing_python: # only these packages actually link against Python
00205                         continue
00206                 # get custom link options
00207                 linkopts = self.macros.get(n + '_linkopts', '')
00208                 components = [m.group(1) or m.group(2)
00209                               for m in re.finditer(r'(?:\$\(%s_linkopts_([^)]*)\))|(?:-l(\w*))' % n,
00210                                                    linkopts)]
00211                 # FIXME: find a general way to treat the special cases
00212                 if n == 'COOL':
00213                     components = ['CoolKernel', 'CoolApplication']
00214                 elif n == 'CORAL':
00215                     components = ['CoralBase', 'CoralKernel', 'RelationalAccess']
00216 
00217                 find_packages[n] = find_packages.get(n, []) + components
00218 
00219         # this second loops avoid double entries do to converging results of extName()
00220         for n in sorted(find_packages):
00221             args = [n]
00222             components = find_packages[n]
00223             if components:
00224                 args.append('COMPONENTS')
00225                 args.extend(components)
00226             data.append('find_package(%s)' % ' '.join(args))
00227         if find_packages:
00228             data.append("")
00229 
00230         if self.name in no_pedantic:
00231             data.append('string(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")\n')
00232 
00233         # the headers can be installed via "PUBLIC_HEADERS" or by hand
00234         if self.install_more_includes:
00235             headers = [d for d in self.install_more_includes.values()
00236                        if os.path.isdir(os.path.join(self.path, d))]
00237         else:
00238             headers = []
00239 
00240         if self.god_headers or self.god_dictionary:
00241             data.append("include(GaudiObjDesc)")
00242             data.append("")
00243 
00244         god_headers_dest = None
00245         if self.god_headers:
00246             godargs = [self.god_headers["files"].replace("../", "")]
00247 
00248             godflags = self.macros.get('%sObj2Doth_GODflags' % self.name, "")
00249             godflags = re.search(r'-s\s*(\S+)', godflags)
00250             if godflags:
00251                 god_headers_dest = os.path.normpath('Event/' + godflags.group(1))
00252                 godargs.append('DESTINATION ' + god_headers_dest)
00253 
00254             data.append(callStringWithIndent('god_build_headers', godargs))
00255             data.append("")
00256 
00257         god_dict = []
00258         if self.god_dictionary:
00259             god_dict = [('--GOD--',
00260                         [self.god_dictionary["files"].replace("../", "")],
00261                         None, [])]
00262 
00263         rflx_dict = []
00264         for d in self.reflex_dictionary:
00265             for k in d:
00266                 v = d[k]
00267                 v = v.replace("$(%sROOT)/" % self.name.upper(), "")
00268                 v = v.replace("../", "")
00269                 d[k] = v
00270             imports = [i.strip('"').replace('-import=', '') for i in d.get('imports', '').strip().split()]
00271             rflx_dict.append((d['dictionary'] + 'Dict',
00272                               [d['headerfiles'], d['selectionfile']],
00273                               None,
00274                               imports))
00275 
00276         # libraries
00277         global_imports = [extName(name[15:])
00278                           for name in self.uses
00279                           if name.startswith('LCG_Interfaces/') and self.uses[name][1]] # list of imported ext
00280         if 'PythonLibs' in global_imports and self.name not in needing_python:
00281             global_imports.remove('PythonLibs')
00282 
00283         subdir_imports = [s.rsplit('/')[-1] for s in subdirs if self.uses[s][1]]
00284         local_links = [] # keep track of linker libraries found so far
00285         applications_names = set([a[0] for a in self.applications])
00286         # Note: a god_dictionary, a reflex_dictionary or an application is like a module
00287         for name, sources, group, imports in self.libraries + god_dict + rflx_dict + self.applications:
00288             isGODDict = isRflxDict = isComp = isApp = isLinker = False
00289             if name == '--GOD--':
00290                 isGODDict = True
00291                 name = '' # no library name for GOD dictionaries
00292             elif name.endswith('Dict') and name[:-4] in self.reflex_dictionaries:
00293                 isRflxDict = True
00294                 name = name[:-4]
00295             elif name in self.component_libraries:
00296                 isComp = True
00297             elif name in applications_names:
00298                 isApp = True
00299             else:
00300                 if name not in self.linker_libraries:
00301                     self.log.warning('library %s not declared as component or linker, assume linker', name)
00302                 isLinker = True
00303 
00304             # prepare the bits of the command: cmd, name, sources, args
00305             if isComp:
00306                 cmd = 'gaudi_add_module'
00307             elif isGODDict:
00308                 cmd = 'god_build_dictionary'
00309             elif isRflxDict:
00310                 cmd = 'gaudi_add_dictionary'
00311             elif isApp:
00312                 cmd = 'gaudi_add_executable'
00313             else: # i.e. isLinker (a fallback)
00314                 cmd = 'gaudi_add_library'
00315 
00316             if not sources:
00317                 self.log.warning("Missing sources for target %s", name)
00318 
00319             args = []
00320             if isLinker:
00321                 if headers:
00322                     args.append('PUBLIC_HEADERS ' + ' '.join(headers))
00323                 else:
00324                     args.append('NO_PUBLIC_HEADERS')
00325             elif isGODDict:
00326                 if god_headers_dest:
00327                     args.append('HEADERS_DESTINATION ' + god_headers_dest)
00328                 # check if we have a customdict in the documents
00329                 for docname, _, docsources in self.documents:
00330                     if docname == 'customdict':
00331                         args.append('EXTEND ' + docsources[0].replace('../', ''))
00332                         break
00333 
00334 
00335             # # collection of link libraries. #
00336             # Externals and subdirs are treated differently:
00337             # - externals: just use the package name
00338             # - subdirs: find the exported libraries in the global var known_subdirs
00339             # We also have to add the local linker libraries.
00340 
00341             # separate external and subdir explicit imports
00342             subdirsnames = [s.rsplit('/')[-1] for s in subdirs]
00343             subdir_local_imports = [i for i in imports if i in subdirsnames]
00344             ext_local_imports = [extName(i) for i in imports if i not in subdir_local_imports]
00345 
00346             # prepare the link list with the externals
00347             links = global_imports + ext_local_imports
00348             if links or inc_dirs:
00349                 # external links need the include dirs
00350                 args.append('INCLUDE_DIRS ' + ' '.join(links + inc_dirs))
00351             # add subdirs...
00352             for s in subdir_imports + subdir_local_imports:
00353                 if s in known_subdirs:
00354                     links.extend(known_subdirs[s]['libraries'])
00355             # ... and local libraries
00356             links.extend(local_links)
00357             if 'AIDA' in links:
00358                 links.remove('AIDA') # FIXME: AIDA does not have a library
00359 
00360             if links:
00361                 not_included = set(links).difference(find_packages, set([s.rsplit('/')[-1] for s in subdirs]))
00362                 if not_included:
00363                     self.log.warning('imports without use: %s', ', '.join(sorted(not_included)))
00364                 # note: in some cases we get quoted library names
00365                 args.append('LINK_LIBRARIES ' + ' '.join([l.strip('"') for l in links]))
00366 
00367             if isRflxDict and self.reflex_dictionaries[name]:
00368                 args.append('OPTIONS ' + self.reflex_dictionaries[name])
00369 
00370             if isLinker:
00371                 local_links.append(name)
00372 
00373             # FIXME: very very special case :(
00374             if name == 'garbage' and self.name == 'FileStager':
00375                 data.append('# only for the applications\nfind_package(Boost COMPONENTS program_options)\n')
00376 
00377             # write command
00378             sources = [s.replace('../src/', '') for s in sources]
00379             # FIXME: special case
00380             sources = [s.replace('$(GAUDICONFROOT)', '${CMAKE_SOURCE_DIR}/GaudiConf') for s in sources]
00381             libdata = callStringWithIndent(cmd, [name] + sources + args)
00382 
00383             # FIXME: wrap the test libraries in one if block (instead of several)
00384             if group in ('tests', 'test'):
00385                 # increase indentation
00386                 libdata = ['  ' + l for l in libdata.splitlines()]
00387                 # and wrap
00388                 libdata.insert(0, 'if(BUILD_TESTS)')
00389                 libdata.append('endif()')
00390                 libdata = '\n'.join(libdata)
00391             data.append(libdata)
00392             data.append('') # empty line
00393 
00394         # PyQt resources and UIs
00395         if self.PyQtResource or self.PyQtUIC:
00396             data.append("# gen_pyqt_* functions are provided by 'pygraphics'")
00397         if self.PyQtResource:
00398             qrc_files = self.PyQtResource["qrc_files"].replace("../", "")
00399             qrc_dest = self.PyQtResource["outputdir"].replace("../python/", "")
00400             qrc_target = qrc_dest.replace('/', '.') + '.Resources'
00401             data.append('gen_pyqt_resource(%s %s %s)' % (qrc_target, qrc_dest, qrc_files))
00402         if self.PyQtUIC:
00403             ui_files = self.PyQtUIC["ui_files"].replace("../", "")
00404             ui_dest = self.PyQtUIC["outputdir"].replace("../python/", "")
00405             ui_target = qrc_dest.replace('/', '.') + '.UI'
00406             data.append('gen_pyqt_uic(%s %s %s)' % (ui_target, ui_dest, ui_files))
00407         if self.PyQtResource or self.PyQtUIC:
00408             data.append('') # empty line
00409 
00410         # installation
00411         installs = []
00412         if headers and not self.linker_libraries: # not installed yet
00413             installs.append("gaudi_install_headers(%s)" % (" ".join(headers)))
00414         if self.install_python_modules:
00415             # if we install Python modules, we need to check if we have special
00416             # names for the ConfUser modules
00417             if (self.name + 'ConfUserModules') in self.macros:
00418                 installs.append('set_property(DIRECTORY PROPERTY CONFIGURABLE_USER_MODULES %s)'
00419                                 % self.macros[self.name + 'ConfUserModules'])
00420             installs.append("gaudi_install_python_modules()")
00421         if self.install_scripts:
00422             installs.append("gaudi_install_scripts()")
00423         if installs:
00424             data.extend(installs)
00425             data.append('') # empty line
00426         # tests
00427         if self.QMTest:
00428             data.append("\ngaudi_add_test(QMTest QMTEST)")
00429 
00430         return "\n".join(data) + "\n"

def cmt2cmake::Package::process (   self,
  force = False 
)

Definition at line 431 of file cmt2cmake.py.

00432                                   :
00433         # @FIXME: do something for the package
00434         cml = os.path.join(self.path, "CMakeLists.txt")
00435         if not force and os.path.exists(cml):
00436             self.log.warning("file %s already exists", cml)
00437             return
00438         data = self.generate()
00439         f = open(cml, "w")
00440         f.write(data)
00441         f.close()


Member Data Documentation

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.

Definition at line 117 of file cmt2cmake.py.


The documentation for this class was generated from the following file:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Mon Sep 17 2012 13:49:53 for Gaudi Framework, version v23r4 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004