00001
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 = ""
00070 for l in imap(lambda l: l.rstrip(), lines):
00071
00072 statement += l
00073 if statement.endswith("\\"):
00074
00075 statement = statement[:-1]
00076 else:
00077
00078 statement = statement.strip()
00079 if statement:
00080 yield statement
00081 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
00101 exceptions = dict(zip(args[2::2],
00102 map(unquote, args[3::2])))
00103 return name, value, exceptions
00104
00105
00106 versions = {}
00107
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":
00111 name, value, exceptions = macro(toks)
00112 if name.endswith("_config_version"):
00113 name = name[:-len("_config_version")]
00114 name = self.__special_names__.get(name, name)
00115 for tag in ["target-slc"]:
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
00131
00132 yield "LCG_AA_project(%-5s %s)" % (name, versions.pop(name))
00133
00134 yield "\n# Compilers"
00135
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
00158 if name == "uuid":
00159 yield "if(NOT ${os} STREQUAL slc6) # uuid is not distributed with SLC6"
00160
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])