1 /* 2 Routines for opening dynamic link libraries (DLLs), keeping a searchable 3 path of DLLs, obtaining remote DLLs via a URL and opening them locally. 4 */ 5 6 #include <petsc/private/petscimpl.h> 7 8 /* ------------------------------------------------------------------------------*/ 9 /* 10 Code to maintain a list of opened dynamic libraries and load symbols 11 */ 12 struct _n_PetscDLLibrary { 13 PetscDLLibrary next; 14 PetscDLHandle handle; 15 char libname[PETSC_MAX_PATH_LEN]; 16 }; 17 18 PetscErrorCode PetscDLLibraryPrintPath(PetscDLLibrary libs) 19 { 20 PetscFunctionBegin; 21 while (libs) { 22 PetscErrorPrintf(" %s\n",libs->libname); 23 libs = libs->next; 24 } 25 PetscFunctionReturn(0); 26 } 27 28 /*@C 29 PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location 30 (if it is remote), indicates if it exits and its local name. 31 32 Collective 33 34 Input Parameters: 35 + comm - processors that are opening the library 36 - libname - name of the library, can be relative or absolute 37 38 Output Parameters: 39 + name - actual name of file on local filesystem if found 40 . llen - length of the name buffer 41 - found - true if the file exists 42 43 Level: developer 44 45 Notes: 46 [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0] 47 48 ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable} 49 occurring in directoryname and filename will be replaced with appropriate values. 50 @*/ 51 PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,size_t llen,PetscBool *found) 52 { 53 char *buf,*par2,suffix[16],*gz,*so; 54 size_t len; 55 PetscErrorCode ierr; 56 57 PetscFunctionBegin; 58 /* 59 make copy of library name and replace $PETSC_ARCH etc 60 so we can add to the end of it to look for something like .so.1.0 etc. 61 */ 62 ierr = PetscStrlen(libname,&len);CHKERRQ(ierr); 63 len = PetscMax(4*len,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 64 ierr = PetscMalloc1(len,&buf);CHKERRQ(ierr); 65 par2 = buf; 66 ierr = PetscStrreplace(comm,libname,par2,len);CHKERRQ(ierr); 67 68 /* temporarily remove .gz if it ends library name */ 69 ierr = PetscStrrstr(par2,".gz",&gz);CHKERRQ(ierr); 70 if (gz) { 71 ierr = PetscStrlen(gz,&len);CHKERRQ(ierr); 72 if (len != 3) gz = NULL; /* do not end (exactly) with .gz */ 73 else *gz = 0; /* ends with .gz, so remove it */ 74 } 75 /* strip out .a from it if user put it in by mistake */ 76 ierr = PetscStrlen(par2,&len);CHKERRQ(ierr); 77 if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0; 78 79 ierr = PetscFileRetrieve(comm,par2,lname,llen,found);CHKERRQ(ierr); 80 if (!(*found)) { 81 /* see if library name does already not have suffix attached */ 82 ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr); 83 ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr); 84 ierr = PetscStrrstr(par2,suffix,&so);CHKERRQ(ierr); 85 /* and attach the suffix if it is not there */ 86 if (!so) { ierr = PetscStrcat(par2,suffix);CHKERRQ(ierr); } 87 88 /* restore the .gz suffix if it was there */ 89 if (gz) { ierr = PetscStrcat(par2,".gz");CHKERRQ(ierr); } 90 91 /* and finally retrieve the file */ 92 ierr = PetscFileRetrieve(comm,par2,lname,llen,found);CHKERRQ(ierr); 93 } 94 95 ierr = PetscFree(buf);CHKERRQ(ierr); 96 PetscFunctionReturn(0); 97 } 98 99 /*@C 100 PetscDLLibraryOpen - Opens a PETSc dynamic link library 101 102 Collective 103 104 Input Parameters: 105 + comm - processors that are opening the library 106 - path - name of the library, can be relative or absolute 107 108 Output Parameter: 109 . entry - a PETSc dynamic link library entry 110 111 Level: developer 112 113 Notes: 114 [[<http,ftp>://hostname]/directoryname/]libbasename[.so.1.0] 115 116 If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run 117 when the library is opened. 118 119 ${PETSC_ARCH} occurring in directoryname and filename 120 will be replaced with the appropriate value. 121 122 .seealso: PetscLoadDynamicLibrary(), PetscDLLibraryAppend() 123 @*/ 124 PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm,const char path[],PetscDLLibrary *entry) 125 { 126 PetscErrorCode ierr; 127 PetscBool foundlibrary,match; 128 char libname[PETSC_MAX_PATH_LEN],par2[PETSC_MAX_PATH_LEN],suffix[16],*s; 129 char *basename,registername[128]; 130 PetscDLHandle handle; 131 PetscErrorCode (*func)(void) = NULL; 132 133 PetscFunctionBegin; 134 PetscValidCharPointer(path,2); 135 PetscValidPointer(entry,3); 136 137 *entry = NULL; 138 139 /* retrieve the library */ 140 ierr = PetscInfo1(NULL,"Retrieving %s\n",path);CHKERRQ(ierr); 141 ierr = PetscDLLibraryRetrieve(comm,path,par2,PETSC_MAX_PATH_LEN,&foundlibrary);CHKERRQ(ierr); 142 if (!foundlibrary) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n %s\n",path); 143 /* Eventually ./configure should determine if the system needs an executable dynamic library */ 144 #define PETSC_USE_NONEXECUTABLE_SO 145 #if !defined(PETSC_USE_NONEXECUTABLE_SO) 146 ierr = PetscTestFile(par2,'x',&foundlibrary);CHKERRQ(ierr); 147 if (!foundlibrary) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n %s\n %s\n",path,par2); 148 #endif 149 150 /* copy path and setup shared library suffix */ 151 ierr = PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 152 ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr); 153 ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr); 154 /* remove wrong suffixes from libname */ 155 ierr = PetscStrrstr(libname,".gz",&s);CHKERRQ(ierr); 156 if (s && s[3] == 0) s[0] = 0; 157 ierr = PetscStrrstr(libname,".a",&s);CHKERRQ(ierr); 158 if (s && s[2] == 0) s[0] = 0; 159 /* remove shared suffix from libname */ 160 ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr); 161 if (s) s[0] = 0; 162 163 /* open the dynamic library */ 164 ierr = PetscInfo1(NULL,"Opening dynamic library %s\n",libname);CHKERRQ(ierr); 165 ierr = PetscDLOpen(par2,PETSC_DL_DECIDE,&handle);CHKERRQ(ierr); 166 167 /* look for [path/]libXXXXX.YYY and extract out the XXXXXX */ 168 ierr = PetscStrrchr(libname,'/',&basename);CHKERRQ(ierr); /* XXX Windows ??? */ 169 if (!basename) basename = libname; 170 ierr = PetscStrncmp(basename,"lib",3,&match);CHKERRQ(ierr); 171 if (match) basename = basename + 3; 172 else { 173 ierr = PetscInfo1(NULL,"Dynamic library %s does not have lib prefix\n",libname);CHKERRQ(ierr); 174 } 175 for (s=basename; *s; s++) if (*s == '-') *s = '_'; 176 ierr = PetscStrncpy(registername,"PetscDLLibraryRegister_",sizeof(registername));CHKERRQ(ierr); 177 ierr = PetscStrlcat(registername,basename,sizeof(registername));CHKERRQ(ierr); 178 ierr = PetscDLSym(handle,registername,(void**)&func);CHKERRQ(ierr); 179 if (func) { 180 ierr = PetscInfo1(NULL,"Loading registered routines from %s\n",libname);CHKERRQ(ierr); 181 ierr = (*func)();CHKERRQ(ierr); 182 } else { 183 ierr = PetscInfo2(NULL,"Dynamic library %s does not have symbol %s\n",libname,registername);CHKERRQ(ierr); 184 } 185 186 ierr = PetscNew(entry);CHKERRQ(ierr); 187 (*entry)->next = NULL; 188 (*entry)->handle = handle; 189 ierr = PetscStrcpy((*entry)->libname,libname);CHKERRQ(ierr); 190 PetscFunctionReturn(0); 191 } 192 193 /*@C 194 PetscDLLibrarySym - Load a symbol from the dynamic link libraries. 195 196 Collective 197 198 Input Parameters: 199 + comm - communicator that will open the library 200 . outlist - list of already open libraries that may contain symbol (can be NULL and only the executable is searched for the function) 201 . path - optional complete library name (if provided checks here before checking outlist) 202 - insymbol - name of symbol 203 204 Output Parameter: 205 . value - if symbol not found then this value is set to NULL 206 207 Level: developer 208 209 Notes: 210 Symbol can be of the form 211 [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional 212 213 Will attempt to (retrieve and) open the library if it is not yet been opened. 214 215 @*/ 216 PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *outlist,const char path[],const char insymbol[],void **value) 217 { 218 char libname[PETSC_MAX_PATH_LEN],suffix[16],*symbol,*s; 219 PetscDLLibrary nlist,prev,list = NULL; 220 PetscErrorCode ierr; 221 222 PetscFunctionBegin; 223 if (outlist) PetscValidPointer(outlist,2); 224 if (path) PetscValidCharPointer(path,3); 225 PetscValidCharPointer(insymbol,4); 226 PetscValidPointer(value,5); 227 228 if (outlist) list = *outlist; 229 *value = NULL; 230 231 ierr = PetscStrchr(insymbol,'(',&s);CHKERRQ(ierr); 232 if (s) { 233 /* make copy of symbol so we can edit it in place */ 234 ierr = PetscStrallocpy(insymbol,&symbol);CHKERRQ(ierr); 235 /* If symbol contains () then replace with a NULL, to support functionname() */ 236 ierr = PetscStrchr(symbol,'(',&s);CHKERRQ(ierr); 237 s[0] = 0; 238 } else symbol = (char*)insymbol; 239 240 /* 241 Function name does include library 242 ------------------------------------- 243 */ 244 if (path && path[0] != '\0') { 245 /* copy path and remove suffix from libname */ 246 ierr = PetscStrncpy(libname,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 247 ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr); 248 ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr); 249 ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr); 250 if (s) s[0] = 0; 251 /* Look if library is already opened and in path */ 252 prev = NULL; 253 nlist = list; 254 while (nlist) { 255 PetscBool match; 256 ierr = PetscStrcmp(nlist->libname,libname,&match);CHKERRQ(ierr); 257 if (match) goto done; 258 prev = nlist; 259 nlist = nlist->next; 260 } 261 /* open the library and append it to path */ 262 ierr = PetscDLLibraryOpen(comm,path,&nlist);CHKERRQ(ierr); 263 ierr = PetscInfo1(NULL,"Appending %s to dynamic library search path\n",path);CHKERRQ(ierr); 264 if (prev) prev->next = nlist; 265 else {if (outlist) *outlist = nlist;} 266 267 done:; 268 ierr = PetscDLSym(nlist->handle,symbol,value);CHKERRQ(ierr); 269 if (*value) { 270 ierr = PetscInfo2(NULL,"Loading function %s from dynamic library %s\n",insymbol,path);CHKERRQ(ierr); 271 } 272 273 /* 274 Function name does not include library so search path 275 ----------------------------------------------------- 276 */ 277 } else { 278 while (list) { 279 ierr = PetscDLSym(list->handle,symbol,value);CHKERRQ(ierr); 280 if (*value) { 281 ierr = PetscInfo2(NULL,"Loading symbol %s from dynamic library %s\n",symbol,list->libname);CHKERRQ(ierr); 282 break; 283 } 284 list = list->next; 285 } 286 if (!*value) { 287 ierr = PetscDLSym(NULL,symbol,value);CHKERRQ(ierr); 288 if (*value) { 289 ierr = PetscInfo1(NULL,"Loading symbol %s from object code\n",symbol);CHKERRQ(ierr); 290 } 291 } 292 } 293 294 if (symbol != insymbol) { 295 ierr = PetscFree(symbol);CHKERRQ(ierr); 296 } 297 PetscFunctionReturn(0); 298 } 299 300 /*@C 301 PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end 302 of the search path. 303 304 Collective 305 306 Input Parameters: 307 + comm - MPI communicator 308 - path - name of the library 309 310 Output Parameter: 311 . outlist - list of libraries 312 313 Level: developer 314 315 Notes: 316 if library is already in path will not add it. 317 318 If the library has the symbol PetscDLLibraryRegister_basename() in it then that function is automatically run 319 when the library is opened. 320 321 .seealso: PetscDLLibraryOpen() 322 @*/ 323 PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[]) 324 { 325 PetscDLLibrary list,prev; 326 PetscErrorCode ierr; 327 size_t len; 328 PetscBool match,dir; 329 char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN]; 330 char *libname,suffix[16],*s; 331 PetscToken token; 332 333 PetscFunctionBegin; 334 PetscValidPointer(outlist,2); 335 336 /* is path a directory? */ 337 ierr = PetscTestDirectory(path,'r',&dir);CHKERRQ(ierr); 338 if (dir) { 339 ierr = PetscInfo1(NULL,"Checking directory %s for dynamic libraries\n",path);CHKERRQ(ierr); 340 ierr = PetscStrncpy(program,path,sizeof(program));CHKERRQ(ierr); 341 ierr = PetscStrlen(program,&len);CHKERRQ(ierr); 342 if (program[len-1] == '/') { 343 ierr = PetscStrlcat(program,"*.",sizeof(program));CHKERRQ(ierr); 344 } else { 345 ierr = PetscStrlcat(program,"/*.",sizeof(program));CHKERRQ(ierr); 346 } 347 ierr = PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));CHKERRQ(ierr); 348 349 ierr = PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr); 350 if (!dir) PetscFunctionReturn(0); 351 } else { 352 ierr = PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 353 } 354 ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr); 355 ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr); 356 357 ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr); 358 ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr); 359 while (libname) { 360 /* remove suffix from libname */ 361 ierr = PetscStrrstr(libname,suffix,&s);CHKERRQ(ierr); 362 if (s) s[0] = 0; 363 /* see if library was already open then we are done */ 364 list = prev = *outlist; 365 match = PETSC_FALSE; 366 while (list) { 367 ierr = PetscStrcmp(list->libname,libname,&match);CHKERRQ(ierr); 368 if (match) break; 369 prev = list; 370 list = list->next; 371 } 372 /* restore suffix from libname */ 373 if (s) s[0] = '.'; 374 if (!match) { 375 /* open the library and add to end of list */ 376 ierr = PetscDLLibraryOpen(comm,libname,&list);CHKERRQ(ierr); 377 ierr = PetscInfo1(NULL,"Appending %s to dynamic library search path\n",libname);CHKERRQ(ierr); 378 if (!*outlist) *outlist = list; 379 else prev->next = list; 380 } 381 ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr); 382 } 383 ierr = PetscTokenDestroy(&token);CHKERRQ(ierr); 384 PetscFunctionReturn(0); 385 } 386 387 /*@C 388 PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of 389 the search path. 390 391 Collective 392 393 Input Parameters: 394 + comm - MPI communicator 395 - path - name of the library 396 397 Output Parameter: 398 . outlist - list of libraries 399 400 Level: developer 401 402 Notes: 403 If library is already in path will remove old reference. 404 405 @*/ 406 PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char path[]) 407 { 408 PetscDLLibrary list,prev; 409 PetscErrorCode ierr; 410 size_t len; 411 PetscBool match,dir; 412 char program[PETSC_MAX_PATH_LEN],found[8*PETSC_MAX_PATH_LEN]; 413 char *libname,suffix[16],*s; 414 PetscToken token; 415 416 PetscFunctionBegin; 417 PetscValidPointer(outlist,2); 418 419 /* is path a directory? */ 420 ierr = PetscTestDirectory(path,'r',&dir);CHKERRQ(ierr); 421 if (dir) { 422 ierr = PetscInfo1(NULL,"Checking directory %s for dynamic libraries\n",path);CHKERRQ(ierr); 423 ierr = PetscStrncpy(program,path,sizeof(program));CHKERRQ(ierr); 424 ierr = PetscStrlen(program,&len);CHKERRQ(ierr); 425 if (program[len-1] == '/') { 426 ierr = PetscStrlcat(program,"*.",sizeof(program));CHKERRQ(ierr); 427 } else { 428 ierr = PetscStrlcat(program,"/*.",sizeof(program));CHKERRQ(ierr); 429 } 430 ierr = PetscStrlcat(program,PETSC_SLSUFFIX,sizeof(program));CHKERRQ(ierr); 431 432 ierr = PetscLs(comm,program,found,8*PETSC_MAX_PATH_LEN,&dir);CHKERRQ(ierr); 433 if (!dir) PetscFunctionReturn(0); 434 } else { 435 ierr = PetscStrncpy(found,path,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 436 } 437 438 ierr = PetscStrncpy(suffix,".",sizeof(suffix));CHKERRQ(ierr); 439 ierr = PetscStrlcat(suffix,PETSC_SLSUFFIX,sizeof(suffix));CHKERRQ(ierr); 440 441 ierr = PetscTokenCreate(found,'\n',&token);CHKERRQ(ierr); 442 ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr); 443 while (libname) { 444 /* remove suffix from libname */ 445 ierr = PetscStrstr(libname,suffix,&s);CHKERRQ(ierr); 446 if (s) s[0] = 0; 447 /* see if library was already open and move it to the front */ 448 prev = NULL; 449 list = *outlist; 450 match = PETSC_FALSE; 451 while (list) { 452 ierr = PetscStrcmp(list->libname,libname,&match);CHKERRQ(ierr); 453 if (match) { 454 ierr = PetscInfo1(NULL,"Moving %s to begin of dynamic library search path\n",libname);CHKERRQ(ierr); 455 if (prev) prev->next = list->next; 456 if (prev) list->next = *outlist; 457 *outlist = list; 458 break; 459 } 460 prev = list; 461 list = list->next; 462 } 463 /* restore suffix from libname */ 464 if (s) s[0] = '.'; 465 if (!match) { 466 /* open the library and add to front of list */ 467 ierr = PetscDLLibraryOpen(comm,libname,&list);CHKERRQ(ierr); 468 ierr = PetscInfo1(NULL,"Prepending %s to dynamic library search path\n",libname);CHKERRQ(ierr); 469 list->next = *outlist; 470 *outlist = list; 471 } 472 ierr = PetscTokenFind(token,&libname);CHKERRQ(ierr); 473 } 474 ierr = PetscTokenDestroy(&token);CHKERRQ(ierr); 475 PetscFunctionReturn(0); 476 } 477 478 /*@C 479 PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries. 480 481 Collective on PetscDLLibrary 482 483 Input Parameter: 484 . head - library list 485 486 Level: developer 487 488 @*/ 489 PetscErrorCode PetscDLLibraryClose(PetscDLLibrary list) 490 { 491 PetscBool done = PETSC_FALSE; 492 PetscDLLibrary prev,tail; 493 PetscErrorCode ierr; 494 495 PetscFunctionBegin; 496 if (!list) PetscFunctionReturn(0); 497 /* traverse the list in reverse order */ 498 while (!done) { 499 if (!list->next) done = PETSC_TRUE; 500 prev = tail = list; 501 while (tail->next) { 502 prev = tail; 503 tail = tail->next; 504 } 505 prev->next = NULL; 506 /* close the dynamic library and free the space in entry data-structure*/ 507 ierr = PetscInfo1(NULL,"Closing dynamic library %s\n",tail->libname);CHKERRQ(ierr); 508 ierr = PetscDLClose(&tail->handle);CHKERRQ(ierr); 509 ierr = PetscFree(tail);CHKERRQ(ierr); 510 } 511 PetscFunctionReturn(0); 512 } 513 514