We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
MESA on arm/aarch64 lacks gallium drivers and fails to build with -Dlibunwind=true
`easybuild/easyblocks/m/mesa.py` specifies the following:
```
        if not gallium_drivers:
            # Add appropriate Gallium drivers for current architecture
            arch = get_cpu_architecture()
            arch_gallium_drivers = {
                'x86_64': ['swrast', 'swr'],
                'POWER': ['swrast'],
            }
```
this leads to:
```
== processing EasyBuild easyconfig /home/terjekv/easybuild/software/EasyBuild/4.2.2/easybuild/easyconfigs/m/Mesa/Mesa-20.0.2-GCCcore-9.3.0.eb
ERROR: Traceback (most recent call last):
  File "/home/terjekv/easybuild/software/EasyBuild/4.2.2/lib/python3.6/site-packages/easybuild/main.py", line 115, in build_and_install_software
    (ec_res['success'], app_log, err) = build_and_install_one(ec, init_env)
  File "/home/terjekv/easybuild/software/EasyBuild/4.2.2/lib/python3.6/site-packages/easybuild/framework/easyblock.py", line 3264, in build_and_install_one
    app = app_class(ecdict['ec'])
  File "/home/terjekv/easybuild/software/EasyBuild/4.2.2/lib/python3.6/site-packages/easybuild/easyblocks/m/mesa.py", line 66, in __init__
    self.log.debug('Gallium driver(s) included in the installation: %s' % ', '.join(gallium_drivers))
TypeError: can only join an iterable
```
Adding `'aarch64': ['swrast']` should be enough. Will patch and test.

