xref: /petsc/src/sys/dll/reg.c (revision df4cd43f92eaa320656440c40edb1046daee8f75)
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 /* ------------------------------------------------------------------------------*/
170 PETSC_HASH_MAP(HMapFunc, const char *, PetscVoidFunction, kh_str_hash_func, kh_str_hash_equal, NULL)
171 
172 struct _n_PetscFunctionList {
173   PetscHMapFunc map;
174 };
175 
176 /* Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones. */
177 typedef struct n_PetscFunctionListDLAll *PetscFunctionListDLAll;
178 struct n_PetscFunctionListDLAll {
179   PetscFunctionList      data;
180   PetscFunctionListDLAll next;
181 };
182 
183 static PetscFunctionListDLAll dlallhead = NULL;
184 
185 static PetscErrorCode PetscFunctionListDLAllPush_Private(PetscFunctionList fl)
186 {
187   PetscFunctionBegin;
188   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
189     PetscFunctionListDLAll head;
190 
191     PetscCall(PetscNew(&head));
192     head->data = fl;
193     head->next = dlallhead;
194     dlallhead  = head;
195   }
196   PetscFunctionReturn(PETSC_SUCCESS);
197 }
198 
199 static PetscErrorCode PetscFunctionListDLAllPop_Private(PetscFunctionList fl)
200 {
201   PetscFunctionBegin;
202   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
203     PetscFunctionListDLAll current = dlallhead, prev = NULL;
204 
205     /* Remove this entry from the main DL list (if it is in it) */
206     while (current) {
207       const PetscFunctionListDLAll next = current->next;
208 
209       if (current->data == fl) {
210         if (prev) {
211           // somewhere in the middle (or end) of the list
212           prev->next = next;
213         } else {
214           // prev = NULL implies current = dlallhead, so front of list
215           dlallhead = next;
216         }
217         PetscCall(PetscFree(current));
218         break;
219       }
220       prev    = current;
221       current = next;
222     }
223   }
224   PetscFunctionReturn(PETSC_SUCCESS);
225 }
226 
227 static PetscErrorCode PetscHMapFuncInsert_Private(PetscHMapFunc map, const char name[], PetscVoidFunction fnc)
228 {
229   PetscHashIter it;
230   PetscBool     found;
231 
232   PetscFunctionBegin;
233   PetscValidCharPointer(name, 2);
234   if (fnc) PetscValidFunction(fnc, 3);
235   PetscCall(PetscHMapFuncFind(map, name, &it, &found));
236   if (fnc) {
237     if (found) {
238       PetscCall(PetscHMapFuncIterSet(map, it, fnc));
239     } else {
240       char *tmp_name;
241 
242       PetscCall(PetscStrallocpy(name, &tmp_name));
243       PetscCall(PetscHMapFuncSet(map, tmp_name, fnc));
244     }
245   } else if (found) {
246     const char *tmp_name;
247 
248     PetscHashIterGetKey(map, it, tmp_name);
249     PetscCall(PetscFree(tmp_name));
250     PetscCall(PetscHMapFuncIterDel(map, it));
251   }
252   PetscFunctionReturn(PETSC_SUCCESS);
253 }
254 
255 static PetscErrorCode PetscFunctionListCreate_Private(PetscInt size, PetscFunctionList *fl)
256 {
257   PetscFunctionBegin;
258   if (*fl) PetscFunctionReturn(PETSC_SUCCESS);
259   PetscCall(PetscNew(fl));
260   PetscCall(PetscHMapFuncCreateWithSize(size, &(*fl)->map));
261   PetscCall(PetscFunctionListDLAllPush_Private(*fl));
262   PetscFunctionReturn(PETSC_SUCCESS);
263 }
264 
265 /*MC
266    PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
267    specified registry.
268 
269    Synopsis:
270    #include <petscsys.h>
271    PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))
272 
273    Not Collective
274 
275    Input Parameters:
276 +  flist - pointer to function list object
277 .  name - string to identify routine
278 -  fptr - function pointer
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     Level: developer
289 
290 .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,
291           `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
292 M*/
293 PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], PetscVoidFunction fnc)
294 {
295   PetscFunctionBegin;
296   PetscValidPointer(fl, 1);
297   if (name) PetscValidCharPointer(name, 2);
298   if (fnc) PetscValidFunction(fnc, 3);
299   PetscCall(PetscFunctionListCreate_Private(0, fl));
300   PetscCall(PetscHMapFuncInsert_Private((*fl)->map, name, fnc));
301   PetscFunctionReturn(PETSC_SUCCESS);
302 }
303 
304 /*@
305     PetscFunctionListDestroy - Destroys a list of registered routines.
306 
307     Input Parameter:
308 .   fl  - pointer to list
309 
310     Level: developer
311 
312 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
313 @*/
314 PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
315 {
316   PetscFunctionBegin;
317   if (!*fl) PetscFunctionReturn(PETSC_SUCCESS);
318   PetscCall(PetscFunctionListDLAllPop_Private(*fl));
319   /* free this list */
320   PetscCall(PetscFunctionListClear(*fl));
321   PetscCall(PetscHMapFuncDestroy(&(*fl)->map));
322   PetscCall(PetscFree(*fl));
323   PetscFunctionReturn(PETSC_SUCCESS);
324 }
325 
326 #define PetscHMapFuncForEach(__func_list__, __key_name__, __val_name__, ...) \
327   do { \
328     const PetscHMapFunc phmfi_map_ = (__func_list__)->map; \
329     PetscHashIter       phmfi_iter_; \
330 \
331     PetscHashIterBegin(phmfi_map_, phmfi_iter_); \
332     while (!PetscHashIterAtEnd(phmfi_map_, phmfi_iter_)) { \
333       const char *PETSC_UNUSED       __key_name__; \
334       PetscVoidFunction PETSC_UNUSED __val_name__; \
335 \
336       PetscHashIterGetKey(phmfi_map_, phmfi_iter_, __key_name__); \
337       PetscHashIterGetVal(phmfi_map_, phmfi_iter_, __val_name__); \
338       { \
339         __VA_ARGS__; \
340       } \
341       PetscHashIterNext(phmfi_map_, phmfi_iter_); \
342     } /* end while */ \
343   } while (0)
344 
345 /*@
346   PetscFunctionListClear - Clear a `PetscFunctionList`
347 
348   Not Collective
349 
350   Input Parameter:
351 . fl - The `PetscFunctionList` to clear
352 
353   Notes:
354   This clears the contents of `fl` but does not deallocate the entries themselves.
355 
356   Level: developer
357 
358 .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
359 @*/
360 PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
361 {
362   PetscFunctionBegin;
363   if (fl) {
364     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscFree(name)));
365     PetscCall(PetscHMapFuncClear(fl->map));
366   }
367   PetscFunctionReturn(PETSC_SUCCESS);
368 }
369 
370 /*
371    Print registered PetscFunctionLists
372 */
373 PetscErrorCode PetscFunctionListPrintAll(void)
374 {
375   PetscFunctionListDLAll current = dlallhead;
376 
377   PetscFunctionBegin;
378   if (current) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
379   while (current) {
380     PetscCall(PetscFunctionListPrintNonEmpty(current->data));
381     current = current->next;
382   }
383   PetscFunctionReturn(PETSC_SUCCESS);
384 }
385 
386 /*MC
387     PetscFunctionListNonEmpty - Print composed names for non null function pointers
388 
389     Input Parameter:
390 .   flist   - pointer to list
391 
392     Level: developer
393 
394 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
395 M*/
396 PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
397 {
398   PetscFunctionBegin;
399   if (fl) {
400     // clang-format off
401     PetscHMapFuncForEach(
402       fl,
403       name, func,
404       PetscCall(PetscFPrintf(PETSC_COMM_SELF, PETSC_STDOUT, "[%d] function name: %s\n", PetscGlobalRank, name));
405     );
406     // clang-format on
407   }
408   PetscFunctionReturn(PETSC_SUCCESS);
409 }
410 
411 /*MC
412     PetscFunctionListFind - Find function registered under given name
413 
414     Synopsis:
415     #include <petscsys.h>
416     PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))
417 
418     Input Parameters:
419 +   flist   - pointer to list
420 -   name - name registered for the function
421 
422     Output Parameters:
423 .   fptr - the function pointer if name was found, else NULL
424 
425     Level: developer
426 
427 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
428 M*/
429 PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], PetscVoidFunction *r)
430 {
431   PetscFunctionBegin;
432   PetscValidCharPointer(name, 2);
433   PetscValidPointer(r, 3);
434   *r = NULL;
435   if (fl) PetscCall(PetscHMapFuncGet(fl->map, name, r));
436   PetscFunctionReturn(PETSC_SUCCESS);
437 }
438 
439 /*@
440    PetscFunctionListView - prints out contents of an PetscFunctionList
441 
442    Collective on `viewer`
443 
444    Input Parameters:
445 +  list - the list of functions
446 -  viewer - the `PetscViewer` used to view the PetscFunctionList
447 
448    Level: developer
449 
450 .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
451 @*/
452 PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
453 {
454   PetscBool iascii;
455 
456   PetscFunctionBegin;
457   PetscValidPointer(list, 1);
458   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));
459   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
460 
461   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
462   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
463   {
464     PetscInt size;
465 
466     PetscCall(PetscHMapFuncGetSize(list->map, &size));
467     PetscCall(PetscViewerASCIIPrintf(viewer, "PetscFunctionList Object:\n"));
468     PetscCall(PetscViewerASCIIPushTab(viewer));
469     PetscCall(PetscViewerASCIIPrintf(viewer, "size: %" PetscInt_FMT "\n", size));
470     if (size) {
471       PetscInt count = 0;
472 
473       PetscCall(PetscViewerASCIIPrintf(viewer, "functions:\n"));
474       PetscCall(PetscViewerASCIIPushTab(viewer));
475       PetscHMapFuncForEach(list, name, func, PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": %s\n", ++count, name)));
476       PetscCall(PetscViewerASCIIPopTab(viewer));
477     }
478     PetscCall(PetscViewerASCIIPopTab(viewer));
479   }
480   PetscFunctionReturn(PETSC_SUCCESS);
481 }
482 
483 /*@C
484    PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
485          by help etc.
486 
487    Not Collective
488 
489    Input Parameter:
490 .  list   - list of types
491 
492    Output Parameters:
493 +  array - array of names
494 -  n - length of array
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    Level: developer
501 
502 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
503 @*/
504 PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
505 {
506   PetscInt size = 0;
507 
508   PetscFunctionBegin;
509   PetscValidPointer(array, 2);
510   *array = NULL;
511   if (list) {
512     const PetscHMapFunc map = list->map;
513     PetscInt            off = 0;
514 
515     PetscCall(PetscHMapFuncGetSize(map, &size));
516     PetscCall(PetscMalloc1(size, (char ***)array));
517     PetscCall(PetscHMapFuncGetKeys(map, &off, *array));
518   }
519   *n = (int)size;
520   PetscFunctionReturn(PETSC_SUCCESS);
521 }
522 
523 /*@C
524    PetscFunctionListPrintTypes - Prints the methods available in a list of functions
525 
526    Collective over MPI_Comm
527 
528    Input Parameters:
529 +  comm   - the communicator (usually `MPI_COMM_WORLD`)
530 .  fd     - file to print to, usually stdout
531 .  prefix - prefix to prepend to name (optional)
532 .  name   - option string (for example, "-ksp_type")
533 .  text - short description of the object (for example, "Krylov solvers")
534 .  man - name of manual page that discusses the object (for example, "KSPCreate")
535 .  list   - list of types
536 .  def - default (current) value
537 -  newv - new value
538 
539    Level: developer
540 
541 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
542 @*/
543 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[])
544 {
545   char p[64];
546 
547   PetscFunctionBegin;
548   (void)fd;
549   PetscCall(PetscStrncpy(p, "-", sizeof(p)));
550   if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
551   PetscCall((*PetscHelpPrintf)(comm, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));
552 
553   PetscHMapFuncForEach(list, name, func, PetscCall((*PetscHelpPrintf)(comm, " %s", name)));
554   PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", man));
555   PetscFunctionReturn(PETSC_SUCCESS);
556 }
557 
558 /*@
559     PetscFunctionListDuplicate - Creates a new list from a given object list.
560 
561     Input Parameters:
562 .   fl   - pointer to list
563 
564     Output Parameters:
565 .   nl - the new list (should point to 0 to start, otherwise appends)
566 
567     Level: developer
568 
569 .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
570 @*/
571 PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl)
572 {
573   PetscFunctionBegin;
574   if (fl) {
575     PetscHMapFunc dup_map;
576 
577     if (!*nl) {
578       PetscInt n;
579 
580       PetscCall(PetscHMapFuncGetSize(fl->map, &n));
581       PetscCall(PetscFunctionListCreate_Private(n, nl));
582     }
583     dup_map = (*nl)->map;
584     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscHMapFuncInsert_Private(dup_map, name, func)));
585   }
586   PetscFunctionReturn(PETSC_SUCCESS);
587 }
588