1
1
openmpi/contrib/dist/linux/ompi-spec-generator.py
2015-06-23 20:59:57 -07:00

814 строки
27 KiB
Python
Исполняемый файл

#!/usr/bin/env python
#
# generator for Open MPI
import sys
import os
import optparse
import ConfigParser
######################################################################
# global stuff
######################################################################
configext = ".package" # the name of the configurations files
configfiles = [] # list with all found config files
params = 0 # contains the cmd line options
packages = {} # directory for packages
options = ["name", "type", "license", "summary", "files", "version", "description", "group", "vendor", "requires"]
shell_cmds = {}
compilers = { "default" : {"compiler":"default",
"cc": " ",
"cxx":" ",
"f77":" ",
"fc":" "},
"gcc" : {"compiler":"gcc",
"cc":"gcc",
"cxx":"c++",
"f77":"f77",
"fc":"gfortran"},
"icc" : {"compiler":"icc",
"cc":"icc",
"cxx":"icpc",
"f77":"ifort",
"fc":"ifort"}
}
copyright_template = """#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2006 Cisco Systems, Inc. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# don't stop with an error if we don't pack all files at once
%define _unpackaged_files_terminate_build 0
"""
build_macro_template = "%%{!?build_%(name)s: %%define build_%(name)s %(value)i}\n"
build_command_template = '''
BUILD_PACKAGE=%(default)s
for entry in %(files)s; do
for file in $RPM_BUILD_ROOT/$entry; do
if [ -e $file ] ; then
BUILD_PACKAGE=1
fi
done
done
if [ $BUILD_PACKAGE == 1 ] ; then
eval export OMPI_PACKAGE_VERSION=`%(version)s`
rpmbuild %(mode)s --define \'_topdir %%_topdir\' --define \'build_%(name)s 1\' --define \'build_default 0\' --define \"ompi_package_version $OMPI_PACKAGE_VERSION\" %%{ompi_specfile}
fi
'''
global_template = """
#
# global Open MPI stuff
#
%%define ompi_name %(name)s
%%define ompi_name_prefix %(name_prefix)s
%%define ompi_version %(version)s
%%{!?ompi_package_version:%%define ompi_package_version default}
%%define ompi_extra_version %(extra_version)s
%%define ompi_release 1
%%define ompi_prefix %(prefix)s
%%define ompi_build_root %%{_tmppath}/%%{ompi_name}-%%{ompi_version}-%%{ompi_release}-root
%%define ompi_source %%{ompi_name_prefix}%%{ompi_name}-%%{ompi_version}.tar.gz
%%define ompi_url %(url)s
%%define ompi_specfile %%{_topdir}/SPECS/%(output)s
%%define ompi_configure_params %(configure_params)s
%%define ompi_compile_root %%{ompi_name_prefix}%%{ompi_name}-%%{ompi_version}
#
# fix configure
#
%%define _prefix %%{ompi_prefix}
%%define _sysconfdir %%{_prefix}/etc
%%define _libdir %%{_prefix}/lib
%%define _includedir %%{_prefix}/include
%%define _mandir %%{_prefix}/man
%%define _pkgdatadir %%{_prefix}/share/%%{ompi_name}
"""
compiler_template = """
#
# compiler settings
#
%%define ompi_compiler %(compiler)s
%%define ompi_cc \"%(cc)s\"
%%define ompi_cxx \"%(cxx)s\"
%%define ompi_f77 \"%(f77)s\"
%%define ompi_fc \"%(fc)s\"
"""
build_template = """
######################################################################
#
# Build section
#
######################################################################
%%if %%{build_build}
Summary: Configure and build the Open MPI tree
Name: %%{ompi_name_prefix}%%{ompi_name}
Version: %%{ompi_version}
Release: %%{ompi_release}
License: BSD
Group: Others
URL: %%{ompi_url}
Source0: %%{ompi_source}
BuildRoot: %%{ompi_build_root}
%%description
This part build and install the Open MPI source tree.
%%prep
%%setup -q
%%build
OMPI_CONFIGURE_FLAGS=\"%%{ompi_configure_params}\"
if [ \"%%{ompi_compiler}\" != \"default\" ]; then
OMPI_CONFIGURE_FLAGS=\"$OMPI_CONFIGURE_FLAGS CC=%%{ompi_cc} CXX=%%{ompi_cxx} F77=%%{ompi_f77} FC=%%{ompi_fc}\"
fi
%%configure $OMPI_CONFIGURE_FLAGS
make -j4
%%install
%%clean
%%files
%%defattr(-,root,root,-)
%%endif
"""
install_template = """
######################################################################
#
# Install section
#
######################################################################
%%if %%{build_install}
Summary: Install a already compiled tree
Name: %%{ompi_name_prefix}%%{ompi_name}
Version: %%{ompi_version}
Release: %%{ompi_release}
License: BSD
Group: Others
URL: %%{ompi_url}
Source0: %%{ompi_source}
BuildRoot: %%{ompi_build_root}
%%description
This part build and install the Open MPI source tree.
%%prep
%%build
%%install
cd %%{ompi_compile_root}
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
#
# create a module file on request
#
if [ %(modulefile_condition)s ] ; then
%%{__mkdir_p} $RPM_BUILD_ROOT/%(modulefile_path)s/%%{ompi_name}/
cat <<EOF >$RPM_BUILD_ROOT/%(modulefile_path)s/%%{ompi_name}/%%{ompi_version}
#%%Module
# NOTE: This is an automatically-generated file! (generated by the
# Open MPI RPM). Any changes made here will be lost a) if the RPM is
# uninstalled, or b) if the RPM is upgraded or uninstalled.
proc ModulesHelp { } {
puts stderr \"This module adds Open MPI v%(ompi_version)s to various paths\"
}
module-whatis \"Sets up Open MPI v%(ompi_version)s in your enviornment\"
append-path PATH \"%%{_prefix}/bin/\"
append-path LD_LIBRARY_PATH %%{_libdir}
append-path MANPATH %%{_mandir}
EOF
fi
#
# profile.d files
#
if [ %(profile_condition)s ] ; then
%%{__mkdir_p} $RPM_BUILD_ROOT/etc/profile.d/
cat <<EOF > $RPM_BUILD_ROOT/etc/profile.d/%%{ompi_name}-%%{ompi_version}.sh
# NOTE: This is an automatically-generated file! (generated by the
# Open MPI RPM). Any changes made here will be lost a) if the RPM is
# uninstalled, or b) if the RPM is upgraded or uninstalled.
CHANGED=0
if test -z \"`echo $PATH | grep %%{_prefix}/bin`\"; then
PATH=\${PATH}:%%{_prefix}/bin/
CHANGED=1
fi
if test -z \"`echo $LD_LIBRARY_PATH | grep %%{_libdir}`\"; then
LD_LIBRARY_PATH=\${LD_LIBRARY_PATH}:%%{_libdir}
CHANGED=1
fi
if test -z \"`echo $MANPATH | grep %%{_mandir}`\"; then
MANPATH=\${MANPATH}:%%{_mandir}
CHANGED=1
fi
if test \"$CHANGED\" = \"1\"; then
export PATH LD_LIBRARY_PATH MANPATH
fi
EOF
cat <<EOF > $RPM_BUILD_ROOT/etc/profile.d/%%{ompi_name}-%%{ompi_version}s.csh
# NOTE: This is an automatically-generated file! (generated by the
# Open MPI RPM). Any changes made here will be lost a) if the RPM is
# uninstalled, or b) if the RPM is upgraded or uninstalled.
if (\"`echo $PATH | grep %%{_prefix}/bin`\") then
setenv PATH \${PATH}:%%{_prefix}/bin/
endif
if (\"$?LD_LIBRARY_PATH\") then
if (\"`echo $LD_LIBRARY_PATH | grep %%{_libdir}`\") then
setenv LD_LIBRARY_PATH \${LD_LIBRARY_PATH}:%%{_libdir}
endif
endif
if (\"$?MANPATH\") then
if (\"`echo $MANPATH | grep %%{_mandir}`\") then
setenv MANPATH \${MANPATH}:%%{_mandir}
endif
endif
EOF
fi
%%clean
%%files
%%defattr(-,root,root,-)
%%endif
"""
package_template = """
######################################################################
#
# %(name)s package section
#
######################################################################
%%if %%{build_%(name)s}
Summary: %(summary)s
Name: %%{ompi_name_prefix}%%{ompi_name}-%(type)s-%(name)s
Version: %%{ompi_version}%(name)s_%%{ompi_package_version}%%{ompi_extra_version}
Release: %%{ompi_release}
License: %(license)s
Group: %(group)s
URL: %%{ompi_url}
Source0: %%{ompi_source}
BuildRoot: %%{ompi_build_root}
Requires: %(requires)s
%%description
%(description)s
%%prep
%%build
%%install
rm -f %(name)s.files
rm -f %(name)s.files.tmp
for i in %(installed_files)s; do
for file in $RPM_BUILD_ROOT/$i ; do
echo $file | sed "s#$RPM_BUILD_ROOT/##g" >> %(name)s.files.tmp
done
done
sort -u %(name)s.files.tmp > %(name)s.files
rm -f %(name)s.files.tmp
%%clean
for i in `cat %(name)s.files`; do
rm -f $RPM_BUILD_ROOT/$i
done
rm %(name)s.files
%%files -f %(name)s.files
%%defattr(-,root,root,-)
%%endif
"""
default_template = """
######################################################################
#
# default
#
######################################################################
%%if %%{build_default}
Summary: Open MPI
Name: %%{ompi_name_prefix}%%{ompi_name}
Version: %%{ompi_version}%%{ompi_extra_version}
Release: %%{ompi_release}
License: %%{ompi_license}
Group: Development/Library
URL: %%{ompi_url}
Source0: %%{ompi_source}
BuildRoot: %%{ompi_build_root}
%%description
Open MPI is a project combining technologies and resources from
several other projects (FT-MPI, LA-MPI, LAM/MPI, and PACX-MPI) in
order to build the best MPI library available.
This RPM contains all the tools necessary to compile, link, and run
Open MPI jobs. Additional this RPM also contains modules for communicating
via shared memory and TCP networks. Components for other transports (e.g.
Myrinet, Infiniband, ...) are provided in separate RPMs.
%%prep
%%build
%(build_cmds)s
%%install
%%clean
rm -rf $RPM_BUILD_ROOT
%%files
%%defattr(-,root,root,-)
%%{ompi_prefix}
%%endif
"""
changelog = """
#############################################################################
#
# Changelog
#
#############################################################################
%changelog
* Tue Jun 27 2006 Sven Stork <stork@hlrs.de>
- switch to specfile generator
* Wed Apr 26 2006 Jeff Squyres <jsquyres@cisco.com>
- Revamp files listings to ensure that rpm -e will remove directories
if rpm -i created them.
- Simplify options for making modulefiles and profile.d scripts.
- Add oscar define.
- Ensure to remove the previous installation root during prep.
- Cleanup the modulefile specification and installation; also ensure
that the profile.d scripts get installed if selected.
- Ensure to list sysconfdir in the files list if it's outside of the
prefix.
* Wed Mar 30 2006 Jeff Squyres <jsquyres@cisco.com>
- Lots of bit rot updates
- Reorganize and rename the subpackages
- Add / formalize a variety of rpmbuild --define options
- Comment out the docs subpackage for the moment (until we have some
documentation -- coming in v1.1!)
* Wed May 03 2005 Jeff Squyres <jsquyres@open-mpi.org>
- Added some defines for LANL defaults
- Added more defines for granulatirty of installation location for
modulefile
- Differentiate between installing in /opt and whether we want to
install environment script files
- Filled in files for man and mca-general subpackages
* Thu Apr 07 2005 Greg Kurtzer <GMKurtzer@lbl.gov>
- Added opt building
- Added profile.d/modulefile logic and creation
- Minor cleanups
* Fri Apr 01 2005 Greg Kurtzer <GMKurtzer@lbl.gov>
- Added comments
- Split package into subpackages
- Cleaned things up a bit
- Sold the code to Microsoft, and now I am retiring. Thanks guys!
* Wed Mar 23 2005 Mezzanine <mezzanine@kainx.org>
- Specfile auto-generated by Mezzanine
"""
######################################################################
#
# class to represent a package
#
######################################################################
class Package:
def __init__(self, name):
self.options = {}
for option in options:
if option == "name":
self.options[option] = name
elif option == "files":
self.options[option] = []
elif option == "version":
self.options[option] = "/bin/echo unknown"
elif option == "group":
self.options[option] = "Development/Library"
elif option == "license":
self.options[option] = "BSD"
elif option == "vendor":
self.options[option] = "Open MPI"
elif option == "requires":
name_prefix = ""
if ( params.ompi_name_prefix != "%{nil}" ):
name_prefix = params.ompi_name_prefix
self.options[option] = name_prefix + params.ompi_name + " >= " + params.ompi_version
else:
self.options[option] = None
def getOption(self, option):
if option in self.options.keys():
return self.options[option]
else:
return None
def setOption(self, option, value):
if ( option == "files" ):
# append file list
self.options["files"] += value.split()
elif ( option == "requires"):
self.options["requires"] += ", " + value
else:
# replace value
self.options[option] = value
def getOptions(self):
return self.options
def Validate(self):
if ( self.options["files"] == [] ):
error("Package %(package)s does not contain files\n" % {"package":self.options["name"]})
sys.exit(-1)
def Dump(self, prefix=""):
global options
for option in options:
print "%(prefix)s %(name)-15s : %(value)s" % {"prefix":prefix, "name":option, "value":self.options[option]}
######################################################################
#
# return the specified package object. If not such an object exist a
# new object will be created and stored in the global packages list
#
######################################################################
def get_package(name):
global packages
if not (name in packages.keys()):
packages[name] = Package(name)
return packages[name]
######################################################################
#
# verbose output
#
######################################################################
def verbose(msg):
if (params.verbose or params.debug):
print msg
######################################################################
#
# debug output
#
######################################################################
def debug(msg):
if (params.debug):
print msg
######################################################################
#
# error output
#
######################################################################
def error(msg):
print "+++ ERROR : " + msg
######################################################################
#
# error output
#
######################################################################
def get_compiler(name):
if name in compilers.keys():
return compilers[name]
else:
error("Failed to find comiler : "+name);
sys.exit(-1)
######################################################################
#
# interactive shell
#
######################################################################
def shell_help(cmd):
for item in shell_cmds.values():
print "%(cmd)-10s - %(help)s" % {"cmd":item["name"], "help":item["help"]}
return True
def shell_quit(cmd):
return False
def shell_list(cmd):
return True
def shell_list(cmd):
for package in packages.keys():
print package
return True
def shell_show(cmd):
if len(cmd) < 2:
print "Usage : show PACKAGE\n"
else:
if cmd[1] in packages.keys():
package = packages[cmd[1]]
package.Dump()
else:
print "Invalid package : " + cmd[1]
return True
def shell_drop(cmd):
if len(cmd) < 2:
print "Usage : drop PACKAGE"
else:
if cmd[1] in packages.keys():
packages.pop(cmd[1])
else:
print "Package not found : " + cmd[1]
return True
def shell_write(cmd):
write_specfile(packages.values())
return True
def register_shell_cmd(name, help, function):
shell_cmds[name] = {"name":name, "help":help, "function":function}
def shell():
loop = True
register_shell_cmd("help", "Display list of available commands.", shell_help)
register_shell_cmd("quit", "Quit the interactive shell", shell_quit)
register_shell_cmd("list", "List all found packages", shell_list)
register_shell_cmd("show", "Display one specific package", shell_show)
register_shell_cmd("drop", "Remove the specified package from the list", shell_drop)
register_shell_cmd("write", "Write the specfile", shell_write)
print "ompi-spec-generator interactive shell"
print "Type 'help' to get more information about available commands."
while loop:
try:
cmd = raw_input("ompi-spec-generator> ")
cmd = cmd.split()
if 0 == len(cmd):
continue
if ( cmd[0] in shell_cmds.keys() ):
shell_cmd = shell_cmds[cmd[0]]
shell_cmd_func = shell_cmd["function"]
loop = shell_cmd_func(cmd)
else:
print "Invalid command"
except Exception:
print "\n"
continue
######################################################################
#
# interactive shell
#
######################################################################
def write_specfile(build_packages):
global params
# create output file
print "--> Create output file"
verbose(" Open outout file : %(filename)s" % {"filename":params.output})
specfile = open(params.output, 'w')
verbose(" Write copyright header")
specfile.write(copyright_template)
verbose(" Create build macros")
specfile.write("# macros to select which part of the specfile should be active\n")
for package in build_packages:
specfile.write(build_macro_template % {"name":package.getOption("name"), "value":0})
specfile.write(build_macro_template % {"name":"build", "value":0})
specfile.write(build_macro_template % {"name":"install", "value":0})
specfile.write(build_macro_template % {"name":"default", "value":1})
verbose(" Write global macro section")
global_params = {"name":params.ompi_name, "prefix" : params.ompi_prefix, "url":params.ompi_url, "version":params.ompi_version, "output":params.output, "extra_version":params.ompi_extra_version, "configure_params":params.ompi_configure_params, "name_prefix":params.ompi_name_prefix}
specfile.write(global_template % global_params)
verbose(" Write compiler section")
specfile.write(compiler_template % get_compiler(params.ompi_compiler))
verbose(" Create package sections")
build_cmds = ""
if params.no_build:
build_cmds += build_command_template % {"files":"/no_build", "default":"0", "name":"build", "mode":"-bc", "version":"/bin/echo unknown"}
else:
build_cmds += build_command_template % {"files":"/no_build", "default":"1", "name":"build", "mode":"-bc", "version":"/bin/echo unknown"}
if params.no_install:
build_cmds += build_command_template % {"files":"/no_install", "default":"0", "name":"install", "mode":"-bi", "version":"/bin/echo unknown"}
else:
build_cmds += build_command_template % {"files":"/no_install", "default":"1", "name":"install", "mode":"-bi", "version":"/bin/echo unknown"}
for package in build_packages:
verbose(" Create section for " + package.getOption("name"));
package_params = package.getOptions()
package_params["installed_files"] = ""
for f in package_params["files"]:
package_params["installed_files"] += "\"" + f + "\" "
specfile.write(package_template % package_params);
# create build command
build_cmds += build_command_template % {"files":package_params["installed_files"], "default":"0", "name":package_params["name"], "mode":"-bb", "version":package_params["version"]}
verbose(" Create build section")
specfile.write(build_template % {"ompi_prefix":params.ompi_prefix})
verbose(" Create install section")
inst_params = {}
inst_params["ompi_name"] = params.ompi_name
inst_params["ompi_version"] = params.ompi_version
if params.ompi_modulefile_path == None:
inst_params["modulefile_condition"] = "1 == 0"
inst_params["modulefile_path"] = "nirwana"
else:
inst_params["modulefile_condition"] = "0 == 0"
inst_params["modulefile_path"] = params.ompi_modulefile_path
if params.ompi_profile_files:
inst_params["profile_condition"] = "0 == 0"
else:
inst_params["profile_condition"] = "1 == 0"
specfile.write(install_template % inst_params)
verbose(" Create default section")
default_params = { "build_cmds": build_cmds, "version":params.ompi_version}
specfile.write(default_template % default_params)
verbose(" Write changelog")
specfile.write(changelog)
verbose(" Close outputfile")
specfile.close()
######################################################################
#
# main function
#
######################################################################
def main():
# parse comand line parameters
global params
param_parser = optparse.OptionParser()
param_parser.add_option("-r", "--root", action="store", dest="root", default="../../../",help="Specify the top root directory of the Open MPI Sources.")
param_parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Dis/Enable verbose output.")
param_parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Dis/Enable debug output.")
param_parser.add_option("-p", "--packages", action="store", dest="packages", default=None, help="Comma separated list of packages to build.")
param_parser.add_option("-o", "--output", action="store", dest="output", default=None, help="Specify the filename of the outputfile.")
param_parser.add_option("-i", "--interactive", action="store_true", dest="interactive", default=False, help="Enter interactive shell after all config files have been parsed.")
param_parser.add_option("--no-build", action="store_true", dest="no_build", default=False, help="Disable the build section.")
param_parser.add_option("--no-install", action="store_true", dest="no_install", default=False, help="Disable the installation.")
param_parser.add_option("--ompi-name", action="store", dest="ompi_name", default="openmpi", help="Specify the name.")
param_parser.add_option("--ompi-prefix", action="store", dest="ompi_prefix", default="/opt/openmpi", help="Specify the installation prefix.")
param_parser.add_option("--ompi-url", action="store", dest="ompi_url", default="http://www.open-mpi.org", help="Specify the tarball to use.")
param_parser.add_option("--ompi-version", action="store", dest="ompi_version", default="1.1", help="Specify the version to use.")
param_parser.add_option("--ompi-extra-version", action="store", dest="ompi_extra_version", default="%{nil}", help="Specify extra version to indicate special builds.")
param_parser.add_option("--ompi-name-prefix", action="store", dest="ompi_name_prefix", default="%{nil}", help="Specify and name prefix for the RPMS.")
param_parser.add_option("--ompi-configure-params", action="store", dest="ompi_configure_params", default="%{nil}", help="Specify extra version to indicate special builds.")
param_parser.add_option("--ompi-compiler", action="store", dest="ompi_compiler", default="default", help="Specify the compiler to use.(default: let configure decide)")
param_parser.add_option("--ompi-modulefile-path", action="store", dest="ompi_modulefile_path", default=None, help="Sets the path of the modulefile directory. If this parameter is omitted no modulefile will be generated.")
param_parser.add_option("--ompi-profile-file", action="store_true", dest="ompi_profile_files", default=False, help="Add file to /etc/profile.d.")
(params, args) = param_parser.parse_args()
if ( params.root == None ):
error("You must specify a the top root directory (option -r).")
sys.exit(-1)
# fix parameters
params.root = os.path.abspath(params.root)
if ( params.ompi_prefix == "/opt/openmpi" ):
params.ompi_prefix = params.ompi_prefix + "/" + params.ompi_version
print "--> Using root " + params.root
if params.output == None:
params.output = params.ompi_name_prefix + params.ompi_name + "-" + params.ompi_version + ".spec"
# find config files
print "--> Search for configuration files"
for root, dirs, files in os.walk(params.root):
for f in files:
if configext != os.path.splitext(f)[1]:
continue
cf = root + "/" + f
configfiles.append(cf)
verbose(" Found : " + cf)
# parse config files
print "--> Parse config files"
for file in configfiles:
verbose(" Parse " + file)
# parse configfile
config = ConfigParser.ConfigParser()
if not (file in config.read(file)):
error("Failed to parse " + file )
sys.exit(-1)
for section in config.sections():
verbose(" Found package information : " + section)
package = get_package(section)
for option in config.options(section):
debug(" Found " + option + "= " + config.get(section, option))
# allow only predefined sections
if not(option in options):
error("Parse error, found invalid option")
error("File : " + file)
error("Package : " + section)
error("Option : " + option)
sys.exit(-1)
# add data into the package object
package.setOption(option, config.get(section, option))
# shell or not shell that's the question
if params.interactive:
shell()
return
# filter packages
print "--> Select packages"
build_packages = []
# filter packages
if params.packages != None:
verbose(" Apply user profided packages list : " + params.packages);
user_packages = params.packages.split(',')
for name in packages.keys():
if name in user_packages:
build_packages.append(packages[name])
else:
verbose(" Remove package : " + name);
else:
# if nothing is specified than use all found packages
build_packages = packages.values()
# do sanity check on the components
print "--> Sanity check packages"
for package in build_packages:
verbose(" Check package " + package.getOption("name") )
if params.debug:
package.Dump(" ")
package.Validate()
# write output file
write_specfile(build_packages)
# done
print "--> Finished."
if ("__main__" == __name__):
main()