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