1import config.base 2import re 3import os 4 5class Configure(config.base.Configure): 6 def __init__(self, framework): 7 config.base.Configure.__init__(self, framework) 8 self.headerPrefix = '' 9 self.substPrefix = '' 10 self.version = {} 11 self.rejected = {} 12 self.text = '' 13 return 14 15 def __str__(self): 16 return self.text 17 18 def setupHelp(self, help): 19 import nargs 20 help.addArgument('Compiler Flags', '-optionsModule=<module name>', nargs.Arg(None, 'config.compilerOptions', 'The Python module used to determine compiler options and versions')) 21 help.addArgument('Compiler Flags', '-with-debugging=<bool>', nargs.ArgBool(None, 1, 'Specify debugging version of libraries')) 22 help.addArgument('Compiler Flags', '-C_VERSION=<string>', nargs.Arg(None, 'Unknown', 'The version of the C compiler')) 23 help.addArgument('Compiler Flags', '-CXX_VERSION=<string>', nargs.Arg(None, 'Unknown', 'The version of the C++ compiler')) 24 help.addArgument('Compiler Flags', '-FC_VERSION=<string>', nargs.Arg(None, 'Unknown', 'The version of the Fortran compiler')) 25 help.addArgument('Compiler Flags', '-CUDA_VERSION=<string>',nargs.Arg(None, 'Unknown', 'The version of the CUDA compiler')) 26 help.addArgument('Compiler Flags', '-HIP_VERSION=<string>',nargs.Arg(None, 'Unknown', 'The version of the HIP compiler')) 27 help.addArgument('Compiler Flags', '-SYCL_VERSION=<string>',nargs.Arg(None, 'Unknown', 'The version of the SYCL compiler')) 28 help.addArgument('Compiler Flags', '-COPTFLAGS=<string>', nargs.Arg(None, None, 'Override the debugging/optimization flags for the C compiler')) 29 help.addArgument('Compiler Flags', '-CXXOPTFLAGS=<string>', nargs.Arg(None, None, 'Override the debugging/optimization flags for the C++ compiler')) 30 help.addArgument('Compiler Flags', '-FOPTFLAGS=<string>', nargs.Arg(None, None, 'Override the debugging/optimization flags for the Fortran compiler')) 31 help.addArgument('Compiler Flags', '-CUDAOPTFLAGS=<string>', nargs.Arg(None, None, 'Override the debugging/optimization flags for the CUDA compiler')) 32 help.addArgument('Compiler Flags', '-HIPOPTFLAGS=<string>', nargs.Arg(None, None, 'Override the debugging/optimization flags for the HIP compiler')) 33 help.addArgument('Compiler Flags', '-SYCLOPTFLAGS=<string>', nargs.Arg(None, None, 'Override the debugging/optimization flags for the SYCL compiler')) 34 help.addArgument('Compiler Flags', '-with-gcov=<bool>', nargs.ArgBool(None, value=None, help='Specify that GNUs coverage tool gcov is used', deprecated='--with-coverage')) 35 return 36 37 def setupDependencies(self, framework): 38 config.base.Configure.setupDependencies(self, framework) 39 self.setCompilers = framework.require('config.setCompilers', self) 40 return 41 42 def getOptionalFlagsName(self, language, compilerOnly = 0): 43 if language == 'C': 44 flagsArg = 'COPTFLAGS' 45 elif language == 'Cxx': 46 if compilerOnly: 47 flagsArg = 'CXX_CXXOPTFLAGS' 48 else: 49 flagsArg = 'CXXOPTFLAGS' 50 elif language == 'FC': 51 flagsArg = 'FOPTFLAGS' 52 elif language == 'CUDA': 53 flagsArg = 'CUDAOPTFLAGS' 54 elif language == 'HIP': 55 flagsArg = 'HIPOPTFLAGS' 56 elif language == 'SYCL': 57 flagsArg = 'SYCLOPTFLAGS' 58 else: 59 raise RuntimeError('Unknown language: '+language) 60 return flagsArg 61 62 def findOptFlags(self, flags): 63 if isinstance(flags, str): 64 flags = flags.split() 65 66 return [f for f in flags if f.startswith('-g') or f.startswith('-O') or f in {'-fast'}] 67 68 def hasOptFlags(self,flags): 69 return len(self.findOptFlags(flags)) > 0 70 71 def getOptionsObject(self): 72 '''Get a configure object which will return default options for each compiler''' 73 options = None 74 try: 75 mod = __import__(self.argDB['optionsModule'], locals(), globals(), ['CompilerOptions']) 76 options = mod.CompilerOptions(self.framework) 77 options.setup() 78 except ImportError: 79 self.logPrint('ERROR: Failed to load user options module '+str(self.argDB['optionsModule'])) 80 return options 81 82 def configureCompilerFlags(self): 83 '''Get the default compiler flags''' 84 self.debugging = self.argDB['with-debugging'] 85 bopts = ['', '+'] 86 if self.debugging: 87 bopts.append('g') 88 else: 89 bopts.append('O') 90 91 options = self.getOptionsObject() 92 if not options: 93 return 94 options.saveLog() 95 for language, compiler in [('C', 'CC'), ('Cxx', 'CXX'), ('FC', 'FC'), ('CUDA', 'CUDAC'), ('HIP', 'HIPC'), ('SYCL', 'SYCLC')]: 96 if not hasattr(self.setCompilers, compiler): 97 continue 98 self.setCompilers.pushLanguage(language) 99 flagsName = config.base.Configure.getCompilerFlagsName(language) 100 try: 101 self.version[language] = self.argDB[language.upper()+'_VERSION'] 102 if self.version[language] == 'Unknown': 103 self.version[language] = options.getCompilerVersion(language, self.setCompilers.getCompiler()) 104 except RuntimeError: 105 pass 106 self.rejected[language] = [] 107 for bopt in bopts: 108 userflags = 0 109 userlangflags = 0 110 if bopt in ['g','O'] and self.getOptionalFlagsName(language) in self.argDB: # check --COPTFLAGS etc 111 # treat user supplied options as single option - as it could include options separated by spaces '-tp k8-64' 112 flags = [self.argDB[self.getOptionalFlagsName(language)]] 113 userflags = 1 114 elif bopt in ['g','O'] and self.hasOptFlags(getattr(self.setCompilers,flagsName)): # check --CFLAGS etc 115 self.logPrint('Optimization options found in '+flagsName+ '. Skipping setting defaults') 116 flags = [] 117 elif bopt == '' and flagsName in self.argDB: 118 self.logPrint('Ignoring default options which were overridden using --'+flagsName+ ' ' + self.argDB[flagsName]) 119 flags = [] 120 elif bopt == '+': 121 if flagsName+'+' in self.argDB: 122 flags = [self.argDB[flagsName+'+']] 123 userlangflags = 1 124 else: 125 continue 126 else: 127 flags = options.getCompilerFlags(language, self.setCompilers.getCompiler(), bopt) 128 129 for testFlag in flags: 130 if isinstance(testFlag, (tuple, list)): 131 testFlag = ' '.join(testFlag) 132 self.logPrint('Trying '+language+' compiler flag '+testFlag) 133 try: 134 self.setCompilers.addCompilerFlag(testFlag) 135 except RuntimeError: 136 if userflags: 137 raise RuntimeError('User provided flags for language '+language+' with '+self.getOptionalFlagsName(language)+': '+self.argDB[self.getOptionalFlagsName(language)]+' are not correct for the compiler') 138 if userlangflags: 139 raise RuntimeError('User provided flags for language '+language+' with '+flagsName+'+: '+self.argDB[flagsName+'+']+' are not correct for the compiler') 140 self.logPrint('Rejected '+language+' compiler flag '+testFlag) 141 self.rejected[language].append(testFlag) 142 self.setCompilers.popLanguage() 143 return 144 145 def outputCompilerMacros(self): 146 '''Cannot use the regular outputCompile because it swallows the output into the -o file''' 147 command = self.getCompilerCmd() 148 if self.compilerDefines: self.framework.outputHeader(self.compilerDefines) 149 self.framework.outputCHeader(self.compilerFixes) 150 f = open(self.compilerSource, 'w') 151 f.close() 152 try: 153 command = command + ' -E -dM ' 154 start = command.find('-o ') 155 end = start + 3 + command[start+3:].find(' ') 156 command = command[:start-1]+command[end:] 157 (out, err, ret) = Configure.executeShellCommand(command, log = self.log) 158 if out.find('__AVX2__') > -1 and out.find('__FMA__') > -1: 159 self.text = self.text + 'Intel instruction sets utilizable by compiler:\n' 160 self.text = self.text + ' AVX2\n' 161 if out.find('__AVX512') > -1: 162 self.text = self.text + ' AVX512: ' 163 self.text = self.text + ' '.join([i for i in out.split('__') if i.startswith('AVX512')]) 164 self.text = self.text + '\n' 165 except: 166 pass 167 for filename in [self.compilerDefines, self.compilerFixes, self.compilerSource, self.compilerObj]: 168 if os.path.isfile(filename): os.remove(filename) 169 170 def checkCompilerMacros(self): 171 '''Save the list of CPP macros defined by the C and C++ compiler, does not work for all compilers''' 172 '''The values will depends on the flags passed to the compiler''' 173 self.outputCompilerMacros() 174 if hasattr(self.setCompilers, 'CXX'): 175 with self.Language('Cxx'): 176 self.outputCompilerMacros() 177 return 178 179 def checkIntelHardwareSupport(self): 180 '''Use Linux/macOS commands to determine what operations the hardware supports''' 181 try: 182 (out, err, ret) = Configure.executeShellCommand('lscpu', log = self.log) 183 except: 184 out = '' 185 if out.find(' avx2 ') > -1 and out.find(' fma ') > -1: 186 self.text = self.text + 'Intel instruction sets found on CPU:\n' 187 self.text = self.text + ' AVX2\n' 188 if out.find(' avx512') > -1: 189 self.text = self.text + ' AVX512: ' 190 self.text = self.text + ' '.join([i for i in out.split(' ') if i.startswith('avx512')]) 191 self.text = self.text + '\n' 192 return 193 194 def configure(self): 195 self.executeTest(self.configureCompilerFlags) 196 self.executeTest(self.checkIntelHardwareSupport) 197 self.executeTest(self.checkCompilerMacros) 198 return 199