Repository: spack/spack

Issue:
hypre/package.py has error on install, but claims to install successfully
I'm having problem with a package that fails to install properly, but still claims to have done so.  See below for relevant part of the log file.

(NOTE: This unrecognized error was obtained by adding "--enable-shared" to the configure() command in package.py.)

Is there a Spack option that keeps the stage around for inspection even after a "successful" install?

-- Elizabeth

```
cfei_hypre.cxx:(.text._ZN3MPI2Op4InitEPFvPKvPviRKNS_8DatatypeEEb[_ZN3MPI2Op4InitEPFvPKvPviRKNS_8DatatypeEEb]+0x18): undefined reference to `ompi_mpi_cxx_op_intercept'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Intracomm::Create_graph(int, int const*, int const*, bool) const':
cfei_hypre.cxx:(.text._ZNK3MPI9Intracomm12Create_graphEiPKiS2_b[_ZNK3MPI9Intracomm12Create_graphEiPKiS2_b]+0x28): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Graphcomm::Clone() const':
cfei_hypre.cxx:(.text._ZNK3MPI9Graphcomm5CloneEv[_ZNK3MPI9Graphcomm5CloneEv]+0x25): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Cartcomm::Clone() const':
cfei_hypre.cxx:(.text._ZNK3MPI8Cartcomm5CloneEv[_ZNK3MPI8Cartcomm5CloneEv]+0x25): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Intercomm::Merge(bool) const':
cfei_hypre.cxx:(.text._ZNK3MPI9Intercomm5MergeEb[_ZNK3MPI9Intercomm5MergeEb]+0x27): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Intracomm::Create(MPI::Group const&) const':
cfei_hypre.cxx:(.text._ZNK3MPI9Intracomm6CreateERKNS_5GroupE[_ZNK3MPI9Intracomm6CreateERKNS_5GroupE]+0x2a): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o:cfei_hypre.cxx:(.text._ZNK3MPI9Intracomm5SplitEii[_ZNK3MPI9Intracomm5SplitEii]+0x26): more undefined references to `MPI::Comm::Comm()' follow
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o:(.data.rel.ro._ZTVN3MPI8DatatypeE[_ZTVN3MPI8DatatypeE]+0x78): undefined reference to `MPI::Datatype::Free()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o:(.data.rel.ro._ZTVN3MPI3WinE[_ZTVN3MPI3WinE]+0x48): undefined reference to `MPI::Win::Free()'
collect2: error: ld returned 1 exit status
make[1]: *** [libHYPRE.so] Error 1
make[1]: Leaving directory `/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/lib'

