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