text: # Copyright 2013-2022 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)
  
  from spack.error import SpackError
  from spack.package import *
  from spack.pkg.builtin.fftw import FftwBase
  
  
  def target_check(spec):
      if spec.target != "a64fx":
          error_msg = ("It can only be built on an A64FX machine.\n")
          raise SpackError(error_msg)
  
  
  class FujitsuFftw(FftwBase):
      """FFTW (Fujitsu Optimized version) is a comprehensive collection of
      fast C routines for computing the Discrete Fourier Transform (DFT)
      and various special cases thereof.
  
      It is an open-source implementation of the Fast Fourier transform
      algorithm. It can compute transforms of real and complex-values
      arrays of arbitrary size and dimension.
      Fujitsu Optimized FFTW is the optimized FFTW implementation targeted
      for A64FX CPUs.
  
      For single precision build, please use precision value as float.
      Example : spack install fujitsufftw precision=float
      """
  
      _name = 'fujitsu-fftw'
      homepage = "https://github.com/fujitsu/fftw3"
      url = "https://github.com/fujitsu/fftw3/archive/sve-v1.0.0.tar.gz"
  
      version('1.0.0', sha256='b5931e352355d8d1ffeb215922f4b96de11b8585c423fceeaffbf3d5436f6f2f')
  
      variant('shared', default=True, description='Builds a shared version of the library')
      variant('openmp', default=True, description="Enable OpenMP support")
      variant('debug', default=False, description='Builds a debug version of the library')
  
      depends_on('texinfo')
  
      provides('fftw-api@3')
  
      conflicts('precision=quad', when='%fj', msg="Fujitsu Compiler doesn't support quad precision")
      conflicts('precision=long_double', when='%fj', msg="ARM-SVE vector instructions only works in single or double precision")
      conflicts('%arm')
      conflicts('%cce')
      conflicts('%apple-clang')
      conflicts('%clang')
      conflicts('%gcc')
      conflicts('%intel')
      conflicts('%nag')
      conflicts('%pgi')
      conflicts('%xl')
      conflicts('%xl_r')
  
      def autoreconf(self, spec, prefix):
          if spec.target != "a64fx":
              target_check(spec)
  
          touch = which('touch')
          touch('ChangeLog')
          autoreconf = which('autoreconf')
          autoreconf('-ifv')
  
      def configure(self, spec, prefix):
          """Configure function"""
          # Base options
          options = [
              'CFLAGS=-Ofast',
              'FFLAGS=-Kfast',
              '--enable-sve',
              '--enable-armv8-cntvct-el0',
              '--enable-fma',
              '--enable-fortran',
              '--prefix={0}'.format(prefix),
              'ac_cv_prog_f77_v=-###'
          ]
  
          if '+shared' in spec:
              options.append('--enable-shared')
          else:
              options.append('--disable-shared')
  
          if '+openmp' in spec:
              options.append('--enable-openmp')
              options.append('OPENMP_CFLAGS=-Kopenmp')
          else:
              options.append('--disable-openmp')
  
          if '+mpi' in spec:
              options.append('--enable-mpi')
          else:
              options.append('--disable-mpi')
  
          # Double is the default precision, for all the others we need
          # to enable the corresponding option.
          enable_precision = {
              'float': ['--enable-float'],
              'double': None,
              'long_double': ['--enable-long-double'],
              'quad': ['--enable-quad-precision']
          }
  
          # Different precisions must be configured and compiled one at a time
          configure = Executable('../configure')
          for precision in self.selected_precisions:
  
              opts = (enable_precision[precision] or []) + options[:]
              with working_dir(precision, create=True):
                  configure(*opts)
  