--- 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/m/mesa.py`
Content:
```
1 ##
2 # Copyright 2009-2020 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 installing Mesa, implemented as an easyblock
27 
28 @author: Andrew Edmondson (University of Birmingham)
29 @author: Kenneth Hoste (HPC-UGent)
30 @author: Alex Domingo (Vrije Universiteit Brussel)
31 @author: Alexander Grund (TU Dresden)
32 """
33 import os
34 from distutils.version import LooseVersion
35 
36 from easybuild.easyblocks.generic.mesonninja import MesonNinja
37 from easybuild.tools.filetools import copy_dir
38 from easybuild.tools.systemtools import POWER, X86_64, get_cpu_architecture, get_cpu_features, get_shared_lib_ext
39 
40 
41 class EB_Mesa(MesonNinja):
42     """Custom easyblock for building and installing Mesa."""
43 
44     def __init__(self, *args, **kwargs):
45         """Constructor for custom Mesa easyblock: figure out which values to pass to swr-arches configuration option."""
46 
47         super(EB_Mesa, self).__init__(*args, **kwargs)
48 
49         self.gallium_configopts = []
50 
51         # Check user-defined Gallium drivers
52         gallium_drivers = self.get_configopt_value('gallium-drivers')
53 
54         if not gallium_drivers:
55             # Add appropriate Gallium drivers for current architecture
56             arch = get_cpu_architecture()
57             arch_gallium_drivers = {
58                 X86_64: ['swrast', 'swr'],
59                 POWER: ['swrast'],
60             }
61             if arch in arch_gallium_drivers:
62                 gallium_drivers = arch_gallium_drivers[arch]
63                 # Add configopt for additional Gallium drivers
64                 self.gallium_configopts.append('-Dgallium-drivers=' + ','.join(gallium_drivers))
65 
66         self.log.debug('Gallium driver(s) included in the installation: %s' % ', '.join(gallium_drivers))
67 
68         self.swr_arches = []
69 
70         if 'swr' in gallium_drivers:
71             # Check user-defined SWR arches
72             self.swr_arches = self.get_configopt_value('swr-arches')
73 
74             if not self.swr_arches:
75                 # Set cpu features of SWR for current micro-architecture
76                 feat_to_swrarch = {
77                     'avx': 'avx',
78                     'avx1.0': 'avx',  # on macOS, AVX is indicated with 'avx1.0' rather than 'avx'
79                     'avx2': 'avx2',
80                     'avx512f': 'skx',  # AVX-512 Foundation - introduced in Skylake
81                     'avx512er': 'knl',  # AVX-512 Exponential and Reciprocal Instructions implemented in Knights Landing
82                 }
83                 # Determine list of values to pass to swr-arches configuration option
84                 cpu_features = get_cpu_features()
85                 self.swr_arches = sorted([swrarch for feat, swrarch in feat_to_swrarch.items() if feat in cpu_features])
86                 # Add configopt for additional SWR arches
87                 self.gallium_configopts.append('-Dswr-arches=' + ','.join(self.swr_arches))
88 
89             self.log.debug('SWR Gallium driver will support: %s' % ', '.join(self.swr_arches))
90 
91     def get_configopt_value(self, configopt_name):
92         """
93         Return list of values for the given configuration option in configopts
94         """
95         configopt_args = [opt for opt in self.cfg['configopts'].split() if opt.startswith('-D%s=' % configopt_name)]
96 
97         if configopt_args:
98             if len(configopt_args) > 1:
99                 self.log.warning("Found multiple instances of %s in configopts, using last one: %s",
100                                  configopt_name, configopt_args[-1])
101             # Get value of last option added
102             configopt_value = configopt_args[-1].split('=')[-1]
103             # Remove quotes and extract individual values
104             configopt_value = configopt_value.strip('"\'').split(',')
105         else:
106             configopt_value = None
107 
108         return configopt_value
109 
110     def configure_step(self):
111         """
112         Customise the configure options based on the processor architecture of the host
113         (Gallium drivers installed, SWR CPU features, ...)
114         """
115 
116         if self.gallium_configopts:
117             self.cfg.update('configopts', self.gallium_configopts)
118 
119         return super(EB_Mesa, self).configure_step()
120 
121     def install_step(self):
122         """Also copy additional header files after installing Mesa."""
123 
124         super(EB_Mesa, self).install_step()
125 
126         # also install header files located in include/GL/internal, unless they're available already;
127         # we can't enable both DRI and Gallium drivers,
128         # but we can provide the DRI header file (GL/internal/dri_interface.h)
129         target_inc_GL_internal = os.path.join(self.installdir, 'include', 'GL', 'internal')
130         if not os.path.exists(target_inc_GL_internal):
131             src_inc_GL_internal = os.path.join(self.start_dir, 'include', 'GL', 'internal')
132             copy_dir(src_inc_GL_internal, target_inc_GL_internal)
133             self.log.info("Copied %s to %s" % (src_inc_GL_internal, target_inc_GL_internal))
134 
135     def sanity_check_step(self):
136         """Custom sanity check for Mesa."""
137 
138         shlib_ext = get_shared_lib_ext()
139 
140         if LooseVersion(self.version) >= LooseVersion('20.0'):
141             header_files = [os.path.join('include', 'EGL', x) for x in ['eglmesaext.h', 'eglextchromium.h']]
142             header_files.extend([
143                 os.path.join('include', 'GL', 'osmesa.h'),
144                 os.path.join('include', 'GL', 'internal', 'dri_interface.h'),
145             ])
146         else:
147             gl_inc_files = ['glext.h', 'gl_mangle.h', 'glx.h', 'osmesa.h', 'gl.h', 'glxext.h', 'glx_mangle.h']
148             gles_inc_files = [('GLES', 'gl.h'), ('GLES2', 'gl2.h'), ('GLES3', 'gl3.h')]
149             header_files = [os.path.join('include', 'GL', x) for x in gl_inc_files]
150             header_files.extend([os.path.join('include', x, y) for (x, y) in gles_inc_files])
151 
152         custom_paths = {
153             'files': [os.path.join('lib', 'libOSMesa.%s' % shlib_ext)] + header_files,
154             'dirs': [os.path.join('include', 'GL', 'internal')],
155         }
156 
157         if self.swr_arches:
158             swr_arch_libs = [os.path.join('lib', 'libswr%s.%s' % (a.upper(), shlib_ext)) for a in self.swr_arches]
159             custom_paths['files'].extend(swr_arch_libs)
160 
161         super(EB_Mesa, self).sanity_check_step(custom_paths=custom_paths)
162
```
--- 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/m/mesa.py b/easybuild/easyblocks/m/mesa.py
--- a/easybuild/easyblocks/m/mesa.py
+++ b/easybuild/easyblocks/m/mesa.py
@@ -35,7 +35,8 @@
 
 from easybuild.easyblocks.generic.mesonninja import MesonNinja
 from easybuild.tools.filetools import copy_dir
-from easybuild.tools.systemtools import POWER, X86_64, get_cpu_architecture, get_cpu_features, get_shared_lib_ext
+from easybuild.tools.systemtools import POWER, X86_64, AARCH64
+from easybuild.tools.systemtools import get_cpu_architecture, get_cpu_features, get_shared_lib_ext
 
 
 class EB_Mesa(MesonNinja):
@@ -48,6 +49,16 @@
 
         self.gallium_configopts = []
 
+        # Mesa fails to build with libunwind on aarch64
+        # See https://github.com/easybuilders/easybuild-easyblocks/issues/2150
+        if get_cpu_architecture() == AARCH64:
+            given_config_opts = self.cfg.get('configopts')
+            if "-Dlibunwind=true" in given_config_opts:
+                self.log.warning('libunwind not supported on aarch64, stripping from configopts!')
+                configopts_libunwind_stripped = given_config_opts.replace('-Dlibunwind=true', '-Dlibunwind=false')
+                self.cfg.set_keys({'configopts': configopts_libunwind_stripped})
+                self.log.warning('New configopts after stripping: ' + self.cfg.get('configopts'))
+
         # Check user-defined Gallium drivers
         gallium_drivers = self.get_configopt_value('gallium-drivers')
 
@@ -57,6 +68,7 @@
             arch_gallium_drivers = {
                 X86_64: ['swrast', 'swr'],
                 POWER: ['swrast'],
+                AARCH64: ['swrast'],
             }
             if arch in arch_gallium_drivers:
                 gallium_drivers = arch_gallium_drivers[arch]

{"golden_diff": "diff --git a/easybuild/easyblocks/m/mesa.py b/easybuild/easyblocks/m/mesa.py\n--- a/easybuild/easyblocks/m/mesa.py\n+++ b/easybuild/easyblocks/m/mesa.py\n@@ -35,7 +35,8 @@\n \n from easybuild.easyblocks.generic.mesonninja import MesonNinja\n from easybuild.tools.filetools import copy_dir\n-from easybuild.tools.systemtools import POWER, X86_64, get_cpu_architecture, get_cpu_features, get_shared_lib_ext\n+from easybuild.tools.systemtools import POWER, X86_64, AARCH64\n+from easybuild.tools.systemtools import get_cpu_architecture, get_cpu_features, get_shared_lib_ext\n \n \n class EB_Mesa(MesonNinja):\n@@ -48,6 +49,16 @@\n \n         self.gallium_configopts = []\n \n+        # Mesa fails to build with libunwind on aarch64\n+        # See https://github.com/easybuilders/easybuild-easyblocks/issues/2150\n+        if get_cpu_architecture() == AARCH64:\n+            given_config_opts = self.cfg.get('configopts')\n+            if \"-Dlibunwind=true\" in given_config_opts:\n+                self.log.warning('libunwind not supported on aarch64, stripping from configopts!')\n+                configopts_libunwind_stripped = given_config_opts.replace('-Dlibunwind=true', '-Dlibunwind=false')\n+                self.cfg.set_keys({'configopts': configopts_libunwind_stripped})\n+                self.log.warning('New configopts after stripping: ' + self.cfg.get('configopts'))\n+\n         # Check user-defined Gallium drivers\n         gallium_drivers = self.get_configopt_value('gallium-drivers')\n \n@@ -57,6 +68,7 @@\n             arch_gallium_drivers = {\n                 X86_64: ['swrast', 'swr'],\n                 POWER: ['swrast'],\n+                AARCH64: ['swrast'],\n             }\n             if arch in arch_gallium_drivers:\n                 gallium_drivers = arch_gallium_drivers[arch]\n", "issue": "MESA on arm/aarch64 lacks gallium drivers and fails to build with -Dlibunwind=true\n`easybuild/easyblocks/m/mesa.py` specifies the following:\r\n```\r\n        if not gallium_drivers:\r\n            # Add appropriate Gallium drivers for current architecture\r\n            arch = get_cpu_architecture()\r\n            arch_gallium_drivers = {\r\n                'x86_64': ['swrast', 'swr'],\r\n                'POWER': ['swrast'],\r\n            }\r\n```\r\nthis leads to:\r\n```\r\n== processing EasyBuild easyconfig /home/terjekv/easybuild/software/EasyBuild/4.2.2/easybuild/easyconfigs/m/Mesa/Mesa-20.0.2-GCCcore-9.3.0.eb\r\nERROR: Traceback (most recent call last):\r\n  File \"/home/terjekv/easybuild/software/EasyBuild/4.2.2/lib/python3.6/site-packages/easybuild/main.py\", line 115, in build_and_install_software\r\n    (ec_res['success'], app_log, err) = build_and_install_one(ec, init_env)\r\n  File \"/home/terjekv/easybuild/software/EasyBuild/4.2.2/lib/python3.6/site-packages/easybuild/framework/easyblock.py\", line 3264, in build_and_install_one\r\n    app = app_class(ecdict['ec'])\r\n  File \"/home/terjekv/easybuild/software/EasyBuild/4.2.2/lib/python3.6/site-packages/easybuild/easyblocks/m/mesa.py\", line 66, in __init__\r\n    self.log.debug('Gallium driver(s) included in the installation: %s' % ', '.join(gallium_drivers))\r\nTypeError: can only join an iterable\r\n```\r\nAdding `'aarch64': ['swrast']` should be enough. Will patch and test.\n", "before_files": [{"content": "##\n# Copyright 2009-2020 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 installing Mesa, implemented as an easyblock\n\n@author: Andrew Edmondson (University of Birmingham)\n@author: Kenneth Hoste (HPC-UGent)\n@author: Alex Domingo (Vrije Universiteit Brussel)\n@author: Alexander Grund (TU Dresden)\n\"\"\"\nimport os\nfrom distutils.version import LooseVersion\n\nfrom easybuild.easyblocks.generic.mesonninja import MesonNinja\nfrom easybuild.tools.filetools import copy_dir\nfrom easybuild.tools.systemtools import POWER, X86_64, get_cpu_architecture, get_cpu_features, get_shared_lib_ext\n\n\nclass EB_Mesa(MesonNinja):\n    \"\"\"Custom easyblock for building and installing Mesa.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Constructor for custom Mesa easyblock: figure out which values to pass to swr-arches configuration option.\"\"\"\n\n        super(EB_Mesa, self).__init__(*args, **kwargs)\n\n        self.gallium_configopts = []\n\n        # Check user-defined Gallium drivers\n        gallium_drivers = self.get_configopt_value('gallium-drivers')\n\n        if not gallium_drivers:\n            # Add appropriate Gallium drivers for current architecture\n            arch = get_cpu_architecture()\n            arch_gallium_drivers = {\n                X86_64: ['swrast', 'swr'],\n                POWER: ['swrast'],\n            }\n            if arch in arch_gallium_drivers:\n                gallium_drivers = arch_gallium_drivers[arch]\n                # Add configopt for additional Gallium drivers\n                self.gallium_configopts.append('-Dgallium-drivers=' + ','.join(gallium_drivers))\n\n        self.log.debug('Gallium driver(s) included in the installation: %s' % ', '.join(gallium_drivers))\n\n        self.swr_arches = []\n\n        if 'swr' in gallium_drivers:\n            # Check user-defined SWR arches\n            self.swr_arches = self.get_configopt_value('swr-arches')\n\n            if not self.swr_arches:\n                # Set cpu features of SWR for current micro-architecture\n                feat_to_swrarch = {\n                    'avx': 'avx',\n                    'avx1.0': 'avx',  # on macOS, AVX is indicated with 'avx1.0' rather than 'avx'\n                    'avx2': 'avx2',\n                    'avx512f': 'skx',  # AVX-512 Foundation - introduced in Skylake\n                    'avx512er': 'knl',  # AVX-512 Exponential and Reciprocal Instructions implemented in Knights Landing\n                }\n                # Determine list of values to pass to swr-arches configuration option\n                cpu_features = get_cpu_features()\n                self.swr_arches = sorted([swrarch for feat, swrarch in feat_to_swrarch.items() if feat in cpu_features])\n                # Add configopt for additional SWR arches\n                self.gallium_configopts.append('-Dswr-arches=' + ','.join(self.swr_arches))\n\n            self.log.debug('SWR Gallium driver will support: %s' % ', '.join(self.swr_arches))\n\n    def get_configopt_value(self, configopt_name):\n        \"\"\"\n        Return list of values for the given configuration option in configopts\n        \"\"\"\n        configopt_args = [opt for opt in self.cfg['configopts'].split() if opt.startswith('-D%s=' % configopt_name)]\n\n        if configopt_args:\n            if len(configopt_args) > 1:\n                self.log.warning(\"Found multiple instances of %s in configopts, using last one: %s\",\n                                 configopt_name, configopt_args[-1])\n            # Get value of last option added\n            configopt_value = configopt_args[-1].split('=')[-1]\n            # Remove quotes and extract individual values\n            configopt_value = configopt_value.strip('\"\\'').split(',')\n        else:\n            configopt_value = None\n\n        return configopt_value\n\n    def configure_step(self):\n        \"\"\"\n        Customise the configure options based on the processor architecture of the host\n        (Gallium drivers installed, SWR CPU features, ...)\n        \"\"\"\n\n        if self.gallium_configopts:\n            self.cfg.update('configopts', self.gallium_configopts)\n\n        return super(EB_Mesa, self).configure_step()\n\n    def install_step(self):\n        \"\"\"Also copy additional header files after installing Mesa.\"\"\"\n\n        super(EB_Mesa, self).install_step()\n\n        # also install header files located in include/GL/internal, unless they're available already;\n        # we can't enable both DRI and Gallium drivers,\n        # but we can provide the DRI header file (GL/internal/dri_interface.h)\n        target_inc_GL_internal = os.path.join(self.installdir, 'include', 'GL', 'internal')\n        if not os.path.exists(target_inc_GL_internal):\n            src_inc_GL_internal = os.path.join(self.start_dir, 'include', 'GL', 'internal')\n            copy_dir(src_inc_GL_internal, target_inc_GL_internal)\n            self.log.info(\"Copied %s to %s\" % (src_inc_GL_internal, target_inc_GL_internal))\n\n    def sanity_check_step(self):\n        \"\"\"Custom sanity check for Mesa.\"\"\"\n\n        shlib_ext = get_shared_lib_ext()\n\n        if LooseVersion(self.version) >= LooseVersion('20.0'):\n            header_files = [os.path.join('include', 'EGL', x) for x in ['eglmesaext.h', 'eglextchromium.h']]\n            header_files.extend([\n                os.path.join('include', 'GL', 'osmesa.h'),\n                os.path.join('include', 'GL', 'internal', 'dri_interface.h'),\n            ])\n        else:\n            gl_inc_files = ['glext.h', 'gl_mangle.h', 'glx.h', 'osmesa.h', 'gl.h', 'glxext.h', 'glx_mangle.h']\n            gles_inc_files = [('GLES', 'gl.h'), ('GLES2', 'gl2.h'), ('GLES3', 'gl3.h')]\n            header_files = [os.path.join('include', 'GL', x) for x in gl_inc_files]\n            header_files.extend([os.path.join('include', x, y) for (x, y) in gles_inc_files])\n\n        custom_paths = {\n            'files': [os.path.join('lib', 'libOSMesa.%s' % shlib_ext)] + header_files,\n            'dirs': [os.path.join('include', 'GL', 'internal')],\n        }\n\n        if self.swr_arches:\n            swr_arch_libs = [os.path.join('lib', 'libswr%s.%s' % (a.upper(), shlib_ext)) for a in self.swr_arches]\n            custom_paths['files'].extend(swr_arch_libs)\n\n        super(EB_Mesa, self).sanity_check_step(custom_paths=custom_paths)\n", "path": "easybuild/easyblocks/m/mesa.py"}], "after_files": [{"content": "##\n# Copyright 2009-2020 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 installing Mesa, implemented as an easyblock\n\n@author: Andrew Edmondson (University of Birmingham)\n@author: Kenneth Hoste (HPC-UGent)\n@author: Alex Domingo (Vrije Universiteit Brussel)\n@author: Alexander Grund (TU Dresden)\n\"\"\"\nimport os\nfrom distutils.version import LooseVersion\n\nfrom easybuild.easyblocks.generic.mesonninja import MesonNinja\nfrom easybuild.tools.filetools import copy_dir\nfrom easybuild.tools.systemtools import POWER, X86_64, AARCH64\nfrom easybuild.tools.systemtools import get_cpu_architecture, get_cpu_features, get_shared_lib_ext\n\n\nclass EB_Mesa(MesonNinja):\n    \"\"\"Custom easyblock for building and installing Mesa.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Constructor for custom Mesa easyblock: figure out which values to pass to swr-arches configuration option.\"\"\"\n\n        super(EB_Mesa, self).__init__(*args, **kwargs)\n\n        self.gallium_configopts = []\n\n        # Mesa fails to build with libunwind on aarch64\n        # See https://github.com/easybuilders/easybuild-easyblocks/issues/2150\n        if get_cpu_architecture() == AARCH64:\n            given_config_opts = self.cfg.get('configopts')\n            if \"-Dlibunwind=true\" in given_config_opts:\n                self.log.warning('libunwind not supported on aarch64, stripping from configopts!')\n                configopts_libunwind_stripped = given_config_opts.replace('-Dlibunwind=true', '-Dlibunwind=false')\n                self.cfg.set_keys({'configopts': configopts_libunwind_stripped})\n                self.log.warning('New configopts after stripping: ' + self.cfg.get('configopts'))\n\n        # Check user-defined Gallium drivers\n        gallium_drivers = self.get_configopt_value('gallium-drivers')\n\n        if not gallium_drivers:\n            # Add appropriate Gallium drivers for current architecture\n            arch = get_cpu_architecture()\n            arch_gallium_drivers = {\n                X86_64: ['swrast', 'swr'],\n                POWER: ['swrast'],\n                AARCH64: ['swrast'],\n            }\n            if arch in arch_gallium_drivers:\n                gallium_drivers = arch_gallium_drivers[arch]\n                # Add configopt for additional Gallium drivers\n                self.gallium_configopts.append('-Dgallium-drivers=' + ','.join(gallium_drivers))\n\n        self.log.debug('Gallium driver(s) included in the installation: %s' % ', '.join(gallium_drivers))\n\n        self.swr_arches = []\n\n        if 'swr' in gallium_drivers:\n            # Check user-defined SWR arches\n            self.swr_arches = self.get_configopt_value('swr-arches')\n\n            if not self.swr_arches:\n                # Set cpu features of SWR for current micro-architecture\n                feat_to_swrarch = {\n                    'avx': 'avx',\n                    'avx1.0': 'avx',  # on macOS, AVX is indicated with 'avx1.0' rather than 'avx'\n                    'avx2': 'avx2',\n                    'avx512f': 'skx',  # AVX-512 Foundation - introduced in Skylake\n                    'avx512er': 'knl',  # AVX-512 Exponential and Reciprocal Instructions implemented in Knights Landing\n                }\n                # Determine list of values to pass to swr-arches configuration option\n                cpu_features = get_cpu_features()\n                self.swr_arches = sorted([swrarch for feat, swrarch in feat_to_swrarch.items() if feat in cpu_features])\n                # Add configopt for additional SWR arches\n                self.gallium_configopts.append('-Dswr-arches=' + ','.join(self.swr_arches))\n\n            self.log.debug('SWR Gallium driver will support: %s' % ', '.join(self.swr_arches))\n\n    def get_configopt_value(self, configopt_name):\n        \"\"\"\n        Return list of values for the given configuration option in configopts\n        \"\"\"\n        configopt_args = [opt for opt in self.cfg['configopts'].split() if opt.startswith('-D%s=' % configopt_name)]\n\n        if configopt_args:\n            if len(configopt_args) > 1:\n                self.log.warning(\"Found multiple instances of %s in configopts, using last one: %s\",\n                                 configopt_name, configopt_args[-1])\n            # Get value of last option added\n            configopt_value = configopt_args[-1].split('=')[-1]\n            # Remove quotes and extract individual values\n            configopt_value = configopt_value.strip('\"\\'').split(',')\n        else:\n            configopt_value = None\n\n        return configopt_value\n\n    def configure_step(self):\n        \"\"\"\n        Customise the configure options based on the processor architecture of the host\n        (Gallium drivers installed, SWR CPU features, ...)\n        \"\"\"\n\n        if self.gallium_configopts:\n            self.cfg.update('configopts', self.gallium_configopts)\n\n        return super(EB_Mesa, self).configure_step()\n\n    def install_step(self):\n        \"\"\"Also copy additional header files after installing Mesa.\"\"\"\n\n        super(EB_Mesa, self).install_step()\n\n        # also install header files located in include/GL/internal, unless they're available already;\n        # we can't enable both DRI and Gallium drivers,\n        # but we can provide the DRI header file (GL/internal/dri_interface.h)\n        target_inc_GL_internal = os.path.join(self.installdir, 'include', 'GL', 'internal')\n        if not os.path.exists(target_inc_GL_internal):\n            src_inc_GL_internal = os.path.join(self.start_dir, 'include', 'GL', 'internal')\n            copy_dir(src_inc_GL_internal, target_inc_GL_internal)\n            self.log.info(\"Copied %s to %s\" % (src_inc_GL_internal, target_inc_GL_internal))\n\n    def sanity_check_step(self):\n        \"\"\"Custom sanity check for Mesa.\"\"\"\n\n        shlib_ext = get_shared_lib_ext()\n\n        if LooseVersion(self.version) >= LooseVersion('20.0'):\n            header_files = [os.path.join('include', 'EGL', x) for x in ['eglmesaext.h', 'eglextchromium.h']]\n            header_files.extend([\n                os.path.join('include', 'GL', 'osmesa.h'),\n                os.path.join('include', 'GL', 'internal', 'dri_interface.h'),\n            ])\n        else:\n            gl_inc_files = ['glext.h', 'gl_mangle.h', 'glx.h', 'osmesa.h', 'gl.h', 'glxext.h', 'glx_mangle.h']\n            gles_inc_files = [('GLES', 'gl.h'), ('GLES2', 'gl2.h'), ('GLES3', 'gl3.h')]\n            header_files = [os.path.join('include', 'GL', x) for x in gl_inc_files]\n            header_files.extend([os.path.join('include', x, y) for (x, y) in gles_inc_files])\n\n        custom_paths = {\n            'files': [os.path.join('lib', 'libOSMesa.%s' % shlib_ext)] + header_files,\n            'dirs': [os.path.join('include', 'GL', 'internal')],\n        }\n\n        if self.swr_arches:\n            swr_arch_libs = [os.path.join('lib', 'libswr%s.%s' % (a.upper(), shlib_ext)) for a in self.swr_arches]\n            custom_paths['files'].extend(swr_arch_libs)\n\n        super(EB_Mesa, self).sanity_check_step(custom_paths=custom_paths)\n", "path": "easybuild/easyblocks/m/mesa.py"}]}