Gaudi Framework, version v23r4

Home   Generated: Mon Sep 17 2012

cmt2cmake.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 """
00003 Script to convert CMT projects/packages to CMake Gaudi-based configuration.
00004 """
00005 import os
00006 import sys
00007 import re
00008 import logging
00009 import shelve
00010 
00011 def makeParser():
00012     from pyparsing import ( Word, QuotedString, Keyword, Literal, SkipTo, StringEnd,
00013                             ZeroOrMore, Optional, Combine,
00014                             alphas, alphanums, printables )
00015     dblQuotedString = QuotedString(quoteChar='"', escChar='\\', unquoteResults=False)
00016     sglQuotedString = QuotedString(quoteChar="'", escChar='\\', unquoteResults=False)
00017     value = dblQuotedString | sglQuotedString | Word(printables)
00018 
00019     tag_name = Word(alphas + "_", alphanums + "_-")
00020     tag_expression = Combine(tag_name + ZeroOrMore('&' + tag_name))
00021     values = value + ZeroOrMore(tag_expression + value)
00022 
00023     identifier = Word(alphas + "_", alphanums + "_")
00024     variable = Combine(identifier + '=' + value)
00025 
00026     constituent_option = (Keyword('-no_share')
00027                           | Keyword('-no_static')
00028                           | Keyword('-prototypes')
00029                           | Keyword('-no_prototypes')
00030                           | Keyword('-check')
00031                           | Keyword('-target_tag')
00032                           | Combine('-group=' + value)
00033                           | Combine('-suffix=' + value)
00034                           | Combine('-import=' + value)
00035                           | variable
00036                           | Keyword('-OS9')
00037                           | Keyword('-windows'))
00038     source = (Word(alphanums + "_*./$()")
00039               | Combine('-s=' + value)
00040               | Combine('-k=' + value)
00041               | Combine('-x=' + value))
00042 
00043     # statements
00044     comment = (Literal("#") + SkipTo(StringEnd())).suppress()
00045 
00046     package = Keyword('package') + Word(printables)
00047     version = Keyword("version") + Word(printables)
00048     use = Keyword("use") + identifier + Word(printables) + Optional(identifier) + Optional(Keyword("-no_auto_imports"))
00049 
00050     constituent = ((Keyword('library') | Keyword('application') | Keyword('document'))
00051                    + identifier + ZeroOrMore(constituent_option | source))
00052     macro = (Keyword('macro') | Keyword('macro_append')) + identifier + values
00053 
00054     apply_pattern = Keyword("apply_pattern") + identifier + ZeroOrMore(variable)
00055 
00056 
00057     statement = (package | version | use | constituent | macro | apply_pattern)
00058 
00059     return Optional(statement) + Optional(comment) + StringEnd()
00060 
00061 CMTParser = makeParser()
00062 
00063 # mappings
00064 ignored_packages = set(["GaudiSys", "GaudiRelease", "GaudiPolicy"])
00065 data_packages = set(['Det/SQLDDDB', 'FieldMap', 'TCK/HltTCK'])
00066 
00067 ignore_dep_on_subdirs = set(ignored_packages)
00068 ignore_dep_on_subdirs.update(data_packages)
00069 
00070 # List of packages known to actually need Python to build
00071 needing_python = ('LoKiCore', 'XMLSummaryKernel', 'CondDBUI')
00072 
00073 # packages that must have the pedantic option disabled
00074 no_pedantic = set(['LHCbMath', 'GenEvent', 'ProcessorKernel', 'TrackKernel',
00075                    'Magnet', 'L0MuonKernel', 'DetDescChecks', 'DetDescSvc',
00076                    'SimComponents', 'DetDescExample', 'CondDBEntityResolver',
00077                    'MuonDAQ', 'STKernel', 'CaloDAQ', 'CaloUtils'])
00078 
00079 # record of known subdirs with their libraries
00080 # {'subdir': {'libraries': [...]}}
00081 _shelve_file = os.environ.get('CMT2CMAKECACHE',
00082                               os.path.join(os.path.dirname(__file__), 'known_subdirs.cache'))
00083 known_subdirs = shelve.open(_shelve_file)
00084 
00085 def extName(n):
00086     mapping = {'Reflex': 'ROOT',
00087                'Python': 'PythonLibs'}
00088     return mapping.get(n, n)
00089 
00090 def isPackage(path):
00091     return os.path.isfile(os.path.join(path, "cmt", "requirements"))
00092 
00093 def isProject(path):
00094     return os.path.isfile(os.path.join(path, "cmt", "project.cmt"))
00095 
00096 def projectCase(name):
00097     if name.upper() == "DAVINCI":
00098         return "DaVinci"
00099     return name.capitalize()
00100 
00101 def callStringWithIndent(cmd, arglines):
00102     '''
00103     Produce a string for a call of a command with indented arguments.
00104 
00105     >>> print callStringWithIndent('example_command', ['arg1', 'arg2', 'arg3'])
00106     example_command(arg1
00107                     arg2
00108                     arg3)
00109     >>> print callStringWithIndent('example_command', ['', 'arg2', 'arg3'])
00110     example_command(arg2
00111                     arg3)
00112     '''
00113     indent = '\n' + ' ' * (len(cmd) + 1)
00114     return cmd + '(' + indent.join(filter(None, arglines)) + ')'
00115 
00116 class Package(object):
00117     def __init__(self, path, project=None):
00118         self.path = os.path.realpath(path)
00119         if not isPackage(self.path):
00120             raise ValueError("%s is not a package" % self.path)
00121 
00122         self.name = os.path.basename(self.path)
00123         self.requirements = os.path.join(self.path, "cmt", "requirements")
00124         self.project = project
00125 
00126         # prepare attributes filled during parsing of requirements
00127         self.uses = {}
00128         self.version = None
00129         self.libraries = []
00130         self.applications = []
00131         self.documents = []
00132         self.macros = {}
00133 
00134         self.singleton_patterns = set(["QMTest", "install_python_modules", "install_scripts",
00135                                        "install_more_includes", "god_headers", "god_dictionary",
00136                                        "PyQtResource", "PyQtUIC"])
00137         self.install_more_includes = {}
00138         self.install_python_modules = self.install_scripts = self.QMTest = False
00139         self.god_headers = {}
00140         self.god_dictionary = {}
00141         self.PyQtResource = {}
00142         self.PyQtUIC = {}
00143 
00144         self.multi_patterns = set(["reflex_dictionary", 'component_library', 'linker_library'])
00145         self.reflex_dictionary = []
00146         self.component_library = []
00147         self.linker_library = []
00148 
00149         self.reflex_dictionaries = {}
00150         self.component_libraries = set()
00151         self.linker_libraries = set()
00152 
00153         self.log = logging.getLogger('Package(%s)' % self.name)
00154         try:
00155             self._parseRequirements()
00156         except:
00157             print "Processing %s" % self.requirements
00158             raise
00159         # update the known subdirs
00160         known_subdirs[self.name] = {# list of linker libraries provided by the package
00161                                     'libraries': list(self.linker_libraries),
00162                                     # true if it's a headers-only package
00163                                     'includes': bool(self.install_more_includes and
00164                                                      not self.linker_libraries)}
00165 
00166     def generate(self):
00167         # header
00168         data = ["#" * 80,
00169                 "# Package: %s" % self.name,
00170                 "#" * 80,
00171                 "gaudi_subdir(%s %s)" % (self.name, self.version),
00172                 ""]
00173         # dependencies
00174         #  subdirectories (excluding specials)
00175         subdirs = [n for n in sorted(self.uses)
00176                    if not n.startswith("LCG_Interfaces/")
00177                       and n not in ignore_dep_on_subdirs]
00178 
00179         inc_dirs = []
00180         if subdirs:
00181             # check if we are missing info for a subdir
00182             missing_subdirs = set([s.rsplit('/')[-1] for s in subdirs]) - set(known_subdirs)
00183             if missing_subdirs:
00184                 self.log.warning('Missing info cache for subdirs %s', ' '.join(sorted(missing_subdirs)))
00185             # declare inclusion order
00186             data.append(callStringWithIndent('gaudi_depends_on_subdirs', subdirs))
00187             data.append('')
00188             # consider header-only subdirs
00189             #  for each required subdir that comes with only headers, add its
00190             #  location to the call to 'include_directories'
00191             inc_only = lambda s: known_subdirs.get(s.rsplit('/')[-1], {}).get('includes')
00192             inc_dirs = filter(inc_only, subdirs)
00193 
00194 
00195         #  externals (excluding specials)
00196         #  - Python needs to be treated in a special way
00197         find_packages = {}
00198         for n in sorted(self.uses):
00199             if n.startswith("LCG_Interfaces/"):
00200                 n = extName(n[15:])
00201                 # FIXME: find a general way to treat these special cases
00202                 if n == "PythonLibs":
00203                     if self.name not in needing_python: # only these packages actually link against Python
00204                         continue
00205                 # get custom link options
00206                 linkopts = self.macros.get(n + '_linkopts', '')
00207                 components = [m.group(1) or m.group(2)
00208                               for m in re.finditer(r'(?:\$\(%s_linkopts_([^)]*)\))|(?:-l(\w*))' % n,
00209                                                    linkopts)]
00210                 # FIXME: find a general way to treat the special cases
00211                 if n == 'COOL':
00212                     components = ['CoolKernel', 'CoolApplication']
00213                 elif n == 'CORAL':
00214                     components = ['CoralBase', 'CoralKernel', 'RelationalAccess']
00215 
00216                 find_packages[n] = find_packages.get(n, []) + components
00217 
00218         # this second loops avoid double entries do to converging results of extName()
00219         for n in sorted(find_packages):
00220             args = [n]
00221             components = find_packages[n]
00222             if components:
00223                 args.append('COMPONENTS')
00224                 args.extend(components)
00225             data.append('find_package(%s)' % ' '.join(args))
00226         if find_packages:
00227             data.append("")
00228 
00229         if self.name in no_pedantic:
00230             data.append('string(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")\n')
00231 
00232         # the headers can be installed via "PUBLIC_HEADERS" or by hand
00233         if self.install_more_includes:
00234             headers = [d for d in self.install_more_includes.values()
00235                        if os.path.isdir(os.path.join(self.path, d))]
00236         else:
00237             headers = []
00238 
00239         if self.god_headers or self.god_dictionary:
00240             data.append("include(GaudiObjDesc)")
00241             data.append("")
00242 
00243         god_headers_dest = None
00244         if self.god_headers:
00245             godargs = [self.god_headers["files"].replace("../", "")]
00246 
00247             godflags = self.macros.get('%sObj2Doth_GODflags' % self.name, "")
00248             godflags = re.search(r'-s\s*(\S+)', godflags)
00249             if godflags:
00250                 god_headers_dest = os.path.normpath('Event/' + godflags.group(1))
00251                 godargs.append('DESTINATION ' + god_headers_dest)
00252 
00253             data.append(callStringWithIndent('god_build_headers', godargs))
00254             data.append("")
00255 
00256         god_dict = []
00257         if self.god_dictionary:
00258             god_dict = [('--GOD--',
00259                         [self.god_dictionary["files"].replace("../", "")],
00260                         None, [])]
00261 
00262         rflx_dict = []
00263         for d in self.reflex_dictionary:
00264             for k in d:
00265                 v = d[k]
00266                 v = v.replace("$(%sROOT)/" % self.name.upper(), "")
00267                 v = v.replace("../", "")
00268                 d[k] = v
00269             imports = [i.strip('"').replace('-import=', '') for i in d.get('imports', '').strip().split()]
00270             rflx_dict.append((d['dictionary'] + 'Dict',
00271                               [d['headerfiles'], d['selectionfile']],
00272                               None,
00273                               imports))
00274 
00275         # libraries
00276         global_imports = [extName(name[15:])
00277                           for name in self.uses
00278                           if name.startswith('LCG_Interfaces/') and self.uses[name][1]] # list of imported ext
00279         if 'PythonLibs' in global_imports and self.name not in needing_python:
00280             global_imports.remove('PythonLibs')
00281 
00282         subdir_imports = [s.rsplit('/')[-1] for s in subdirs if self.uses[s][1]]
00283         local_links = [] # keep track of linker libraries found so far
00284         applications_names = set([a[0] for a in self.applications])
00285         # Note: a god_dictionary, a reflex_dictionary or an application is like a module
00286         for name, sources, group, imports in self.libraries + god_dict + rflx_dict + self.applications:
00287             isGODDict = isRflxDict = isComp = isApp = isLinker = False
00288             if name == '--GOD--':
00289                 isGODDict = True
00290                 name = '' # no library name for GOD dictionaries
00291             elif name.endswith('Dict') and name[:-4] in self.reflex_dictionaries:
00292                 isRflxDict = True
00293                 name = name[:-4]
00294             elif name in self.component_libraries:
00295                 isComp = True
00296             elif name in applications_names:
00297                 isApp = True
00298             else:
00299                 if name not in self.linker_libraries:
00300                     self.log.warning('library %s not declared as component or linker, assume linker', name)
00301                 isLinker = True
00302 
00303             # prepare the bits of the command: cmd, name, sources, args
00304             if isComp:
00305                 cmd = 'gaudi_add_module'
00306             elif isGODDict:
00307                 cmd = 'god_build_dictionary'
00308             elif isRflxDict:
00309                 cmd = 'gaudi_add_dictionary'
00310             elif isApp:
00311                 cmd = 'gaudi_add_executable'
00312             else: # i.e. isLinker (a fallback)
00313                 cmd = 'gaudi_add_library'
00314 
00315             if not sources:
00316                 self.log.warning("Missing sources for target %s", name)
00317 
00318             args = []
00319             if isLinker:
00320                 if headers:
00321                     args.append('PUBLIC_HEADERS ' + ' '.join(headers))
00322                 else:
00323                     args.append('NO_PUBLIC_HEADERS')
00324             elif isGODDict:
00325                 if god_headers_dest:
00326                     args.append('HEADERS_DESTINATION ' + god_headers_dest)
00327                 # check if we have a customdict in the documents
00328                 for docname, _, docsources in self.documents:
00329                     if docname == 'customdict':
00330                         args.append('EXTEND ' + docsources[0].replace('../', ''))
00331                         break
00332 
00333 
00334             # # collection of link libraries. #
00335             # Externals and subdirs are treated differently:
00336             # - externals: just use the package name
00337             # - subdirs: find the exported libraries in the global var known_subdirs
00338             # We also have to add the local linker libraries.
00339 
00340             # separate external and subdir explicit imports
00341             subdirsnames = [s.rsplit('/')[-1] for s in subdirs]
00342             subdir_local_imports = [i for i in imports if i in subdirsnames]
00343             ext_local_imports = [extName(i) for i in imports if i not in subdir_local_imports]
00344 
00345             # prepare the link list with the externals
00346             links = global_imports + ext_local_imports
00347             if links or inc_dirs:
00348                 # external links need the include dirs
00349                 args.append('INCLUDE_DIRS ' + ' '.join(links + inc_dirs))
00350             # add subdirs...
00351             for s in subdir_imports + subdir_local_imports:
00352                 if s in known_subdirs:
00353                     links.extend(known_subdirs[s]['libraries'])
00354             # ... and local libraries
00355             links.extend(local_links)
00356             if 'AIDA' in links:
00357                 links.remove('AIDA') # FIXME: AIDA does not have a library
00358 
00359             if links:
00360                 not_included = set(links).difference(find_packages, set([s.rsplit('/')[-1] for s in subdirs]))
00361                 if not_included:
00362                     self.log.warning('imports without use: %s', ', '.join(sorted(not_included)))
00363                 # note: in some cases we get quoted library names
00364                 args.append('LINK_LIBRARIES ' + ' '.join([l.strip('"') for l in links]))
00365 
00366             if isRflxDict and self.reflex_dictionaries[name]:
00367                 args.append('OPTIONS ' + self.reflex_dictionaries[name])
00368 
00369             if isLinker:
00370                 local_links.append(name)
00371 
00372             # FIXME: very very special case :(
00373             if name == 'garbage' and self.name == 'FileStager':
00374                 data.append('# only for the applications\nfind_package(Boost COMPONENTS program_options)\n')
00375 
00376             # write command
00377             sources = [s.replace('../src/', '') for s in sources]
00378             # FIXME: special case
00379             sources = [s.replace('$(GAUDICONFROOT)', '${CMAKE_SOURCE_DIR}/GaudiConf') for s in sources]
00380             libdata = callStringWithIndent(cmd, [name] + sources + args)
00381 
00382             # FIXME: wrap the test libraries in one if block (instead of several)
00383             if group in ('tests', 'test'):
00384                 # increase indentation
00385                 libdata = ['  ' + l for l in libdata.splitlines()]
00386                 # and wrap
00387                 libdata.insert(0, 'if(BUILD_TESTS)')
00388                 libdata.append('endif()')
00389                 libdata = '\n'.join(libdata)
00390             data.append(libdata)
00391             data.append('') # empty line
00392 
00393         # PyQt resources and UIs
00394         if self.PyQtResource or self.PyQtUIC:
00395             data.append("# gen_pyqt_* functions are provided by 'pygraphics'")
00396         if self.PyQtResource:
00397             qrc_files = self.PyQtResource["qrc_files"].replace("../", "")
00398             qrc_dest = self.PyQtResource["outputdir"].replace("../python/", "")
00399             qrc_target = qrc_dest.replace('/', '.') + '.Resources'
00400             data.append('gen_pyqt_resource(%s %s %s)' % (qrc_target, qrc_dest, qrc_files))
00401         if self.PyQtUIC:
00402             ui_files = self.PyQtUIC["ui_files"].replace("../", "")
00403             ui_dest = self.PyQtUIC["outputdir"].replace("../python/", "")
00404             ui_target = qrc_dest.replace('/', '.') + '.UI'
00405             data.append('gen_pyqt_uic(%s %s %s)' % (ui_target, ui_dest, ui_files))
00406         if self.PyQtResource or self.PyQtUIC:
00407             data.append('') # empty line
00408 
00409         # installation
00410         installs = []
00411         if headers and not self.linker_libraries: # not installed yet
00412             installs.append("gaudi_install_headers(%s)" % (" ".join(headers)))
00413         if self.install_python_modules:
00414             # if we install Python modules, we need to check if we have special
00415             # names for the ConfUser modules
00416             if (self.name + 'ConfUserModules') in self.macros:
00417                 installs.append('set_property(DIRECTORY PROPERTY CONFIGURABLE_USER_MODULES %s)'
00418                                 % self.macros[self.name + 'ConfUserModules'])
00419             installs.append("gaudi_install_python_modules()")
00420         if self.install_scripts:
00421             installs.append("gaudi_install_scripts()")
00422         if installs:
00423             data.extend(installs)
00424             data.append('') # empty line
00425         # tests
00426         if self.QMTest:
00427             data.append("\ngaudi_add_test(QMTest QMTEST)")
00428 
00429         return "\n".join(data) + "\n"
00430 
00431     def process(self, force=False):
00432         # @FIXME: do something for the package
00433         cml = os.path.join(self.path, "CMakeLists.txt")
00434         if not force and os.path.exists(cml):
00435             self.log.warning("file %s already exists", cml)
00436             return
00437         data = self.generate()
00438         f = open(cml, "w")
00439         f.write(data)
00440         f.close()
00441 
00442     def _parseRequirements(self):
00443         def requirements():
00444             statement = ""
00445             for l in open(self.requirements):
00446                 if '#' in l:
00447                     l = l[:l.find('#')]
00448                 l = l.strip()
00449                 if l:
00450                     statement += l
00451                     if statement.endswith('\\'):
00452                         statement = statement[:-1] + ' '
00453                         continue
00454                     else:
00455                         try:
00456                             yield list(CMTParser.parseString(statement))
00457                         except:
00458                             # ignore not know statements
00459                             self.log.debug("Failed to parse statement: %r", statement)
00460                         statement = ""
00461 
00462         for args in requirements():
00463             cmd = args.pop(0)
00464             if cmd == 'version':
00465                 self.version = args[0]
00466             elif cmd == "use":
00467                 if "-no_auto_imports" in args:
00468                     imp = False
00469                     args.remove("-no_auto_imports")
00470                 else:
00471                     imp = True
00472                 if len(args) > 1: # only one argument means usually a conditional use
00473                     if len(args) > 2:
00474                         name = "%s/%s" % (args[2], args[0])
00475                     else:
00476                         name = args[0]
00477                     self.uses[name] = (args[1], imp)
00478 
00479             elif cmd == "apply_pattern":
00480                 pattern = args.pop(0)
00481                 args = dict([x.split('=', 1) for x in args])
00482                 if pattern in self.singleton_patterns:
00483                     setattr(self, pattern, args or True)
00484                 elif pattern in self.multi_patterns:
00485                     getattr(self, pattern).append(args)
00486 
00487             elif cmd == 'library':
00488                 name = args.pop(0)
00489                 # digest arguments (options, variables, sources)
00490                 imports = []
00491                 group = None
00492                 sources = []
00493                 for a in args:
00494                     if a.startswith('-'): # options
00495                         if a.startswith('-import='):
00496                             imports.append(a[8:])
00497                         elif a.startswith('-group='):
00498                             group = a[7:]
00499                     elif '=' in a: # variable
00500                         pass
00501                     else: # source
00502                         sources.append(a)
00503                 self.libraries.append((name, sources, group, imports))
00504 
00505             elif cmd == 'application':
00506                 name = args.pop(0)
00507                 # digest arguments (options, variables, sources)
00508                 imports = []
00509                 group = None
00510                 sources = []
00511                 for a in args:
00512                     if a.startswith('-'): # options
00513                         if a.startswith('-import='):
00514                             imports.append(a[8:])
00515                         elif a.startswith('-group='):
00516                             group = a[7:]
00517                         elif a == '-check': # used for test applications
00518                             group = 'tests'
00519                     elif '=' in a: # variable
00520                         pass
00521                     else: # source
00522                         sources.append(a)
00523                 if 'test' in name.lower() or [s for s in sources if 'test' in s.lower()]:
00524                     # usually, developers do not put tests in the right group
00525                     group = 'tests'
00526                 self.applications.append((name, sources, group, imports))
00527 
00528             elif cmd == 'document':
00529                 name = args.pop(0)
00530                 constituent = args.pop(0)
00531                 sources = args
00532                 self.documents.append((name, constituent, sources))
00533 
00534             elif cmd == 'macro':
00535                 # FIXME: should handle macro tags
00536                 name = args.pop(0)
00537                 value = args[0].strip('"').strip("'")
00538                 self.macros[name] = value
00539 
00540             elif cmd == 'macro_append':
00541                 # FIXME: should handle macro tags
00542                 name = args.pop(0)
00543                 value = args[0].strip('"').strip("'")
00544                 self.macros[name] = self.macros.get(name, "") + value
00545 
00546 
00547         # classification of libraries in the package
00548         unquote = lambda x: x.strip('"').strip("'")
00549         self.component_libraries = set([unquote(l['library']) for l in self.component_library])
00550         self.linker_libraries = set([unquote(l['library']) for l in self.linker_library])
00551         self.reflex_dictionaries = dict([(unquote(l['dictionary']), l.get('options', ''))
00552                                          for l in self.reflex_dictionary])
00553 
00554 class Project(object):
00555     def __init__(self, path):
00556         """
00557         Crete a project instance from the root directory of the project.
00558         """
00559         self.path = os.path.realpath(path)
00560         if not isProject(self.path):
00561             raise ValueError("%s is not a project" % self.path)
00562         self.requirements = os.path.join(self.path, "cmt", "project.cmt")
00563         # Private variables for cached properties
00564         self._packages = None
00565         self._container = None
00566 
00567     @property
00568     def packages(self):
00569         """
00570         Dictionary of packages contained in the project.
00571         """
00572         if self._packages is None:
00573             self._packages = {}
00574             for root, dirs, _files in os.walk(self.path):
00575                 if isPackage(root):
00576                     p = Package(root, self)
00577                     name = os.path.relpath(p.path, self.path)
00578                     self._packages[name] = p
00579                     dirs[:] = []
00580         return self._packages
00581 
00582     @property
00583     def container(self):
00584         """
00585         Name of the container package of the project.
00586 
00587         The name of the container is deduced using the usual LHCb convention
00588         (instead of the content of project.cmt).
00589         """
00590         if self._container is None:
00591             for suffix in ["Release", "Sys"]:
00592                 try:
00593                     # gets the first package that ends with the suffix, and does
00594                     # not have a hat.. or raise StopIteration
00595                     c = (p for p in self.packages
00596                          if p.endswith(suffix) and "/" not in p).next()
00597                     self._container = self.packages[c]
00598                     break
00599                 except StopIteration:
00600                     pass
00601         return self._container
00602 
00603     @property
00604     def name(self):
00605         # The name of the project is the same of the container without
00606         # the 'Release' or 'Sys' suffixes.
00607         return self.container.name.replace("Release", "").replace("Sys", "")
00608 
00609     @property
00610     def version(self):
00611         return self.container.version
00612 
00613     def uses(self):
00614         for l in open(self.requirements):
00615             l = l.split()
00616             if l and l[0] == "use" and l[1] != "LCGCMT" and len(l) == 3:
00617                 yield (projectCase(l[1]), l[2].rsplit('_', 1)[-1])
00618 
00619     def generate(self):
00620         # list containing the lines to write to the file
00621         data = ["CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5)",
00622                 "",
00623                 "set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_SOURCE_DIR}/cmake/modules  ${CMAKE_MODULE_PATH})",
00624                 "",
00625                 "#---------------------------------------------------------------",
00626                 "# Load macros and functions for Gaudi-based projects",
00627                 "find_package(GaudiProject)",
00628                 "#---------------------------------------------------------------",
00629                 "",
00630                 "# Declare project name and version"]
00631         l = "gaudi_project(%s %s" % (self.name, self.version)
00632         use = "\n                  ".join(["%s %s" % u for u in self.uses()])
00633         if use:
00634             l += "\n              USE " + use
00635         l += ")"
00636         data.append(l)
00637         return "\n".join(data) + "\n"
00638 
00639     def process(self, force=False):
00640         # Prepare the project configuration
00641         cml = os.path.join(self.path, "CMakeLists.txt")
00642         if force or not os.path.exists(cml):
00643             # write the file
00644             data = self.generate()
00645             f = open(cml, "w")
00646             f.write(data)
00647             f.close()
00648         else:
00649             logging.warning("file %s already exists", cml)
00650         # Recurse in the packages
00651         for p in sorted(self.packages):
00652             self.packages[p].process(force)
00653 
00654 
00655 def main(args=None):
00656     from optparse import OptionParser
00657     parser = OptionParser(usage="%prog [options] [path to project or package]",
00658                           description="Convert CMT-based projects/packages to CMake (Gaudi project)")
00659     parser.add_option("-f", "--force", action="store_true",
00660                       help="overwrite existing files")
00661     parser.add_option('--cache-only', action='store_true',
00662                       help='just update the cache without creating the CMakeLists.txt files.')
00663     #parser.add_option('--cache-file', action='store',
00664     #                  help='file to be used for the cache')
00665 
00666     opts, args = parser.parse_args(args=args)
00667 
00668     logging.basicConfig(level=logging.INFO)
00669 
00670     top_dir = os.getcwd()
00671     if args:
00672         top_dir = args[0]
00673         if not os.path.isdir(top_dir):
00674             parser.error("%s is not a directory" % top_dir)
00675 
00676     if isProject(top_dir):
00677         root = Project(top_dir)
00678     elif isPackage(top_dir):
00679         root = Package(top_dir)
00680         if opts.cache_only:
00681             return # the cache is updated instantiating the package
00682     else:
00683         raise ValueError("%s is neither a project nor a package" % top_dir)
00684 
00685     if opts.cache_only:
00686         root.packages # the cache is updated by instantiating the packages
00687         # note that we can get here only if root is a project
00688     else:
00689         root.process(opts.force)
00690 
00691 
00692 if __name__ == '__main__':
00693     main()
00694     sys.exit(0)
00695 
00696 all_packs = ["Kernel/XMLSummaryBase",
00697 "DAQ/Tell1Kernel",
00698 "Si/SiDAQ",
00699 "Calo/CaloKernel",
00700 "GaudiObjDesc",
00701 "GaudiConfUtils",
00702 "Kernel/Relations",
00703 "Event/DAQEvent",
00704 "Tools/FileStager",
00705 "Tools/XmlTools",
00706 "Kernel/HistoStrings",
00707 "L0/L0Base",
00708 "GaudiMTTools",
00709 "DAQ/MDF",
00710 "DAQ/MDF_ROOT",
00711 "Kernel/LHCbMath",
00712 "Kernel/HltInterfaces",
00713 "Det/DetDesc",
00714 "Det/DetDescSvc",
00715 "Det/DetDescCnv",
00716 "Det/BcmDet",
00717 "Kernel/PartProp",
00718 "Kernel/LHCbKernel",
00719 "L0/ProcessorKernel",
00720 "L0/L0MuonKernel",
00721 "Event/VeloEvent",
00722 "Det/VeloPixDet",
00723 "Det/VeloDet",
00724 "Det/STDet",
00725 "Rich/RichKernel",
00726 "Det/RichDet",
00727 "GaudiConf",
00728 "Kernel/XMLSummaryKernel",
00729 "Det/DetCond",
00730 "Tools/CondDBEntityResolver",
00731 "Ex/DetCondExample",
00732 "Det/DDDB",
00733 "Tools/CondDBUI",
00734 "Det/Magnet",
00735 "Det/DetDescChecks",
00736 "Det/OTDet",
00737 "Muon/MuonKernel",
00738 "Det/MuonDet",
00739 "Event/L0Event",
00740 "L0/L0Interfaces",
00741 "Det/CaloDet",
00742 "Det/CaloDetXmlCnv",
00743 "Ex/DetDescExample",
00744 "Det/DetSys",
00745 "Event/LinkerEvent",
00746 "Event/TrackEvent",
00747 "Tr/TrackKernel",
00748 "Event/DigiEvent",
00749 "OT/OTDAQ",
00750 "Event/EventBase",
00751 "Event/LumiEvent",
00752 "Event/GenEvent",
00753 "Event/MCEvent",
00754 "Kernel/MCInterfaces",
00755 "Sim/SimComponents",
00756 "Event/RecEvent",
00757 "Rich/RichRecBase",
00758 "Phys/LoKiCore",
00759 "Phys/LoKiNumbers",
00760 "Phys/LoKiMC",
00761 "Phys/LoKiGen",
00762 "Muon/MuonInterfaces",
00763 "Tf/TfKernel",
00764 "Tf/TsaKernel",
00765 "Tf/PatKernel",
00766 "ST/STKernel",
00767 "ST/STTELL1Event",
00768 "Kernel/KernelSys",
00769 "Kernel/LHCbAlgs",
00770 "Event/RecreatePIDTools",
00771 "DAQ/DAQUtils",
00772 "Muon/MuonDAQ",
00773 "Tr/TrackInterfaces",
00774 "Calo/CaloInterfaces",
00775 "Event/PhysEvent",
00776 "Event/SwimmingEvent",
00777 "Event/LinkerInstances",
00778 "Event/MicroDst",
00779 "Event/PackedEvent",
00780 "Event/HltEvent",
00781 "Phys/LoKiHlt",
00782 "Event/EventPacker",
00783 "Ex/IOExample",
00784 "Event/EventAssoc",
00785 "Event/EventSys",
00786 "Calo/CaloUtils",
00787 "Calo/CaloDAQ",
00788 "DAQ/DAQSys",
00789 "Associators/MCAssociators",
00790 "LHCbSys",
00791 ]
00792 
00793 #idx = 6
00794 idx = all_packs.index('Event/GenEvent')
00795 
00796 if __name__ == "__main__":
00797     logging.basicConfig(level=logging.INFO)
00798     pr = Project("/home/marco/Devel/LHCb/workspace/LHCb_trunk")
00799     print pr.packages.keys()
00800     print "Woring on", all_packs[idx]
00801 
00802     print "=== Project CMakeLists.txt", "=" * 80
00803     print pr.generate()
00804 
00805     pack = pr.packages[all_packs[idx]]
00806     print "=== Package requirements", "=" * 80
00807     print open(pack.requirements).read()
00808     print "=== Pacakge CMakeLists.txt", "=" * 80
00809     print pack.generate()
00810 
00811     #print "=" * 80
00812     #print pr.packages["Det/DetCond"].generate()
00813 
00814     #print "=" * 80
00815     #print pr.packages["Kernel/LHCbKernel"].generate()
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

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