text: # Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
  # Spack Project Developers. See the top-level COPYRIGHT file for details.
  #
  # SPDX-License-Identifier: (Apache-2.0 OR MIT)
  
  import re
  import sys
  
  import llnl.util.lang
  
  from spack.compiler import Compiler, UnsupportedCompilerFlag
  from spack.version import ver
  
  
  #: compiler symlink mappings for mixed f77 compilers
  f77_mapping = [
      ('gfortran', 'clang/gfortran'),
      ('xlf_r', 'xl_r/xlf_r'),
      ('xlf', 'xl/xlf'),
      ('pgfortran', 'pgi/pgfortran'),
      ('ifort', 'intel/ifort')
  ]
  
  #: compiler symlink mappings for mixed f90/fc compilers
  fc_mapping = [
      ('gfortran', 'clang/gfortran'),
      ('xlf90_r', 'xl_r/xlf90_r'),
      ('xlf90', 'xl/xlf90'),
      ('pgfortran', 'pgi/pgfortran'),
      ('ifort', 'intel/ifort')
  ]
  
  
  class Clang(Compiler):
      # Subclasses use possible names of C compiler
      cc_names = ['clang']
  
      # Subclasses use possible names of C++ compiler
      cxx_names = ['clang++']
  
      # Subclasses use possible names of Fortran 77 compiler
      f77_names = ['flang', 'gfortran', 'xlf_r']
  
      # Subclasses use possible names of Fortran 90 compiler
      fc_names = ['flang', 'gfortran', 'xlf90_r']
  
      version_argument = '--version'
  
      @property
      def debug_flags(self):
          return ['-gcodeview', '-gdwarf-2', '-gdwarf-3', '-gdwarf-4',
                  '-gdwarf-5', '-gline-tables-only', '-gmodules', '-gz', '-g']
  
      @property
      def opt_flags(self):
          return ['-O0', '-O1', '-O2', '-O3', '-Ofast', '-Os', '-Oz', '-Og',
                  '-O', '-O4']
  
      # Clang has support for using different fortran compilers with the
      # clang executable.
      @property
      def link_paths(self):
          # clang links are always the same
          link_paths = {'cc': 'clang/clang',
                        'cxx': 'clang/clang++'}
  
          # fortran links need to look at the actual compiler names from
          # compilers.yaml to figure out which named symlink to use
          for compiler_name, link_path in f77_mapping:
              if self.f77 and compiler_name in self.f77:
                  link_paths['f77'] = link_path
                  break
          else:
              link_paths['f77'] = 'clang/flang'
  
          for compiler_name, link_path in fc_mapping:
              if self.fc and compiler_name in self.fc:
                  link_paths['fc'] = link_path
                  break
          else:
              link_paths['fc'] = 'clang/flang'
  
          return link_paths
  
      @property
      def verbose_flag(self):
          return "-v"
  
      openmp_flag = "-fopenmp"
  
      @property
      def cxx11_flag(self):
          if self.real_version < ver('3.3'):
              raise UnsupportedCompilerFlag(
                  self, "the C++11 standard", "cxx11_flag", "< 3.3"
              )
          return "-std=c++11"
  
      @property
      def cxx14_flag(self):
          if self.real_version < ver('3.4'):
              raise UnsupportedCompilerFlag(
                  self, "the C++14 standard", "cxx14_flag", "< 3.5"
              )
          elif self.real_version < ver('3.5'):
              return "-std=c++1y"
  
          return "-std=c++14"
  
      @property
      def cxx17_flag(self):
          if self.real_version < ver('3.5'):
              raise UnsupportedCompilerFlag(
                  self, "the C++17 standard", "cxx17_flag", "< 3.5"
              )
          elif self.real_version < ver('5.0'):
              return "-std=c++1z"
  
          return "-std=c++17"
  
      @property
      def c99_flag(self):
          return '-std=c99'
  
      @property
      def c11_flag(self):
          if self.real_version < ver('6.1.0'):
              raise UnsupportedCompilerFlag(self,
                                            "the C11 standard",
                                            "c11_flag",
                                            "< 6.1.0")
          else:
              return "-std=c11"
  
      @property
      def cc_pic_flag(self):
          return "-fPIC"
  
      @property
      def cxx_pic_flag(self):
          return "-fPIC"
  
      @property
      def f77_pic_flag(self):
          return "-fPIC"
  
      @property
      def fc_pic_flag(self):
          return "-fPIC"
  
      required_libs = ['libclang']
  
      @classmethod
      @llnl.util.lang.memoized
      def extract_version_from_output(cls, output):
          ver = 'unknown'
          if ('Apple' in output) or ('AMD' in output):
              return ver
  
          match = re.search(
              # Normal clang compiler versions are left as-is
              r'clang version ([^ )\n]+)-svn[~.\w\d-]*|'
              # Don't include hyphenated patch numbers in the version
              # (see https://github.com/spack/spack/pull/14365 for details)
              r'clang version ([^ )\n]+?)-[~.\w\d-]*|'
              r'clang version ([^ )\n]+)',
              output
          )
          if match:
              ver = match.group(match.lastindex)
          return ver
  
      @classmethod
      def fc_version(cls, fc):
          # We could map from gcc/gfortran version to clang version, but on macOS
          # we normally mix any version of gfortran with any version of clang.
          if sys.platform == 'darwin':
              return cls.default_version('clang')
          else:
              return cls.default_version(fc)
  
      @classmethod
      def f77_version(cls, f77):
          return cls.fc_version(f77)
  