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 return 22 23 def setupDependencies(self, framework): 24 config.base.Configure.setupDependencies(self, framework) 25 self.setCompilers = framework.require('config.setCompilers', self) 26 self.compilerFlags = framework.require('config.compilerFlags', self) 27 self.libraries = framework.require('config.libraries', None) 28 self.compilers = framework.require('config.compilers', self) 29 return 30 31 def __getattr__(self, name): 32 if 'dispatchNames' in self.__dict__: 33 if name in self.dispatchNames: 34 if not hasattr(self.setCompilers, name): 35 raise MissingProcessor(self.dispatchNames[name]) 36 return getattr(self.setCompilers, name) 37 if name in ['CC_LINKER_FLAGS', 'FC_LINKER_FLAGS', 'CXX_LINKER_FLAGS', 'CUDAC_LINKER_FLAGS', 'HIPC_LINKER_FLAGS', 'SYCLC_LINKER_FLAGS', 'sharedLibraryFlags', 'dynamicLibraryFlags']: 38 flags = getattr(self.setCompilers, name) 39 if not isinstance(flags, list): flags = [flags] 40 return ' '.join(flags) 41 raise AttributeError('Configure attribute not found: '+name) 42 43 def __setattr__(self, name, value): 44 if 'dispatchNames' in self.__dict__: 45 if name in self.dispatchNames: 46 return setattr(self.setCompilers, name, value) 47 config.base.Configure.__setattr__(self, name, value) 48 return 49 50 def checkFortranTypeSizes(self): 51 '''Check whether real*8 is supported and suggest flags which will allow support''' 52 self.pushLanguage('FC') 53 # Check whether the compiler (ifc) bitches about real*8, if so try using -w90 -w to eliminate bitch 54 (output, error, returnCode) = self.outputCompile('', ' real*8 variable', 1) 55 if (output+error).find('Type size specifiers are an extension to standard Fortran 95') >= 0: 56 oldFlags = self.setCompilers.FFLAGS 57 self.setCompilers.FFLAGS += ' -w90 -w' 58 (output, error, returnCode) = self.outputCompile('', ' real*8 variable', 1) 59 if returnCode or (output+error).find('Type size specifiers are an extension to standard Fortran 95') >= 0: 60 self.setCompilers.FFLAGS = oldFlags 61 else: 62 self.logPrint('Looks like ifc compiler, adding -w90 -w flags to avoid warnings about real*8 etc', 4, 'compilers') 63 self.popLanguage() 64 return 65 66 def checkFortranPreprocessor(self): 67 '''Determine if Fortran handles preprocessing properly''' 68 self.setCompilers.pushLanguage('FC') 69 # Does Fortran compiler need special flag for using CPP 70 for flag in ['', '-cpp', '-xpp=cpp', '-F', '-Cpp', '-fpp', '-fpp:-m']: 71 try: 72 flagsArg = self.setCompilers.getCompilerFlagsArg() 73 oldFlags = getattr(self.setCompilers, flagsArg) 74 self.setCompilers.saveLog() 75 self.setCompilers.addCompilerFlag(flag, body = '#define dummy \n dummy\n#ifndef dummy\n fooey\n#endif') 76 self.logWrite(self.setCompilers.restoreLog()) 77 setattr(self.setCompilers, flagsArg, oldFlags+' '+flag) 78 self.fortranPreprocess = 1 79 self.setCompilers.popLanguage() 80 self.logPrint('Fortran uses '+flag+' preprocessor', 3, 'compilers') 81 return 82 except RuntimeError: 83 setattr(self.setCompilers, flagsArg, oldFlags) 84 self.setCompilers.popLanguage() 85 self.fortranPreprocess = 0 86 self.logPrint('Fortran does NOT use preprocessor', 3, 'compilers') 87 return 88 89 def checkFortranDefineCompilerOption(self): 90 '''Check if -WF,-Dfoobar or -Dfoobar is the compiler option to define a macro''' 91 self.FortranDefineCompilerOption = '' 92 if not self.fortranPreprocess: 93 return 94 self.setCompilers.saveLog() 95 self.setCompilers.pushLanguage('FC') 96 for flag in ['-D', '-WF,-D']: 97 if self.setCompilers.checkCompilerFlag(flag+'Testing', body = '#define dummy \n dummy\n#ifndef Testing\n fooey\n#endif'): 98 self.logWrite(self.setCompilers.restoreLog()) 99 self.FortranDefineCompilerOption = flag 100 self.framework.addMakeMacro('FC_DEFINE_FLAG',self.FortranDefineCompilerOption) 101 self.setCompilers.popLanguage() 102 self.logPrint('Fortran uses '+flag+' for defining macro', 3, 'compilers') 103 return 104 self.logWrite(self.setCompilers.restoreLog()) 105 self.setCompilers.popLanguage() 106 self.logPrint('Fortran does not support defining macro', 3, 'compilers') 107 return 108 109 def configureFortranFlush(self): 110 '''Determine if Fortran has a flush() command''' 111 self.pushLanguage('FC') 112 for baseName in ['flush','flush_']: 113 if self.checkLink(body=' call '+baseName+'(6)'): 114 self.addDefine('HAVE_FORTRAN_'+baseName.upper(), 1) 115 break 116 self.popLanguage() 117 return 118 119 def checkFortranTypeStar(self): 120 '''Determine whether the Fortran compiler handles type(*)''' 121 '''Newer nvfortran support (*) but they introduce extra arguments at the end that interfere with char * lengths''' 122 '''So it cannot be used in interface definitions''' 123 '''Not using type(*) :: b(:) prevents this compiler from certifying it has (*)''' 124 self.pushLanguage('FC') 125 if self.checkCompile(body = ' interface\n subroutine a(b)\n type(*) b\n end subroutine\n end interface\n'): 126 self.addDefine('HAVE_FORTRAN_TYPE_STAR', 1) 127 self.logPrint('Fortran compiler supports type(*)') 128 else: 129 self.logPrint('Fortran compiler does not support type(*)') 130 self.popLanguage() 131 return 132 133 def checkFortran90(self): 134 '''Determine whether the Fortran compiler handles F90''' 135 self.pushLanguage('FC') 136 if self.checkLink(body = ''' 137 REAL(KIND=SELECTED_REAL_KIND(10)) d 138 INTEGER, PARAMETER :: int = SELECTED_INT_KIND(8) 139 INTEGER (KIND=int) :: ierr 140 ierr = 1'''): 141 self.fortranIsF90 = 1 142 self.logPrint('Fortran compiler supports F90') 143 else: 144 self.fortranIsF90 = 0 145 self.logPrint('Fortran compiler does not support F90') 146 self.popLanguage() 147 return 148 149 def checkFortranBool(self): 150 ''' 151 Determine whether the Fortran compiler has interoperable Bool/logical 152 153 requires '-fpscomp logicals' or similar for Intel compilers 154 requires '-Munixlogical' for NVIDIA compilers 155 ''' 156 self.fortranBoolIsInteroperable = 1 157 if self.argDB['with-batch']: 158 self.logPrint('Using --with-batch, so assume that Fortran Bool is interoperable', 3, 'compilers') 159 return 160 self.pushLanguage('FC') 161 if not self.checkRun(None, 162 ''' 163 use, intrinsic :: ISO_C_binding 164 implicit none 165 integer(C_INT8_T) :: int8_t 166 167 if (transfer(.true._C_BOOL,int8_t) /= 1_C_INT8_T) error stop 'true !=1' 168 if (transfer(.false._C_BOOL,int8_t) /= 0_C_INT8_T) error stop 'false !=0' 169 '''): 170 self.fortranBoolIsInteroperable = 0 171 self.logPrint('Fortran compiler uses non-interoperable Bool representation', 3, 'compilers') 172 else: 173 self.logPrint('Fortran compiler uses interoperable Bool representation', 3, 'compilers') 174 self.popLanguage() 175 return 176 177 def checkFortran90LineLength(self): 178 '''Determine whether the Fortran compiler has infinite line length''' 179 self.pushLanguage('FC') 180 if self.checkLink(body = ' INTEGER, PARAMETER :: int = SELECTED_INT_KIND(8); INTEGER (KIND=int) :: ierr,ierr2; ierr = 1; ierr2 = 2'): 181 self.addDefine('HAVE_FORTRAN_FREE_LINE_LENGTH_NONE', 1) 182 self.logPrint('Fortran compiler has unlimited line length') 183 else: 184 self.logPrint('Fortran compiler does not have unlimited line length') 185 self.popLanguage() 186 return 187 188 def checkFortranPointerInit(self): 189 '''Determine whether the Fortran compiler supports initializing a pointer in the declaration''' 190 self.pushLanguage('FC') 191 if self.checkLink(body = ''' 192 implicit none 193 integer, target :: targ 194 integer, pointer :: point => targ 195 targ = 3'''): 196 self.logPrint('Fortran compiler has pointer initialization in the declaration') 197 self.fortranInitializePtrInDecl = 1 198 else: 199 self.logPrint('Fortran compiler does not have pointer initialization in the declaration') 200 self.fortranInitializePtrInDecl = 0 201 self.popLanguage() 202 return 203 204 def checkFortran90FreeForm(self): 205 '''Determine whether the Fortran compiler handles F90FreeForm 206 We also require that the compiler handles lines longer than 132 characters''' 207 self.pushLanguage('FC') 208 if self.checkLink(body = ' INTEGER, PARAMETER :: int = SELECTED_INT_KIND(8); INTEGER (KIND=int) :: ierr; ierr = 1'): 209 self.addDefine('USING_F90FREEFORM', 1) 210 self.fortranIsF90FreeForm = 1 211 self.logPrint('Fortran compiler supports F90FreeForm') 212 else: 213 self.fortranIsF90FreeForm = 0 214 self.logPrint('Fortran compiler does not support F90FreeForm') 215 self.popLanguage() 216 return 217 218 def checkFortran2003(self): 219 '''Determine whether the Fortran compiler handles F2003''' 220 self.pushLanguage('FC') 221 if self.fortranIsF90 and self.checkLink(codeBegin = ''' 222 module Base_module 223 type, public :: base_type 224 integer :: A 225 contains 226 procedure, public :: Print => BasePrint 227 end type base_type 228 contains 229 subroutine BasePrint(this) 230 class(base_type) :: this 231 end subroutine BasePrint 232 end module Base_module 233 234 program main''',body = ''' 235 use,intrinsic :: iso_c_binding 236 Type(C_Ptr),Dimension(:),Pointer :: CArray 237 character(kind=c_char),pointer :: nullc => null() 238 character(kind=c_char,len=5),dimension(:),pointer::list1 239 240 allocate(list1(5)) 241 CArray(1:Len) = c_loc(list1) 242 CArray(Len+1) = c_loc(nullc)'''): 243 self.addDefine('USING_F2003', 1) 244 self.fortranIsF2003 = 1 245 self.logPrint('Fortran compiler supports F2003') 246 else: 247 self.fortranIsF2003 = 0 248 self.logPrint('Fortran compiler does not support F2003') 249 self.popLanguage() 250 for f in [os.path.abspath('base_module.mod'), os.path.abspath('BASE_MODULE.mod'), os.path.join(os.path.dirname(self.compilerObj),'base_module.mod'), os.path.join(os.path.dirname(self.compilerObj),'BASE_MODULE.mod')]: 251 if os.path.isfile(f): os.remove(f) 252 return 253 254 def checkFortran90Array(self): 255 '''Check for F90 array interfaces''' 256 if not self.fortranIsF90: 257 self.logPrint('Not a Fortran90 compiler - hence skipping f90-array test') 258 return 259 # do an approximate test when batch mode is used, as we cannot run the proper test.. 260 if self.argDB['with-batch']: 261 if config.setCompilers.Configure.isPGI(self.setCompilers.FC, self.log): 262 self.addDefine('HAVE_F90_2PTR_ARG', 1) 263 self.logPrint('PGI F90 compiler detected & using --with-batch, so use two arguments for array pointers', 3, 'compilers') 264 else: 265 self.logPrint('Using --with-batch, so guess that F90 uses a single argument for array pointers', 3, 'compilers') 266 return 267 # do not check on windows - as it pops up the annoying debugger 268 if config.setCompilers.Configure.isCygwin(self.log): 269 self.logPrint('Cygwin detected: ignoring HAVE_F90_2PTR_ARG test') 270 return 271 272 # Compile the C test object 273 cinc = '#include<stdio.h>\n#include <stdlib.h>\n' 274 ccode = 'void '+self.compilers.mangleFortranFunction('f90arraytest')+'''(void* a1, void* a2,void* a3, void* i) 275{ 276 printf("arrays [%p %p %p]\\n",a1,a2,a3); 277 fflush(stdout); 278 return; 279} 280''' + 'void '+self.compilers.mangleFortranFunction('f90ptrtest')+'''(void* a1, void* a2,void* a3, void* i, void* p1 ,void* p2, void* p3) 281{ 282 printf("arrays [%p %p %p]\\n",a1,a2,a3); 283 if ((p1 == p3) && (p1 != p2)) { 284 printf("pointers match! [%p %p] [%p]\\n",p1,p3,p2); 285 fflush(stdout); 286 } else { 287 printf("pointers do not match! [%p %p] [%p]\\n",p1,p3,p2); 288 fflush(stdout); 289 exit(111); 290 } 291 return; 292}\n''' 293 cobj = os.path.join(self.tmpDir, 'fooobj.o') 294 self.pushLanguage('C') 295 if not self.checkCompile(cinc+ccode, None, cleanup = 0): 296 self.logPrint('Cannot compile C function: f90ptrtest', 3, 'compilers') 297 raise RuntimeError('Could not check Fortran pointer arguments') 298 if not os.path.isfile(self.compilerObj): 299 self.logPrint('Cannot locate object file: '+os.path.abspath(self.compilerObj), 3, 'compilers') 300 raise RuntimeError('Could not check Fortran pointer arguments') 301 os.rename(self.compilerObj, cobj) 302 self.popLanguage() 303 # Link the test object against a Fortran driver 304 self.pushLanguage('FC') 305 oldLIBS = self.setCompilers.LIBS 306 self.setCompilers.LIBS = cobj+' '+self.setCompilers.LIBS 307 fcode = '''\ 308 Interface 309 Subroutine f90ptrtest(p1,p2,p3,i) 310 integer, pointer :: p1(:,:) 311 integer, pointer :: p2(:,:) 312 integer, pointer :: p3(:,:) 313 integer i 314 End Subroutine 315 End Interface 316 317 integer, pointer :: ptr1(:,:),ptr2(:,:) 318 integer, target :: array(6:8,9:21) 319 integer in 320 321 in = 25 322 ptr1 => array 323 ptr2 => array 324 325 call f90arraytest(ptr1,ptr2,ptr1,in) 326 call f90ptrtest(ptr1,ptr2,ptr1,in)\n''' 327 328 found = self.checkRun(None, fcode, defaultArg = 'f90-2ptr-arg') 329 self.setCompilers.LIBS = oldLIBS 330 self.popLanguage() 331 # Cleanup 332 if os.path.isfile(cobj): 333 os.remove(cobj) 334 if found: 335 self.addDefine('HAVE_F90_2PTR_ARG', 1) 336 self.logPrint('F90 compiler uses two arguments for array pointers', 3, 'compilers') 337 else: 338 self.logPrint('F90 uses a single argument for array pointers', 3, 'compilers') 339 return 340 341 def checkFortran90AssumedType(self): 342 '''Check if Fortran compiler array pointer is a raw pointer in C''' 343 if config.setCompilers.Configure.isIBM(self.setCompilers.FC, self.log): 344 self.addDefine('HAVE_F90_ASSUMED_TYPE_NOT_PTR', 1) 345 self.logPrint('IBM F90 compiler detected so using HAVE_F90_ASSUMED_TYPE_NOT_PTR', 3, 'compilers') 346 347 def checkFortranModuleInclude(self): 348 '''Figures out what flag is used to specify the include path for Fortran modules''' 349 self.setCompilers.fortranModuleIncludeFlag = None 350 if not self.fortranIsF90: 351 self.logPrint('Not a Fortran90 compiler - hence skipping module include test') 352 return 353 found = False 354 testdir = os.path.join(self.tmpDir, 'confdir') 355 modobj = os.path.join(self.tmpDir, 'configtest.o') 356 modcode = '''\ 357 module configtest 358 integer testint 359 parameter (testint = 42) 360 end module configtest\n''' 361 # Compile the Fortran test module 362 self.pushLanguage('FC') 363 if not self.checkCompile(modcode, None, cleanup = 0): 364 self.logPrint('Cannot compile Fortran module', 3, 'compilers') 365 self.popLanguage() 366 raise RuntimeError('Cannot determine Fortran module include flag') 367 if not os.path.isfile(self.compilerObj): 368 self.logPrint('Cannot locate object file: '+os.path.abspath(self.compilerObj), 3, 'compilers') 369 self.popLanguage() 370 raise RuntimeError('Cannot determine Fortran module include flag') 371 if not os.path.isdir(testdir): 372 os.mkdir(testdir) 373 os.rename(self.compilerObj, modobj) 374 foundModule = 0 375 for f in [os.path.abspath('configtest.mod'), os.path.abspath('CONFIGTEST.mod'), os.path.join(os.path.dirname(self.compilerObj),'configtest.mod'), os.path.join(os.path.dirname(self.compilerObj),'CONFIGTEST.mod')]: 376 if os.path.isfile(f): 377 modname = f 378 foundModule = 1 379 break 380 if not foundModule: 381 d = os.path.dirname(os.path.abspath('configtest.mod')) 382 self.logPrint('Directory '+d+' contents:\n'+str(os.listdir(d))) 383 raise RuntimeError('Fortran module was not created during the compile. %s/CONFIGTEST.mod not found' % os.path.abspath('configtest.mod')) 384 shutil.move(modname, os.path.join(testdir, os.path.basename(modname))) 385 fcode = '''\ 386 use configtest 387 388 write(*,*) testint\n''' 389 self.pushLanguage('FC') 390 oldFLAGS = self.setCompilers.FFLAGS 391 oldLIBS = self.setCompilers.LIBS 392 for flag in ['-I', '-p', '-M']: 393 self.setCompilers.FFLAGS = flag+testdir+' '+self.setCompilers.FFLAGS 394 self.setCompilers.LIBS = modobj+' '+self.setCompilers.LIBS 395 if not self.checkLink(None, fcode): 396 self.logPrint('Fortran module include flag '+flag+' failed', 3, 'compilers') 397 else: 398 self.logPrint('Fortran module include flag '+flag+' found', 3, 'compilers') 399 self.setCompilers.fortranModuleIncludeFlag = flag 400 found = 1 401 self.setCompilers.LIBS = oldLIBS 402 self.setCompilers.FFLAGS = oldFLAGS 403 if found: break 404 self.popLanguage() 405 if os.path.isfile(modobj): 406 os.remove(modobj) 407 os.remove(os.path.join(testdir, os.path.basename(modname))) 408 os.rmdir(testdir) 409 if not found: 410 raise RuntimeError('Cannot determine Fortran module include flag') 411 return 412 413 def checkFortranModuleOutput(self): 414 '''Figures out what flag is used to specify the output path for Fortran modules''' 415 self.setCompilers.fortranModuleOutputFlag = None 416 if not self.fortranIsF90: 417 self.logPrint('Not a Fortran90 compiler - hence skipping module include test') 418 return 419 found = False 420 testdir = os.path.join(self.tmpDir, 'confdir') 421 modobj = os.path.join(self.tmpDir, 'configtest.o') 422 modcode = '''\ 423 module configtest 424 integer testint 425 parameter (testint = 42) 426 end module configtest\n''' 427 modname = None 428 # Compile the Fortran test module 429 if not os.path.isdir(testdir): 430 os.mkdir(testdir) 431 self.pushLanguage('FC') 432 oldFLAGS = self.setCompilers.FFLAGS 433 oldLIBS = self.setCompilers.LIBS 434 for flag in ['-module ', '-module:', '-fmod=', '-J', '-M', '-p', '-qmoddir=', '-moddir=']: 435 self.setCompilers.FFLAGS = flag+testdir+' '+self.setCompilers.FFLAGS 436 self.setCompilers.LIBS = modobj+' '+self.setCompilers.LIBS 437 if not self.checkCompile(modcode, None, cleanup = 0): 438 self.logPrint('Fortran module output flag '+flag+' compile failed', 3, 'compilers') 439 elif os.path.isfile(os.path.join(testdir, 'configtest.mod')) or os.path.isfile(os.path.join(testdir, 'CONFIGTEST.mod')): 440 if os.path.isfile(os.path.join(testdir, 'configtest.mod')): modname = 'configtest.mod' 441 if os.path.isfile(os.path.join(testdir, 'CONFIGTEST.mod')): modname = 'CONFIGTEST.mod' 442 self.logPrint('Fortran module output flag '+flag+' found', 3, 'compilers') 443 self.setCompilers.fortranModuleOutputFlag = flag 444 found = 1 445 else: 446 self.logPrint('Fortran module output flag '+flag+' failed', 3, 'compilers') 447 self.setCompilers.LIBS = oldLIBS 448 self.setCompilers.FFLAGS = oldFLAGS 449 if found: break 450 self.popLanguage() 451 if modname: os.remove(os.path.join(testdir, modname)) 452 os.rmdir(testdir) 453 # Flag not used by PETSc - do not flag a runtime error 454 #if not found: 455 # raise RuntimeError('Cannot determine Fortran module output flag') 456 return 457 458 def checkDependencyGenerationFlag(self): 459 '''Check if -MMD works for dependency generation, and add it if it does''' 460 self.generateDependencies = {} 461 self.dependenciesGenerationFlag = {} 462 if not self.argDB['with-dependencies'] : 463 self.logPrint("Skip checking dependency compiler options on user request") 464 return 465 languages = ['FC'] 466 for language in languages: 467 self.generateDependencies[language] = 0 468 self.setCompilers.saveLog() 469 self.setCompilers.pushLanguage(language) 470 for testFlag in ['-MMD -MP', # GCC, Intel, Clang, Pathscale 471 '-MMD', # PGI 472 '-xMMD', # Sun 473 '-qmakedep=gcc', # xlc 474 '-MD', 475 # Cray only supports -M, which writes to stdout 476 ]: 477 try: 478 self.logPrint('Trying '+language+' compiler flag '+testFlag) 479 if self.setCompilers.checkCompilerFlag(testFlag, compilerOnly = 1): 480 depFilename = os.path.splitext(self.setCompilers.compilerObj)[0]+'.d' 481 if os.path.isfile(depFilename): 482 os.remove(depFilename) 483 #self.setCompilers.insertCompilerFlag(testFlag, compilerOnly = 1) 484 self.framework.addMakeMacro(language.upper()+'_DEPFLAGS',testFlag) 485 self.dependenciesGenerationFlag[language] = testFlag 486 self.generateDependencies[language] = 1 487 break 488 else: 489 self.logPrint('Rejected '+language+' compiler flag '+testFlag+' because no dependency file ('+depFilename+') was generated') 490 else: 491 self.logPrint('Rejected '+language+' compiler flag '+testFlag) 492 except RuntimeError: 493 self.logPrint('Rejected '+language+' compiler flag '+testFlag) 494 self.setCompilers.popLanguage() 495 self.logWrite(self.setCompilers.restoreLog()) 496 return 497 498 def configure(self): 499 import config.setCompilers 500 if hasattr(self.setCompilers, 'FC'): 501 self.executeTest(self.checkFortranTypeSizes) 502 self.executeTest(self.checkFortranPreprocessor) 503 self.executeTest(self.checkFortranDefineCompilerOption) 504 self.executeTest(self.checkFortran90) 505 self.executeTest(self.checkFortranBool) 506 self.executeTest(self.checkFortran90FreeForm) 507 self.executeTest(self.checkFortran2003) 508 self.executeTest(self.checkFortran90Array) 509 self.executeTest(self.checkFortran90AssumedType) 510 self.executeTest(self.checkFortranModuleInclude) 511 self.executeTest(self.checkFortranModuleOutput) 512 self.executeTest(self.checkFortranTypeStar) 513 self.executeTest(self.configureFortranFlush) 514 self.executeTest(self.checkDependencyGenerationFlag) 515 self.executeTest(self.checkFortran90LineLength) 516 self.executeTest(self.checkFortranPointerInit) 517 return 518