We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
OpenMPI: Unknown UCC configure option
Trying to build OpenMPI 4.1.1 I get the error/warning that `--with-ucc` is not a known configure option.

It was added in https://github.com/easybuilders/easybuild-easyblocks/pull/2847 

@SebastianAchilles Do you remember which version has this for sure, i.e. where you found that to be missing/required/supported?

We might need to add a version check there.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `easybuild/easyblocks/o/openmpi.py`
Content:
```
1 ##
2 # Copyright 2019-2023 Ghent University
3 #
4 # This file is part of EasyBuild,
5 # originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
6 # with support of Ghent University (http://ugent.be/hpc),
7 # the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
8 # Flemish Research Foundation (FWO) (http://www.fwo.be/en)
9 # and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
10 #
11 # https://github.com/easybuilders/easybuild
12 #
13 # EasyBuild is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation v2.
16 #
17 # EasyBuild is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.
24 ##
25 """
26 EasyBuild support for OpenMPI, implemented as an easyblock
27 
28 @author: Kenneth Hoste (Ghent University)
29 @author: Robert Mijakovic (LuxProvide)
30 """
31 import os
32 import re
33 from easybuild.tools import LooseVersion
34 
35 import easybuild.tools.toolchain as toolchain
36 from easybuild.easyblocks.generic.configuremake import ConfigureMake
37 from easybuild.framework.easyconfig.constants import EASYCONFIG_CONSTANTS
38 from easybuild.tools.build_log import EasyBuildError
39 from easybuild.tools.config import build_option
40 from easybuild.tools.modules import get_software_root
41 from easybuild.tools.systemtools import check_os_dependency, get_shared_lib_ext
42 from easybuild.tools.toolchain.mpi import get_mpi_cmd_template
43 
44 
45 class EB_OpenMPI(ConfigureMake):
46     """OpenMPI easyblock."""
47 
48     def configure_step(self):
49         """Custom configuration step for OpenMPI."""
50 
51         def config_opt_used(key, enable_opt=False):
52             """Helper function to check whether a configure option is already specified in 'configopts'."""
53             if enable_opt:
54                 regex = '--(disable|enable)-%s' % key
55             else:
56                 regex = '--(with|without)-%s' % key
57 
58             return bool(re.search(regex, self.cfg['configopts']))
59 
60         config_opt_names = [
61             # suppress failure modes in relation to mpirun path
62             'mpirun-prefix-by-default',
63             # build shared libraries
64             'shared',
65         ]
66 
67         for key in config_opt_names:
68             if not config_opt_used(key, enable_opt=True):
69                 self.cfg.update('configopts', '--enable-%s' % key)
70 
71         # List of EasyBuild dependencies for which OMPI has known options
72         known_dependencies = ('CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX', 'UCC')
73         # Value to use for `--with-<dep>=<value>` if the dependency is not specified in the easyconfig
74         # No entry is interpreted as no option added at all
75         # This is to make builds reproducible even when the system libraries are changed and avoids failures
76         # due to e.g. finding only PMIx but not libevent on the system
77         unused_dep_value = dict()
78         # Known options since version 3.0 (no earlier ones checked)
79         if LooseVersion(self.version) >= LooseVersion('3.0'):
80             # Default to disable the option with "no"
81             unused_dep_value = {dep: 'no' for dep in known_dependencies}
82             # For these the default is to use an internal copy and not using any is not supported
83             for dep in ('hwloc', 'libevent', 'PMIx'):
84                 unused_dep_value[dep] = 'internal'
85 
86         # handle dependencies
87         for dep in known_dependencies:
88             opt_name = dep.lower()
89             # If the option is already used, don't add it
90             if config_opt_used(opt_name):
91                 continue
92 
93             # libfabric option renamed in OpenMPI 3.1.0 to ofi
94             if dep == 'libfabric' and LooseVersion(self.version) >= LooseVersion('3.1'):
95                 opt_name = 'ofi'
96                 # Check new option name. They are synonyms since 3.1.0 for backward compatibility
97                 if config_opt_used(opt_name):
98                     continue
99 
100             dep_root = get_software_root(dep)
101             # If the dependency is loaded, specify its path, else use the "unused" value, if any
102             if dep_root:
103                 opt_value = dep_root
104             else:
105                 opt_value = unused_dep_value.get(dep)
106             if opt_value is not None:
107                 self.cfg.update('configopts', '--with-%s=%s' % (opt_name, opt_value))
108 
109         if bool(get_software_root('PMIx')) != bool(get_software_root('libevent')):
110             raise EasyBuildError('You must either use both PMIx and libevent as dependencies or none of them. '
111                                  'This is to enforce the same libevent is used for OpenMPI as for PMIx or '
112                                  'the behavior may be unpredictable.')
113 
114         # check whether VERBS support should be enabled
115         if not config_opt_used('verbs'):
116 
117             # for OpenMPI v4.x, the openib BTL should be disabled when UCX is used;
118             # this is required to avoid "error initializing an OpenFabrics device" warnings,
119             # see also https://www.open-mpi.org/faq/?category=all#ofa-device-error
120             is_ucx_enabled = ('--with-ucx' in self.cfg['configopts'] and
121                               '--with-ucx=no' not in self.cfg['configopts'])
122             if LooseVersion(self.version) >= LooseVersion('4.0.0') and is_ucx_enabled:
123                 verbs = False
124             else:
125                 # auto-detect based on available OS packages
126                 os_packages = EASYCONFIG_CONSTANTS['OS_PKG_IBVERBS_DEV'][0]
127                 verbs = any(check_os_dependency(osdep) for osdep in os_packages)
128             # for OpenMPI v5.x, the verbs support is removed, only UCX is available
129             # see https://github.com/open-mpi/ompi/pull/6270
130             if LooseVersion(self.version) <= LooseVersion('5.0.0'):
131                 if verbs:
132                     self.cfg.update('configopts', '--with-verbs')
133                 else:
134                     self.cfg.update('configopts', '--without-verbs')
135 
136         super(EB_OpenMPI, self).configure_step()
137 
138     def test_step(self):
139         """Test step for OpenMPI"""
140         # Default to `make check` if nothing is set. Disable with "runtest = False" in the EC
141         if self.cfg['runtest'] is None:
142             self.cfg['runtest'] = 'check'
143 
144         super(EB_OpenMPI, self).test_step()
145 
146     def load_module(self, *args, **kwargs):
147         """
148         Load (temporary) module file, after resetting to initial environment.
149 
150         Also put RPATH wrappers back in place if needed, to ensure that sanity check commands work as expected.
151         """
152         super(EB_OpenMPI, self).load_module(*args, **kwargs)
153 
154         # ensure RPATH wrappers are in place, otherwise compiling minimal test programs will fail
155         if build_option('rpath'):
156             if self.toolchain.options.get('rpath', True):
157                 self.toolchain.prepare_rpath_wrappers(rpath_filter_dirs=self.rpath_filter_dirs,
158                                                       rpath_include_dirs=self.rpath_include_dirs)
159 
160     def sanity_check_step(self):
161         """Custom sanity check for OpenMPI."""
162 
163         bin_names = ['mpicc', 'mpicxx', 'mpif90', 'mpifort', 'mpirun', 'ompi_info', 'opal_wrapper']
164         if LooseVersion(self.version) >= LooseVersion('5.0.0'):
165             bin_names.append('prterun')
166         else:
167             bin_names.append('orterun')
168         bin_files = [os.path.join('bin', x) for x in bin_names]
169 
170         shlib_ext = get_shared_lib_ext()
171         lib_names = ['mpi_mpifh', 'mpi', 'open-pal']
172         if LooseVersion(self.version) >= LooseVersion('5.0.0'):
173             lib_names.append('prrte')
174         else:
175             lib_names.extend(['ompitrace', 'open-rte'])
176         lib_files = [os.path.join('lib', 'lib%s.%s' % (x, shlib_ext)) for x in lib_names]
177 
178         inc_names = ['mpi-ext', 'mpif-config', 'mpif', 'mpi', 'mpi_portable_platform']
179         if LooseVersion(self.version) >= LooseVersion('5.0.0'):
180             inc_names.append('prte')
181         inc_files = [os.path.join('include', x + '.h') for x in inc_names]
182 
183         custom_paths = {
184             'files': bin_files + inc_files + lib_files,
185             'dirs': [],
186         }
187 
188         # make sure MPI compiler wrappers pick up correct compilers
189         expected = {
190             'mpicc': os.getenv('CC', 'gcc'),
191             'mpicxx': os.getenv('CXX', 'g++'),
192             'mpifort': os.getenv('FC', 'gfortran'),
193             'mpif90': os.getenv('F90', 'gfortran'),
194         }
195         # actual pattern for gfortran is "GNU Fortran"
196         for key in ['mpifort', 'mpif90']:
197             if expected[key] == 'gfortran':
198                 expected[key] = "GNU Fortran"
199         # for PGI, correct pattern is "pgfortran" with mpif90
200         if expected['mpif90'] == 'pgf90':
201             expected['mpif90'] = 'pgfortran'
202         # for Clang the pattern is always clang
203         for key in ['mpicxx', 'mpifort', 'mpif90']:
204             if expected[key] in ['clang++', 'flang']:
205                 expected[key] = 'clang'
206 
207         custom_commands = ["%s --version | grep '%s'" % (key, expected[key]) for key in sorted(expected.keys())]
208 
209         # Add minimal test program to sanity checks
210         # Run with correct MPI launcher
211         mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.OPENMPI, dict(), mpi_version=self.version)
212         # Limit number of ranks to 8 to avoid it failing due to hyperthreading
213         ranks = min(8, self.cfg['parallel'])
214         for srcdir, src, compiler in (
215             ('examples', 'hello_c.c', 'mpicc'),
216             ('examples', 'hello_mpifh.f', 'mpifort'),
217             ('examples', 'hello_usempi.f90', 'mpif90'),
218             ('examples', 'ring_c.c', 'mpicc'),
219             ('examples', 'ring_mpifh.f', 'mpifort'),
220             ('examples', 'ring_usempi.f90', 'mpif90'),
221             ('test/simple', 'thread_init.c', 'mpicc'),
222             ('test/simple', 'intercomm1.c', 'mpicc'),
223             ('test/simple', 'mpi_barrier.c', 'mpicc'),
224         ):
225             src_path = os.path.join(self.cfg['start_dir'], srcdir, src)
226             if os.path.exists(src_path):
227                 test_exe = os.path.join(self.builddir, 'mpi_test_' + os.path.splitext(src)[0])
228                 self.log.info("Adding minimal MPI test program to sanity checks: %s", test_exe)
229 
230                 # Build test binary
231                 custom_commands.append("%s %s -o %s" % (compiler, src_path, test_exe))
232 
233                 # Run the test if chosen
234                 if build_option('mpi_tests'):
235                     params.update({'nr_ranks': ranks, 'cmd': test_exe})
236                     # Allow oversubscription for this test (in case of hyperthreading)
237                     custom_commands.append("OMPI_MCA_rmaps_base_oversubscribe=1 " + mpi_cmd_tmpl % params)
238                     # Run with 1 process which may trigger other bugs
239                     # See https://github.com/easybuilders/easybuild-easyconfigs/issues/12978
240                     params['nr_ranks'] = 1
241                     custom_commands.append(mpi_cmd_tmpl % params)
242 
243         super(EB_OpenMPI, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)
244
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/easybuild/easyblocks/o/openmpi.py b/easybuild/easyblocks/o/openmpi.py
--- a/easybuild/easyblocks/o/openmpi.py
+++ b/easybuild/easyblocks/o/openmpi.py
@@ -69,7 +69,10 @@
                 self.cfg.update('configopts', '--enable-%s' % key)
 
         # List of EasyBuild dependencies for which OMPI has known options
-        known_dependencies = ('CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX', 'UCC')
+        known_dependencies = ['CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX']
+        if LooseVersion(self.version) >= '4.1.4':
+            known_dependencies.append('UCC')
+
         # Value to use for `--with-<dep>=<value>` if the dependency is not specified in the easyconfig
         # No entry is interpreted as no option added at all
         # This is to make builds reproducible even when the system libraries are changed and avoids failures

{"golden_diff": "diff --git a/easybuild/easyblocks/o/openmpi.py b/easybuild/easyblocks/o/openmpi.py\n--- a/easybuild/easyblocks/o/openmpi.py\n+++ b/easybuild/easyblocks/o/openmpi.py\n@@ -69,7 +69,10 @@\n                 self.cfg.update('configopts', '--enable-%s' % key)\n \n         # List of EasyBuild dependencies for which OMPI has known options\n-        known_dependencies = ('CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX', 'UCC')\n+        known_dependencies = ['CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX']\n+        if LooseVersion(self.version) >= '4.1.4':\n+            known_dependencies.append('UCC')\n+\n         # Value to use for `--with-<dep>=<value>` if the dependency is not specified in the easyconfig\n         # No entry is interpreted as no option added at all\n         # This is to make builds reproducible even when the system libraries are changed and avoids failures\n", "issue": "OpenMPI: Unknown UCC configure option\nTrying to build OpenMPI 4.1.1 I get the error/warning that `--with-ucc` is not a known configure option.\r\n\r\nIt was added in https://github.com/easybuilders/easybuild-easyblocks/pull/2847 \r\n\r\n@SebastianAchilles Do you remember which version has this for sure, i.e. where you found that to be missing/required/supported?\r\n\r\nWe might need to add a version check there.\n", "before_files": [{"content": "##\n# Copyright 2019-2023 Ghent University\n#\n# This file is part of EasyBuild,\n# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),\n# with support of Ghent University (http://ugent.be/hpc),\n# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),\n# Flemish Research Foundation (FWO) (http://www.fwo.be/en)\n# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).\n#\n# https://github.com/easybuilders/easybuild\n#\n# EasyBuild is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation v2.\n#\n# EasyBuild is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.\n##\n\"\"\"\nEasyBuild support for OpenMPI, implemented as an easyblock\n\n@author: Kenneth Hoste (Ghent University)\n@author: Robert Mijakovic (LuxProvide)\n\"\"\"\nimport os\nimport re\nfrom easybuild.tools import LooseVersion\n\nimport easybuild.tools.toolchain as toolchain\nfrom easybuild.easyblocks.generic.configuremake import ConfigureMake\nfrom easybuild.framework.easyconfig.constants import EASYCONFIG_CONSTANTS\nfrom easybuild.tools.build_log import EasyBuildError\nfrom easybuild.tools.config import build_option\nfrom easybuild.tools.modules import get_software_root\nfrom easybuild.tools.systemtools import check_os_dependency, get_shared_lib_ext\nfrom easybuild.tools.toolchain.mpi import get_mpi_cmd_template\n\n\nclass EB_OpenMPI(ConfigureMake):\n    \"\"\"OpenMPI easyblock.\"\"\"\n\n    def configure_step(self):\n        \"\"\"Custom configuration step for OpenMPI.\"\"\"\n\n        def config_opt_used(key, enable_opt=False):\n            \"\"\"Helper function to check whether a configure option is already specified in 'configopts'.\"\"\"\n            if enable_opt:\n                regex = '--(disable|enable)-%s' % key\n            else:\n                regex = '--(with|without)-%s' % key\n\n            return bool(re.search(regex, self.cfg['configopts']))\n\n        config_opt_names = [\n            # suppress failure modes in relation to mpirun path\n            'mpirun-prefix-by-default',\n            # build shared libraries\n            'shared',\n        ]\n\n        for key in config_opt_names:\n            if not config_opt_used(key, enable_opt=True):\n                self.cfg.update('configopts', '--enable-%s' % key)\n\n        # List of EasyBuild dependencies for which OMPI has known options\n        known_dependencies = ('CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX', 'UCC')\n        # Value to use for `--with-<dep>=<value>` if the dependency is not specified in the easyconfig\n        # No entry is interpreted as no option added at all\n        # This is to make builds reproducible even when the system libraries are changed and avoids failures\n        # due to e.g. finding only PMIx but not libevent on the system\n        unused_dep_value = dict()\n        # Known options since version 3.0 (no earlier ones checked)\n        if LooseVersion(self.version) >= LooseVersion('3.0'):\n            # Default to disable the option with \"no\"\n            unused_dep_value = {dep: 'no' for dep in known_dependencies}\n            # For these the default is to use an internal copy and not using any is not supported\n            for dep in ('hwloc', 'libevent', 'PMIx'):\n                unused_dep_value[dep] = 'internal'\n\n        # handle dependencies\n        for dep in known_dependencies:\n            opt_name = dep.lower()\n            # If the option is already used, don't add it\n            if config_opt_used(opt_name):\n                continue\n\n            # libfabric option renamed in OpenMPI 3.1.0 to ofi\n            if dep == 'libfabric' and LooseVersion(self.version) >= LooseVersion('3.1'):\n                opt_name = 'ofi'\n                # Check new option name. They are synonyms since 3.1.0 for backward compatibility\n                if config_opt_used(opt_name):\n                    continue\n\n            dep_root = get_software_root(dep)\n            # If the dependency is loaded, specify its path, else use the \"unused\" value, if any\n            if dep_root:\n                opt_value = dep_root\n            else:\n                opt_value = unused_dep_value.get(dep)\n            if opt_value is not None:\n                self.cfg.update('configopts', '--with-%s=%s' % (opt_name, opt_value))\n\n        if bool(get_software_root('PMIx')) != bool(get_software_root('libevent')):\n            raise EasyBuildError('You must either use both PMIx and libevent as dependencies or none of them. '\n                                 'This is to enforce the same libevent is used for OpenMPI as for PMIx or '\n                                 'the behavior may be unpredictable.')\n\n        # check whether VERBS support should be enabled\n        if not config_opt_used('verbs'):\n\n            # for OpenMPI v4.x, the openib BTL should be disabled when UCX is used;\n            # this is required to avoid \"error initializing an OpenFabrics device\" warnings,\n            # see also https://www.open-mpi.org/faq/?category=all#ofa-device-error\n            is_ucx_enabled = ('--with-ucx' in self.cfg['configopts'] and\n                              '--with-ucx=no' not in self.cfg['configopts'])\n            if LooseVersion(self.version) >= LooseVersion('4.0.0') and is_ucx_enabled:\n                verbs = False\n            else:\n                # auto-detect based on available OS packages\n                os_packages = EASYCONFIG_CONSTANTS['OS_PKG_IBVERBS_DEV'][0]\n                verbs = any(check_os_dependency(osdep) for osdep in os_packages)\n            # for OpenMPI v5.x, the verbs support is removed, only UCX is available\n            # see https://github.com/open-mpi/ompi/pull/6270\n            if LooseVersion(self.version) <= LooseVersion('5.0.0'):\n                if verbs:\n                    self.cfg.update('configopts', '--with-verbs')\n                else:\n                    self.cfg.update('configopts', '--without-verbs')\n\n        super(EB_OpenMPI, self).configure_step()\n\n    def test_step(self):\n        \"\"\"Test step for OpenMPI\"\"\"\n        # Default to `make check` if nothing is set. Disable with \"runtest = False\" in the EC\n        if self.cfg['runtest'] is None:\n            self.cfg['runtest'] = 'check'\n\n        super(EB_OpenMPI, self).test_step()\n\n    def load_module(self, *args, **kwargs):\n        \"\"\"\n        Load (temporary) module file, after resetting to initial environment.\n\n        Also put RPATH wrappers back in place if needed, to ensure that sanity check commands work as expected.\n        \"\"\"\n        super(EB_OpenMPI, self).load_module(*args, **kwargs)\n\n        # ensure RPATH wrappers are in place, otherwise compiling minimal test programs will fail\n        if build_option('rpath'):\n            if self.toolchain.options.get('rpath', True):\n                self.toolchain.prepare_rpath_wrappers(rpath_filter_dirs=self.rpath_filter_dirs,\n                                                      rpath_include_dirs=self.rpath_include_dirs)\n\n    def sanity_check_step(self):\n        \"\"\"Custom sanity check for OpenMPI.\"\"\"\n\n        bin_names = ['mpicc', 'mpicxx', 'mpif90', 'mpifort', 'mpirun', 'ompi_info', 'opal_wrapper']\n        if LooseVersion(self.version) >= LooseVersion('5.0.0'):\n            bin_names.append('prterun')\n        else:\n            bin_names.append('orterun')\n        bin_files = [os.path.join('bin', x) for x in bin_names]\n\n        shlib_ext = get_shared_lib_ext()\n        lib_names = ['mpi_mpifh', 'mpi', 'open-pal']\n        if LooseVersion(self.version) >= LooseVersion('5.0.0'):\n            lib_names.append('prrte')\n        else:\n            lib_names.extend(['ompitrace', 'open-rte'])\n        lib_files = [os.path.join('lib', 'lib%s.%s' % (x, shlib_ext)) for x in lib_names]\n\n        inc_names = ['mpi-ext', 'mpif-config', 'mpif', 'mpi', 'mpi_portable_platform']\n        if LooseVersion(self.version) >= LooseVersion('5.0.0'):\n            inc_names.append('prte')\n        inc_files = [os.path.join('include', x + '.h') for x in inc_names]\n\n        custom_paths = {\n            'files': bin_files + inc_files + lib_files,\n            'dirs': [],\n        }\n\n        # make sure MPI compiler wrappers pick up correct compilers\n        expected = {\n            'mpicc': os.getenv('CC', 'gcc'),\n            'mpicxx': os.getenv('CXX', 'g++'),\n            'mpifort': os.getenv('FC', 'gfortran'),\n            'mpif90': os.getenv('F90', 'gfortran'),\n        }\n        # actual pattern for gfortran is \"GNU Fortran\"\n        for key in ['mpifort', 'mpif90']:\n            if expected[key] == 'gfortran':\n                expected[key] = \"GNU Fortran\"\n        # for PGI, correct pattern is \"pgfortran\" with mpif90\n        if expected['mpif90'] == 'pgf90':\n            expected['mpif90'] = 'pgfortran'\n        # for Clang the pattern is always clang\n        for key in ['mpicxx', 'mpifort', 'mpif90']:\n            if expected[key] in ['clang++', 'flang']:\n                expected[key] = 'clang'\n\n        custom_commands = [\"%s --version | grep '%s'\" % (key, expected[key]) for key in sorted(expected.keys())]\n\n        # Add minimal test program to sanity checks\n        # Run with correct MPI launcher\n        mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.OPENMPI, dict(), mpi_version=self.version)\n        # Limit number of ranks to 8 to avoid it failing due to hyperthreading\n        ranks = min(8, self.cfg['parallel'])\n        for srcdir, src, compiler in (\n            ('examples', 'hello_c.c', 'mpicc'),\n            ('examples', 'hello_mpifh.f', 'mpifort'),\n            ('examples', 'hello_usempi.f90', 'mpif90'),\n            ('examples', 'ring_c.c', 'mpicc'),\n            ('examples', 'ring_mpifh.f', 'mpifort'),\n            ('examples', 'ring_usempi.f90', 'mpif90'),\n            ('test/simple', 'thread_init.c', 'mpicc'),\n            ('test/simple', 'intercomm1.c', 'mpicc'),\n            ('test/simple', 'mpi_barrier.c', 'mpicc'),\n        ):\n            src_path = os.path.join(self.cfg['start_dir'], srcdir, src)\n            if os.path.exists(src_path):\n                test_exe = os.path.join(self.builddir, 'mpi_test_' + os.path.splitext(src)[0])\n                self.log.info(\"Adding minimal MPI test program to sanity checks: %s\", test_exe)\n\n                # Build test binary\n                custom_commands.append(\"%s %s -o %s\" % (compiler, src_path, test_exe))\n\n                # Run the test if chosen\n                if build_option('mpi_tests'):\n                    params.update({'nr_ranks': ranks, 'cmd': test_exe})\n                    # Allow oversubscription for this test (in case of hyperthreading)\n                    custom_commands.append(\"OMPI_MCA_rmaps_base_oversubscribe=1 \" + mpi_cmd_tmpl % params)\n                    # Run with 1 process which may trigger other bugs\n                    # See https://github.com/easybuilders/easybuild-easyconfigs/issues/12978\n                    params['nr_ranks'] = 1\n                    custom_commands.append(mpi_cmd_tmpl % params)\n\n        super(EB_OpenMPI, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)\n", "path": "easybuild/easyblocks/o/openmpi.py"}], "after_files": [{"content": "##\n# Copyright 2019-2023 Ghent University\n#\n# This file is part of EasyBuild,\n# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),\n# with support of Ghent University (http://ugent.be/hpc),\n# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),\n# Flemish Research Foundation (FWO) (http://www.fwo.be/en)\n# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).\n#\n# https://github.com/easybuilders/easybuild\n#\n# EasyBuild is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation v2.\n#\n# EasyBuild is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.\n##\n\"\"\"\nEasyBuild support for OpenMPI, implemented as an easyblock\n\n@author: Kenneth Hoste (Ghent University)\n@author: Robert Mijakovic (LuxProvide)\n\"\"\"\nimport os\nimport re\nfrom easybuild.tools import LooseVersion\n\nimport easybuild.tools.toolchain as toolchain\nfrom easybuild.easyblocks.generic.configuremake import ConfigureMake\nfrom easybuild.framework.easyconfig.constants import EASYCONFIG_CONSTANTS\nfrom easybuild.tools.build_log import EasyBuildError\nfrom easybuild.tools.config import build_option\nfrom easybuild.tools.modules import get_software_root\nfrom easybuild.tools.systemtools import check_os_dependency, get_shared_lib_ext\nfrom easybuild.tools.toolchain.mpi import get_mpi_cmd_template\n\n\nclass EB_OpenMPI(ConfigureMake):\n    \"\"\"OpenMPI easyblock.\"\"\"\n\n    def configure_step(self):\n        \"\"\"Custom configuration step for OpenMPI.\"\"\"\n\n        def config_opt_used(key, enable_opt=False):\n            \"\"\"Helper function to check whether a configure option is already specified in 'configopts'.\"\"\"\n            if enable_opt:\n                regex = '--(disable|enable)-%s' % key\n            else:\n                regex = '--(with|without)-%s' % key\n\n            return bool(re.search(regex, self.cfg['configopts']))\n\n        config_opt_names = [\n            # suppress failure modes in relation to mpirun path\n            'mpirun-prefix-by-default',\n            # build shared libraries\n            'shared',\n        ]\n\n        for key in config_opt_names:\n            if not config_opt_used(key, enable_opt=True):\n                self.cfg.update('configopts', '--enable-%s' % key)\n\n        # List of EasyBuild dependencies for which OMPI has known options\n        known_dependencies = ['CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX']\n        if LooseVersion(self.version) >= '4.1.4':\n            known_dependencies.append('UCC')\n\n        # Value to use for `--with-<dep>=<value>` if the dependency is not specified in the easyconfig\n        # No entry is interpreted as no option added at all\n        # This is to make builds reproducible even when the system libraries are changed and avoids failures\n        # due to e.g. finding only PMIx but not libevent on the system\n        unused_dep_value = dict()\n        # Known options since version 3.0 (no earlier ones checked)\n        if LooseVersion(self.version) >= LooseVersion('3.0'):\n            # Default to disable the option with \"no\"\n            unused_dep_value = {dep: 'no' for dep in known_dependencies}\n            # For these the default is to use an internal copy and not using any is not supported\n            for dep in ('hwloc', 'libevent', 'PMIx'):\n                unused_dep_value[dep] = 'internal'\n\n        # handle dependencies\n        for dep in known_dependencies:\n            opt_name = dep.lower()\n            # If the option is already used, don't add it\n            if config_opt_used(opt_name):\n                continue\n\n            # libfabric option renamed in OpenMPI 3.1.0 to ofi\n            if dep == 'libfabric' and LooseVersion(self.version) >= LooseVersion('3.1'):\n                opt_name = 'ofi'\n                # Check new option name. They are synonyms since 3.1.0 for backward compatibility\n                if config_opt_used(opt_name):\n                    continue\n\n            dep_root = get_software_root(dep)\n            # If the dependency is loaded, specify its path, else use the \"unused\" value, if any\n            if dep_root:\n                opt_value = dep_root\n            else:\n                opt_value = unused_dep_value.get(dep)\n            if opt_value is not None:\n                self.cfg.update('configopts', '--with-%s=%s' % (opt_name, opt_value))\n\n        if bool(get_software_root('PMIx')) != bool(get_software_root('libevent')):\n            raise EasyBuildError('You must either use both PMIx and libevent as dependencies or none of them. '\n                                 'This is to enforce the same libevent is used for OpenMPI as for PMIx or '\n                                 'the behavior may be unpredictable.')\n\n        # check whether VERBS support should be enabled\n        if not config_opt_used('verbs'):\n\n            # for OpenMPI v4.x, the openib BTL should be disabled when UCX is used;\n            # this is required to avoid \"error initializing an OpenFabrics device\" warnings,\n            # see also https://www.open-mpi.org/faq/?category=all#ofa-device-error\n            is_ucx_enabled = ('--with-ucx' in self.cfg['configopts'] and\n                              '--with-ucx=no' not in self.cfg['configopts'])\n            if LooseVersion(self.version) >= LooseVersion('4.0.0') and is_ucx_enabled:\n                verbs = False\n            else:\n                # auto-detect based on available OS packages\n                os_packages = EASYCONFIG_CONSTANTS['OS_PKG_IBVERBS_DEV'][0]\n                verbs = any(check_os_dependency(osdep) for osdep in os_packages)\n            # for OpenMPI v5.x, the verbs support is removed, only UCX is available\n            # see https://github.com/open-mpi/ompi/pull/6270\n            if LooseVersion(self.version) <= LooseVersion('5.0.0'):\n                if verbs:\n                    self.cfg.update('configopts', '--with-verbs')\n                else:\n                    self.cfg.update('configopts', '--without-verbs')\n\n        super(EB_OpenMPI, self).configure_step()\n\n    def test_step(self):\n        \"\"\"Test step for OpenMPI\"\"\"\n        # Default to `make check` if nothing is set. Disable with \"runtest = False\" in the EC\n        if self.cfg['runtest'] is None:\n            self.cfg['runtest'] = 'check'\n\n        super(EB_OpenMPI, self).test_step()\n\n    def load_module(self, *args, **kwargs):\n        \"\"\"\n        Load (temporary) module file, after resetting to initial environment.\n\n        Also put RPATH wrappers back in place if needed, to ensure that sanity check commands work as expected.\n        \"\"\"\n        super(EB_OpenMPI, self).load_module(*args, **kwargs)\n\n        # ensure RPATH wrappers are in place, otherwise compiling minimal test programs will fail\n        if build_option('rpath'):\n            if self.toolchain.options.get('rpath', True):\n                self.toolchain.prepare_rpath_wrappers(rpath_filter_dirs=self.rpath_filter_dirs,\n                                                      rpath_include_dirs=self.rpath_include_dirs)\n\n    def sanity_check_step(self):\n        \"\"\"Custom sanity check for OpenMPI.\"\"\"\n\n        bin_names = ['mpicc', 'mpicxx', 'mpif90', 'mpifort', 'mpirun', 'ompi_info', 'opal_wrapper']\n        if LooseVersion(self.version) >= LooseVersion('5.0.0'):\n            bin_names.append('prterun')\n        else:\n            bin_names.append('orterun')\n        bin_files = [os.path.join('bin', x) for x in bin_names]\n\n        shlib_ext = get_shared_lib_ext()\n        lib_names = ['mpi_mpifh', 'mpi', 'open-pal']\n        if LooseVersion(self.version) >= LooseVersion('5.0.0'):\n            lib_names.append('prrte')\n        else:\n            lib_names.extend(['ompitrace', 'open-rte'])\n        lib_files = [os.path.join('lib', 'lib%s.%s' % (x, shlib_ext)) for x in lib_names]\n\n        inc_names = ['mpi-ext', 'mpif-config', 'mpif', 'mpi', 'mpi_portable_platform']\n        if LooseVersion(self.version) >= LooseVersion('5.0.0'):\n            inc_names.append('prte')\n        inc_files = [os.path.join('include', x + '.h') for x in inc_names]\n\n        custom_paths = {\n            'files': bin_files + inc_files + lib_files,\n            'dirs': [],\n        }\n\n        # make sure MPI compiler wrappers pick up correct compilers\n        expected = {\n            'mpicc': os.getenv('CC', 'gcc'),\n            'mpicxx': os.getenv('CXX', 'g++'),\n            'mpifort': os.getenv('FC', 'gfortran'),\n            'mpif90': os.getenv('F90', 'gfortran'),\n        }\n        # actual pattern for gfortran is \"GNU Fortran\"\n        for key in ['mpifort', 'mpif90']:\n            if expected[key] == 'gfortran':\n                expected[key] = \"GNU Fortran\"\n        # for PGI, correct pattern is \"pgfortran\" with mpif90\n        if expected['mpif90'] == 'pgf90':\n            expected['mpif90'] = 'pgfortran'\n        # for Clang the pattern is always clang\n        for key in ['mpicxx', 'mpifort', 'mpif90']:\n            if expected[key] in ['clang++', 'flang']:\n                expected[key] = 'clang'\n\n        custom_commands = [\"%s --version | grep '%s'\" % (key, expected[key]) for key in sorted(expected.keys())]\n\n        # Add minimal test program to sanity checks\n        # Run with correct MPI launcher\n        mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.OPENMPI, dict(), mpi_version=self.version)\n        # Limit number of ranks to 8 to avoid it failing due to hyperthreading\n        ranks = min(8, self.cfg['parallel'])\n        for srcdir, src, compiler in (\n            ('examples', 'hello_c.c', 'mpicc'),\n            ('examples', 'hello_mpifh.f', 'mpifort'),\n            ('examples', 'hello_usempi.f90', 'mpif90'),\n            ('examples', 'ring_c.c', 'mpicc'),\n            ('examples', 'ring_mpifh.f', 'mpifort'),\n            ('examples', 'ring_usempi.f90', 'mpif90'),\n            ('test/simple', 'thread_init.c', 'mpicc'),\n            ('test/simple', 'intercomm1.c', 'mpicc'),\n            ('test/simple', 'mpi_barrier.c', 'mpicc'),\n        ):\n            src_path = os.path.join(self.cfg['start_dir'], srcdir, src)\n            if os.path.exists(src_path):\n                test_exe = os.path.join(self.builddir, 'mpi_test_' + os.path.splitext(src)[0])\n                self.log.info(\"Adding minimal MPI test program to sanity checks: %s\", test_exe)\n\n                # Build test binary\n                custom_commands.append(\"%s %s -o %s\" % (compiler, src_path, test_exe))\n\n                # Run the test if chosen\n                if build_option('mpi_tests'):\n                    params.update({'nr_ranks': ranks, 'cmd': test_exe})\n                    # Allow oversubscription for this test (in case of hyperthreading)\n                    custom_commands.append(\"OMPI_MCA_rmaps_base_oversubscribe=1 \" + mpi_cmd_tmpl % params)\n                    # Run with 1 process which may trigger other bugs\n                    # See https://github.com/easybuilders/easybuild-easyconfigs/issues/12978\n                    params['nr_ranks'] = 1\n                    custom_commands.append(mpi_cmd_tmpl % params)\n\n        super(EB_OpenMPI, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)\n", "path": "easybuild/easyblocks/o/openmpi.py"}]}