1import config.base 2 3import os 4import re 5 6class Configure(config.base.Configure): 7 def __init__(self, framework, libraries = []): 8 config.base.Configure.__init__(self, framework) 9 self.headerPrefix = '' 10 self.substPrefix = '' 11 self.libraries = libraries 12 self.rpathSkipDirs = [] # do not generate RPATH for dirs in this list; useful when compiling with stub libraries (.so) that do not have corresponding runtime library (.so.1) at this location. Check cuda.py for usage. 13 self.sysDirs = ['/usr/lib','/lib','/usr/lib64','/lib64'] # skip conversion from full path to link line argument format for libraries in these dirs. For ex: some compilers internally use /usr/lib/libm.so that should not be converted to '-L/usr/lib -lm' 14 return 15 16 def setupDependencies(self, framework): 17 config.base.Configure.setupDependencies(self, framework) 18 self.setCompilers = framework.require('config.setCompilers', self) 19 self.compilers = framework.require('config.compilers', self) 20 self.headers = framework.require('config.headers', self) 21 self.types = framework.require('config.types', self) 22 return 23 24 def getLibArgumentList(self, library, with_rpath=True): 25 '''Return the proper link line argument for the given filename library as a list of options 26 - If the path is empty, return it unchanged 27 - If starts with - then return unchanged 28 - If the path ends in ".lib" return it unchanged 29 - If the path is absolute and the filename is "lib"<name>, return -L<dir> -l<name> (optionally including rpath flag) 30 - If the filename is "lib"<name>, return -l<name> 31 - If the path ends in ".so" or ".dylib" return it unchanged 32 - If the path ends in ".o" return it unchanged 33 - If the path is absolute, return it unchanged 34 - Otherwise return -l<library>''' 35 if not library: 36 return [] 37 if library.startswith('${CC_LINKER_SLFLAG}'): 38 return [library] if with_rpath else [] 39 if library.startswith('${FC_LINKER_SLFLAG}'): 40 return [library] if with_rpath else [] 41 flagName = self.language[-1]+'SharedLinkerFlag' 42 flagSubst = self.language[-1].upper()+'_LINKER_SLFLAG' 43 rpathFlag = '' 44 if hasattr(self.setCompilers, flagName) and not getattr(self.setCompilers, flagName) is None: 45 rpathFlag = getattr(self.setCompilers, flagName) 46 elif flagSubst in self.argDB: 47 rpathFlag = self.argDB[flagSubst] 48 if library.startswith('-L'): 49 dirname = library[2:] 50 if not dirname.startswith('$') and not os.path.isdir(dirname): self.logPrint('Warning! getLibArgumentList(): could not locate dir '+ dirname) 51 if dirname in self.sysDirs: 52 return [] 53 elif with_rpath and rpathFlag and not dirname in self.rpathSkipDirs: 54 return [rpathFlag+dirname,library] 55 else: 56 return [library] 57 if library.lstrip()[0] == '-': 58 return [library] 59 if len(library) > 3 and library[-4:] == '.lib': 60 return [library.replace('\\ ',' ').replace(' ', '\\ ').replace('\\(','(').replace('(', '\\(').replace('\\)',')').replace(')', '\\)')] 61 if os.path.basename(library).startswith('lib'): 62 name = self.getLibName(library) 63 if ((len(library) > 2 and library[1] == ':') or os.path.isabs(library)): 64 dirname = os.path.dirname(library).replace('\\ ',' ').replace(' ', '\\ ').replace('\\(','(').replace('(', '\\(').replace('\\)',')').replace(')', '\\)') 65 if dirname in self.sysDirs: 66 return [library] 67 if with_rpath and not dirname in self.rpathSkipDirs: 68 if hasattr(self.setCompilers, flagName) and not getattr(self.setCompilers, flagName) is None: 69 import pathlib 70 if pathlib.Path(library).suffix[1:].isnumeric(): # libfoo.so.1.0 71 return [getattr(self.setCompilers, flagName)+dirname,library] 72 else: 73 return [getattr(self.setCompilers, flagName)+dirname,'-L'+dirname,'-l'+name] 74 if flagSubst in self.argDB: 75 return [self.argDB[flagSubst]+dirname,'-L'+dirname,'-l'+name] 76 return ['-L'+dirname,'-l'+name] 77 else: 78 return ['-l'+name] 79 if os.path.splitext(library)[1] == '.so' or os.path.splitext(library)[1] == '.o' or os.path.splitext(library)[1] == '.dylib': 80 return [library] 81 if os.path.isabs(library): 82 return [library] 83 return ['-l'+library] 84 85 def getLibArgument(self, library): 86 '''Same as getLibArgumentList - except it returns a string instead of list.''' 87 return ' '.join(self.getLibArgumentList(library)) 88 89 def addRpathSkipDir(self, dirname): 90 '''Do not generate RPATH for this dir in getLibArgumentList.''' 91 if dirname not in self.rpathSkipDirs: self.rpathSkipDirs.append(dirname) 92 93 def addSysDir(self, dirname): 94 '''Add the dir to sysDirs[]''' 95 if dirname not in self.sysDirs: self.sysDirs.append(dirname) 96 97 def getLibName(library): 98 if os.path.basename(library).startswith('lib'): 99 return os.path.splitext(os.path.basename(library))[0][3:] 100 return library 101 getLibName = staticmethod(getLibName) 102 103 def getDefineName(self, library): 104 return 'HAVE_LIB'+self.getLibName(library).upper().replace('-','_').replace('=','_').replace('+','_').replace('.', '_').replace('/','_') 105 106 def getDefineNameFunc(self, funcName): 107 return 'HAVE_'+ funcName.upper() 108 109 def haveLib(self, library): 110 return self.getDefineName(library) in self.defines 111 112 def add(self, libName, funcs, libDir = None, otherLibs = [], prototype = '', call = '', fortranMangle = 0): 113 '''Checks that the library "libName" contains "funcs", and if it does defines HAVE_LIB"libName AND adds it to $LIBS" 114 - libDir may be a list of directories 115 - libName may be a list of library names''' 116 if not isinstance(libName, list): libName = [libName] 117 if self.check(libName, funcs, libDir, otherLibs, prototype, call, fortranMangle): 118 self.logPrint('Adding '+str(libName)+' to LIBS') 119 # Note: this MUST be setCompilers since it can happen before dispatch names is made 120 self.setCompilers.LIBS = self.toString(libName)+' '+self.setCompilers.LIBS 121 return 1 122 return 0 123 124 def toString(self,libs): 125 '''Converts a list of libraries to a string suitable for a linker''' 126 newlibs = [] 127 frame = 0 128 for lib in libs: 129 if frame: 130 newlibs += [lib] 131 frame = 0 132 elif lib == '-framework': 133 newlibs += [lib] 134 frame = 1 135 else: 136 newlibs += self.getLibArgumentList(lib) 137 return ' '.join(newlibs) 138 139 def toStringNoDupes(self,libs,with_rpath=True): 140 '''Converts a list of libraries to a string suitable for a linker, removes duplicates''' 141 '''Moves the flags that can be moved to the beginning of the string but always leaves the libraries and other items that must remain in the same order''' 142 newlibs = [] 143 frame = 0 144 for lib in libs: 145 if frame: 146 newlibs += [lib] 147 frame = 0 148 elif lib == '-framework': 149 newlibs += [lib] 150 frame = 1 151 else: 152 newlibs += self.getLibArgumentList(lib, with_rpath) 153 libs = newlibs 154 newldflags = [] 155 newlibs = [] 156 frame = 0 157 dupflags = ['-L'] 158 flagName = self.language[-1]+'SharedLinkerFlag' 159 if hasattr(self.setCompilers, flagName) and not getattr(self.setCompilers, flagName) is None: 160 dupflags.append(getattr(self.setCompilers, flagName)) 161 for j in libs: 162 # remove duplicate -L, -Wl,-rpath options - and only consecutive -l options 163 if j in newldflags and any([j.startswith(flg) for flg in dupflags]): continue 164 if newlibs and j == newlibs[-1]: continue 165 if list(filter(j.startswith,['-l'])) or list(filter(j.endswith,['.lib','.a','.so','.o'])) or j in ['-Wl,-Bstatic','-Wl,-Bdynamic','-Wl,--start-group','-Wl,--end-group']: 166 newlibs.append(j) 167 else: 168 newldflags.append(j) 169 liblist = ' '.join(newldflags + newlibs) 170 return liblist 171 172 def getShortLibName(self,lib): 173 '''returns the short name for the library. Valid names are foo -lfoo or libfoo.[a,so,lib]''' 174 if lib.startswith('-l'): 175 libname = lib[2:] 176 return libname 177 if lib.startswith('-'): # must be some compiler options - not a library 178 return '' 179 if lib.endswith('.a') or lib.endswith('.so') or lib.endswith('.lib'): 180 libname = os.path.splitext(os.path.basename(lib))[0] 181 if lib.startswith('lib'): libname = libname[3:] 182 return libname 183 # no match - assuming the given name is already in short notation 184 return lib 185 186 def check(self, libName, funcs, libDir = None, otherLibs = [], prototype = '', call = '', fortranMangle = 0, cxxMangle = 0, cxxLink = 0, functionDefine = 0, examineOutput=lambda ret,out,err:None): 187 '''Checks that the library "libName" contains "funcs", and if it does defines HAVE_LIB"libName" 188 - libDir may be a list of directories 189 - libName may be a list of library names''' 190 if not isinstance(funcs,list): funcs = [funcs] 191 if not isinstance(libName, list): libName = [libName] 192 def genPreamble(f, funcName): 193 # Construct prototype 194 if self.language[-1] == 'FC': 195 return '' 196 if prototype: 197 if isinstance(prototype, str): 198 pre = prototype 199 else: 200 pre = prototype[f] 201 else: 202 # We use char because int might match the return type of a gcc2 builtin and its argument prototype would still apply. 203 pre = 'char '+funcName+'(void);' 204 # Capture the function call in a static function so that any local variables are isolated from 205 # calls to other library functions. 206 return pre + '\nstatic void _check_%s(void) { %s }' % (funcName, genCall(f, funcName, pre=True)) 207 def genCall(f, funcName, pre=False): 208 if self.language[-1] != 'FC' and not pre: 209 return '_check_' + funcName + '();' 210 # Construct function call 211 if call: 212 if isinstance(call, str): 213 body = call 214 else: 215 body = call[f] 216 else: 217 body = funcName+'()' 218 if self.language[-1] != 'FC': 219 body += ';' 220 return body 221 # Handle Fortran mangling 222 if fortranMangle: 223 funcs = list(map(self.compilers.mangleFortranFunction, funcs)) 224 if not funcs: 225 self.logPrint('No functions to check for in library '+str(libName)+' '+str(otherLibs)) 226 return True 227 self.logPrint('Checking for functions ['+' '.join(funcs)+'] in library '+str(libName)+' '+str(otherLibs)) 228 if self.language[-1] == 'FC': 229 includes = '' 230 else: 231 includes = '/* Override any gcc2 internal prototype to avoid an error. */\n' 232 # Handle C++ mangling 233 if self.language[-1] == 'Cxx' and not cxxMangle: 234 includes += ''' 235#ifdef __cplusplus 236extern "C" { 237#endif 238''' 239 includes += '\n'.join([genPreamble(f, fname) for f, fname in enumerate(funcs)]) 240 # Handle C++ mangling 241 if self.language[-1] == 'Cxx' and not cxxMangle: 242 includes += ''' 243#ifdef __cplusplus 244} 245#endif 246''' 247 body = '\n'.join([genCall(f, fname) for f, fname in enumerate(funcs)]) 248 # Setup link line 249 oldLibs = self.setCompilers.LIBS 250 if libDir: 251 if not isinstance(libDir, list): libDir = [libDir] 252 for dir in libDir: 253 self.setCompilers.LIBS += ' -L'+dir 254 # new libs may/will depend on system libs so list new libs first! 255 # Matt, do not change this without talking to me 256 if libName and otherLibs: 257 self.setCompilers.LIBS = ' '+self.toString(libName+otherLibs) +' '+ self.setCompilers.LIBS 258 elif otherLibs: 259 self.setCompilers.LIBS = ' '+self.toString(otherLibs) +' '+ self.setCompilers.LIBS 260 elif libName: 261 self.setCompilers.LIBS = ' '+self.toString(libName) +' '+ self.setCompilers.LIBS 262 if cxxMangle: compileLang = 'Cxx' 263 else: compileLang = self.language[-1] 264 if cxxLink: linklang = 'Cxx' 265 else: linklang = self.language[-1] 266 self.pushLanguage(compileLang) 267 268 found = 1 269 if libName and libName[0].startswith('/'): 270 dir = os.path.dirname(libName[0]) 271 lib = os.path.basename(libName[0])[:-1] 272 self.logPrint('Checking directory of requested libraries:'+dir+' for first library:'+lib) 273 found = 0 274 try: 275 files = os.listdir(dir) 276 except: 277 self.logPrint('Directory of requested libraries '+dir+' does not exist') 278 else: 279 self.logPrint('Files in directory:'+str(files)) 280 for i in files: 281 if i.startswith(lib): 282 found = 1 283 break 284 285 if found and self.checkLink(includes, body, linkLanguage=linklang, examineOutput=examineOutput): 286 if hasattr(self.compilers, 'FC') and self.language[-1] == 'C': 287 if self.compilers.checkCrossLink(includes+'\nvoid dummy(void) {'+body+'}\n'," program main\n print*,'testing'\n stop\n end\n",language1='C',language2='FC'): 288 # define the symbol as found 289 if functionDefine: [self.addDefine(self.getDefineNameFunc(fname), 1) for f, fname in enumerate(funcs)] 290 # add to list of found libraries 291 elif libName: 292 for lib in libName: 293 shortlib = self.getShortLibName(lib) 294 if shortlib: self.addDefine(self.getDefineName(shortlib), 1) 295 else: 296 found = 0 297 else: 298 found = 0 299 self.setCompilers.LIBS = oldLibs 300 self.popLanguage() 301 return found 302 303 def checkClassify(self, libName, funcs, libDir=None, otherLibs=[], prototype='', call='', fortranMangle=0, cxxMangle=0, cxxLink=0): 304 '''Recursive decompose to rapidly classify functions as found or missing''' 305 import config 306 def functional(funcs): 307 named = config.NamedInStderr(funcs) 308 if self.check(libName, funcs, libDir, otherLibs, prototype, call, fortranMangle, cxxMangle, cxxLink, examineOutput = named.examineStderr): 309 return True 310 else: 311 return named.named 312 found, missing = config.classify(funcs, functional) 313 return found, missing 314 315 def checkMath(self): 316 '''Check for sin() in libm, the math library''' 317 self.math = None 318 funcs = ['sin', 'floor', 'log10', 'pow'] 319 prototypes = ['#include <stdio.h>\ndouble sin(double);', 320 '#include <stdio.h>\ndouble floor(double);', 321 '#include <stdio.h>\ndouble log10(double);', 322 '#include <stdio.h>\ndouble pow(double, double);'] 323 calls = ['double x,y; int s = scanf("%lf",&x); y = sin(x); printf("%f %d",y,s)', 324 'double x,y; int s = scanf("%lf",&x); y = floor(x); printf("%f %d",y,s)', 325 'double x,y; int s = scanf("%lf",&x); y = log10(x); printf("%f %d",y,s)', 326 'double x,y; int s = scanf("%lf",&x); y = pow(x,x); printf("%f %d",y,s)'] 327 if self.check('', funcs, prototype = prototypes, call = calls): 328 self.math = [] 329 elif self.check('m', funcs, prototype = prototypes, call = calls): 330 self.math = ['libm.a'] 331 if self.math == None: 332 raise RuntimeError('Cannot find basic math functions') 333 self.logPrint('CheckMath: using math library '+str(self.math)) 334 return 335 336 def checkMathErf(self): 337 '''Check for erf() in libm, the math library''' 338 if not self.math is None and self.check(self.math, ['erf'], prototype = ['#include <math.h>'], call = ['double (*checkErf)(double) = erf;double x = 0,y; y = (*checkErf)(x); (void)y']): 339 self.logPrint('erf() found') 340 self.addDefine('HAVE_ERF', 1) 341 else: 342 self.logPrint('erf() not found') 343 return 344 345 def checkMathTgamma(self): 346 '''Check for tgamma() in libm, the math library''' 347 if not self.math is None and self.check(self.math, ['tgamma'], prototype = ['#include <math.h>'], call = ['double (*checkTgamma)(double) = tgamma;double x = 0,y; y = (*checkTgamma)(x); (void)y']): 348 self.logPrint('tgamma() found') 349 self.addDefine('HAVE_TGAMMA', 1) 350 else: 351 self.logPrint('tgamma() not found') 352 return 353 354 def checkMathLgamma(self): 355 '''Check for lgamma() in libm, the math library''' 356 if not self.math is None and self.check(self.math, ['lgamma'], prototype = ['#include <math.h>\n#include <stdlib.h>'], call = ['double (*checkLgamma)(double) = lgamma;double x = 1,y; y = (*checkLgamma)(x);if (y != 0.) abort()']): 357 self.logPrint('lgamma() found') 358 self.addDefine('HAVE_LGAMMA', 1) 359 elif not self.math is None and self.check(self.math, ['gamma'], prototype = ['#include <math.h>\n#include <stdlib.h>'], call = ['double (*checkLgamma)(double) = gamma;double x = 1,y; y = (*checkLgamma)(x);if (y != 0.) abort()']): 360 self.logPrint('gamma() found') 361 self.addDefine('HAVE_LGAMMA', 1) 362 self.addDefine('HAVE_LGAMMA_IS_GAMMA', 1) 363 else: 364 self.logPrint('lgamma() and gamma() not found') 365 return 366 367 def checkMathFenv(self): 368 '''Checks if <fenv.h> can be used with FE_DFL_ENV''' 369 if not self.math is None and self.check(self.math, ['fesetenv'], prototype = ['#include <fenv.h>'], call = ['fesetenv(FE_DFL_ENV)']): 370 self.addDefine('HAVE_FENV_H', 1) 371 else: 372 self.logPrint('<fenv.h> with FE_DFL_ENV not found') 373 if not self.math is None and self.check(self.math, ['feclearexcept'], prototype = ['#include <fenv.h>'], call = ['feclearexcept(FE_INEXACT)']): 374 self.addDefine('HAVE_FE_VALUES', 1) 375 else: 376 self.logPrint('<fenv.h> with FE_INEXACT not found') 377 return 378 379 def checkMathLog2(self): 380 '''Check for log2() in libm, the math library''' 381 if not self.math is None and self.check(self.math, ['log2'], prototype = ['#include <math.h>'], call = ['double (*checkLog2)(double) = log2; double x = 2.5, y = (*checkLog2)(x); (void)y']): 382 self.logPrint('log2() found') 383 self.addDefine('HAVE_LOG2', 1) 384 else: 385 self.logPrint('log2() not found') 386 return 387 388 def checkRealtime(self): 389 '''Check for presence of clock_gettime() in realtime library (POSIX Realtime extensions)''' 390 self.rt = None 391 funcs = ['clock_gettime'] 392 prototypes = ['#include <time.h>'] 393 calls = ['struct timespec tp; clock_gettime(CLOCK_REALTIME,&tp)'] 394 if self.check('', funcs, prototype=prototypes, call=calls): 395 self.logPrint('realtime functions are linked in by default') 396 self.rt = [] 397 elif self.check('rt', funcs, prototype=prototypes, call=calls): 398 self.logPrint('Using librt for the realtime library') 399 self.rt = ['librt.a'] 400 else: 401 self.logPrint('No realtime library found') 402 return 403 404 def checkDynamic(self): 405 '''Check for the header and libraries necessary for dynamic library manipulation''' 406 if 'with-dynamic-loading' in self.argDB and not self.argDB['with-dynamic-loading']: return 407 self.check(['dl'], 'dlopen') 408 self.headers.check('dlfcn.h') 409 return 410 411 def checkShared(self, includes, initFunction, checkFunction, finiFunction = None, checkLink = None, libraries = [], initArgs = '&argc, &argv', boolType = 'int', noCheckArg = 0, defaultArg = '', executor = None, timeout = 60): 412 '''Determine whether a library is shared 413 - initFunction(int *argc, char *argv[]) is called to initialize some static data 414 - checkFunction(int *check) is called to verify that the static data wer set properly 415 - finiFunction() is called to finalize the data, and may be omitted 416 - checkLink may be given as ana alternative to the one in base.Configure''' 417 isShared = 0 418 if checkLink is None: 419 checkLink = self.checkLink 420 configObj = self 421 else: 422 if hasattr(checkLink, '__self__'): 423 configObj = checkLink.__self__ 424 else: 425 configObj = self 426 427 # Fix these flags 428 oldFlags = self.setCompilers.LIBS 429 self.setCompilers.LIBS = ' '+self.toString(libraries)+' '+self.setCompilers.LIBS 430 431 # Make a library which calls initFunction(), and returns checkFunction() 432 lib1Name = os.path.join(self.tmpDir, 'lib1.'+self.setCompilers.sharedLibraryExt) 433 if noCheckArg: 434 checkCode = 'isInitialized = '+checkFunction+'();' 435 else: 436 checkCode = checkFunction+'(&isInitialized);' 437 codeBegin = ''' 438#ifdef __cplusplus 439extern "C" 440#endif 441int init(int argc, char *argv[]) { 442''' 443 body = ''' 444 %s isInitialized; 445 446 %s(%s); 447 %s 448 return (int) isInitialized; 449''' % (boolType, initFunction, initArgs, checkCode) 450 codeEnd = '\n}\n' 451 if not checkLink(includes, body, cleanup = 0, codeBegin = codeBegin, codeEnd = codeEnd, shared = 1): 452 if os.path.isfile(configObj.compilerObj): os.remove(configObj.compilerObj) 453 self.setCompilers.LIBS = oldFlags 454 raise RuntimeError('Could not complete shared library check') 455 if os.path.isfile(configObj.compilerObj): os.remove(configObj.compilerObj) 456 os.rename(configObj.linkerObj, lib1Name) 457 458 # Make a library which calls checkFunction() 459 lib2Name = os.path.join(self.tmpDir, 'lib2.'+self.setCompilers.sharedLibraryExt) 460 codeBegin = ''' 461#ifdef __cplusplus 462extern "C" 463#endif 464int checkInit(void) { 465''' 466 body = ''' 467 %s isInitialized; 468 469 %s 470''' % (boolType, checkCode) 471 if finiFunction: 472 body += ' if (isInitialized) '+finiFunction+'();\n' 473 body += ' return (int) isInitialized;\n' 474 codeEnd = '\n}\n' 475 if not checkLink(includes, body, cleanup = 0, codeBegin = codeBegin, codeEnd = codeEnd, shared = 1): 476 if os.path.isfile(configObj.compilerObj): os.remove(configObj.compilerObj) 477 self.setCompilers.LIBS = oldFlags 478 raise RuntimeError('Could not complete shared library check') 479 return 0 480 if os.path.isfile(configObj.compilerObj): os.remove(configObj.compilerObj) 481 os.rename(configObj.linkerObj, lib2Name) 482 483 self.setCompilers.LIBS = oldFlags 484 485 # Make an executable that dynamically loads and calls both libraries 486 # If the check returns true in the second library, the static data was shared 487 guard = self.headers.getDefineName('dlfcn.h') 488 if self.headers.headerPrefix: 489 guard = self.headers.headerPrefix+'_'+guard 490 defaultIncludes = ''' 491#include <stdio.h> 492#include <stdlib.h> 493#ifdef %s 494#include <dlfcn.h> 495#endif 496 ''' % guard 497 body = ''' 498 int argc = 1; 499 char *argv[2] = {(char *) "conftest", NULL}; 500 void *lib; 501 int (*init)(int, char **); 502 int (*checkInit)(void); 503 504 lib = dlopen("'''+lib1Name+'''", RTLD_LAZY); 505 if (!lib) { 506 fprintf(stderr, "Could not open lib1.so: %s\\n", dlerror()); 507 exit(1); 508 } 509 init = (int (*)(int, char **)) dlsym(lib, "init"); 510 if (!init) { 511 fprintf(stderr, "Could not find initialization function\\n"); 512 exit(1); 513 } 514 if (!(*init)(argc, argv)) { 515 fprintf(stderr, "Could not initialize library\\n"); 516 exit(1); 517 } 518 lib = dlopen("'''+lib2Name+'''", RTLD_LAZY); 519 if (!lib) { 520 fprintf(stderr, "Could not open lib2.so: %s\\n", dlerror()); 521 exit(1); 522 } 523 checkInit = (int (*)(void)) dlsym(lib, "checkInit"); 524 if (!checkInit) { 525 fprintf(stderr, "Could not find initialization check function\\n"); 526 exit(1); 527 } 528 if (!(*checkInit)()) { 529 fprintf(stderr, "Did not link with shared library\\n"); 530 exit(2); 531 } 532 ''' 533 oldLibs = self.setCompilers.LIBS 534 if self.haveLib('dl'): 535 self.setCompilers.LIBS += ' -ldl' 536 isShared = 0 537 try: 538 isShared = self.checkRun(defaultIncludes, body, defaultArg = defaultArg, executor = executor, timeout = timeout) 539 except RuntimeError as e: 540 if executor and str(e).find('Runaway process exceeded time limit') > -1: 541 raise RuntimeError('Timeout: Unable to run MPI program with '+executor+'\n\ 542 (1) make sure this is the correct program to run MPI jobs\n\ 543 (2) your network may be misconfigured; see https://petsc.org/release/faq/#mpi-network-misconfigure\n\ 544 (3) you may have VPN running whose network settings may not play nice with MPI\n') 545 546 self.setCompilers.LIBS = oldLibs 547 if os.path.isfile(lib1Name) and self.framework.doCleanup: os.remove(lib1Name) 548 if os.path.isfile(lib2Name) and self.framework.doCleanup: os.remove(lib2Name) 549 if isShared: 550 self.logPrint('Library was shared') 551 else: 552 self.logPrint('Library was not shared') 553 return isShared 554 555 def checkExportedSymbols(self, flags, checkLink = None, libraries = [], defaultArg = '', executor = None, timeout = 60): 556 '''Determine whether an executable exports shared symbols 557 - checkLink may be given as an alternative to the one in base.Configure''' 558 exports = False 559 560 if 'USE_VISIBILITY_C' in self.types.defines: 561 visibility = '__attribute__((visibility ("default")))' 562 else: 563 visibility = '' 564 565 # Make an executable that dynamically loads a symbol it contains 566 guard = self.headers.getDefineName('dlfcn.h') 567 if self.headers.headerPrefix: 568 guard = self.headers.headerPrefix+'_'+guard 569 defaultIncludes = ''' 570#include <stdio.h> 571#include <stdlib.h> 572#ifdef %s 573#include <dlfcn.h> 574#endif 575 576#define PETSC_DLLEXPORT %s 577 578extern PETSC_DLLEXPORT int foo(void) { 579 return 42; 580} 581 ''' % (guard, visibility) 582 body = ''' 583 void *lib; 584 int (*foo)(void); 585 586 lib = dlopen(NULL, RTLD_LAZY); 587 if (!lib) { 588 fprintf(stderr, "Could not open executable: %s\\n", dlerror()); 589 exit(1); 590 } 591 foo = (int (*)(void)) dlsym(lib, "foo"); 592 if (!foo) { 593 fprintf(stderr, "Could not find function in executable\\n"); 594 exit(1); 595 } 596 if ((*foo)() != 42) { 597 fprintf(stderr, "Could not run function\\n"); 598 exit(1); 599 } 600 ''' 601 oldFlags = self.setCompilers.CFLAGS 602 oldLibs = self.setCompilers.LIBS 603 self.setCompilers.CFLAGS += ' '+flags 604 if self.haveLib('dl'): 605 self.setCompilers.LIBS += ' -ldl' 606 try: 607 exports = self.checkRun(defaultIncludes, body, defaultArg = defaultArg, executor = executor, timeout = timeout) 608 except RuntimeError as e: 609 self.logPrint('FAIL: '+str(e)) 610 self.setCompilers.CFLAGS = oldFlags 611 self.setCompilers.LIBS = oldLibs 612 if exports: 613 self.logPrint('Executable exports symbols for dlopen()') 614 else: 615 self.logPrint('Executable does not export symbols for dlopen()') 616 return exports 617 618 def checkPthreadMutex(self): 619 '''Check for pthread mutex support''' 620 # Per Pim Heeman from petsc-maint, OpenBSD does not support PTHREAD_PROCESS_SHARED, which is used by pcmpi.c 621 funcs = ['pthread_mutex_unlock', 'pthread_mutexattr_setpshared'] 622 prototypes = ['#include <pthread.h>', '#include <pthread.h>'] 623 calls = ['pthread_mutex_t m; pthread_mutex_unlock(&m)', 'pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)'] 624 self.pthreadmutex = [] 625 if self.check('', funcs, prototype=prototypes, call=calls): 626 self.logPrint('pthread mutex are linked in by default') 627 self.pthreadmutex = [] 628 self.addDefine('HAVE_PTHREAD_MUTEX',1) 629 elif self.check('pthread', funcs, prototype=prototypes, call=calls): 630 self.logPrint('Using libpthread for the mutex') 631 self.pthreadmutex = ['libpthread.a'] 632 self.addDefine('HAVE_PTHREAD_MUTEX',1) 633 else: 634 self.logPrint('No pthread mutex support found') 635 return 636 637 def checkExecutableExportFlag(self): 638 '''Checks for the flag that allows executables to export symbols to dlsym()''' 639 # Right now, we just check some compilers, but we should make a test trying to load a symbol from the executable 640 # Discussion: https://stackoverflow.com/questions/6292473/how-to-call-function-in-executable-from-my-library/6298434#6298434 641 for flag in ['', '-Wl,-export_dynamic', '-Wl,-export-dynamic', '-export-dynamic']: 642 if self.checkExportedSymbols(flag): 643 self.addDefine('HAVE_EXECUTABLE_EXPORT', 1) 644 self.addMakeMacro('EXEFLAGS', flag) 645 break 646 return 647 648 def configure(self): 649 list(map(lambda args: self.executeTest(self.check, list(args)), self.libraries)) 650 self.executeTest(self.checkMath) 651 self.executeTest(self.checkMathErf) 652 self.executeTest(self.checkMathTgamma) 653 self.executeTest(self.checkMathLgamma) 654 self.executeTest(self.checkMathFenv) 655 self.executeTest(self.checkMathLog2) 656 self.executeTest(self.checkRealtime) 657 self.executeTest(self.checkDynamic) 658 self.executeTest(self.checkPthreadMutex) 659 if not self.argDB['with-batch']: 660 self.executeTest(self.checkExecutableExportFlag) 661 return 662