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