From 15d2883abecec3433d2b3daa61a4edbb730d8451 Mon Sep 17 00:00:00 2001
From: Sergey Kosukhin <sergey.kosukhin@mpimet.mpg.de>
Date: Tue, 26 May 2020 02:14:47 +0200
Subject: [PATCH] openmpi: get rid of implicit system dependencies (#16758)

* openmpi: get rid of implicit system dependencies

* Python 2 compatibility.

* Rename pbspro to openpbs and revert packages.yaml.

* Remove virtual package 'sendmail'.
---
 .../repos/builtin/packages/libical/package.py |  22 ++
 .../repos/builtin/packages/lsf/package.py     |   9 +-
 .../repos/builtin/packages/mxm/package.py     |  30 +++
 .../repos/builtin/packages/openmpi/package.py |  98 ++------
 .../builtin/packages/openpbs/install.patch    |  52 ++++
 .../builtin/packages/openpbs/no_crypt.patch   |  21 ++
 .../repos/builtin/packages/openpbs/package.py |  94 +++++++
 .../builtin/packages/openpbs/python.patch     |  11 +
 .../builtin/packages/openpbs/with_lib.patch   | 231 ++++++++++++++++++
 .../builtin/packages/ssmtp/install.patch      |  11 +
 .../repos/builtin/packages/ssmtp/package.py   |  58 +++++
 11 files changed, 553 insertions(+), 84 deletions(-)
 create mode 100644 var/spack/repos/builtin/packages/libical/package.py
 create mode 100644 var/spack/repos/builtin/packages/mxm/package.py
 create mode 100644 var/spack/repos/builtin/packages/openpbs/install.patch
 create mode 100644 var/spack/repos/builtin/packages/openpbs/no_crypt.patch
 create mode 100644 var/spack/repos/builtin/packages/openpbs/package.py
 create mode 100644 var/spack/repos/builtin/packages/openpbs/python.patch
 create mode 100644 var/spack/repos/builtin/packages/openpbs/with_lib.patch
 create mode 100644 var/spack/repos/builtin/packages/ssmtp/install.patch
 create mode 100644 var/spack/repos/builtin/packages/ssmtp/package.py

diff --git a/var/spack/repos/builtin/packages/libical/package.py b/var/spack/repos/builtin/packages/libical/package.py
new file mode 100644
index 0000000000..6116b0b649
--- /dev/null
+++ b/var/spack/repos/builtin/packages/libical/package.py
@@ -0,0 +1,22 @@
+# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack import *
+
+
+class Libical(CMakePackage):
+    """Libical - an implementation of iCalendar protocols and data formats."""
+
+    homepage = "https://github.com/libical/libical"
+    url = "https://github.com/libical/libical/archive/v3.0.8.tar.gz"
+
+    version('3.0.8', sha256='09fecacaf75ba5a242159e3a9758a5446b5ce4d0ab684f98a7040864e1d1286f')
+
+    depends_on('cmake@3.11.0:', type='build')
+    depends_on('perl', type='build')
+    depends_on('icu4c')
+
+    def cmake_args(self):
+        return ['-DENABLE_GTK_DOC=OFF']
diff --git a/var/spack/repos/builtin/packages/lsf/package.py b/var/spack/repos/builtin/packages/lsf/package.py
index ccb04d01ac..5c92693c4d 100644
--- a/var/spack/repos/builtin/packages/lsf/package.py
+++ b/var/spack/repos/builtin/packages/lsf/package.py
@@ -10,7 +10,10 @@
 class Lsf(Package):
     """IBM Platform LSF is a batch scheduler for HPC environments"""
 
-    homepage = "https://www.ibm.com/marketplace/hpc-workload-management"
+    homepage = "https://www.ibm.com/products/hpc-workload-management"
+    has_code = False
+
+    version('10.1')
 
     # LSF needs to be added as an external package to SPACK. For this, the
     # config file packages.yaml needs to be adjusted:
@@ -21,4 +24,6 @@ class Lsf(Package):
     #     buildable: False
 
     def install(self, spec, prefix):
-        raise InstallError('LSF is not installable; it is vendor supplied')
+        raise InstallError(
+            self.spec.format('{name} is not installable, you need to specify '
+                             'it as an external package in packages.yaml'))
diff --git a/var/spack/repos/builtin/packages/mxm/package.py b/var/spack/repos/builtin/packages/mxm/package.py
new file mode 100644
index 0000000000..897f1c24b3
--- /dev/null
+++ b/var/spack/repos/builtin/packages/mxm/package.py
@@ -0,0 +1,30 @@
+# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack import *
+
+
+class Mxm(Package):
+    """Mellanox Messaging Accelerator (MXM) provides enhancements to parallel
+    communication libraries by fully utilizing the underlying networking
+    infrastructure provided by Mellanox HCA/switch hardware."""
+
+    homepage = 'https://www.mellanox.com/products/mxm'
+    has_code = False
+
+    version('3.6.3104')
+
+    # MXM needs to be added as an external package to SPACK. For this, the
+    # config file packages.yaml needs to be adjusted:
+    #   mxm:
+    #     version: [3.6.3104]
+    #     paths:
+    #       mxm@3.6.3104: /opt/mellanox/mxm (path to your MXM installation)
+    #     buildable: False
+
+    def install(self, spec, prefix):
+        raise InstallError(
+            self.spec.format('{name} is not installable, you need to specify '
+                             'it as an external package in packages.yaml'))
diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py
index 700711c55e..183447236f 100644
--- a/var/spack/repos/builtin/packages/openmpi/package.py
+++ b/var/spack/repos/builtin/packages/openmpi/package.py
@@ -9,54 +9,6 @@
 import llnl.util.tty as tty
 
 
-def _verbs_dir():
-    """Try to find the directory where the OpenFabrics verbs package is
-    installed. Return None if not found.
-    """
-    try:
-        # Try to locate Verbs by looking for a utility in the path
-        ibv_devices = which("ibv_devices")
-        # Run it (silently) to ensure it works
-        ibv_devices(output=str, error=str)
-        # Get path to executable
-        path = ibv_devices.exe[0]
-        # Remove executable name and "bin" directory
-        path = os.path.dirname(path)
-        path = os.path.dirname(path)
-        # There's usually no "/include" on Unix; use "/usr/include" instead
-        if path == "/":
-            path = "/usr"
-        return path
-    except TypeError:
-        return None
-    except ProcessError:
-        return None
-
-
-def _mxm_dir():
-    """Look for default directory where the Mellanox package is
-    installed. Return None if not found.
-    """
-    # Only using default directory; make this more flexible in the future
-    path = "/opt/mellanox/mxm"
-    if os.path.isdir(path):
-        return path
-    else:
-        return None
-
-
-def _tm_dir():
-    """Look for default directory where the PBS/TM package is
-    installed. Return None if not found.
-    """
-    # /opt/pbs from PBS 18+; make this more flexible in the future
-    paths_list = ("/opt/pbs", )
-    for path in paths_list:
-        if os.path.isdir(path) and os.path.isfile(path + "/include/tm.h"):
-            return path
-    return None
-
-
 class Openmpi(AutotoolsPackage):
     """An open source Message Passing Interface implementation.
 
@@ -276,6 +228,8 @@ class Openmpi(AutotoolsPackage):
     depends_on('m4',       type='build', when='@develop')
     depends_on('perl',     type='build', when='@develop')
 
+    depends_on('pkgconfig', type='build')
+
     depends_on('hwloc')
     # ompi@:3.0.0 doesn't support newer hwloc releases:
     # "configure: error: OMPI does not currently support hwloc v2 API"
@@ -288,13 +242,18 @@ class Openmpi(AutotoolsPackage):
     depends_on('sqlite', when='+sqlite3@:1.11')
     depends_on('zlib', when='@3.0.0:')
     depends_on('valgrind~mpi', when='+memchecker')
+
     depends_on('ucx', when='fabrics=ucx')
     depends_on('ucx +thread_multiple', when='fabrics=ucx +thread_multiple')
     depends_on('ucx +thread_multiple', when='@3.0.0: fabrics=ucx')
     depends_on('libfabric', when='fabrics=libfabric')
+    depends_on('mxm', when='fabrics=mxm')
+    depends_on('binutils+libiberty', when='fabrics=mxm')
+    depends_on('rdma-core', when='fabrics=verbs')
+
     depends_on('slurm', when='schedulers=slurm')
     depends_on('lsf', when='schedulers=lsf')
-    depends_on('binutils+libiberty', when='fabrics=mxm')
+    depends_on('openpbs', when='schedulers=tm')
 
     conflicts('+cuda', when='@:1.6')  # CUDA support was added in 1.7
     conflicts('fabrics=psm2', when='@:1.8')  # PSM2 support was added in 1.10.0
@@ -359,43 +318,17 @@ def setup_dependent_package(self, module, dependent_spec):
         ]
 
     def with_or_without_verbs(self, activated):
-        # Up through version 1.6, this option was previously named
-        # --with-openib
-        opt = 'openib'
-        # In version 1.7, it was renamed to be --with-verbs
-        if self.spec.satisfies('@1.7:'):
-            opt = 'verbs'
-        # If the option has not been activated return
-        # --without-openib or --without-verbs
+        # Up through version 1.6, this option was named --with-openib.
+        # In version 1.7, it was renamed to be --with-verbs.
+        opt = 'verbs' if self.spec.satisfies('@1.7:') else 'openib'
         if not activated:
             return '--without-{0}'.format(opt)
-        line = '--with-{0}'.format(opt)
-        path = _verbs_dir()
-        if (path is not None) and (path not in ('/usr', '/usr/local')):
-            line += '={0}'.format(path)
-        return line
-
-    def with_or_without_mxm(self, activated):
-        opt = 'mxm'
-        # If the option has not been activated return --without-mxm
-        if not activated:
-            return '--without-{0}'.format(opt)
-        line = '--with-{0}'.format(opt)
-        path = _mxm_dir()
-        if path is not None:
-            line += '={0}'.format(path)
-        return line
+        return '--with-{0}={1}'.format(opt, self.spec['rdma-core'].prefix)
 
     def with_or_without_tm(self, activated):
-        opt = 'tm'
-        # If the option has not been activated return --without-tm
         if not activated:
-            return '--without-{0}'.format(opt)
-        line = '--with-{0}'.format(opt)
-        path = _tm_dir()
-        if path is not None:
-            line += '={0}'.format(path)
-        return line
+            return '--without-tm'
+        return '--with-tm={0}'.format(self.spec['openpbs'].prefix)
 
     @run_before('autoreconf')
     def die_without_fortran(self):
@@ -471,7 +404,8 @@ def configure_args(self):
 
         # Fabrics
         if 'fabrics=auto' not in spec:
-            config_args.extend(self.with_or_without('fabrics'))
+            config_args.extend(self.with_or_without('fabrics',
+                                                    activation_value='prefix'))
         # The wrappers fail to automatically link libfabric. This will cause
         # undefined references unless we add the appropriate flags.
         if 'fabrics=libfabric' in spec:
diff --git a/var/spack/repos/builtin/packages/openpbs/install.patch b/var/spack/repos/builtin/packages/openpbs/install.patch
new file mode 100644
index 0000000000..8e97fd497c
--- /dev/null
+++ b/var/spack/repos/builtin/packages/openpbs/install.patch
@@ -0,0 +1,52 @@
+--- a/m4/pbs_systemd_unitdir.m4
++++ b/m4/pbs_systemd_unitdir.m4
+@@ -39,14 +39,19 @@
+ AC_DEFUN([PBS_AC_SYSTEMD_UNITDIR],
+ [
+   AC_MSG_CHECKING([system/machine type for systemd unit dir])
+-  systemd_dir="/usr/lib/systemd/system"
+-  AS_IF([test -r "/etc/os-release"],
+-    [system_type=$( cat /etc/os-release | awk -F'=' '/^ID=/' | cut -d "=" -f 2 )
+-      AS_IF([test "x$system_type" = "xubuntu" -o "x$system_type" = "xdebian"],
+-      [systemd_dir="/lib/systemd/system"])
+-    ]
+-  )
+-  _unitdir=$systemd_dir
++dnl  systemd_dir="/usr/lib/systemd/system"
++dnl  AS_IF([test -r "/etc/os-release"],
++dnl    [system_type=$( cat /etc/os-release | awk -F'=' '/^ID=/' | cut -d "=" -f 2 )
++dnl      AS_IF([test "x$system_type" = "xubuntu" -o "x$system_type" = "xdebian"],
++dnl      [systemd_dir="/lib/systemd/system"])
++dnl    ]
++dnl  )
++dnl  _unitdir=$systemd_dir
++  _save_prefix=$prefix; _save_exec_prefix=$exec_prefix
++  test "x$prefix" = xNONE && prefix=$ac_default_prefix
++  test "x$exec_prefix" = xNONE && exec_prefix=$prefix
++  eval "_unitdir=$libdir/systemd/system"
++  prefix=$_save_prefix; exec_prefix=$_save_exec_prefix
+   AC_MSG_RESULT([$_unitdir])
+   AC_SUBST([_unitdir])
+ ])
+--- a/src/cmds/scripts/Makefile.am
++++ b/src/cmds/scripts/Makefile.am
+@@ -67,7 +67,7 @@ dist_pythonlib_PYTHON = \
+ 	pbs_bootcheck.py \
+ 	pbs_topologyinfo.py
+ 
+-sysprofiledir = /etc/profile.d
++sysprofiledir = $(sysconfdir)
+ 
+ dist_sysprofile_DATA = \
+ 	pbs.csh \
+--- a/test/fw/Makefile.am
++++ b/test/fw/Makefile.am
+@@ -59,7 +59,7 @@ ptlpkg_pylib_pluginsdir = $(ptlpkg_pylib_utilsdir)/plugins
+ 
+ dist_ptlpkg_pylib_plugins_PYTHON = $(wildcard $(srcdir)/ptl/utils/plugins/*.py)
+ 
+-sysprofiledir = /etc/profile.d
++sysprofiledir = $(sysconfdir)
+ 
+ dist_sysprofile_DATA = \
+ 	ptl.csh \
diff --git a/var/spack/repos/builtin/packages/openpbs/no_crypt.patch b/var/spack/repos/builtin/packages/openpbs/no_crypt.patch
new file mode 100644
index 0000000000..b91683478d
--- /dev/null
+++ b/var/spack/repos/builtin/packages/openpbs/no_crypt.patch
@@ -0,0 +1,21 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -83,10 +83,6 @@ AC_CHECK_LIB([c], [ruserok],
+   [],
+   AC_CHECK_LIB(socket, ruserok)
+ )
+-AC_CHECK_LIB([c], [crypt],
+-  [],
+-  AC_CHECK_LIB(crypt, crypt)
+-)
+ AC_CHECK_LIB([c], [posix_openpt],
+   AC_DEFINE([HAVE_POSIX_OPENPT], [], [Defined whe posix_openpt is available])
+ )
+@@ -125,7 +121,6 @@ AC_CHECK_HEADERS([ \
+ 	arpa/inet.h \
+ 	asm/types.h \
+ 	assert.h \
+-	crypt.h \
+ 	ctype.h \
+ 	dirent.h \
+ 	dlfcn.h \
diff --git a/var/spack/repos/builtin/packages/openpbs/package.py b/var/spack/repos/builtin/packages/openpbs/package.py
new file mode 100644
index 0000000000..695e5ad595
--- /dev/null
+++ b/var/spack/repos/builtin/packages/openpbs/package.py
@@ -0,0 +1,94 @@
+# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import llnl.util.tty as tty
+from spack import *
+
+
+class Openpbs(AutotoolsPackage):
+    """PBS Professional software optimizes job scheduling and workload
+    management in high-performance computing (HPC) environments - clusters,
+    clouds, and supercomputers - improving system efficiency and people's
+    productivity."""
+
+    # TODO: update the description and the homepage url once the renaming is
+    #  finished: http://community.pbspro.org/t/openpbs-and-version-20-0/2075
+
+    homepage = "https://www.pbspro.org"
+    url = "https://github.com/openpbs/openpbs/archive/v19.1.3.tar.gz"
+
+    version('19.1.3', sha256='6e9d2614f839ff3d91d0ace3de04752b7c075da60c72fe6def76437aa05c9857')
+
+    depends_on('autoconf', type='build')
+    depends_on('automake', type='build')
+    depends_on('libtool', type='build')
+    depends_on('m4', type='build')
+    depends_on('flex', type='build')
+    depends_on('bison', type='build')
+    depends_on('perl', type='build')
+
+    depends_on('ssmtp', type=('build', 'run'))
+    depends_on('xauth', type=('build', 'run'))
+
+    depends_on('python@2.6:2.7', type=('build', 'link', 'run'))
+
+    depends_on('libx11')
+    depends_on('libice')
+    depends_on('libsm')
+    depends_on('openssl')
+    depends_on('postgresql')
+    depends_on('expat')
+    depends_on('libedit')
+    depends_on('ncurses')
+    depends_on('hwloc@:1')
+    depends_on('libical')
+    depends_on('swig')
+    depends_on('tcl')
+    depends_on('tk')
+    depends_on('zlib')
+
+    # The configure script cannot properly handle dependencies in non-system
+    # directories.
+    patch('with_lib.patch')
+
+    # The package does not really depend on libcrypt but links to it. We
+    # eliminate this redundant dependency to avoid linking to a system library.
+    patch('no_crypt.patch')
+
+    # Fix installation directories.
+    patch('install.patch')
+
+    # Link to the dynamic library of Python instead of the static one.
+    patch('python.patch')
+
+    def autoreconf(self, spec, prefix):
+        Executable('./autogen.sh')()
+
+    def configure_args(self):
+        return [
+            '--x-includes=%s' % self.spec['libx11'].prefix.include,
+            '--x-libraries=%s' % self.spec['libx11'].prefix.lib,
+            '--with-pbs-server-home=%s' % self.spec.prefix.var.spool.pbs,
+            '--with-database-dir=%s' % self.spec['postgresql'].prefix,
+            '--with-pbs-conf-file=%s' % self.spec.prefix.etc.join('pbs.conf'),
+            '--with-expat=%s' % self.spec['expat'].prefix,
+            '--with-editline=%s' % self.spec['libedit'].prefix,
+            '--with-hwloc=%s' % self.spec['hwloc'].prefix,
+            '--with-libical=%s' % self.spec['libical'].prefix,
+            '--with-sendmail=%s' % self.spec['ssmtp'].prefix.sbin.sendmail,
+            '--with-swig=%s' % self.spec['swig'].prefix,
+            '--with-tcl=%s' % self.spec['tcl'].prefix,
+            # The argument --with-tk is introduced with with_lib.patch
+            '--with-tk=%s' % self.spec['tk'].prefix,
+            '--with-xauth=xauth',
+            '--with-libz=%s' % self.spec['zlib'].prefix]
+
+    @run_after('install')
+    def post_install(self):
+        # Calling the postinstall script requires root privileges
+        # Executable(self.prefix.libexec.pbs_postinstall)()
+        tty.warn(self.spec.format(
+            'To finalize the installation of {name}, you need to run '
+            '"{prefix}/libexec/pbs_postinstall" with root privileges'))
diff --git a/var/spack/repos/builtin/packages/openpbs/python.patch b/var/spack/repos/builtin/packages/openpbs/python.patch
new file mode 100644
index 0000000000..aacf73140e
--- /dev/null
+++ b/var/spack/repos/builtin/packages/openpbs/python.patch
@@ -0,0 +1,11 @@
+--- a/buildutils/python-autoconf.py
++++ b/buildutils/python-autoconf.py
+@@ -70,7 +70,7 @@ if py_stdlibdir:
+ else:
+     py_stdlibdir_real  = "%s/lib" % (sysconfig.PREFIX,) 
+ 
+-py_lib_configdir = get_py_config_var('LIBPL')
++py_lib_configdir = ''  # get_py_config_var('LIBPL')
+ if py_lib_configdir:
+     py_lib_configdir=py_lib_configdir.replace(py_stdlibdir,py_stdlibdir_real)
+ 
diff --git a/var/spack/repos/builtin/packages/openpbs/with_lib.patch b/var/spack/repos/builtin/packages/openpbs/with_lib.patch
new file mode 100644
index 0000000000..6a607a1611
--- /dev/null
+++ b/var/spack/repos/builtin/packages/openpbs/with_lib.patch
@@ -0,0 +1,231 @@
+--- a/m4/with_database_dir.m4
++++ b/m4/with_database_dir.m4
+@@ -56,20 +56,11 @@ AC_DEFUN([PBS_AC_WITH_DATABASE_DIR],
+       AS_IF([test -r "$database_dir/include/postgresql/libpq-fe.h"],
+         [database_inc="-I$database_dir/include/postgresql"],
+         AC_MSG_ERROR([Database headers not found.]))))
+-  AS_IF([test "$database_dir" = "/usr"],
+-    # Using system installed PostgreSQL
+-    AS_IF([test -r "/usr/lib64/libpq.so" -o -r "/usr/lib/libpq.so" -o -r "/usr/lib/x86_64-linux-gnu/libpq.so"],
+-      [database_lib="-lpq"],
+-      AC_MSG_ERROR([PBS database shared object library not found.])),
+-    # Using developer installed PostgreSQL
+-      AS_IF([test -r "$database_dir/lib64/libpq.a"],
+-        [database_lib="$database_dir/lib64/libpq.a"],
+-        AS_IF([test -r "$database_dir/lib/libpq.a"],
+-          [database_lib="$database_dir/lib/libpq.a"],
+-          AC_MSG_ERROR([PBS database library not found.])
+-        )
+-      )
+-  )
++  AS_IF([test -r "$database_dir/lib64/libpq.so"],
++    [database_lib="-L$database_dir/lib64 -lpq"],
++    [test -r "$database_dir/lib/libpq.so"],
++    [database_lib="-L$database_dir/lib -lpq"],
++    AC_MSG_ERROR([PBS database shared object library not found.]))
+   AC_MSG_RESULT([$database_dir])
+   AC_SUBST([database_dir])
+   AC_SUBST([database_inc])
+--- a/m4/with_editline.m4
++++ b/m4/with_editline.m4
+@@ -52,31 +52,12 @@ AC_DEFUN([PBS_AC_WITH_EDITLINE],
+     AS_IF([test "$editline_dir" != "/usr"],
+       [editline_inc="-I$editline_dir/include"]),
+     AC_MSG_ERROR([editline headers not found.]))
+-  AS_IF([test "$editline_dir" = "/usr"],
+-    # Using system installed editline
+-    AS_IF([test -r /usr/lib64/libedit.so],
+-      [editline_lib="-ledit"],
+-      AS_IF([test -r /usr/lib/libedit.so],
+-        [editline_lib="-ledit"],
+-        AS_IF([test -r /usr/lib/x86_64-linux-gnu/libedit.so],
+-          [editline_lib="-ledit"],
+-          AC_MSG_ERROR([editline shared object library not found.])))),
+-    # Using developer installed editline
+-    AS_IF([test -r "${editline_dir}/lib64/libedit.a"],
+-      [editline_lib="${editline_dir}/lib64/libedit.a"],
+-      AS_IF([test -r "${editline_dir}/lib/libedit.a"],
+-        [editline_lib="${editline_dir}/lib/libedit.a"],
+-        AC_MSG_ERROR([editline library not found.])
+-      )
+-    )
+-  )
++  AS_IF([test -r "$editline_dir/lib64/libedit.so"],
++    [editline_lib="-L$editline_dir/lib64 -ledit"],
++    [test -r "$editline_dir/lib/libedit.so"],
++    [editline_lib="-L$editline_dir/lib -ledit"],
++    AC_MSG_ERROR([editline shared object library not found.]))
+   AC_MSG_RESULT([$editline_dir])
+-  AC_CHECK_LIB([ncurses], [tgetent],
+-    [curses_lib="-lncurses"],
+-    AC_CHECK_LIB([curses], [tgetent],
+-      [curses_lib="-lcurses"],
+-      AC_MSG_ERROR([curses library not found.])))
+-  [editline_lib="$editline_lib $curses_lib"]
+   AC_SUBST(editline_inc)
+   AC_SUBST(editline_lib)
+   AC_DEFINE([QMGR_HAVE_HIST], [], [Defined when editline is available])
+--- a/m4/with_expat.m4
++++ b/m4/with_expat.m4
+@@ -52,20 +52,11 @@ AC_DEFUN([PBS_AC_WITH_EXPAT],
+     AS_IF([test "$expat_dir" != "/usr"],
+       [expat_inc="-I$expat_dir/include"]),
+     AC_MSG_ERROR([expat headers not found.]))
+-  AS_IF([test "$expat_dir" = "/usr"],
+-    # Using system installed expat
+-    AS_IF([test -r "/usr/lib64/libexpat.so" -o -r "/usr/lib/libexpat.so" -o -r "/usr/lib/x86_64-linux-gnu/libexpat.so"],
+-      [expat_lib="-lexpat"],
+-      AC_MSG_ERROR([expat shared object library not found.])),
+-    # Using developer installed expat
+-    AS_IF([test -r "${expat_dir}/lib64/libexpat.a"],
+-      [expat_lib="${expat_dir}/lib64/libexpat.a"],
+-      AS_IF([test -r "${expat_dir}/lib/libexpat.a"],
+-        [expat_lib="${expat_dir}/lib/libexpat.a"],
+-        AC_MSG_ERROR([expat library not found.])
+-      )
+-    )
+-  )
++  AS_IF([test -r "$expat_dir/lib64/libexpat.so"],
++    [expat_lib="-L$expat_dir/lib64 -lexpat"],
++    [test -r "$expat_dir/lib/libexpat.so"],
++    [expat_lib="-L$expat_dir/lib -lexpat"],
++    AC_MSG_ERROR([expat shared object library not found.]))
+   AC_MSG_RESULT([$expat_dir])
+   AC_SUBST(expat_inc)
+   AC_SUBST(expat_lib)
+--- a/m4/with_hwloc.m4
++++ b/m4/with_hwloc.m4
+@@ -56,28 +56,12 @@ AC_DEFUN([PBS_AC_WITH_HWLOC],
+       [hwloc_inc="-I$hwloc_dir/include"]),
+       AC_MSG_ERROR([hwloc headers not found.])
+   )
+-  AS_IF([test "$hwloc_dir" = "/usr"],
+-    # Using system installed hwloc
+-    AS_IF([test -r "/usr/lib64/libhwloc.so" -o -r "/usr/lib/libhwloc.so" -o -r "/usr/lib/x86_64-linux-gnu/libhwloc.so"],
+-      [hwloc_lib="-lhwloc"],
+-      AC_MSG_ERROR([hwloc shared object library not found.])
+-    ),
+-    # Using developer installed hwloc
+-    AS_IF([test -r "${hwloc_dir}/lib64/libhwloc_embedded.a"],
+-      [hwloc_lib="${hwloc_dir}/lib64/libhwloc_embedded.a"],
+-      AS_IF([test -r "${hwloc_dir}/lib/libhwloc_embedded.a"],
+-        [hwloc_lib="${hwloc_dir}/lib/libhwloc_embedded.a"],
+-        AC_MSG_ERROR([hwloc library not found.])
+-      )
+-    )
+-  )
++  AS_IF([test -r "$hwloc_dir/lib64/libhwloc.so"],
++    [hwloc_lib="-L$hwloc_dir/lib64 -lhwloc"],
++    [test -r "$hwloc_dir/lib/libhwloc.so"],
++    [hwloc_lib="-L$hwloc_dir/lib -lhwloc"],
++    AC_MSG_ERROR([hwloc shared object library not found.]))
+   AC_MSG_RESULT([$hwloc_dir])
+-  AS_CASE([x$target_os],
+-    [xlinux*],
+-      AC_CHECK_LIB([numa], [mbind], [hwloc_lib="$hwloc_lib -lnuma"])
+-      AC_CHECK_LIB([udev], [udev_new], [hwloc_lib="$hwloc_lib -ludev"])
+-      AC_CHECK_LIB([pciaccess], [pci_system_init], [hwloc_lib="$hwloc_lib -lpciaccess"])
+-  )
+   AC_SUBST(hwloc_flags)
+   AC_SUBST(hwloc_inc)
+   AC_SUBST(hwloc_lib)
+--- a/m4/with_libical.m4
++++ b/m4/with_libical.m4
+@@ -59,23 +59,13 @@ AC_DEFUN([PBS_AC_WITH_LIBICAL],
+   AS_IF([test $libical_version -gt 1],
+     AC_DEFINE([LIBICAL_API2], [], [Defined when libical version >= 2])
+   )
+-  AS_IF([test "$libical_dir" = "/usr"],
+-    dnl Using system installed libical
+-    libical_inc=""
+-    AS_IF([test -r "/usr/lib64/libical.so" -o -r "/usr/lib/libical.so" -o -r "/usr/lib/x86_64-linux-gnu/libical.so"],
+-      [libical_lib="-lical"],
+-      AC_MSG_ERROR([libical shared object library not found.])
+-    ),
+-    dnl Using developer installed libical
+-    libical_inc="-I$libical_include"
+-    AS_IF([test -r "${libical_dir}/lib64/libical.a"],
+-      [libical_lib="${libical_dir}/lib64/libical.a"],
+-      AS_IF([test -r "${libical_dir}/lib/libical.a"],
+-        [libical_lib="${libical_dir}/lib/libical.a"],
+-        AC_MSG_ERROR([ical library not found.])
+-      )
+-    )
+-  )
++  AS_IF([test "$libical_dir" != "/usr"],
++    [libical_inc="-I$libical_include"])
++  AS_IF([test -r "$libical_dir/lib64/libical.so"],
++    [libical_lib="-L$libical_dir/lib64 -lical"],
++    [test -r "$libical_dir/lib/libical.so"],
++    [libical_lib="-L$libical_dir/lib -lical"],
++    AC_MSG_ERROR([libical shared object library not found.]))
+   AC_MSG_RESULT([$libical_dir])
+   AC_SUBST(libical_inc)
+   AC_SUBST(libical_lib)
+--- a/m4/with_tcl.m4
++++ b/m4/with_tcl.m4
+@@ -52,9 +52,7 @@ AC_DEFUN([PBS_AC_WITH_TCL],
+     [. "$tcl_dir/lib64/tclConfig.sh"],
+     AS_IF([test -r "$tcl_dir/lib/tclConfig.sh"],
+       [. "$tcl_dir/lib/tclConfig.sh"],
+-      AS_IF([test -r "$tcl_dir/lib/x86_64-linux-gnu/tclConfig.sh"],
+-        [. "$tcl_dir/lib/x86_64-linux-gnu/tclConfig.sh"],
+-        AC_MSG_ERROR([tclConfig.sh not found]))))
++      AC_MSG_ERROR([tclConfig.sh not found])))
+   AC_MSG_RESULT([$tcl_dir])
+   AC_MSG_CHECKING([for Tcl version])
+   AS_IF([test "x$TCL_VERSION" = "x"],
+@@ -62,32 +60,34 @@ AC_DEFUN([PBS_AC_WITH_TCL],
+   AC_MSG_RESULT([$TCL_VERSION])
+   [tcl_version="$TCL_VERSION"]
+   AC_SUBST(tcl_version)
++
++  AC_ARG_WITH([tk],
++    AS_HELP_STRING([--with-tk=DIR],
++      [Specify the directory where Tk is installed.]
++    )
++  )
++  AS_IF([test "x$with_tk" != "x"],
++    tk_dir=["$with_tk"],
++    tk_dir=["/usr"]
++  )
+   AC_MSG_CHECKING([for Tk])
+-  AS_IF([test -r "$tcl_dir/lib64/tkConfig.sh"],
+-    [. "$tcl_dir/lib64/tkConfig.sh"],
+-    AS_IF([test -r "$tcl_dir/lib/tkConfig.sh"],
+-      [. "$tcl_dir/lib/tkConfig.sh"],
+-      AS_IF([test -r "$tcl_dir/lib/x86_64-linux-gnu/tkConfig.sh"],
+-        [. "$tcl_dir/lib/x86_64-linux-gnu/tkConfig.sh"],
+-        AC_MSG_ERROR([tkConfig.sh not found]))))
+-  AC_MSG_RESULT([$tcl_dir])
++  AS_IF([test -r "$tk_dir/lib64/tkConfig.sh"],
++    [. "$tk_dir/lib64/tkConfig.sh"],
++    AS_IF([test -r "$tk_dir/lib/tkConfig.sh"],
++      [. "$tk_dir/lib/tkConfig.sh"],
++        AC_MSG_ERROR([tkConfig.sh not found])))
++  AC_MSG_RESULT([$tk_dir])
+   AC_MSG_CHECKING([for Tk version])
+   AS_IF([test "x$TK_VERSION" = "x"],
+     AC_MSG_ERROR([Could not determine Tk version]))
+   AC_MSG_RESULT([$TK_VERSION])
+   [tk_version="$TK_VERSION"]
+   AC_SUBST(tk_version)
+-  AS_IF([test x$TCL_INCLUDE_SPEC = x],
+-    # Using developer installed tcl
+-    [tcl_inc="-I$tcl_dir/include"]
+-    [tcl_lib="$tcl_dir/lib/libtcl$TCL_VERSION.a $TCL_LIBS"]
+-    [tk_inc="-I$tcl_dir/include"]
+-    [tk_lib="$tcl_dir/lib/libtcl$TCL_VERSION.a $tcl_dir/lib/libtk$TK_VERSION.a $TK_LIBS"],
+-    # Using system installed tcl
+-    [tcl_inc="$TCL_INCLUDE_SPEC"]
+-    [tcl_lib="$TCL_LIB_SPEC $TCL_LIBS"]
+-    [tk_inc="$TK_INCLUDE_SPEC"]
+-    [tk_lib=`echo "$TCL_LIB_SPEC $TK_LIB_SPEC $TK_LIBS" | ${SED} -e 's/-lXss //'`])
++
++  tcl_inc="$TCL_INCLUDE_SPEC"
++  tcl_lib="$TCL_LIB_SPEC $TCL_LIBS"
++  tk_inc="$TK_INCLUDE_SPEC"
++  tk_lib=`echo "$TCL_LIB_SPEC $TK_LIB_SPEC $TK_LIBS" | ${SED} -e 's/-lXss //'`
+   AC_SUBST(tcl_inc)
+   AC_SUBST(tcl_lib)
+   AC_SUBST(tk_inc)
diff --git a/var/spack/repos/builtin/packages/ssmtp/install.patch b/var/spack/repos/builtin/packages/ssmtp/install.patch
new file mode 100644
index 0000000000..89992f7ba0
--- /dev/null
+++ b/var/spack/repos/builtin/packages/ssmtp/install.patch
@@ -0,0 +1,11 @@
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -61,7 +61,7 @@ install-sendmail: install
+ 	$(LN_S) ssmtp $(bindir)/sendmail
+ 	$(INSTALL) -d -m 755 $(libexecdir)
+ 	$(RM) $(libexecdir)/sendmail
+-	$(LN_S) sendmail /lib/sendmail
++	$(LN_S) $(bindir)/sendmail $(libexecdir)/sendmail
+ 	$(RM) $(mandir)/sendmail.8
+ 	$(LN_S) ssmtp.8 $(mandir)/sendmail.8
+ 
diff --git a/var/spack/repos/builtin/packages/ssmtp/package.py b/var/spack/repos/builtin/packages/ssmtp/package.py
new file mode 100644
index 0000000000..c1ed9055f2
--- /dev/null
+++ b/var/spack/repos/builtin/packages/ssmtp/package.py
@@ -0,0 +1,58 @@
+# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack import *
+
+
+class Ssmtp(AutotoolsPackage):
+    """A program that replaces sendmail on workstations that should send their
+    mail via the departmental mailhub from which they pick up their mail."""
+
+    homepage = "https://salsa.debian.org/debian/ssmtp"
+    url = "http://deb.debian.org/debian/pool/main/s/ssmtp/ssmtp_2.64.orig.tar.bz2"
+
+    version('2.64', sha256='22c37dc90c871e8e052b2cab0ad219d010fa938608cd66b21c8f3c759046fa36')
+
+    variant('ssl', default=True,
+            description='Enable support for secure connection to mail server')
+    variant('inet6', default=True,
+            description='Enable support for IPv6 transport')
+    variant('md5auth', default=True,
+            description='Enable support for MD5 authentication')
+
+    depends_on('libnsl')
+    depends_on('openssl', when='+ssl')
+
+    patch('install.patch')
+
+    @when('+ssl')
+    def setup_build_environment(self, env):
+        # The configure script is generated with a very old version of
+        # autoconf, which cannot accept LIBS as a command-line argument
+        env.set('LIBS', self.spec['openssl'].libs.link_flags)
+
+    def configure_args(self):
+        args = self.enable_or_disable('ssl')
+        args += self.enable_or_disable('inet6')
+        args += self.enable_or_disable('md5auth')
+        return args
+
+    def install(self, spec, prefix):
+        install_answers = [
+            # Please enter the mail name of your system.
+            # This is the hostname portion of the address to be shown
+            # on outgoing news and mail messages headers.
+            # The default is your system's host name.
+            #
+            # Mail name [system.host.name]:
+            '\n',
+            # Please enter the SMTP port number [25]:
+            '\n'
+        ]
+        install_answers_filename = 'spack-install.in'
+        with working_dir(self.build_directory):
+            with open(install_answers_filename, 'w') as f:
+                f.writelines(install_answers)
+            make('install-sendmail', input=install_answers_filename)
-- 
GitLab