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