Installing hypre ...
mkdir -p -- /home/rpfische/spack/opt/spack/linux-x86_64/gcc-4.9.3/hypre-2.10.0b-d4ed63tt5dncdjplfv6jjz55xevbkj3y/lib /home/rpfische/spack/opt/spack/linux-x86_64/gcc-4.9.3/hypre-2.10.0b-d4ed63tt5dncdjplfv6jjz55xevbkj3y/include
cp: cannot stat ‘/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/hypre/lib/*’: No such file or directory

==> Successfully installed hypre
  Fetch: 6.61s.  Build: 40.01s.  Total: 46.62s
[+] /home/rpfische/spack/opt/spack/linux-x86_64/gcc-4.9.3/hypre-2.10.0b-d4ed63tt5dncdjplfv6jjz55xevbkj3y
[rpfische@ankeli build]$ 
```

hypre/package.py has error on install, but claims to install successfully
I'm having problem with a package that fails to install properly, but still claims to have done so.  See below for relevant part of the log file.

(NOTE: This unrecognized error was obtained by adding "--enable-shared" to the configure() command in package.py.)

Is there a Spack option that keeps the stage around for inspection even after a "successful" install?

-- Elizabeth

```
cfei_hypre.cxx:(.text._ZN3MPI2Op4InitEPFvPKvPviRKNS_8DatatypeEEb[_ZN3MPI2Op4InitEPFvPKvPviRKNS_8DatatypeEEb]+0x18): undefined reference to `ompi_mpi_cxx_op_intercept'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Intracomm::Create_graph(int, int const*, int const*, bool) const':
cfei_hypre.cxx:(.text._ZNK3MPI9Intracomm12Create_graphEiPKiS2_b[_ZNK3MPI9Intracomm12Create_graphEiPKiS2_b]+0x28): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Graphcomm::Clone() const':
cfei_hypre.cxx:(.text._ZNK3MPI9Graphcomm5CloneEv[_ZNK3MPI9Graphcomm5CloneEv]+0x25): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Cartcomm::Clone() const':
cfei_hypre.cxx:(.text._ZNK3MPI8Cartcomm5CloneEv[_ZNK3MPI8Cartcomm5CloneEv]+0x25): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Intercomm::Merge(bool) const':
cfei_hypre.cxx:(.text._ZNK3MPI9Intercomm5MergeEb[_ZNK3MPI9Intercomm5MergeEb]+0x27): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o: In function `MPI::Intracomm::Create(MPI::Group const&) const':
cfei_hypre.cxx:(.text._ZNK3MPI9Intracomm6CreateERKNS_5GroupE[_ZNK3MPI9Intracomm6CreateERKNS_5GroupE]+0x2a): undefined reference to `MPI::Comm::Comm()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o:cfei_hypre.cxx:(.text._ZNK3MPI9Intracomm5SplitEii[_ZNK3MPI9Intracomm5SplitEii]+0x26): more undefined references to `MPI::Comm::Comm()' follow
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o:(.data.rel.ro._ZTVN3MPI8DatatypeE[_ZTVN3MPI8DatatypeE]+0x78): undefined reference to `MPI::Datatype::Free()'
/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/FEI_mv/fei-hypre/cfei_hypre.o:(.data.rel.ro._ZTVN3MPI3WinE[_ZTVN3MPI3WinE]+0x48): undefined reference to `MPI::Win::Free()'
collect2: error: ld returned 1 exit status
make[1]: *** [libHYPRE.so] Error 1
make[1]: Leaving directory `/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/lib'

Installing hypre ...
mkdir -p -- /home/rpfische/spack/opt/spack/linux-x86_64/gcc-4.9.3/hypre-2.10.0b-d4ed63tt5dncdjplfv6jjz55xevbkj3y/lib /home/rpfische/spack/opt/spack/linux-x86_64/gcc-4.9.3/hypre-2.10.0b-d4ed63tt5dncdjplfv6jjz55xevbkj3y/include
cp: cannot stat ‘/tmp/rpfische/spack-stage/spack-stage-u5iMsT/hypre-2.10.0b/src/hypre/lib/*’: No such file or directory

==> Successfully installed hypre
  Fetch: 6.61s.  Build: 40.01s.  Total: 46.62s
[+] /home/rpfische/spack/opt/spack/linux-x86_64/gcc-4.9.3/hypre-2.10.0b-d4ed63tt5dncdjplfv6jjz55xevbkj3y
[rpfische@ankeli build]$ 
```



Discussion:
Like `spack install --keep-stage`?

```
$ spack install -h
usage: spack install [-h] [-i] [-j JOBS] [--keep-prefix] [--keep-stage] [-n]
                     [-v] [--fake]
                     ...

positional arguments:
  packages              specs of packages to install

optional arguments:
  -h, --help            show this help message and exit
  -i, --ignore-dependencies
                        Do not try to install dependencies of requested
                        packages.
  -j JOBS, --jobs JOBS  Explicitly set number of make jobs. Default is #cpus.
  --keep-prefix         Don't remove the install prefix if installation fails.
  --keep-stage          Don't remove the build stage if installation succeeds.
  -n, --no-checksum     Do not check packages against checksum
  -v, --verbose         Display verbose build output while installing.
  --fake                Fake install. Just remove the prefix and touch a fake
                        file in it.
```

Are there any thoughts on the core bug here --- that  a package had failures on install, but Spack claimed it installed successfully?

Like `spack install --keep-stage`?

```
$ spack install -h
usage: spack install [-h] [-i] [-j JOBS] [--keep-prefix] [--keep-stage] [-n]
                     [-v] [--fake]
                     ...

positional arguments:
  packages              specs of packages to install

optional arguments:
  -h, --help            show this help message and exit
  -i, --ignore-dependencies
                        Do not try to install dependencies of requested
                        packages.
  -j JOBS, --jobs JOBS  Explicitly set number of make jobs. Default is #cpus.
  --keep-prefix         Don't remove the install prefix if installation fails.
  --keep-stage          Don't remove the build stage if installation succeeds.
  -n, --no-checksum     Do not check packages against checksum
  -v, --verbose         Display verbose build output while installing.
  --fake                Fake install. Just remove the prefix and touch a fake
                        file in it.
```

Are there any thoughts on the core bug here --- that  a package had failures on install, but Spack claimed it installed successfully?


Resolving patch:
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -318,6 +318,17 @@ class SomePackage(Package):
     """Most packages are NOT extendable.  Set to True if you want extensions."""
     extendable = False
 
+    """List of prefix-relative file paths. If these do not exist after
+       install, or if they exist but are not files, sanity checks fail.
+    """
+    sanity_check_files = []
+
+    """List of prefix-relative directory paths. If these do not exist
+       after install, or if they exist but are not directories, sanity
+       checks will fail.
+    """
+    sanity_check_dirs = []
+
 
     def __init__(self, spec):
         # this determines how the package should be built.
@@ -909,7 +920,7 @@ def build_process():
                          raise e
 
                      # Ensure that something was actually installed.
-                     self._sanity_check_install()
+                     self.sanity_check_prefix()
 
                      # Copy provenance into the install directory on success
                      log_install_path = spack.install_layout.build_log_path(self.spec)
@@ -952,7 +963,18 @@ def build_process():
         spack.hooks.post_install(self)
 
 
-    def _sanity_check_install(self):
+    def sanity_check_prefix(self):
+        """This function checks whether install succeeded."""
+        def check_paths(path_list, filetype, predicate):
+            for path in path_list:
+                abs_path = os.path.join(self.prefix, path)
+                if not predicate(abs_path):
+                    raise InstallError("Install failed for %s. No such %s in prefix: %s"
+                                       % (self.name, filetype, path))
+
+        check_paths(self.sanity_check_files, 'file', os.path.isfile)
+        check_paths(self.sanity_check_dirs, 'directory', os.path.isdir)
+
         installed = set(os.listdir(self.prefix))
         installed.difference_update(spack.install_layout.hidden_file_paths)
         if not installed:
diff --git a/var/spack/repos/builtin/packages/libelf/package.py b/var/spack/repos/builtin/packages/libelf/package.py
--- a/var/spack/repos/builtin/packages/libelf/package.py
+++ b/var/spack/repos/builtin/packages/libelf/package.py
@@ -38,6 +38,9 @@ class Libelf(Package):
 
     provides('elf')
 
+    sanity_check_files = ['include/libelf.h']
+    sanity_check_dirs  = ['lib']
+
     def install(self, spec, prefix):
         configure("--prefix=" + prefix,
                   "--enable-shared",


Test patch: