Repository: easybuilders/easybuild-easyblocks

Issue:
GCCcore sanity check fails under --module-only
Example:

```
$ eb GCCcore-7.3.0.eb --module-only
...
== FAILED: Installation ended unsuccessfully (build directory: /home/example/easybuild/build/GCCcore/7.3.0/dummy-): build failed (first 300 chars): Sanity check failed: no file found at 'libexec/gcc/x86_64-unknown-linux-gnu/7.3.0/lto1' or 'lib/gcc/x86_64-unknown-linux-gnu/7.3.0/lto1' in /home/example/easybuild/software/GCCcore/7.3.0
```

```
$ ls /home/example/easybuild/software/GCCcore/7.3.0/libexec/gcc
x86_64-pc-linux-gnu
```

Problem is that `self.platform_lib` in the `GCC` easyblock is set based on the result of the `get_platform_name` from `easybuild.tools.systemtools`. This value gets overwritten with the correct value in `configure_step` (based on the `config.guess` script included in the build directory), but this is skipped entirely under `--module-only`...

This can be fixed by simply checking the name of the subdirectory of `libexec/gcc` and `lib/gcc`, rather than deriving it from either `config.guess` or `get_platform_name`.


Discussion:

Resolving patch:
diff --git a/easybuild/easyblocks/g/gcc.py b/easybuild/easyblocks/g/gcc.py
--- a/easybuild/easyblocks/g/gcc.py
+++ b/easybuild/easyblocks/g/gcc.py
@@ -48,9 +48,10 @@
 from easybuild.tools.filetools import apply_regex_substitutions, symlink, write_file
 from easybuild.tools.modules import get_software_root
 from easybuild.tools.run import run_cmd
-from easybuild.tools.systemtools import check_os_dependency, get_os_name, get_os_type, get_platform_name
+from easybuild.tools.systemtools import check_os_dependency, get_os_name, get_os_type
 from easybuild.tools.systemtools import get_gcc_version, get_shared_lib_ext
 from easybuild.tools.toolchain.compiler import OPTARCH_GENERIC
+from easybuild.tools.utilities import nub
 
 
 COMP_CMD_SYMLINKS = {
@@ -381,22 +382,14 @@ def configure_step(self):
         else:
             objdir = self.create_dir("obj")
 
+        # note: this also triggers the use of an updated config.guess script
+        # (unless both the 'build_type' and 'host_type' easyconfig parameters are specified)
         build_type, host_type = self.determine_build_and_host_type()
         if build_type:
             configopts += ' --build=' + build_type
         if host_type:
             configopts += ' --host=' + host_type
 
-        # instead of relying on uname, we use the actual --build option
-        if build_type:
-            self.platform_lib = build_type
-        else:
-            # Fallback
-            out, ec = run_cmd("../config.guess")
-            if ec != 0:
-                raise EasyBuildError('Failed to obtain platform_lib value from config.guess')
-            self.platform_lib = out.strip()
-
         # IV) actual configure, but not on default path
         cmd = "../configure  %s %s" % (self.configopts, configopts)
 
@@ -632,7 +625,26 @@ def sanity_check_step(self):
 
         os_type = get_os_type()
         sharedlib_ext = get_shared_lib_ext()
-        common_infix = os.path.join('gcc', self.platform_lib, self.version)
+
+        # determine "configuration name" directory, see https://sourceware.org/autobook/autobook/autobook_17.html
+        # this differs across GCC versions;
+        # x86_64-unknown-linux-gnu was common for old GCC versions,
+        # x86_64-pc-linux-gnu is more likely with an updated config.guess script;
+        # since this is internal to GCC, we don't really care how it is named exactly,
+        # we only care that it's actually there
+
+        # we may get multiple hits (libexec/, lib/), which is fine,
+        # but we expect the same configuration name subdirectory in each of them
+        glob_pattern = os.path.join(self.installdir, 'lib*', 'gcc', '*-linux-gnu', self.version)
+        matches = glob.glob(glob_pattern)
+        if matches:
+            cands = nub([os.path.basename(os.path.dirname(x)) for x in matches])
+            if len(cands) == 1:
+                config_name_subdir = cands[0]
+            else:
+                raise EasyBuildError("Found multiple candidates for configuration name: %s", ', '.join(cands))
+        else:
+            raise EasyBuildError("Failed to determine configuration name: no matches for '%s'", glob_pattern)
 
         bin_files = ["gcov"]
         lib_files = []
@@ -647,7 +659,7 @@ def sanity_check_step(self):
             else:
                 lib_files.extend(["libasan.%s" % sharedlib_ext, "libasan.a"])
         libexec_files = []
-        dirs = ['lib/%s' % common_infix]
+        dirs = [os.path.join('lib', 'gcc', config_name_subdir, self.version)]
 
         if not self.cfg['languages']:
             # default languages are c, c++, fortran
@@ -686,7 +698,8 @@ def sanity_check_step(self):
             lib_files = [tuple([os.path.join(libdir, x) for libdir in libdirs]) for x in lib_files]
         # lib on SuSE, libexec otherwise
         libdirs = ['libexec', 'lib']
-        libexec_files = [tuple([os.path.join(libdir, common_infix, x) for libdir in libdirs]) for x in libexec_files]
+        common_infix = os.path.join('gcc', config_name_subdir, self.version)
+        libexec_files = [tuple([os.path.join(d, common_infix, x) for d in libdirs]) for x in libexec_files]
 
         old_cmds = [os.path.join('bin', x) for x in COMP_CMD_SYMLINKS.keys()]
 


Test patch: