Repository: spack/spack

Issue:
hdf5 install check failure
While trying to install hdf5 I see below error : 

```
make[1]: Leaving directory `/tmp/kumbhar/spack-stage/spack-stage-a_bGUR/hdf5-1.8.15/hl'
Checking HDF5 installation...
==> '/usr/bin/cc' '-c' '-I/home/kumbhar/SPACK_INSTALL/install/linux-rhel7-x86_64/gcc-4.8.5/hdf5-1.8.15-qogppfgr52yh7splcf77xjbsdat63oe3/include' 'check.c'
==> '/usr/bin/cc' '-o' 'check' 'check.o' '-L/home/kumbhar/SPACK_INSTALL/install/linux-rhel7-x86_64/gcc-4.8.5/hdf5-1.8.15-qogppfgr52yh7splcf77xjbsdat63oe3/lib' '-L/home/kumbhar/SPACK_INSTALL/install/linux-rhel7-x86_64/gcc-4.8.5/hdf5-1.8.15-qogppfgr52yh7splcf77xjbsdat63oe3/lib64' '-lhdf5' '-lz'
==> './check'
./check: error while loading shared libraries: libhdf5.so.10: cannot open shared object file: No such file or directory
Produced output does not match expected output.
Expected output:
```

The `package.py` has:

```
            if '+mpi' in spec:
                cc = which('%s' % spec['mpi'].mpicc)
            else:
                cc = which('cc')
            # TODO: Automate these path and library settings
            cc('-c', "-I%s" % join_path(spec.prefix, "include"), "check.c")
```

The problem is obvious due to library paths. Wondering if using `spack_cc` will help for rpath.

Also, if I am building on cross compiling environment, instead of adding check for every platform cray, bg-q etc, is there any way to say `don't run test if I am cross-compiling`? 

P.S. I am using bit older version of spack but it should not matter.



Discussion:
this is similar to https://github.com/LLNL/spack/issues/2276 . `spack_cc` may not help here because, as far as I recall, it only has link flags for dependencies of `hdf5` itself. 

It's probably better to fix it by manually adding link flags for the installed `hdf5`, i.e. `-L<prefix>/lib(64)`.
> It's probably better to fix it by manually adding link flags for the installed hdf5, i.e. -L<prefix>/lib(64).

If I understood your comment correctly, it does that already. But it won't have `LD_LIBRARY_PATH` while executing the exe : 

```
            # TODO: Automate these path and library settings
            cc('-c', "-I%s" % join_path(spec.prefix, "include"), "check.c")
            cc('-o', "check", "check.o",
               "-L%s" % join_path(spec.prefix, "lib"),
               "-L%s" % join_path(spec.prefix, "lib64"),
               "-lhdf5",
               "-lz")
            try:
                check = Executable('./check')
                output = check(return_output=True)
            except:
                output = ""
            success = output == expected
```
As an aside, can we get rid of the `try/except` statement? It makes it really difficult to tell what actually went wrong.
I really think we should be using `spack_cc` here. You shouldn't be compiling with `/usr/bin/cc`, and we shouldn't have to manually provide link flags. But I think @davydden is right in that `spack_cc` only provides RPATHs for dependencies, not for hdf5 itself. So you may need to set `LD_LIBRARY_PATH` as well.
agree, one should switch to `spack_cc`, but you would need to add `LD_LIBRARY_PATH` as well or add `rpaths` manually during building of executables.
I wouldn't add RPATHs because then you need to add OS-specific stuff (I think macOS is different). Easier to just use `LD_LIBRARY_PATH` for this one.
 `LD_LIBRARY_PATH` is also os-specific, in mac-OS it's `DYLD_LIBRARY_PATH` and it also does not work by default on Sierra due to some extra security settings. But I am ok with `LD_LIBRARY_PATH` solution here.
Huh, didn't know that. Maybe we can use RPATH then.
here's one of the relevant posts http://apple.stackexchange.com/questions/215030/el-capitan-make-check-dyld-library-path (it actually started from El Capitan):

> when SIP is enabled, no DYLD_* is exported from a process to its children.

SIP - [System Integrity Protection](https://en.wikipedia.org/wiki/System_Integrity_Protection)
but there are also some corner cases with shells being used, i don't have a detailed understanding of the issue.
This test is supposed to test the already-installed package. Isn't there a simple way to build a small executable against a Spack-installed library? If anything, that's what Spack is for, so it should be easy. I agree about having to use the right compiler (and not `/usr/bin/cc`). Is there a straightforward way to get the relevant information from `pkgconfig`?

Should we generate a small `CMakeLists.txt` file instead of calling `cc` manually with a myriad of difficult flags? Or should we use `pkgconfig` as a simpler means (simpler than `cmake`) to find out what compiler and flags to use?
>  Isn't there a simple way to build a small executable against a Spack-installed library? If anything, that's what Spack is for, so it should be easy.

yeah, there should be easy way to compile the test programs.  
FYI, tests are being discussed here https://github.com/LLNL/spack/issues/2060 but it's mostly for large test suites. Small / simple tests are supposed to work OOB with each package. 

> Isn't there a simple way to build a small executable against a Spack-installed library? 

there is not because the package being installed, or more precisely, it's `prefix.lib` and `prefix.include` are not added anyhow to compiler wrappers. This can be hacked in `build_environment.py` to set `SPACK_DEPENDENCIES` to contain the prefix to the package being installed. Same for `SPACK_RPATH_DEPS` and `SPACK_LINK_DEPS`. Not sure it won't break anything like `cmake` which will have prefix in `CMAKE_PREFIX_PATH`.

To be on the safe side and not to break other 1000+ packages which may have not-ideal build systems, **i would just make the test in this single package work**.


Resolving patch:
diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py
--- a/var/spack/repos/builtin/packages/hdf5/package.py
+++ b/var/spack/repos/builtin/packages/hdf5/package.py
@@ -196,16 +196,12 @@ def check_install(self):
             with open("check.c", 'w') as f:
                 f.write(source)
             if '+mpi' in spec:
-                cc = which('%s' % spec['mpi'].mpicc)
+                cc = Executable(spec['mpi'].mpicc)
             else:
-                cc = which('cc')
-            # TODO: Automate these path and library settings
-            cc('-c', "-I%s" % join_path(spec.prefix, "include"), "check.c")
-            cc('-o', "check", "check.o",
-               "-L%s" % join_path(spec.prefix, "lib"),
-               "-L%s" % join_path(spec.prefix, "lib64"),
-               "-lhdf5",
-               "-lz")
+                cc = Executable(self.compiler.cc)
+            cc(*(['-c', "check.c"] + spec['hdf5'].cppflags.split()))
+            cc(*(['-o', "check", "check.o"] +
+                 spec['hdf5'].libs.ld_flags.split()))
             try:
                 check = Executable('./check')
                 output = check(return_output=True)


Test patch: