xref: /petsc/src/sys/dll/reg.c (revision bcd3bd92eda2d5998e2f14c4bbfb33bd936bdc3e)
1 
2 /*
3     Provides a general mechanism to allow one to register new routines in
4     dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
5 */
6 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/
7 #include <petscviewer.h>
8 
9 #include <petsc/private/hashmap.h>
10 /*
11     This is the default list used by PETSc with the PetscDLLibrary register routines
12 */
13 PetscDLLibrary PetscDLLibrariesLoaded = NULL;
14 
15 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
16 
17 static PetscErrorCode PetscLoadDynamicLibrary(const char *name, PetscBool *found)
18 {
19   char libs[PETSC_MAX_PATH_LEN], dlib[PETSC_MAX_PATH_LEN];
20 
21   PetscFunctionBegin;
22   PetscCall(PetscStrncpy(libs, "${PETSC_LIB_DIR}/libpetsc", sizeof(libs)));
23   PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
24   PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
25   if (*found) {
26     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
27   } else {
28     PetscCall(PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs)));
29     PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
30     PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
31     if (*found) PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
32   }
33   PetscFunctionReturn(PETSC_SUCCESS);
34 }
35 #endif
36 
37 #if defined(PETSC_USE_SINGLE_LIBRARY) && !(defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES))
38 PETSC_EXTERN PetscErrorCode AOInitializePackage(void);
39 PETSC_EXTERN PetscErrorCode PetscSFInitializePackage(void);
40   #if !defined(PETSC_USE_COMPLEX)
41 PETSC_EXTERN PetscErrorCode CharacteristicInitializePackage(void);
42   #endif
43 PETSC_EXTERN PetscErrorCode ISInitializePackage(void);
44 PETSC_EXTERN PetscErrorCode VecInitializePackage(void);
45 PETSC_EXTERN PetscErrorCode MatInitializePackage(void);
46 PETSC_EXTERN PetscErrorCode DMInitializePackage(void);
47 PETSC_EXTERN PetscErrorCode PCInitializePackage(void);
48 PETSC_EXTERN PetscErrorCode KSPInitializePackage(void);
49 PETSC_EXTERN PetscErrorCode SNESInitializePackage(void);
50 PETSC_EXTERN PetscErrorCode TSInitializePackage(void);
51 PETSC_EXTERN PetscErrorCode TaoInitializePackage(void);
52 #endif
53 
54 /*
55     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
56     search path.
57 */
58 PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void)
59 {
60   char     *libname[32];
61   PetscInt  nmax, i;
62   PetscBool preload = PETSC_FALSE;
63 #if defined(PETSC_HAVE_ELEMENTAL)
64   PetscBool PetscInitialized = PetscInitializeCalled;
65 #endif
66 
67   PetscFunctionBegin;
68 #if defined(PETSC_HAVE_THREADSAFETY)
69   /* These must be all initialized here because it is not safe for individual threads to call these initialize routines */
70   preload = PETSC_TRUE;
71 #endif
72 
73   nmax = 32;
74   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL));
75   for (i = 0; i < nmax; i++) {
76     PetscCall(PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
77     PetscCall(PetscFree(libname[i]));
78   }
79 
80   PetscCall(PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL));
81   if (!preload) {
82     PetscCall(PetscSysInitializePackage());
83   } else {
84 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
85     PetscBool found;
86   #if defined(PETSC_USE_SINGLE_LIBRARY)
87     PetscCall(PetscLoadDynamicLibrary("", &found));
88     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
89   #else
90     PetscCall(PetscLoadDynamicLibrary("sys", &found));
91     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
92     PetscCall(PetscLoadDynamicLibrary("vec", &found));
93     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
94     PetscCall(PetscLoadDynamicLibrary("mat", &found));
95     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
96     PetscCall(PetscLoadDynamicLibrary("dm", &found));
97     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
98     PetscCall(PetscLoadDynamicLibrary("ksp", &found));
99     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
100     PetscCall(PetscLoadDynamicLibrary("snes", &found));
101     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
102     PetscCall(PetscLoadDynamicLibrary("ts", &found));
103     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
104     PetscCall(PetscLoadDynamicLibrary("tao", &found));
105     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate Tao dynamic library \n You cannot move the dynamic libraries!");
106   #endif
107 #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
108   #if defined(PETSC_USE_SINGLE_LIBRARY)
109     PetscCall(AOInitializePackage());
110     PetscCall(PetscSFInitializePackage());
111     #if !defined(PETSC_USE_COMPLEX)
112     PetscCall(CharacteristicInitializePackage());
113     #endif
114     PetscCall(ISInitializePackage());
115     PetscCall(VecInitializePackage());
116     PetscCall(MatInitializePackage());
117     PetscCall(DMInitializePackage());
118     PetscCall(PCInitializePackage());
119     PetscCall(KSPInitializePackage());
120     PetscCall(SNESInitializePackage());
121     PetscCall(TSInitializePackage());
122     PetscCall(TaoInitializePackage());
123   #else
124     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Cannot use -library_preload with multiple static PETSc libraries");
125   #endif
126 #endif /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
127   }
128 
129 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
130   {
131     PetscBool found;
132     PetscCall(PetscLoadDynamicLibrary("bamg", &found));
133     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc BAMG dynamic library \n You cannot move the dynamic libraries!");
134   }
135 #endif
136 
137   nmax = 32;
138   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL));
139   for (i = 0; i < nmax; i++) {
140     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
141     PetscCall(PetscFree(libname[i]));
142   }
143 
144 #if defined(PETSC_HAVE_ELEMENTAL)
145   /* in Fortran, PetscInitializeCalled is set to PETSC_TRUE before PetscInitialize_DynamicLibraries() */
146   /* in C, it is not the case, but the value is forced to PETSC_TRUE so that PetscRegisterFinalize() is called */
147   PetscInitializeCalled = PETSC_TRUE;
148   PetscCall(PetscElementalInitializePackage());
149   PetscInitializeCalled = PetscInitialized;
150 #endif
151   PetscFunctionReturn(PETSC_SUCCESS);
152 }
153 
154 /*
155      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
156 */
157 PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void)
158 {
159   PetscBool flg = PETSC_FALSE;
160 
161   PetscFunctionBegin;
162   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL));
163   if (flg) PetscCall(PetscDLLibraryPrintPath(PetscDLLibrariesLoaded));
164   PetscCall(PetscDLLibraryClose(PetscDLLibrariesLoaded));
165   PetscDLLibrariesLoaded = NULL;
166   PetscFunctionReturn(PETSC_SUCCESS);
167 }
168 
169 PETSC_HASH_MAP(HMapFunc, const char *, PetscVoidFunction, kh_str_hash_func, kh_str_hash_equal, NULL)
170 
171 struct _n_PetscFunctionList {
172   PetscHMapFunc map;
173 };
174 
175 /* Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones. */
176 typedef struct n_PetscFunctionListDLAll *PetscFunctionListDLAll;
177 struct n_PetscFunctionListDLAll {
178   PetscFunctionList      data;
179   PetscFunctionListDLAll next;
180 };
181 
182 static PetscFunctionListDLAll dlallhead = NULL;
183 
184 static PetscErrorCode PetscFunctionListDLAllPush_Private(PetscFunctionList fl)
185 {
186   PetscFunctionBegin;
187   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
188     PetscFunctionListDLAll head;
189 
190     PetscCall(PetscNew(&head));
191     head->data = fl;
192     head->next = dlallhead;
193     dlallhead  = head;
194   }
195   PetscFunctionReturn(PETSC_SUCCESS);
196 }
197 
198 static PetscErrorCode PetscFunctionListDLAllPop_Private(PetscFunctionList fl)
199 {
200   PetscFunctionBegin;
201   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
202     PetscFunctionListDLAll current = dlallhead, prev = NULL;
203 
204     /* Remove this entry from the main DL list (if it is in it) */
205     while (current) {
206       const PetscFunctionListDLAll next = current->next;
207 
208       if (current->data == fl) {
209         if (prev) {
210           // somewhere in the middle (or end) of the list
211           prev->next = next;
212         } else {
213           // prev = NULL implies current = dlallhead, so front of list
214           dlallhead = next;
215         }
216         PetscCall(PetscFree(current));
217         break;
218       }
219       prev    = current;
220       current = next;
221     }
222   }
223   PetscFunctionReturn(PETSC_SUCCESS);
224 }
225 
226 static PetscErrorCode PetscHMapFuncInsert_Private(PetscHMapFunc map, const char name[], PetscVoidFunction fnc)
227 {
228   PetscHashIter it;
229   PetscBool     found;
230 
231   PetscFunctionBegin;
232   PetscAssertPointer(name, 2);
233   if (fnc) PetscValidFunction(fnc, 3);
234   PetscCall(PetscHMapFuncFind(map, name, &it, &found));
235   if (fnc) {
236     if (found) {
237       PetscCall(PetscHMapFuncIterSet(map, it, fnc));
238     } else {
239       char *tmp_name;
240 
241       PetscCall(PetscStrallocpy(name, &tmp_name));
242       PetscCall(PetscHMapFuncSet(map, tmp_name, fnc));
243     }
244   } else if (found) {
245     const char *tmp_name;
246 
247     PetscHashIterGetKey(map, it, tmp_name);
248     PetscCall(PetscFree(tmp_name));
249     PetscCall(PetscHMapFuncIterDel(map, it));
250   }
251   PetscFunctionReturn(PETSC_SUCCESS);
252 }
253 
254 static PetscErrorCode PetscFunctionListCreate_Private(PetscInt size, PetscFunctionList *fl)
255 {
256   PetscFunctionBegin;
257   if (*fl) PetscFunctionReturn(PETSC_SUCCESS);
258   PetscCall(PetscNew(fl));
259   PetscCall(PetscHMapFuncCreateWithSize(size, &(*fl)->map));
260   PetscCall(PetscFunctionListDLAllPush_Private(*fl));
261   PetscFunctionReturn(PETSC_SUCCESS);
262 }
263 
264 /*MC
265   PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
266   specified registry.
267 
268   Synopsis:
269   #include <petscsys.h>
270   PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))
271 
272   Not Collective
273 
274   Input Parameters:
275 + fl   - pointer to function list object
276 . name - string to identify routine
277 - fptr - function pointer
278 
279   Level: developer
280 
281   Notes:
282   To remove a registered routine, pass in a `NULL` `fptr`.
283 
284   Users who wish to register new classes for use by a particular PETSc
285   component (e.g., `SNES`) should generally call the registration routine
286   for that particular component (e.g., `SNESRegister()`) instead of
287   calling `PetscFunctionListAdd()` directly.
288 
289 .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,`PetscFunctionListDuplicate()`
290           `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
291 M*/
292 PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], PetscVoidFunction fptr)
293 {
294   PetscFunctionBegin;
295   PetscAssertPointer(fl, 1);
296   if (name) PetscAssertPointer(name, 2);
297   if (fptr) PetscValidFunction(fptr, 3);
298   PetscCall(PetscFunctionListCreate_Private(0, fl));
299   PetscCall(PetscHMapFuncInsert_Private((*fl)->map, name, fptr));
300   PetscFunctionReturn(PETSC_SUCCESS);
301 }
302 
303 /*@
304   PetscFunctionListDestroy - Destroys a list of registered routines.
305 
306   Input Parameter:
307 . fl - pointer to list
308 
309   Level: developer
310 
311 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
312 @*/
313 PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
314 {
315   PetscFunctionBegin;
316   if (!*fl) PetscFunctionReturn(PETSC_SUCCESS);
317   PetscCall(PetscFunctionListDLAllPop_Private(*fl));
318   /* free this list */
319   PetscCall(PetscFunctionListClear(*fl));
320   PetscCall(PetscHMapFuncDestroy(&(*fl)->map));
321   PetscCall(PetscFree(*fl));
322   PetscFunctionReturn(PETSC_SUCCESS);
323 }
324 
325 #define PetscHMapFuncForEach(__func_list__, __key_name__, __val_name__, ...) \
326   do { \
327     const PetscHMapFunc phmfi_map_ = (__func_list__)->map; \
328     PetscHashIter       phmfi_iter_; \
329 \
330     PetscHashIterBegin(phmfi_map_, phmfi_iter_); \
331     while (!PetscHashIterAtEnd(phmfi_map_, phmfi_iter_)) { \
332       const char *PETSC_UNUSED       __key_name__; \
333       PetscVoidFunction PETSC_UNUSED __val_name__; \
334 \
335       PetscHashIterGetKey(phmfi_map_, phmfi_iter_, __key_name__); \
336       PetscHashIterGetVal(phmfi_map_, phmfi_iter_, __val_name__); \
337       { \
338         __VA_ARGS__; \
339       } \
340       PetscHashIterNext(phmfi_map_, phmfi_iter_); \
341     } /* end while */ \
342   } while (0)
343 
344 /*@
345   PetscFunctionListClear - Clear a `PetscFunctionList`
346 
347   Not Collective
348 
349   Input Parameter:
350 . fl - The `PetscFunctionList` to clear
351 
352   Level: developer
353 
354   Notes:
355   This clears the contents of `fl` but does not deallocate the entries themselves.
356 
357 .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
358 @*/
359 PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
360 {
361   PetscFunctionBegin;
362   if (fl) {
363     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscFree(name)));
364     PetscCall(PetscHMapFuncClear(fl->map));
365   }
366   PetscFunctionReturn(PETSC_SUCCESS);
367 }
368 
369 /*
370    Print registered PetscFunctionLists
371 */
372 PetscErrorCode PetscFunctionListPrintAll(void)
373 {
374   PetscFunctionListDLAll current = dlallhead;
375 
376   PetscFunctionBegin;
377   if (current) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
378   while (current) {
379     PetscCall(PetscFunctionListPrintNonEmpty(current->data));
380     current = current->next;
381   }
382   PetscFunctionReturn(PETSC_SUCCESS);
383 }
384 
385 /*@C
386   PetscFunctionListPrintNonEmpty - Print composed names for non `NULL` function pointers
387 
388   Input Parameter:
389 . fl - the function list
390 
391   Level: developer
392 
393 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
394 @*/
395 PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
396 {
397   PetscFunctionBegin;
398   if (fl) {
399     // clang-format off
400     PetscHMapFuncForEach(
401       fl,
402       name, func,
403       PetscCall(PetscFPrintf(PETSC_COMM_SELF, PETSC_STDOUT, "[%d] function name: %s\n", PetscGlobalRank, name));
404     );
405     // clang-format on
406   }
407   PetscFunctionReturn(PETSC_SUCCESS);
408 }
409 
410 /*MC
411   PetscFunctionListFind - Find function registered under given name
412 
413   Synopsis:
414   #include <petscsys.h>
415   PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))
416 
417   Input Parameters:
418 + fl   - the function list
419 - name - name registered for the function
420 
421   Output Parameter:
422 . fptr - the function pointer if name was found, else `NULL`
423 
424   Level: developer
425 
426 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`, `PetscFunctionListDuplicate()`
427 M*/
428 PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], PetscVoidFunction *fptr)
429 {
430   PetscFunctionBegin;
431   PetscAssertPointer(name, 2);
432   PetscAssertPointer(fptr, 3);
433   *fptr = NULL;
434   if (fl) PetscCall(PetscHMapFuncGet(fl->map, name, fptr));
435   PetscFunctionReturn(PETSC_SUCCESS);
436 }
437 
438 /*@
439   PetscFunctionListView - prints out contents of a `PetscFunctionList`
440 
441   Collective
442 
443   Input Parameters:
444 + list   - the list of functions
445 - viewer - the `PetscViewer` used to view the `PetscFunctionList`
446 
447   Level: developer
448 
449 .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
450 @*/
451 PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
452 {
453   PetscBool iascii;
454 
455   PetscFunctionBegin;
456   PetscAssertPointer(list, 1);
457   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));
458   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
459 
460   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
461   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
462   {
463     PetscInt size;
464 
465     PetscCall(PetscHMapFuncGetSize(list->map, &size));
466     PetscCall(PetscViewerASCIIPrintf(viewer, "PetscFunctionList Object:\n"));
467     PetscCall(PetscViewerASCIIPushTab(viewer));
468     PetscCall(PetscViewerASCIIPrintf(viewer, "size: %" PetscInt_FMT "\n", size));
469     if (size) {
470       PetscInt count = 0;
471 
472       PetscCall(PetscViewerASCIIPrintf(viewer, "functions:\n"));
473       PetscCall(PetscViewerASCIIPushTab(viewer));
474       PetscHMapFuncForEach(list, name, func, PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": %s\n", ++count, name)));
475       PetscCall(PetscViewerASCIIPopTab(viewer));
476     }
477     PetscCall(PetscViewerASCIIPopTab(viewer));
478   }
479   PetscFunctionReturn(PETSC_SUCCESS);
480 }
481 
482 /*@C
483   PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
484   by help etc.
485 
486   Not Collective
487 
488   Input Parameter:
489 . list - list of types
490 
491   Output Parameters:
492 + array - array of names
493 - n     - length of `array`
494 
495   Level: developer
496 
497   Note:
498   This allocates the array so that must be freed. BUT the individual entries are
499   not copied so should not be freed.
500 
501 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
502 @*/
503 PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
504 {
505   PetscInt size = 0;
506 
507   PetscFunctionBegin;
508   PetscAssertPointer(array, 2);
509   *array = NULL;
510   if (list) {
511     const PetscHMapFunc map = list->map;
512     PetscInt            off = 0;
513 
514     PetscCall(PetscHMapFuncGetSize(map, &size));
515     PetscCall(PetscMalloc1(size, (char ***)array));
516     PetscCall(PetscHMapFuncGetKeys(map, &off, *array));
517   }
518   *n = (int)size;
519   PetscFunctionReturn(PETSC_SUCCESS);
520 }
521 
522 /*@C
523   PetscFunctionListPrintTypes - Prints the methods available in a list of functions
524 
525   Collective over MPI_Comm
526 
527   Input Parameters:
528 + comm   - the communicator (usually `MPI_COMM_WORLD`)
529 . fd     - file to print to, usually `stdout`
530 . prefix - prefix to prepend to name (optional)
531 . name   - option string (for example, `-ksp_type`)
532 . text   - short description of the object (for example, "Krylov solvers")
533 . man    - name of manual page that discusses the object (for example, `KSPCreate`)
534 . list   - list of types
535 . def    - default (current) value
536 - newv   - new value
537 
538   Level: developer
539 
540 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
541 @*/
542 PetscErrorCode PetscFunctionListPrintTypes(MPI_Comm comm, FILE *fd, const char prefix[], const char name[], const char text[], const char man[], PetscFunctionList list, const char def[], const char newv[])
543 {
544   char p[64];
545 
546   PetscFunctionBegin;
547   (void)fd;
548   PetscCall(PetscStrncpy(p, "-", sizeof(p)));
549   if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
550   PetscCall((*PetscHelpPrintf)(comm, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));
551 
552   if (list) PetscHMapFuncForEach(list, name, func, PetscCall((*PetscHelpPrintf)(comm, " %s", name)));
553   PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", man));
554   PetscFunctionReturn(PETSC_SUCCESS);
555 }
556 
557 /*@
558   PetscFunctionListDuplicate - Creates a new list from a given function list `PetscFunctionList`.
559 
560   Input Parameter:
561 . fl - pointer to list
562 
563   Output Parameter:
564 . nl - the new list (should point to `NULL` to start, otherwise appends)
565 
566   Level: developer
567 
568 .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
569 @*/
570 PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl)
571 {
572   PetscFunctionBegin;
573   if (fl) {
574     PetscHMapFunc dup_map;
575 
576     if (!*nl) {
577       PetscInt n;
578 
579       PetscCall(PetscHMapFuncGetSize(fl->map, &n));
580       PetscCall(PetscFunctionListCreate_Private(n, nl));
581     }
582     dup_map = (*nl)->map;
583     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscHMapFuncInsert_Private(dup_map, name, func)));
584   }
585   PetscFunctionReturn(PETSC_SUCCESS);
586 }
587