Gaudi Framework, version v23r4

Home   Generated: Mon Sep 17 2012

make_heptools.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 """
00003 Small tool to generate the heptools toolchain from a given LCGCMT.
00004 """
00005 __author__ = "Marco Clemencic <marco.clemencic@cern.ch>"
00006 
00007 import os
00008 import re
00009 
00010 class HepToolsGenerator(object):
00011     """
00012     Class wrapping the details needed to generate the toolchain file from LCGCMT.
00013     """
00014     __header__ = """cmake_minimum_required(VERSION 2.8.5)
00015 
00016 # Declare the version of HEP Tools we use
00017 # (must be done before including heptools-common to allow evolution of the
00018 # structure)
00019 set(heptools_version  %s)
00020 
00021 include(${CMAKE_CURRENT_LIST_DIR}/heptools-common.cmake)
00022 
00023 # please keep alphabetic order and the structure (tabbing).
00024 # it makes it much easier to edit/read this file!
00025 """
00026     __trailer__ = """
00027 # Prepare the search paths according to the versions above
00028 LCG_prepare_paths()"""
00029 
00030     __AA_projects__ = ("COOL", "CORAL", "RELAX", "ROOT")
00031 
00032     __special_dirs__ = {"CLHEP": "clhep",
00033                         "fftw": "fftw3",
00034                         "Frontier_Client": "frontier_client",
00035                         "GCCXML":  "gccxml",
00036                         "Qt":  "qt",
00037                         "CASTOR":  "castor",
00038                         "lfc": "Grid/LFC",
00039                         }
00040 
00041     __special_names__ = {"qt": "Qt"}
00042 
00043     def __init__(self, lcgcmt_root):
00044         """
00045         Prepare the instance.
00046 
00047         @param lcgcmt_root: path to the root directory of a given LCGCMT version
00048         """
00049         self.lcgcmt_root = lcgcmt_root
00050 
00051     def __repr__(self):
00052         """
00053         Representation of the instance.
00054         """
00055         return "HepToolsGenerator(%r)" % self.lcgcmt_root
00056 
00057     @property
00058     def versions(self):
00059         """
00060         Extract the external names and versions from an installed LCGCMT.
00061 
00062         @return: dictionary mapping external names to versions
00063         """
00064         from itertools import imap
00065         def statements(lines):
00066             """
00067             Generator of CMT statements from a list of lines.
00068             """
00069             statement = "" # we start with an empty statement
00070             for l in imap(lambda l: l.rstrip(), lines): # CMT ignores spaces at the end of line when checking for '\'
00071                 # append the current line to the statement so far
00072                 statement += l
00073                 if statement.endswith("\\"):
00074                     # in this case we need  to strip the '\' and continue the concatenation
00075                     statement = statement[:-1]
00076                 else:
00077                     # we can stop concatenating, but we return only non-trivial statements
00078                     statement = statement.strip()
00079                     if statement:
00080                         yield statement
00081                         statement = "" # we start collecting a new statement
00082 
00083         def tokens(statement):
00084             """
00085             Split a statement in tokens.
00086 
00087             Trivial implementation assuming the tokens do not contain spaces.
00088             """
00089             return statement.split()
00090 
00091         def macro(args):
00092             """
00093             Analyze the arguments of a macro command.
00094 
00095             @return: tuple (name, value, exceptionsDict)
00096             """
00097             unquote = lambda s: s.strip('"')
00098             name = args[0]
00099             value = unquote(args[1])
00100             # make a dictionary of the even to odd remaining args (unquoting the values)
00101             exceptions = dict(zip(args[2::2],
00102                                   map(unquote, args[3::2])))
00103             return name, value, exceptions
00104 
00105         # prepare the dictionary for the results
00106         versions = {}
00107         # We extract the statements from the requirements file of the LCG_Configuration package
00108         req = open(os.path.join(self.lcgcmt_root, "LCG_Configuration", "cmt", "requirements"))
00109         for toks in imap(tokens, statements(req)):
00110             if toks.pop(0) == "macro": # get only the macros ...
00111                 name, value, exceptions = macro(toks)
00112                 if name.endswith("_config_version"): # that end with _config_version
00113                     name = name[:-len("_config_version")]
00114                     name = self.__special_names__.get(name, name)
00115                     for tag in ["target-slc"]: # we use the alternative for 'target-slc' if present
00116                         value = exceptions.get(tag, value)
00117                     versions[name] = value.replace('(', '{').replace(')', '}')
00118         return versions
00119 
00120     def _content(self):
00121         """
00122         Generator producing the content (in blocks) of the toolchain file.
00123         """
00124         versions = self.versions
00125 
00126         yield self.__header__ % versions.pop("LCG")
00127 
00128         yield "\n# Application Area Projects"
00129         for name in self.__AA_projects__:
00130             # the width of the first string is bound to the length of the names
00131             # in self.__AA_projects__
00132             yield "LCG_AA_project(%-5s %s)" % (name, versions.pop(name))
00133 
00134         yield "\n# Compilers"
00135         # @FIXME: to be made cleaner and more flexible
00136         for compiler in [("gcc43", "gcc", "4.3.5"),
00137                          ("gcc46", "gcc", "4.6.2"),
00138                          ("gcc47", "gcc", "4.7.0"),
00139                          ("clang30", "clang", "3.0"),
00140                          ("gccmax", "gcc", "4.7.0")]:
00141             yield "LCG_compiler(%s %s %s)" % compiler
00142 
00143         yield "\n# Externals"
00144         lengths = (max(map(len, versions.keys())),
00145                    max(map(len, versions.values())),
00146                    max(map(len, self.__special_dirs__.values()))
00147                    )
00148         template = "LCG_external_package(%%-%ds %%-%ds %%-%ds)" % lengths
00149 
00150         def packageSorting(pkg):
00151             "special package sorting keys"
00152             key = pkg.lower()
00153             if key == "javajni":
00154                 key = "javasdk_javajni"
00155             return key
00156         for name in sorted(versions.keys(), key=packageSorting):
00157             # special case
00158             if name == "uuid":
00159                 yield "if(NOT ${os} STREQUAL slc6) # uuid is not distributed with SLC6"
00160             # LCG_external_package(CLHEP            1.9.4.7             clhep)
00161             yield template % (name, versions[name], self.__special_dirs__.get(name, ""))
00162             if name == "uuid":
00163                 yield "endif()"
00164 
00165         yield self.__trailer__
00166 
00167     def __str__(self):
00168         """
00169         Return the content of the toolchain file.
00170         """
00171         return "\n".join(self._content())
00172 
00173 if __name__ == '__main__':
00174     import sys
00175     if len(sys.argv) != 2 or not os.path.exists(sys.argv[1]):
00176         print "Usage : %s <path to LCGCMT version>" % os.path.basename(sys.argv[0])
00177         sys.exit(1)
00178     print HepToolsGenerator(sys.argv[1])
 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