xref: /petsc/config/BuildSystem/config/compilers.py (revision 7b5fd022a6ba26727040df7457b27566b4c6742d) !
1import config.base
2
3import re
4import os
5import shutil
6
7def remove_xcode_verbose(buf):
8  retbuf =[]
9  for line in buf.splitlines():
10    if not line.startswith('ld: warning: text-based stub file'): retbuf.append(line)
11  return ('\n').join(retbuf)
12
13class MissingProcessor(AttributeError):
14  pass
15
16class Configure(config.base.Configure):
17  def __init__(self, framework):
18    config.base.Configure.__init__(self, framework)
19    self.headerPrefix     = ''
20    self.substPrefix      = ''
21    self.fortranMangling  = 'unchanged'
22    self.fmainlibs        = []
23    self.fincs            = []
24    self.flibs            = []  # libraries needed for linking using the C or C++ compiler Fortran source code compiled with Fortran
25    self.clibs            = []  # libraries needed for linking using the C++ or Fortran compiler C source code compiled with C
26    self.cxxlibs          = []  # libraries needed for linking using the C or Fortran compiler C++ source code compiled with C++
27                                # clibs is only used in this file. The final link line that PETSc users use includes cxxlibs and flibs
28    self.skipdefaultpaths = []
29    self.cxxCompileC      = False
30    self.cxxRestrict      = ' '
31    self.c99flag          = None
32    return
33
34  def getSkipDefaultPaths(self):
35    if len(self.skipdefaultpaths):
36      return self.skipdefaultpaths
37    else:
38      self.skipdefaultpaths = ['/usr/lib','/lib','/usr/lib64','/lib64']
39      for loc in ['/usr/lib','/lib']:
40        for arch in ['x86_64','i386','aarch64']:
41          self.skipdefaultpaths.append(os.path.join(loc,arch+'-linux-gnu'))
42      conda_sysrt = os.getenv('CONDA_BUILD_SYSROOT')
43      if conda_sysrt:
44        conda_sysrt = os.path.abspath(conda_sysrt)
45        self.skipdefaultpaths.extend([conda_sysrt+lib for lib in self.skipdefaultpaths])
46      return self.skipdefaultpaths
47
48  def setupHelp(self, help):
49    import nargs
50
51    help.addArgument('Compilers','-with-clib-autodetect=<bool>',      nargs.ArgBool(None,1,'Autodetect C compiler libraries'))
52    help.addArgument('Compilers','-with-fortranlib-autodetect=<bool>',nargs.ArgBool(None,1,'Autodetect Fortran compiler libraries'))
53    help.addArgument('Compilers','-with-cxxlib-autodetect=<bool>',    nargs.ArgBool(None,1,'Autodetect C++ compiler libraries'))
54    help.addArgument('Compilers','-with-dependencies=<bool>',         nargs.ArgBool(None,1,'Compile with -MMD or equivalent flag if possible'))
55    return
56
57  def getDispatchNames(self):
58    '''Return all the attributes which are dispatched from config.setCompilers'''
59    names = {}
60    names['CC'] = 'No C compiler found.'
61    names['CPP'] = 'No C preprocessor found.'
62    names['CUDAC'] = 'No CUDA compiler found.'
63    names['CUDAPP'] = 'No CUDA preprocessor found.'
64    names['HIPC'] = 'No HIP compiler found.'
65    names['HIPPP'] = 'No HIP preprocessor found.'
66    names['SYCLC'] = 'No SYCL compiler found.'
67    names['SYCLPP'] = 'No SYCL preprocessor found.'
68    names['CXX'] = 'No C++ compiler found.'
69    names['CXXPP'] = 'No C++ preprocessor found.'
70    names['FC'] = 'No Fortran compiler found.'
71    names['FPP'] = 'No Fortran preprocessor found.'
72    names['AR'] = 'No archiver found.'
73    names['RANLIB'] = 'No ranlib found.'
74    names['LD_SHARED'] = 'No shared linker found.'
75    names['CC_LD'] = 'No C linker found.'
76    names['dynamicLinker'] = 'No dynamic linker found.'
77    for language in ['C', 'CUDA', 'HIP', 'SYCL', 'Cxx', 'FC']:
78      self.pushLanguage(language)
79      key = self.getCompilerFlagsName(language, 0)
80      names[key] = 'No '+language+' compiler flags found.'
81      key = self.getCompilerFlagsName(language, 1)
82      names[key] = 'No '+language+' compiler flags found.'
83      key = self.getLinkerFlagsName(language)
84      names[key] = 'No '+language+' linker flags found.'
85      self.popLanguage()
86    names['CPPFLAGS'] = 'No preprocessor flags found.'
87    names['FPPFLAGS'] = 'No Fortran preprocessor flags found.'
88    names['CUDAPPFLAGS'] = 'No CUDA preprocessor flags found.'
89    names['HIPPPFLAGS'] = 'No HIP preprocessor flags found.'
90    names['SYCLPPFLAGS'] = 'No SYCL preprocessor flags found.'
91    names['CXXPPFLAGS'] = 'No C++ preprocessor flags found.'
92    names['AR_FLAGS'] = 'No archiver flags found.'
93    names['AR_LIB_SUFFIX'] = 'No static library suffix found.'
94    names['LIBS'] = 'No extra libraries found.'
95    return names
96
97  def setupDependencies(self, framework):
98    config.base.Configure.setupDependencies(self, framework)
99    self.setCompilers = framework.require('config.setCompilers', self)
100    self.compilerFlags = framework.require('config.compilerFlags', self)
101    self.libraries = framework.require('config.libraries', None)
102    self.dispatchNames = self.getDispatchNames()
103    return
104
105  def __getattr__(self, name):
106    if 'dispatchNames' in self.__dict__:
107      if name in self.dispatchNames:
108        if not hasattr(self.setCompilers, name):
109          raise MissingProcessor(self.dispatchNames[name])
110        return getattr(self.setCompilers, name)
111      if name in ['CC_LINKER_FLAGS', 'FC_LINKER_FLAGS', 'CXX_LINKER_FLAGS', 'CUDAC_LINKER_FLAGS', 'HIPC_LINKER_FLAGS', 'SYCLC_LINKER_FLAGS','sharedLibraryFlags', 'dynamicLibraryFlags']:
112        flags = getattr(self.setCompilers, name)
113        if not isinstance(flags, list): flags = [flags]
114        return ' '.join(flags)
115    raise AttributeError('Configure attribute not found: '+name)
116
117  def __setattr__(self, name, value):
118    if 'dispatchNames' in self.__dict__:
119      if name in self.dispatchNames:
120        return setattr(self.setCompilers, name, value)
121    config.base.Configure.__setattr__(self, name, value)
122    return
123
124  def checkCxxRestrict(self):
125    '''Check for the CXX restrict keyword equivalent to C99 restrict'''
126    with self.Language('Cxx'):
127      for kw in ['__restrict', ' __restrict__', 'restrict', ' ']:
128        if self.checkCompile('', 'float * '+kw+' x;\n(void)x'):
129          self.cxxRestrict = kw
130          break
131    self.logPrint('Set Cxx restrict keyword to : '+self.cxxRestrict, 4, 'compilers')
132    self.addDefine('CXX_RESTRICT', self.cxxRestrict)
133    return
134
135  def checkCrossLink(self, func1, func2, language1 = 'C', language2='FC',extraObjs = None, extralibs=None):
136    '''Compiles C/C++ and Fortran code and tries to link them together; the C and Fortran code are independent so no name mangling is needed
137       language1 is used to compile the first code, language2 compiles the second and links them togetether'''
138    obj1 = os.path.join(self.tmpDir, 'confc.o')
139    found = 0
140    # Compile the C test object
141    self.pushLanguage(language1)
142    if not self.checkCompile(func1, None, cleanup = 0):
143      self.logPrint('Cannot compile C function: '+func1, 3, 'compilers')
144      self.popLanguage()
145      return found
146    if not os.path.isfile(self.compilerObj):
147      self.logPrint('Cannot locate object file: '+os.path.abspath(self.compilerObj), 3, 'compilers')
148      self.popLanguage()
149      return found
150    os.rename(self.compilerObj, obj1)
151    self.popLanguage()
152    # Link the test object against a Fortran driver
153    self.pushLanguage(language2)
154    oldLIBS = self.setCompilers.LIBS
155    self.setCompilers.LIBS = obj1+' '+self.setCompilers.LIBS
156    if extraObjs or extralibs:
157      if extraObjs is None:
158        extraObjs = []
159      if extralibs is None:
160        extralibs = self.clibs
161      self.setCompilers.LIBS = ' '.join(extraObjs)+' '+' '.join([self.libraries.getLibArgument(lib) for lib in extralibs])+' '+self.setCompilers.LIBS
162    found = self.checkLink("", func2,codeBegin = " ", codeEnd = " ")
163    self.setCompilers.LIBS = oldLIBS
164    self.popLanguage()
165    if os.path.isfile(obj1):
166      os.remove(obj1)
167    return found
168
169  def checkCLibraries(self):
170    '''Determines the libraries needed to link using the C++ or Fortran compiler C source code compiled with C. Result is stored in clibs'''
171    skipclibraries = 1
172    if hasattr(self.setCompilers, 'FC'):
173      self.setCompilers.saveLog()
174      try:
175        if self.checkCrossLink('#include <stdio.h>\nvoid asub(void)\n{char s[16];printf("testing %s",s);}\n',"     program main\n      print*,'testing'\n      stop\n      end\n",language1='C',language2='FC'):
176          self.logWrite(self.setCompilers.restoreLog())
177          self.logPrint('C libraries are not needed when using Fortran linker')
178        else:
179          self.logWrite(self.setCompilers.restoreLog())
180          self.logPrint('C code cannot directly be linked with Fortran linker, therefore will determine needed C libraries')
181          skipclibraries = 0
182      except RuntimeError as e:
183        self.logWrite(self.setCompilers.restoreLog())
184        self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
185        self.logPrint('C code cannot directly be linked with Fortran linker, therefore will determine needed C libraries')
186        skipclibraries = 0
187    if hasattr(self.setCompilers, 'CXX'):
188      self.setCompilers.saveLog()
189      try:
190        if self.checkCrossLink('#include <stdio.h>\nvoid asub(void)\n{char s[16];printf("testing %s",s);}\n',"int main(int argc,char **args)\n{(void)argc, (void)args; return 0;}\n",language1='C',language2='C++'):
191          self.logWrite(self.setCompilers.restoreLog())
192          self.logPrint('C libraries are not needed when using C++ linker')
193        else:
194          self.logWrite(self.setCompilers.restoreLog())
195          self.logPrint('C code cannot directly be linked with C++ linker, therefore will determine needed C libraries')
196          skipclibraries = 0
197      except RuntimeError as e:
198        self.logWrite(self.setCompilers.restoreLog())
199        self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
200        self.logPrint('C code cannot directly be linked with C++ linker, therefore will determine needed C libraries')
201        skipclibraries = 0
202    if skipclibraries == 1: return
203
204    oldFlags = self.setCompilers.LDFLAGS
205    self.setCompilers.LDFLAGS += ' -v'
206    self.pushLanguage('C')
207    (output, returnCode) = self.outputLink('', '')
208    self.setCompilers.LDFLAGS = oldFlags
209    self.popLanguage()
210
211    # Cray: remove libsci link
212    iscray = config.setCompilers.Configure.isCray(self.getCompiler('C'), self.log)
213
214    output = remove_xcode_verbose(output)
215    # PGI: kill anything enclosed in single quotes
216    if output.find('\'') >= 0:
217      # Cray has crazy non-matching single quotes so skip the removal
218      if not output.count('\'')%2:
219        while output.find('\'') >= 0:
220          start = output.index('\'')
221          end   = output.index('\'', start+1)+1
222          output = output.replace(output[start:end], '')
223
224    # The easiest thing to do for xlc output is to replace all the commas
225    # with spaces.  Try to only do that if the output is really from xlc,
226    # since doing that causes problems on other systems.
227    if output.find('XL_CONFIG') >= 0:
228      output = output.replace(',', ' ')
229
230    # Parse output
231    argIter = iter(output.split())
232    clibs = []
233    skipdefaultpaths = self.getSkipDefaultPaths()
234    lflags  = []
235    rpathflags = []
236    try:
237      while 1:
238        arg = next(argIter)
239        self.logPrint( 'Checking arg '+arg, 4, 'compilers')
240
241        # Intel compiler sometimes puts " " around an option like "-lsomething"
242        if arg.startswith('"') and arg.endswith('"'):
243          arg = arg[1:-1]
244        # Intel also puts several options together inside a " " so the last one
245        # has a stray " at the end
246        if arg.endswith('"') and arg[:-1].find('"') == -1:
247          arg = arg[:-1]
248        # Intel 11 has a bogus -long_double option
249        if arg == '-long_double':
250          continue
251        if arg == '-lto_library':
252          lib = next(argIter)
253          self.logPrint('Skipping Apple LLVM linker option -lto_library '+lib)
254          continue
255        # ASan
256        if arg in ['-lasan', '-lubsan']:
257          self.logPrint('Skipping ASan libraries')
258          continue
259        # if options of type -L foobar
260        if arg == '-L':
261          lib = next(argIter)
262          self.logPrint('Found -L '+lib, 4, 'compilers')
263          clibs.append('-L'+lib)
264          continue
265        # Check for full library name
266        m = re.match(r'^/.*\.a$', arg)
267        if m:
268          if not arg in lflags:
269            lflags.append(arg)
270            self.logPrint('Found full library spec: '+arg, 4, 'compilers')
271            clibs.append(arg)
272          else:
273            self.logPrint('Skipping, already in lflags: '+arg, 4, 'compilers')
274          continue
275        # Check for full dylib library name
276        m = re.match(r'^/.*\.dylib$', arg)
277        if m:
278          if not arg in lflags:
279            lflags.append(arg)
280            self.logPrint('Found full library spec: '+arg, 4, 'compilers')
281            clibs.append(arg)
282          else:
283            self.logPrint('already in lflags: '+arg, 4, 'compilers')
284          continue
285        # Check for system libraries
286        m = re.match(r'^-l(ang.*|crt[0-9].o|crtbegin.o|c|gcc|gcc_ext(.[0-9]+)*|System|cygwin|xlomp_ser|crt[0-9].[0-9][0-9].[0-9].o)$', arg)
287        if m:
288          self.logPrint('Skipping system library: '+arg, 4, 'compilers')
289          continue
290        # Check for special library arguments
291        m = re.match(r'^-l.*$', arg)
292        if m:
293          if not arg in lflags:
294            if arg == '-lkernel32':
295              continue
296            elif iscray and (arg == '-lsci_cray_mpi' or arg == '-lsci_cray' or arg == '-lsci_cray_mp'):
297              self.logPrint('Skipping CRAY LIBSCI library: '+arg, 4, 'compilers')
298              continue
299            else:
300              lflags.append(arg)
301            self.logPrint('Found library : '+arg, 4, 'compilers')
302            clibs.append(arg)
303          continue
304        m = re.match(r'^-L.*$', arg)
305        if m:
306          arg = os.path.abspath(arg[2:])
307          if arg in skipdefaultpaths: continue
308          arg = '-L'+arg
309          lflags.append(arg)
310          self.logPrint('Found library directory: '+arg, 4, 'compilers')
311          clibs.append(arg)
312          continue
313        # Check for '-rpath /sharedlibpath/ or -R /sharedlibpath/'
314        if arg == '-rpath' or arg == '-R':
315          lib = next(argIter)
316          if lib.startswith('-') or lib.startswith('@loader_path'): continue # perhaps the path was striped due to quotes?
317          if lib.startswith('"') and lib.endswith('"') and lib.find(' ') == -1: lib = lib[1:-1]
318          lib = os.path.abspath(lib)
319          if lib in skipdefaultpaths: continue
320          if not lib in rpathflags:
321            rpathflags.append(lib)
322            self.logPrint('Found '+arg+' library: '+lib, 4, 'compilers')
323            clibs.append(self.setCompilers.CSharedLinkerFlag+lib)
324          else:
325            self.logPrint('Already in rpathflags, skipping'+arg, 4, 'compilers')
326          continue
327        # Check for '-R/sharedlibpath/'
328        m = re.match(r'^-R.*$', arg)
329        if m:
330          lib = os.path.abspath(arg[2:])
331          if not lib in rpathflags:
332            rpathflags.append(lib)
333            self.logPrint('Found -R library: '+lib, 4, 'compilers')
334            clibs.append(self.setCompilers.CSharedLinkerFlag+lib)
335          else:
336            self.logPrint('Already in rpathflags, skipping'+arg, 4, 'compilers')
337          continue
338        self.logPrint('Unknown arg '+arg, 4, 'compilers')
339    except StopIteration:
340      pass
341
342    self.clibs = []
343    for lib in clibs:
344      if not self.setCompilers.staticLibraries and lib.startswith('-L') and not self.setCompilers.CSharedLinkerFlag == '-L':
345        self.clibs.append(self.setCompilers.CSharedLinkerFlag+lib[2:])
346      self.clibs.append(lib)
347
348    self.logPrint('Libraries needed to link C code with another linker: '+str(self.clibs), 3, 'compilers')
349
350    if hasattr(self.setCompilers, 'FC') or hasattr(self.setCompilers, 'CXX'):
351      self.logPrint('Check that C libraries can be used with Fortran as linker', 4, 'compilers')
352      oldLibs = self.setCompilers.LIBS
353      self.setCompilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.clibs])+' '+self.setCompilers.LIBS
354    if hasattr(self.setCompilers, 'FC'):
355      self.setCompilers.saveLog()
356      try:
357        self.setCompilers.checkCompiler('FC')
358      except RuntimeError as e:
359        self.setCompilers.LIBS = oldLibs
360        self.logWrite(self.setCompilers.restoreLog())
361        self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
362        raise RuntimeError('C libraries cannot directly be used with Fortran as linker')
363      except OSError as e:
364        self.setCompilers.LIBS = oldLibs
365        self.logWrite(self.setCompilers.restoreLog())
366        raise e
367      self.logWrite(self.setCompilers.restoreLog())
368    return
369
370  def checkCFormatting(self):
371    '''Activate format string checking if using the GNU compilers'''
372    '''No checking because we use additional formatting conventions'''
373    if self.isGCC and 0:
374      self.gccFormatChecking = ('PRINTF_FORMAT_CHECK(A,B)', '__attribute__((format (printf, A, B)))')
375      self.logPrint('Added gcc printf format checking', 4, 'compilers')
376      self.addDefine(self.gccFormatChecking[0], self.gccFormatChecking[1])
377    else:
378      self.gccFormatChecking = None
379    return
380
381  def checkDynamicLoadFlag(self):
382    '''Checks that dlopen() takes RTLD_XXX, and defines PETSC_HAVE_RTLD_XXX if it does'''
383    if self.setCompilers.dynamicLibraries:
384      if self.checkLink('#include <dlfcn.h>\nchar *libname;\n', 'dlopen(libname, RTLD_LAZY);dlopen(libname, RTLD_NOW);dlopen(libname, RTLD_LOCAL);dlopen(libname, RTLD_GLOBAL)'):
385        self.addDefine('HAVE_RTLD_LAZY', 1)
386        self.addDefine('HAVE_RTLD_NOW', 1)
387        self.addDefine('HAVE_RTLD_LOCAL', 1)
388        self.addDefine('HAVE_RTLD_GLOBAL', 1)
389      else:
390        if self.checkLink('#include <dlfcn.h>\nchar *libname;\n', 'dlopen(libname, RTLD_LAZY)'):
391          self.addDefine('HAVE_RTLD_LAZY', 1)
392        if self.checkLink('#include <dlfcn.h>\nchar *libname;\n', 'dlopen(libname, RTLD_NOW)'):
393          self.addDefine('HAVE_RTLD_NOW', 1)
394        if self.checkLink('#include <dlfcn.h>\nchar *libname;\n', 'dlopen(libname, RTLD_LOCAL)'):
395          self.addDefine('HAVE_RTLD_LOCAL', 1)
396        if self.checkLink('#include <dlfcn.h>\nchar *libname;\n', 'dlopen(libname, RTLD_GLOBAL)'):
397          self.addDefine('HAVE_RTLD_GLOBAL', 1)
398      if self.checkLink('#include <dlfcn.h>\nchar *libname;\n', 'dlopen(libname, RTLD_NOLOAD)'):
399        self.addDefine('HAVE_RTLD_NOLOAD', 1)
400    return
401
402  def checkCxxOptionalExtensions(self):
403    '''Check whether the C++ compiler (IBM xlC, OSF5) need special flag for .c files which contain C++'''
404    self.setCompilers.saveLog()
405    self.setCompilers.pushLanguage('Cxx')
406    cxxObj = self.framework.getCompilerObject('Cxx')
407    oldExt = cxxObj.sourceExtension
408    cxxObj.sourceExtension = self.framework.getCompilerObject('C').sourceExtension
409    for flag in ['', '-+', '-x cxx -tlocal', '-Kc++']:
410      try:
411        self.setCompilers.addCompilerFlag(flag, body = 'class somename { public: int i; };\nsomename b;\nb.i = 0;\n(void)b.i')
412        self.cxxCompileC = True
413        break
414      except RuntimeError:
415        pass
416    if not self.cxxCompileC:
417      for flag in ['-x c++', '-TP','-P']:
418        try:
419          self.setCompilers.addCompilerFlag(flag, body = 'class somename { public: int i; };\nsomename b;\nb.i = 0;\n(void)b.i', compilerOnly = 1)
420          self.cxxCompileC = True
421          break
422        except RuntimeError:
423          pass
424    cxxObj.sourceExtension = oldExt
425    self.setCompilers.popLanguage()
426    self.logWrite(self.setCompilers.restoreLog())
427    return
428
429  def checkCxxComplexFix(self):
430    """Determine if the CXX compiler supports utilities provided by petsccxxcomplexfix.h"""
431    includes = """
432      #include <iostream>
433      #include <complex>
434      #define Type         int
435      #define PetscReal    double
436      #define PetscComplex std::complex<double>
437      /* The two lines, from petsccxxcomplexfix.h, can cause the combination "C++14 + GCC-4.x libstdc++ library" to fail, complaining imag()
438         is not marked const. If the compiler can compile these two lines, it should be able to compile other lines.
439      */
440      static inline PetscComplex operator-(const Type& lhs, const PetscComplex& rhs) { return PetscReal(lhs) - const_cast<PetscComplex&>(rhs); }
441      static inline PetscComplex operator/(const Type& lhs, const PetscComplex& rhs) { return PetscReal(lhs) / const_cast<PetscComplex&>(rhs); }
442      """
443    body = """
444      Type x = 2;
445      PetscComplex y(1.0,1.0),z,w;
446      z = x - y;
447      w = x / y;
448      std::cout << z << w;
449      """
450    self.pushLanguage('Cxx')
451    if self.checkCompile(includes,body):
452      self.logPrint('the CXX compiler supports petsccxxcomplexfix.h')
453      self.addDefine('HAVE_CXX_COMPLEX_FIX',1)
454    else:
455      self.logPrint('the CXX compiler does not support petsccxxcomplexfix.h')
456    self.popLanguage()
457
458  def checkCxxLibraries(self):
459    '''Determines the libraries needed to link using the C or Fortran compiler C++ source code compiled with C++. Result is stored in cxxlibs'''
460    skipcxxlibraries = 1
461    self.setCompilers.saveLog()
462    body   = '''#include <iostream>\n#include <vector>\nvoid asub(void)\n{std::vector<int> v;\ntry  { throw 20;  }  catch (int e)  { std::cout << "An exception occurred";  }}'''
463    oldLibs = ''
464    try:
465      if self.checkCrossLink(body,"int main(int argc,char **args)\n{return 0;}\n",language1='C++',language2='C'):
466        self.logWrite(self.setCompilers.restoreLog())
467        self.logPrint('C++ libraries are not needed when using C linker')
468      else:
469        skipcxxlibraries = 0
470        self.logWrite(self.setCompilers.restoreLog())
471        if self.setCompilers.isDarwin(self.log) and config.setCompilers.Configure.isClang(self.getCompiler('C'), self.log):
472          oldLibs = self.setCompilers.LIBS
473          self.setCompilers.LIBS = '-lc++ '+self.setCompilers.LIBS
474          self.setCompilers.saveLog()
475          if self.checkCrossLink(body,"int main(int argc,char **args)\n{return 0;}\n",language1='C++',language2='C'):
476            self.setCompilers.LIBS = oldLibs
477            self.logWrite(self.setCompilers.restoreLog())
478            self.logPrint('C++ requires -lc++ to link with C compiler', 3, 'compilers')
479            self.cxxlibs.append('-lc++')
480            skipcxxlibraries = 1
481          else:
482            self.logWrite(self.setCompilers.restoreLog())
483            self.setCompilers.LIBS = oldLibs
484            self.logPrint('C++ code cannot directly be linked with C linker using -lc++, therefore will determine needed C++ libraries')
485            skipcxxlibraries = 0
486        if self.setCompilers.isNEC(self.getCompiler('C'),self.log):
487          oldLibs = self.setCompilers.LIBS
488          self.setCompilers.LIBS = '-lnc++ '+self.setCompilers.LIBS
489          self.setCompilers.saveLog()
490          if self.checkCrossLink(body,"int main(int argc,char **args)\n{return 0;}\n",language1='C++',language2='C'):
491            self.setCompilers.LIBS = oldLibs
492            self.logWrite(self.setCompilers.restoreLog())
493            self.logPrint('C++ requires -lnc++ to link with C compiler', 3, 'compilers')
494            self.cxxlibs.append('-lnc++')
495            skipcxxlibraries = 1
496          else:
497            self.logWrite(self.setCompilers.restoreLog())
498            self.setCompilers.LIBS = oldLibs
499            self.logPrint('C++ code cannot directly be linked with C linker using -lnc++, therefore will determine needed C++ libraries')
500            skipcxxlibraries = 0
501        if not skipcxxlibraries:
502          self.setCompilers.saveLog()
503          oldLibs = self.setCompilers.LIBS
504          self.setCompilers.LIBS = '-lstdc++ '+self.setCompilers.LIBS
505          if self.checkCrossLink(body,"int main(int argc,char **args)\n{return 0;}\n",language1='C++',language2='C'):
506            self.setCompilers.LIBS = oldLibs
507            self.logWrite(self.setCompilers.restoreLog())
508            self.logPrint('C++ requires -lstdc++ to link with C compiler', 3, 'compilers')
509            self.cxxlibs.append('-lstdc++')
510            skipcxxlibraries = 1
511          else:
512            self.logWrite(self.setCompilers.restoreLog())
513            self.setCompilers.LIBS = oldLibs
514            self.logPrint('C++ code cannot directly be linked with C linker using -lstdc++, therefore will determine needed C++ libraries')
515            skipcxxlibraries = 0
516    except RuntimeError as e:
517      self.logWrite(self.setCompilers.restoreLog())
518      self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
519      self.logPrint('C++ code cannot directly be linked with C linker, therefore will determine needed C++ libraries')
520      skipcxxlibraries = 0
521    if skipcxxlibraries and hasattr(self.setCompilers, 'FC'):
522      self.setCompilers.saveLog()
523      oldLibs = self.setCompilers.LIBS
524      self.setCompilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.cxxlibs])+' '+self.setCompilers.LIBS
525      try:
526        if self.checkCrossLink(body,"     program main\n      print*,'testing'\n      stop\n      end\n",language1='C++',language2='FC'):
527          self.logWrite(self.setCompilers.restoreLog())
528          self.logPrint('Additional C++ libraries are not needed when using FC linker')
529        else:
530          self.logWrite(self.setCompilers.restoreLog())
531          self.logPrint('Additional C++ libraries are needed when using FC linker')
532          skipcxxlibraries = 0
533      except RuntimeError as e:
534        self.logWrite(self.setCompilers.restoreLog())
535        self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
536        self.logPrint('C++ code cannot directly be linked with FC linker, therefore will determine needed C++ libraries')
537        skipcxxlibraries = 0
538    self.setCompilers.LIBS = oldLibs
539
540    if skipcxxlibraries: return
541
542    oldFlags = self.setCompilers.LDFLAGS
543    self.setCompilers.LDFLAGS += ' -v'
544    self.pushLanguage('Cxx')
545    (output, returnCode) = self.outputLink('', '')
546    self.setCompilers.LDFLAGS = oldFlags
547    self.popLanguage()
548
549    # Cray: remove libsci link
550    iscray = config.setCompilers.Configure.isCray(self.getCompiler('Cxx'), self.log)
551
552    output = remove_xcode_verbose(output)
553    # PGI: kill anything enclosed in single quotes
554    if output.find('\'') >= 0:
555      if output.count('\'')%2: raise RuntimeError('Mismatched single quotes in C library string')
556      while output.find('\'') >= 0:
557        start = output.index('\'')
558        end   = output.index('\'', start+1)+1
559        output = output.replace(output[start:end], '')
560
561    # The easiest thing to do for xlc output is to replace all the commas
562    # with spaces.  Try to only do that if the output is really from xlc,
563    # since doing that causes problems on other systems.
564    if output.find('XL_CONFIG') >= 0:
565      output = output.replace(',', ' ')
566
567    # Parse output
568    argIter = iter(output.split())
569    cxxlibs = []
570    skipdefaultpaths = self.getSkipDefaultPaths()
571    lflags  = []
572    rpathflags = []
573    try:
574      while 1:
575        arg = next(argIter)
576        self.logPrint( 'Checking arg '+arg, 4, 'compilers')
577
578        # Intel compiler sometimes puts " " around an option like "-lsomething"
579        if arg.startswith('"') and arg.endswith('"'):
580          arg = arg[1:-1]
581        # Intel also puts several options together inside a " " so the last one
582        # has a stray " at the end
583        if arg.endswith('"') and arg[:-1].find('"') == -1:
584          arg = arg[:-1]
585        # Intel 11 has a bogus -long_double option
586        if arg == '-long_double':
587          continue
588
589        # ASan
590        if arg in ['-lasan', '-lubsan']:
591          self.logPrint('Skipping ASan libraries')
592          continue
593        # if options of type -L foobar
594        if arg == '-L':
595          lib = next(argIter)
596          self.logPrint('Found -L '+lib, 4, 'compilers')
597          cxxlibs.append('-L'+lib)
598          continue
599        if arg == '-lto_library':
600          lib = next(argIter)
601          self.logPrint('Skipping Apple LLVM linker option -lto_library '+lib)
602          continue
603        # Check for full library name
604        m = re.match(r'^/.*\.a$', arg)
605        if m:
606          if not arg in lflags:
607            lflags.append(arg)
608            self.logPrint('Found full library spec: '+arg, 4, 'compilers')
609            cxxlibs.append(arg)
610          else:
611            self.logPrint('Already in lflags: '+arg, 4, 'compilers')
612          continue
613        # Check for full dylib library name
614        m = re.match(r'^/.*\.dylib$', arg)
615        if m:
616          if not arg in lflags and not arg.endswith('LTO.dylib'):
617            lflags.append(arg)
618            self.logPrint('Found full library spec: '+arg, 4, 'compilers')
619            cxxlibs.append(arg)
620          else:
621            self.logPrint('already in lflags: '+arg, 4, 'compilers')
622          continue
623        # Check for system libraries
624        m = re.match(r'^-l(ang.*|crt[0-9].o|crtbegin.o|c|gcc|gcc_ext(.[0-9]+)*|System|cygwin|xlomp_ser|crt[0-9].[0-9][0-9].[0-9].o)$', arg)
625        if m:
626          self.logPrint('Skipping system library: '+arg, 4, 'compilers')
627          continue
628        # Check for special library arguments
629        m = re.match(r'^-l.*$', arg)
630        if m:
631          if not arg in lflags:
632            if arg == '-lkernel32':
633              continue
634            elif arg == '-lLTO' and self.setCompilers.isDarwin(self.log):
635              self.logPrint('Skipping -lTO')
636              continue
637            elif arg.find('-libpath:')>=0:
638              self.logPrint('Skipping Intel oneAPI icx (on Microsoft Windows) compiler option: '+arg)
639              continue
640            elif iscray and (arg == '-lsci_cray_mpi' or arg == '-lsci_cray' or arg == '-lsci_cray_mp'):
641              self.logPrint('Skipping CRAY LIBSCI library: '+arg, 4, 'compilers')
642              continue
643            elif arg in self.clibs:
644              self.logPrint('Library already in C list so skipping in C++', 4, 'compilers')
645              continue
646            else:
647              lflags.append(arg)
648            self.logPrint('Found library: '+arg, 4, 'compilers')
649            cxxlibs.append(arg)
650          else:
651            self.logPrint('Already in flags: '+arg, 4, 'compilers')
652          continue
653        m = re.match(r'^-L.*$', arg)
654        if m:
655          arg = os.path.abspath(arg[2:])
656          if arg in skipdefaultpaths: continue
657          arg = '-L'+arg
658          if not arg in lflags:
659            lflags.append(arg)
660            self.logPrint('Found library directory: '+arg, 4, 'compilers')
661            cxxlibs.append(arg)
662          continue
663        # Check for '-rpath /sharedlibpath/ or -R /sharedlibpath/'
664        if arg == '-rpath' or arg == '-R':
665          lib = next(argIter)
666          if lib.startswith('-') or lib.startswith('@loader_path'): continue # perhaps the path was striped due to quotes?
667          if lib.startswith('"') and lib.endswith('"') and lib.find(' ') == -1: lib = lib[1:-1]
668          lib = os.path.abspath(lib)
669          if lib in skipdefaultpaths: continue
670          if not lib in rpathflags:
671            rpathflags.append(lib)
672            self.logPrint('Found '+arg+' library: '+lib, 4, 'compilers')
673            cxxlibs.append(self.setCompilers.CSharedLinkerFlag+lib)
674          else:
675            self.logPrint('Already in rpathflags, skipping:'+arg, 4, 'compilers')
676          continue
677        # Check for '-R/sharedlibpath/'
678        m = re.match(r'^-R.*$', arg)
679        if m:
680          lib = os.path.abspath(arg[2:])
681          if not lib in rpathflags:
682            rpathflags.append(lib)
683            self.logPrint('Found -R library: '+lib, 4, 'compilers')
684            cxxlibs.append(self.setCompilers.CSharedLinkerFlag+lib)
685          else:
686            self.logPrint('Already in rpathflags, skipping:'+arg, 4, 'compilers')
687          continue
688        self.logPrint('Unknown arg '+arg, 4, 'compilers')
689    except StopIteration:
690      pass
691
692    self.cxxlibs = []
693    for lib in cxxlibs:
694      if not self.setCompilers.staticLibraries and lib.startswith('-L') and not self.setCompilers.CSharedLinkerFlag == '-L':
695        self.cxxlibs.append(self.setCompilers.CSharedLinkerFlag+lib[2:])
696      self.cxxlibs.append(lib)
697
698    self.logPrint('Libraries needed to link Cxx code with another linker: '+str(self.cxxlibs), 3, 'compilers')
699
700    self.logPrint('Check that Cxx libraries can be used with C as linker', 4, 'compilers')
701    oldLibs = self.setCompilers.LIBS
702    self.setCompilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.cxxlibs])+' '+self.setCompilers.LIBS
703    self.setCompilers.saveLog()
704    try:
705      self.setCompilers.checkCompiler('C')
706    except RuntimeError as e:
707      self.logWrite(self.setCompilers.restoreLog())
708      self.logPrint('Cxx libraries cannot directly be used with C as linker', 4, 'compilers')
709      self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
710      raise RuntimeError("Cxx libraries cannot directly be used with C as linker.\n\
711If you don't need the C++ compiler to build external packages or for you application you can run\n\
712./configure with --with-cxx=0. Otherwise you need a different combination of C and C++ compilers")
713    else:
714      self.logWrite(self.setCompilers.restoreLog())
715    self.setCompilers.LIBS = oldLibs
716
717    if hasattr(self.setCompilers, 'FC'):
718
719      self.logPrint('Check that Cxx libraries can be used with Fortran as linker', 4, 'compilers')
720      oldLibs = self.setCompilers.LIBS
721      self.setCompilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.cxxlibs])+' '+self.setCompilers.LIBS
722      self.setCompilers.saveLog()
723      try:
724        self.setCompilers.checkCompiler('FC')
725      except RuntimeError as e:
726        self.logWrite(self.setCompilers.restoreLog())
727        self.logPrint('Cxx libraries cannot directly be used with Fortran as linker', 4, 'compilers')
728        self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
729        raise RuntimeError("Cxx libraries cannot directly be used with Fortran as linker.\n\
730If you don't need the C++ compiler to build external packages or for you application you can run\n\
731./configure with --with-cxx=0. If you don't need the Fortran compiler to build external packages\n\
732or for you application you can run ./configure with --with-fc=0.\n\
733Otherwise you need a different combination of C, C++, and Fortran compilers")
734      else:
735        self.logWrite(self.setCompilers.restoreLog())
736      self.setCompilers.LIBS = oldLibs
737    return
738
739  def mangleFortranFunction(self, name):
740    if self.fortranMangling == 'underscore':
741      if self.fortranManglingDoubleUnderscore and name.find('_') >= 0:
742        return name.lower()+'__'
743      else:
744        return name.lower()+'_'
745    elif self.fortranMangling == 'unchanged':
746      return name.lower()
747    elif self.fortranMangling == 'caps':
748      return name.upper()
749    elif self.fortranMangling == 'stdcall':
750      return name.upper()
751    raise RuntimeError('Unknown Fortran name mangling: '+self.fortranMangling)
752
753  def testMangling(self, cfunc, ffunc, clanguage = 'C', extraObjs = []):
754    '''Test a certain name mangling'''
755    cobj = os.path.join(self.tmpDir, 'confc.o')
756    found = 0
757    # Compile the C test object
758    self.pushLanguage(clanguage)
759    if not self.checkCompile(cfunc, None, cleanup = 0):
760      self.logPrint('Cannot compile C function: '+cfunc, 3, 'compilers')
761      self.popLanguage()
762      return found
763    if not os.path.isfile(self.compilerObj):
764      self.logPrint('Cannot locate object file: '+os.path.abspath(self.compilerObj), 3, 'compilers')
765      self.popLanguage()
766      return found
767    os.rename(self.compilerObj, cobj)
768    self.popLanguage()
769    # Link the test object against a Fortran driver
770    self.pushLanguage('FC')
771    oldLIBS = self.setCompilers.LIBS
772    self.setCompilers.LIBS = cobj+' '+' '.join([self.libraries.getLibArgument(lib) for lib in self.clibs])+' '+self.setCompilers.LIBS
773    if extraObjs:
774      self.setCompilers.LIBS = ' '.join(extraObjs)+' '+' '.join([self.libraries.getLibArgument(lib) for lib in self.clibs])+' '+self.setCompilers.LIBS
775    found = self.checkLink(None, ffunc)
776    self.setCompilers.LIBS = oldLIBS
777    self.popLanguage()
778    if os.path.isfile(cobj):
779      os.remove(cobj)
780    return found
781
782  def checkFortranNameMangling(self):
783    '''Checks Fortran name mangling, and defines HAVE_FORTRAN_UNDERSCORE, HAVE_FORTRAN_NOUNDERSCORE, HAVE_FORTRAN_CAPS'''
784    self.manglerFuncs = {'underscore': ('void d1chk_(void);', 'void d1chk_(void){return;}\n', '       call d1chk()\n'),
785                         'unchanged': ('void d1chk(void);', 'void d1chk(void){return;}\n', '       call d1chk()\n'),
786                         'caps': ('void D1CHK(void);', 'void D1CHK(void){return;}\n', '       call d1chk()\n'),
787                         'stdcall': ('void __stdcall D1CHK(void);', 'void __stdcall D1CHK(void){return;}\n', '       call d1chk()\n'),
788                         'double': ('void d1_chk__(void)', 'void d1_chk__(void){return;}\n', '       call d1_chk()\n')}
789    #some compilers silently ignore '__stdcall' directive, so do stdcall test last
790    # double test is not done here, so its not listed
791    key_list = ['underscore','unchanged','caps','stdcall']
792    for mangler in key_list:
793      cfunc = self.manglerFuncs[mangler][1]
794      ffunc = self.manglerFuncs[mangler][2]
795      self.logWrite('Testing Fortran mangling type '+mangler+' with code '+cfunc)
796      if self.testMangling(cfunc, ffunc):
797        self.fortranMangling = mangler
798        break
799    else:
800      if self.setCompilers.isDarwin(self.log):
801        mess = '  See https://petsc.org/release/faq/#macos-gfortran'
802      else:
803        mess = ''
804      raise RuntimeError('Unknown Fortran name mangling: Are you sure the C and Fortran compilers are compatible?\n  Perhaps one is 64-bit and one is 32-bit?\n'+mess)
805    self.logPrint('Fortran name mangling is '+self.fortranMangling, 4, 'compilers')
806    if self.fortranMangling == 'underscore':
807      self.addDefine('HAVE_FORTRAN_UNDERSCORE', 1)
808    elif self.fortranMangling == 'unchanged':
809      self.addDefine('HAVE_FORTRAN_NOUNDERSCORE', 1)
810    elif self.fortranMangling == 'caps':
811      self.addDefine('HAVE_FORTRAN_CAPS', 1)
812    elif self.fortranMangling == 'stdcall':
813      raise RuntimeError('Fortran STDCALL compilers are unsupported!\n')
814    if config.setCompilers.Configure.isGfortran8plus(self.getCompiler('FC'), self.log):
815      self.addDefine('FORTRAN_CHARLEN_T', 'size_t')
816    else:
817      self.addDefine('FORTRAN_CHARLEN_T', 'int')
818    return
819
820  def checkFortranNameManglingDouble(self):
821    '''Checks if symbols containing an underscore append an extra underscore, and defines HAVE_FORTRAN_UNDERSCORE_UNDERSCORE if necessary'''
822    if self.testMangling(self.manglerFuncs['double'][1], self.manglerFuncs['double'][2]):
823      self.logPrint('Fortran appends an extra underscore to names containing underscores', 4, 'compilers')
824      self.fortranManglingDoubleUnderscore = 1
825      self.addDefine('HAVE_FORTRAN_UNDERSCORE_UNDERSCORE',1)
826    else:
827      self.fortranManglingDoubleUnderscore = 0
828    return
829
830  def checkFortranLibraries(self):
831    '''Substitutes for FLIBS the libraries needed to link using the C or C++ compiler Fortran source code compiled with Fortran. Result is stored in flibs.
832
833    This macro is intended to be used in those situations when it is
834    necessary to mix, e.g. C++ and Fortran 77, source code into a single
835    program or shared library.
836
837    For example, if object files from a C++ and Fortran 77 compiler must
838    be linked together, then the C++ compiler/linker must be used for
839    linking (since special C++-ish things need to happen at link time
840    like calling global constructors, instantiating templates, enabling
841    exception support, etc.).
842
843    However, the Fortran 77 intrinsic and run-time libraries must be
844    linked in as well, but the C++ compiler/linker does not know how to
845    add these Fortran 77 libraries.
846
847    This code was translated from the autoconf macro which was packaged in
848    its current form by Matthew D. Langston <langston@SLAC.Stanford.EDU>.
849    However, nearly all of this macro came from the OCTAVE_FLIBS macro in
850    octave-2.0.13/aclocal.m4, and full credit should go to John W. Eaton
851    for writing this extremely useful macro.'''
852    if not hasattr(self.setCompilers, 'CC') or not hasattr(self.setCompilers, 'FC'):
853      return
854    skipfortranlibraries = 1
855    self.setCompilers.saveLog()
856    asub=self.mangleFortranFunction("asub")
857    cbody = "extern void "+asub+"(void);\nint main(int argc,char **args)\n{\n  "+asub+"();\n  (void)argc, (void)args;\n  return 0;\n}\n";
858    cxxbody = 'extern "C" void '+asub+'(void);\nint main(int argc,char **args)\n{\n  '+asub+'();\n  (void)argc, (void)args;\n  return 0;\n}\n';
859    self.pushLanguage('FC')
860    if self.checkLink(body='      use mpi\n      call MPI_Allreduce()\n'):
861      fbody = "      subroutine asub()\n      use mpi\n      print*,'testing'\n      call MPI_Allreduce()\n      return\n      end\n"
862    elif self.checkLink(includes='#include <mpif.h>',body='      call MPI_Allreduce()\n'):
863      fbody = "      subroutine asub()\n      print*,'testing'\n      call MPI_Allreduce()\n      return\n      end\n"
864    else:
865      fbody = "      subroutine asub()\n      print*,'testing'\n      return\n      end\n"
866    self.popLanguage()
867    iscray = config.setCompilers.Configure.isCray(self.getCompiler('FC'), self.log)
868    isintel = config.setCompilers.Configure.isIntel(self.getCompiler('C'), self.log)
869    try:
870      if self.checkCrossLink(fbody,cbody,language1='FC',language2='C'):
871        self.logWrite(self.setCompilers.restoreLog())
872        self.logPrint('Fortran libraries are not needed when using C linker')
873      else:
874        skipfortranlibraries = 0
875        self.logWrite(self.setCompilers.restoreLog())
876        oldLibs = self.setCompilers.LIBS
877        testlibs = ['-lgfortran']
878        if iscray: testlibs.append('-lmpifort_cray')
879        if isintel: testlibs.append('-fortlib')
880        for testlib in testlibs:
881          self.setCompilers.LIBS = testlib+' '+self.setCompilers.LIBS
882          self.setCompilers.saveLog()
883          if self.checkCrossLink(fbody,cbody,language1='FC',language2='C'):
884            self.logWrite(self.setCompilers.restoreLog())
885            self.logPrint('Fortran requires '+testlib+' to link with C compiler', 3, 'compilers')
886            self.setCompilers.LIBS = oldLibs
887            self.flibs.append(testlib)
888            skipfortranlibraries = 1
889            break
890          else:
891            self.logWrite(self.setCompilers.restoreLog())
892            self.setCompilers.LIBS = oldLibs
893            skipfortranlibraries = 0
894        if not skipfortranlibraries:
895          self.logPrint('Fortran code cannot directly be linked with C linker, therefore will determine needed Fortran libraries')
896    except RuntimeError as e:
897      self.logWrite(self.setCompilers.restoreLog())
898      self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
899      self.logPrint('Fortran code cannot directly be linked with C linker, therefore will determine needed Fortran libraries')
900      skipfortranlibraries = 0
901    if skipfortranlibraries and hasattr(self.setCompilers, 'CXX'):
902      self.setCompilers.saveLog()
903      oldLibs = self.setCompilers.LIBS
904      try:
905        self.setCompilers.LIBS =  ' '.join([self.libraries.getLibArgument(lib) for lib in self.flibs]) + ' ' + self.setCompilers.LIBS
906        if self.checkCrossLink(fbody,cxxbody,language1='FC',language2='C++'):
907          self.logWrite(self.setCompilers.restoreLog())
908          self.setCompilers.LIBS = oldLibs
909          self.logPrint('Additional Fortran libraries are not needed when using C++ linker')
910        else:
911          self.logWrite(self.setCompilers.restoreLog())
912          self.setCompilers.LIBS = oldLibs
913          self.logPrint('Fortran code cannot directly be linked with C++ linker, therefore will determine needed Fortran libraries')
914          skipfortranlibraries = 0
915      except RuntimeError as e:
916        self.logWrite(self.setCompilers.restoreLog())
917        self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
918        self.setCompilers.LIBS = oldLibs
919        self.logPrint('Fortran code cannot directly be linked with CXX linker, therefore will determine needed Fortran libraries')
920        skipfortranlibraries = 0
921
922    if skipfortranlibraries == 1: return
923
924    self.pushLanguage('FC')
925    oldFlags = self.setCompilers.LDFLAGS
926    self.setCompilers.LDFLAGS += ' -v'
927    (output, returnCode) = self.outputLink('', '')
928    if returnCode: raise RuntimeError('Unable to run linker to determine needed Fortran libraries')
929    output = self.filterLinkOutput(output, filterAlways = 1)
930    self.setCompilers.LDFLAGS = oldFlags
931    self.popLanguage()
932
933    output = remove_xcode_verbose(output)
934    # replace \CR that ifc puts in each line of output
935    output = output.replace('\\\n', '')
936
937    if output.lower().find('absoft') >= 0:
938      loc = output.find(' -lf90math')
939      if loc == -1: loc = output.find(' -lf77math')
940      if loc >= -1:
941        output = output[0:loc]+' -lU77 -lV77 '+output[loc:]
942
943    # PGI/Windows: to properly resolve symbols, we need to list the fortran runtime libraries before -lpgf90
944    # PGI Fortran compiler uses PETSC_HAVE_F90_2PTR_ARG which is incompatible with
945    # certain PETSc example uses of Fortran (like passing classes) hence we need to define
946    # HAVE_PGF90_COMPILER so those examples are not run
947    if output.find(' -lpgf90') >= 0 and output.find(' -lkernel32') >= 0:
948      loc  = output.find(' -lpgf90')
949      loc2 = output.find(' -lpgf90rtl -lpgftnrtl')
950      if loc2 >= -1:
951        output = output[0:loc] + ' -lpgf90rtl -lpgftnrtl' + output[loc:]
952    elif output.find(' -lpgf90rtl -lpgftnrtl') >= 0:
953      # somehow doing this hacky thing appears to get rid of error with undefined __hpf_exit
954      self.logPrint('Adding -lpgftnrtl before -lpgf90rtl in librarylist')
955      output = output.replace(' -lpgf90rtl -lpgftnrtl',' -lpgftnrtl -lpgf90rtl -lpgftnrtl')
956
957    # PGI: kill anything enclosed in single quotes
958    if output.find('\'') >= 0:
959      if output.count('\'')%2: raise RuntimeError('Mismatched single quotes in Fortran library string')
960      while output.find('\'') >= 0:
961        start = output.index('\'')
962        end   = output.index('\'', start+1)+1
963        output = output.replace(output[start:end], '')
964
965    # The easiest thing to do for xlf output is to replace all the commas
966    # with spaces.  Try to only do that if the output is really from xlf,
967    # since doing that causes problems on other systems.
968    if output.find('XL_CONFIG') >= 0:
969      output = output.replace(',', ' ')
970    # We are only supposed to find LD_RUN_PATH on Solaris systems
971    # and the run path should be absolute
972    ldRunPath = re.findall(r'^.*LD_RUN_PATH *= *([^ ]*).*', output)
973    if ldRunPath: ldRunPath = ldRunPath[0]
974    if ldRunPath and ldRunPath[0] == '/':
975      if self.isGCC:
976        ldRunPath = ['-Xlinker -R -Xlinker '+ldRunPath]
977      else:
978        ldRunPath = ['-R '+ldRunPath]
979    else:
980      ldRunPath = []
981
982    # Parse output
983    argIter = iter(output.split())
984    fincs   = []
985    flibs   = []
986    skipdefaultpaths = self.getSkipDefaultPaths()
987    fmainlibs = []
988    lflags  = []
989    rpathflags = []
990    try:
991      while 1:
992        arg = next(argIter)
993        self.logPrint( 'Checking arg '+arg, 4, 'compilers')
994
995        # Intel compiler sometimes puts " " around an option like "-lsomething"
996        if arg.startswith('"') and arg.endswith('"'):
997          arg = arg[1:-1]
998        # Intel also puts several options together inside a " " so the last one
999        # has a stray " at the end
1000        if arg.endswith('"') and arg[:-1].find('"') == -1:
1001          arg = arg[:-1]
1002
1003        # ASan
1004        if arg in ['-lasan', '-lubsan']:
1005          self.logPrint('Skipping ASan libraries')
1006          continue
1007        if arg == '-lto_library':
1008          lib = next(argIter)
1009          self.logPrint('Skipping Apple LLVM linker option -lto_library '+lib)
1010          continue
1011        # Check for full library name
1012        m = re.match(r'^/.*\.a$', arg)
1013        if m:
1014          if not arg in lflags:
1015            lflags.append(arg)
1016            self.logPrint('Found full library spec: '+arg, 4, 'compilers')
1017#            # check for Nag Fortran library that must be handled as static because shared version does not have all the symbols
1018            base = os.path.basename(arg)
1019            m = re.match(r'libf[1-9][0-9]rts.a', base)
1020            if m:
1021              self.logPrint('Detected Nag Fortran compiler library; preserving as static library: '+arg, 4, 'compilers')
1022              flibs.append(arg)
1023              flibs.append('-Wl,-Bstatic')
1024              flibs.append(arg)
1025              flibs.append('-Wl,-Bdynamic')
1026            else:
1027              flibs.append(arg)
1028          else:
1029            self.logPrint('already in lflags: '+arg, 4, 'compilers')
1030          continue
1031        # Check for full dylib library name
1032        m = re.match(r'^/.*\.dylib$', arg)
1033        if m:
1034          if not arg.endswith('LTO.dylib') and not arg in lflags:
1035            lflags.append(arg)
1036            self.logPrint('Found full library spec: '+arg, 4, 'compilers')
1037            flibs.append(arg)
1038          else:
1039            self.logPrint('already in lflags: '+arg, 4, 'compilers')
1040          continue
1041        # prevent false positives for include with pathscalr
1042        if re.match(r'^-INTERNAL.*$', arg): continue
1043        # Check for special include argument
1044        # AIX does this for MPI and perhaps other things
1045        m = re.match(r'^-I.*$', arg)
1046        if m:
1047          inc = arg.replace('-I','',1)
1048          self.logPrint('Found include directory: '+inc, 4, 'compilers')
1049          fincs.append(inc)
1050          continue
1051        # Check for ???
1052        m = re.match(r'^-bI:.*$', arg)
1053        if m:
1054          if not arg in lflags:
1055            if self.isGCC:
1056              lflags.append('-Xlinker')
1057            lflags.append(arg)
1058            self.logPrint('Found binary include: '+arg, 4, 'compilers')
1059            flibs.append(arg)
1060          else:
1061            self.logPrint('Already in lflags so skipping: '+arg, 4, 'compilers')
1062          continue
1063        # Check for system libraries
1064        m = re.match(r'^-l(ang.*|crt[0-9].o|crtbegin.o|c|gcc|gcc_ext(.[0-9]+)*|System|cygwin|xlomp_ser|crt[0-9].[0-9][0-9].[0-9].o)$', arg)
1065        if m:
1066          self.logPrint('Found system library therefore skipping: '+arg, 4, 'compilers')
1067          continue
1068        # Check for canonical library argument
1069        m = re.match(r'^-[lL]$', arg)
1070        if m:
1071          lib = arg+next(argIter)
1072          self.logPrint('Found canonical library: '+lib, 4, 'compilers')
1073          if not lib == '-LLTO' or not self.setCompilers.isDarwin(self.log):
1074            flibs.append(lib)
1075          continue
1076        # Check for special library arguments
1077        m = re.match(r'^-l.*$', arg)
1078        if m:
1079          # HP Fortran prints these libraries in a very strange way
1080          if arg == '-l:libU77.a':  arg = '-lU77'
1081          if arg == '-l:libF90.a':  arg = '-lF90'
1082          if arg == '-l:libIO77.a': arg = '-lIO77'
1083          if not arg in lflags:
1084            if arg == '-lkernel32':
1085              continue
1086            elif arg == '-lgfortranbegin':
1087              fmainlibs.append(arg)
1088              continue
1089            elif arg == '-lfrtbegin' and not config.setCompilers.Configure.isCygwin(self.log):
1090              fmainlibs.append(arg)
1091              continue
1092            elif arg == '-lLTO' and self.setCompilers.isDarwin(self.log):
1093              self.logPrint('Skipping -lTO')
1094            elif arg == '-lnvc':
1095              self.logPrint('Skipping -lnvc: https://forums.developer.nvidia.com/t/failed-cuda-device-detection-when-explicitly-linking-libnvc/203225')
1096              continue
1097            elif arg.find('-libpath:')>=0:
1098              self.logPrint('Skipping Intel oneAPI ifort (on Microsoft Windows) compiler option: '+arg)
1099              continue
1100            elif iscray and (arg == '-lsci_cray_mpi' or arg == '-lsci_cray' or arg == '-lsci_cray_mp'):
1101              self.logPrint('Skipping CRAY LIBSCI library: '+arg, 4, 'compilers')
1102              continue
1103            elif arg in self.clibs:
1104              self.logPrint('Library already in C list so skipping in Fortran', 4, 'compilers')
1105              continue
1106            else:
1107              lflags.append(arg)
1108            self.logPrint('Found library: '+arg, 4, 'compilers')
1109            flibs.append(arg)
1110          else:
1111            self.logPrint('Already in lflags: '+arg, 4, 'compilers')
1112          continue
1113        m = re.match(r'^-L.*$', arg)
1114        if m:
1115          arg = os.path.abspath(arg[2:])
1116          if arg in skipdefaultpaths: continue
1117          arg = '-L'+arg
1118          if not arg in lflags:
1119            lflags.append(arg)
1120            self.logPrint('Found library directory: '+arg, 4, 'compilers')
1121            flibs.append(arg)
1122          else:
1123            self.logPrint('Already in lflags so skipping: '+arg, 4, 'compilers')
1124          continue
1125        # Check for '-rpath /sharedlibpath/ or -R /sharedlibpath/'
1126        if arg == '-rpath' or arg == '-R':
1127          lib = next(argIter)
1128          if lib == '\\': lib = next(argIter)
1129          if lib.startswith('-') or lib.startswith('@loader_path'): continue # perhaps the path was striped due to quotes?
1130          if lib.startswith('"') and lib.endswith('"') and lib.find(' ') == -1: lib = lib[1:-1]
1131          lib = os.path.abspath(lib)
1132          if lib in skipdefaultpaths: continue
1133          if not lib in rpathflags:
1134            rpathflags.append(lib)
1135            self.logPrint('Found '+arg+' library: '+lib, 4, 'compilers')
1136            flibs.append(self.setCompilers.CSharedLinkerFlag+lib)
1137          else:
1138            self.logPrint('Already in rpathflags so skipping: '+arg, 4, 'compilers')
1139          continue
1140        # Check for '-R/sharedlibpath/'
1141        m = re.match(r'^-R.*$', arg)
1142        if m:
1143          lib = os.path.abspath(arg[2:])
1144          if not lib in rpathflags:
1145            rpathflags.append(lib)
1146            self.logPrint('Found -R library: '+lib, 4, 'compilers')
1147            flibs.append(self.setCompilers.CSharedLinkerFlag+lib)
1148          else:
1149            self.logPrint('Already in rpathflags so skipping: '+arg, 4, 'compilers')
1150          continue
1151        if arg.startswith('-zallextract') or arg.startswith('-zdefaultextract') or arg.startswith('-zweakextract'):
1152          self.logWrite( 'Found Solaris -z option: '+arg+'\n')
1153          flibs.append(arg)
1154          continue
1155        # Check for ???
1156        # Should probably try to ensure unique directory options here too.
1157        # This probably only applies to Solaris systems, and then will only
1158        # work with gcc...
1159        if arg == '-Y':
1160          libs = next(argIter)
1161          if libs.startswith('"') and libs.endswith('"'):
1162            libs = libs[1:-1]
1163          for lib in libs.split(':'):
1164            #solaris gnu g77 has this extra P, here, not sure why it means
1165            if lib.startswith('P,'):lib = lib[2:]
1166            self.logPrint('Handling -Y option: '+lib, 4, 'compilers')
1167            lib1 = os.path.abspath(lib)
1168            if lib1 in skipdefaultpaths: continue
1169            lib1 = '-L'+lib1
1170            flibs.append(lib1)
1171          continue
1172        if arg.startswith('COMPILER_PATH=') or arg.startswith('LIBRARY_PATH='):
1173          self.logPrint('Skipping arg '+arg, 4, 'compilers')
1174          continue
1175        # HPUX lists a bunch of library directories separated by :
1176        if arg.find(':') >=0:
1177          founddir = 0
1178          for l in arg.split(':'):
1179            if os.path.isdir(l):
1180              lib1 = os.path.abspath(l)
1181              if lib1 in skipdefaultpaths: continue
1182              lib1 = '-L'+lib1
1183              if not arg in lflags:
1184                flibs.append(lib1)
1185                lflags.append(lib1)
1186                self.logPrint('Handling HPUX list of directories: '+l, 4, 'compilers')
1187                founddir = 1
1188          if founddir:
1189            continue
1190        # needed with NCC/NFORT 3.2.0 on NEC and by the FORTRAN NAG Compiler (f61init and quickfit) https://www.nag.com/nagware/np/r62_doc/manual/compiler_11_1.html
1191        if arg.find('f61init.o')>=0 or arg.find('quickfit.o')>=0 or arg.find('f90_init.o')>=0 or arg.find('nousemmap.o')>=0 or arg.find('async_noio.o')>=0:
1192          flibs.append(arg)
1193          self.logPrint('Found '+arg+' in argument, adding it')
1194          continue
1195        # gcc+pgf90 might require pgi.dl
1196        if arg.find('pgi.ld')>=0:
1197          flibs.append(arg)
1198          self.logPrint('Found strange PGI file ending with .ld, adding it')
1199          continue
1200        self.logPrint('Unknown arg '+arg, 4, 'compilers')
1201    except StopIteration:
1202      pass
1203
1204    self.fincs = fincs
1205    self.flibs = []
1206    for lib in flibs:
1207      if not self.setCompilers.staticLibraries and lib.startswith('-L') and not self.setCompilers.FCSharedLinkerFlag == '-L':
1208        self.flibs.append(self.setCompilers.FCSharedLinkerFlag+lib[2:])
1209      self.flibs.append(lib)
1210    self.fmainlibs = fmainlibs
1211    # Append run path
1212    self.flibs = ldRunPath+self.flibs
1213
1214    # on OS X, mixing g77 3.4 with gcc-3.3 requires using -lcc_dynamic
1215    for l in self.flibs:
1216      if l.find('-L/sw/lib/gcc/powerpc-apple-darwin') >= 0:
1217        self.logWrite('Detected Apple Mac Fink libraries')
1218        appleLib = 'libcc_dynamic.so'
1219        self.libraries.saveLog()
1220        if self.libraries.check(appleLib, 'foo'):
1221          self.flibs.append(self.libraries.getLibArgument(appleLib))
1222          self.logWrite('Adding '+self.libraries.getLibArgument(appleLib)+' so that Fortran can work with C++')
1223        self.logWrite(self.libraries.restoreLog())
1224        break
1225
1226    self.logPrint('Libraries needed to link Fortran code with the C linker: '+str(self.flibs), 3, 'compilers')
1227    self.logPrint('Libraries needed to link Fortran main with the C linker: '+str(self.fmainlibs), 3, 'compilers')
1228
1229    self.logPrint('Check that Fortran libraries can be used with Fortran as the linker', 4, 'compilers')
1230    oldLibs = self.setCompilers.LIBS
1231    self.setCompilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.flibs])+' '+self.setCompilers.LIBS
1232    try:
1233      self.setCompilers.checkCompiler('FC')
1234    except RuntimeError as e:
1235      self.logPrint('Fortran libraries cannot directly be used with Fortran as the linker, try with -Wl,-z -Wl,muldefs', 4, 'compilers')
1236      self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
1237      try:
1238        self.setCompilers.pushLanguage('FC')
1239        # this is needed with NEC Fortran compiler
1240        self.setCompilers.addLinkerFlag('-Wl,-z -Wl,muldefs')
1241        self.setCompilers.popLanguage()
1242      except RuntimeError as e:
1243        self.logPrint('Fortran libraries still cannot directly be used with Fortran as the linker', 4, 'compilers')
1244        self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
1245        raise RuntimeError('Fortran libraries cannot be used with Fortran as linker')
1246    self.setCompilers.LIBS = oldLibs
1247
1248    self.logPrint('Check that Fortran libraries can be used with C as the linker', 4, 'compilers')
1249    oldLibs = self.setCompilers.LIBS
1250    self.setCompilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.flibs])+' '+self.setCompilers.LIBS
1251    self.setCompilers.saveLog()
1252    try:
1253      self.setCompilers.checkCompiler('C')
1254    except RuntimeError as e:
1255      self.logWrite(self.setCompilers.restoreLog())
1256      self.logPrint('Fortran libraries cannot directly be used with C as the linker, try without -lcrt2.o', 4, 'compilers')
1257      self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
1258      # try removing this one
1259      if '-lcrt2.o' in self.flibs: self.flibs.remove('-lcrt2.o')
1260      self.setCompilers.LIBS = oldLibs+' '+' '.join([self.libraries.getLibArgument(lib) for lib in self.flibs])
1261      self.setCompilers.saveLog()
1262      try:
1263        self.setCompilers.checkCompiler('C')
1264      except RuntimeError as e:
1265        self.logWrite(self.setCompilers.restoreLog())
1266        self.logPrint('Fortran libraries still cannot directly be used with C as the linker, try without pgi.ld files', 4, 'compilers')
1267        self.logPrint('Error message from compiling {'+str(e)+'}', 4, 'compilers')
1268        tmpflibs = self.flibs
1269        for lib in tmpflibs:
1270          if lib.find('pgi.ld')>=0:
1271            self.flibs.remove(lib)
1272        self.setCompilers.LIBS = oldLibs+' '+' '.join([self.libraries.getLibArgument(lib) for lib in self.flibs])
1273        self.setCompilers.saveLog()
1274        try:
1275          self.setCompilers.checkCompiler('C')
1276        except:
1277          self.logWrite(self.setCompilers.restoreLog())
1278          self.logPrint(str(e), 4, 'compilers')
1279          raise RuntimeError('Fortran libraries cannot be used with C as linker')
1280      else:
1281        self.logWrite(self.setCompilers.restoreLog())
1282    else:
1283      self.logWrite(self.setCompilers.restoreLog())
1284
1285    if hasattr(self.setCompilers, 'CXX'):
1286      self.logPrint('Check that Fortran libraries can be used with C++ as linker', 4, 'compilers')
1287      self.setCompilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.flibs])+' '+oldLibs
1288      self.setCompilers.saveLog()
1289      try:
1290        self.setCompilers.checkCompiler('Cxx')
1291        self.logPrint('Fortran libraries can be used from C++', 4, 'compilers')
1292      except RuntimeError as e:
1293        self.logWrite(self.setCompilers.restoreLog())
1294        self.logPrint(str(e), 4, 'compilers')
1295        # try removing this one causes grief with gnu g++ and Intel Fortran
1296        if '-lintrins' in self.flibs: self.flibs.remove('-lintrins')
1297        self.setCompilers.LIBS = oldLibs+' '+' '.join([self.libraries.getLibArgument(lib) for lib in self.flibs])
1298        self.setCompilers.saveLog()
1299        try:
1300          self.setCompilers.checkCompiler('Cxx')
1301        except RuntimeError as e:
1302          self.logWrite(self.setCompilers.restoreLog())
1303          self.logPrint(str(e), 4, 'compilers')
1304          if str(e).find('INTELf90_dclock') >= 0:
1305            self.logPrint('Intel 7.1 Fortran compiler cannot be used with g++ 3.2!', 2, 'compilers')
1306        else:
1307           self.logWrite(self.setCompilers.restoreLog())
1308        raise RuntimeError('Fortran libraries cannot be used with C++ as linker.\n Run with --with-fc=0 or --with-cxx=0')
1309      else:
1310        self.logWrite(self.setCompilers.restoreLog())
1311
1312    self.setCompilers.LIBS = oldLibs
1313    return
1314
1315  def checkFortranLinkingCxx(self):
1316    '''Check that Fortran can link C++ libraries'''
1317    link = 0
1318    cinc, cfunc, ffunc = self.manglerFuncs[self.fortranMangling]
1319    cinc = 'extern "C" '+cinc+'\n'
1320
1321    cxxCode = 'void foo(void){'+self.mangleFortranFunction('d1chk')+'();}'
1322    cxxobj  = os.path.join(self.tmpDir, 'cxxobj.o')
1323    self.pushLanguage('Cxx')
1324    if not self.checkCompile(cinc+cxxCode, None, cleanup = 0):
1325      self.logPrint('Cannot compile Cxx function: '+cfunc, 3, 'compilers')
1326      raise RuntimeError('Fortran could not successfully link C++ objects')
1327    if not os.path.isfile(self.compilerObj):
1328      self.logPrint('Cannot locate object file: '+os.path.abspath(self.compilerObj), 3, 'compilers')
1329      raise RuntimeError('Fortran could not successfully link C++ objects')
1330    os.rename(self.compilerObj, cxxobj)
1331    self.popLanguage()
1332
1333    if self.testMangling(cinc+cfunc, ffunc, 'Cxx', extraObjs = [cxxobj]):
1334      self.logPrint('Fortran can link C++ functions', 3, 'compilers')
1335      link = 1
1336    else:
1337      oldLibs = self.setCompilers.LIBS
1338      self.setCompilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.cxxlibs])+' '+self.setCompilers.LIBS
1339      if self.testMangling(cinc+cfunc, ffunc, 'Cxx', extraObjs = [cxxobj]):
1340        self.logPrint('Fortran can link C++ functions using the C++ compiler libraries', 3, 'compilers')
1341        link = 1
1342      else:
1343        self.setCompilers.LIBS = oldLibs
1344    if os.path.isfile(cxxobj):
1345      os.remove(cxxobj)
1346    if not link:
1347      raise RuntimeError('Fortran could not successfully link C++ objects with Fortran as linker')
1348    return
1349
1350  def checkDependencyGenerationFlag(self):
1351    '''Check if -MMD works for dependency generation, and add it if it does'''
1352    self.generateDependencies       = {}
1353    self.dependenciesGenerationFlag = {}
1354    if not self.argDB['with-dependencies'] :
1355      self.logPrint("Skip checking dependency compiler options on user request")
1356      return
1357    languages = ['C']
1358    if hasattr(self, 'CXX'):
1359      languages.append('Cxx')
1360    # Fortran is handled in compilersfortran.py
1361    if hasattr(self, 'CUDAC'):
1362      languages.append('CUDA')
1363    if hasattr(self, 'HIPC'):
1364      languages.append('HIP')
1365    if hasattr(self, 'SYCLC'):
1366      languages.append('SYCL')
1367    for language in languages:
1368      self.generateDependencies[language] = 0
1369      self.setCompilers.saveLog()
1370      self.setCompilers.pushLanguage(language)
1371      for testFlag in ['-MMD -MP', # GCC, Intel, Clang, Pathscale
1372                       '-MMD',     # PGI
1373                       '-xMMD',    # Sun
1374                       '-qmakedep=gcc', # xlc
1375                       '-MD',
1376                       # Cray only supports -M, which writes to stdout
1377                     ]:
1378        try:
1379          self.logPrint('Trying '+language+' compiler flag '+testFlag)
1380          if self.setCompilers.checkCompilerFlag(testFlag, compilerOnly = 1):
1381            depFilename = os.path.splitext(self.setCompilers.compilerObj)[0]+'.d'
1382            if os.path.isfile(depFilename):
1383              os.remove(depFilename)
1384              #self.setCompilers.insertCompilerFlag(testFlag, compilerOnly = 1)
1385              self.framework.addMakeMacro(language.upper()+'_DEPFLAGS',testFlag)
1386              self.dependenciesGenerationFlag[language] = testFlag
1387              self.generateDependencies[language]       = 1
1388              break
1389            else:
1390              self.logPrint('Rejected '+language+' compiler flag '+testFlag+' because no dependency file ('+depFilename+') was generated')
1391          else:
1392            self.logPrint('Rejected '+language+' compiler flag '+testFlag)
1393        except RuntimeError:
1394          self.logPrint('Rejected '+language+' compiler flag '+testFlag)
1395      self.setCompilers.popLanguage()
1396      self.logWrite(self.setCompilers.restoreLog())
1397    return
1398
1399  def checkLinux(self):
1400    '''Check for __linux__'''
1401    includes = """
1402    #if !defined(__linux__)
1403    #error "__linux__ not defined"
1404    #endif
1405    """
1406    body = ""
1407    if self.checkCompile(includes, body):
1408      self.addDefine('HAVE_LINUX', 1)
1409
1410  def checkC99Flag(self):
1411    '''Check for -std=c99 or equivalent flag'''
1412    includes = "#include <float.h>"
1413    body = """
1414    float x[2],y;
1415    float *restrict z = &y;
1416    y = FLT_ROUNDS;
1417    // c++ comment
1418    int j = 2;
1419    for (int i=0; i<2; i++){
1420      x[i] = i*j*(*z);
1421    }
1422    (void)x"""
1423    self.setCompilers.pushLanguage('C')
1424    flags_to_try = ['','-std=c99','-std=gnu99','-std=c11','-std=gnu11','-c99']
1425    for flag in flags_to_try:
1426      self.setCompilers.saveLog()
1427      if self.setCompilers.checkCompilerFlag(flag, includes, body):
1428        self.logWrite(self.setCompilers.restoreLog())
1429        self.c99flag = flag
1430        if flag:
1431          self.setCompilers.CPPFLAGS += ' ' + flag
1432        self.framework.logPrint('Accepted C99 compile flag: '+flag)
1433        break
1434      else:
1435        self.logWrite(self.setCompilers.restoreLog())
1436    self.setCompilers.popLanguage()
1437    if self.c99flag is None:
1438      if self.isGCC: additionalErrorMsg = '\nPerhaps you have an Intel compiler environment or module set that is interfering with the GNU compilers.\nTry removing that environment or module and running ./configure again.'
1439      else: additionalErrorMsg = ''
1440      raise RuntimeError('PETSc requires c99 compiler! Configure could not determine compatible compiler flag.\nPerhaps you can specify it via CFLAGS.'+additionalErrorMsg)
1441    return
1442
1443  def checkStdAtomic(self,cxx=False):
1444    includes = """
1445    #if defined(__cplusplus)
1446    #include <atomic>
1447    using namespace std;
1448    #else
1449    #include <stdatomic.h>
1450    #endif
1451    double dcount = 0;
1452    atomic_flag cat = ATOMIC_FLAG_INIT;
1453    """
1454    body = """
1455    do {} while (atomic_flag_test_and_set(&cat));
1456    dcount++;
1457    atomic_flag_clear(&cat);
1458    """
1459    if self.checkCompile(includes, body):
1460      if cxx:
1461        self.addDefine('HAVE_CXX_ATOMIC', 1)
1462      else:
1463        self.addDefine('HAVE_STDATOMIC_H', 1)
1464
1465  def configure(self):
1466    import config.setCompilers
1467    if hasattr(self.setCompilers, 'CC'):
1468      self.isGCC = config.setCompilers.Configure.isGNU(self.setCompilers.CC, self.log)
1469      self.executeTest(self.checkLinux)
1470      self.executeTest(self.checkC99Flag)
1471      self.executeTest(self.checkCFormatting)
1472      self.executeTest(self.checkDynamicLoadFlag)
1473      self.executeTest(self.checkStdAtomic)
1474      if self.argDB['with-clib-autodetect']:
1475        self.executeTest(self.checkCLibraries)
1476      self.executeTest(self.checkDependencyGenerationFlag)
1477    else:
1478      self.isGCC = 0
1479
1480    if hasattr(self.setCompilers, 'CXX'):
1481      self.isGCXX = config.setCompilers.Configure.isGNU(self.setCompilers.CXX, self.log)
1482      self.executeTest(self.checkCxxRestrict)
1483      # Adding -x c++ it causes Clang to SEGV, http://llvm.org/bugs/show_bug.cgi?id=12924
1484      if not config.setCompilers.Configure.isClang(self.setCompilers.CXX, self.log):
1485        self.executeTest(self.checkCxxOptionalExtensions)
1486      self.executeTest(self.checkCxxComplexFix)
1487      self.executeTest(self.checkStdAtomic,kargs={'cxx' : True})
1488      if self.argDB['with-cxxlib-autodetect']:
1489        self.executeTest(self.checkCxxLibraries)
1490      # To skip Sun C++ compiler warnings/errors
1491      if config.setCompilers.Configure.isSun(self.setCompilers.CXX, self.log):
1492        self.addDefine('HAVE_SUN_CXX', 1)
1493    else:
1494      self.isGCXX = 0
1495    if hasattr(self.setCompilers, 'FC'):
1496      self.executeTest(self.checkFortranNameMangling)
1497      self.executeTest(self.checkFortranNameManglingDouble)
1498      if self.argDB['with-fortranlib-autodetect']:
1499        self.executeTest(self.checkFortranLibraries)
1500      if hasattr(self.setCompilers, 'CXX'):
1501        self.executeTest(self.checkFortranLinkingCxx)
1502
1503    self.no_configure()
1504    return
1505
1506  def setupFrameworkCompilers(self):
1507    '''Sets the selected compilers into the framework'''
1508    if self.framework.compilers is None:
1509      self.logPrint('Setting framework compilers to this module', 2, 'compilers')
1510      self.framework.compilers = self
1511    return
1512
1513  def no_configure(self):
1514    self.executeTest(self.setupFrameworkCompilers)
1515    return
1516