This is about making procps have a proper library but it really is a generic sort of question. Say you are making a library and a program that uses that library. Now at times you may have convience type functions; procps has them for things like escaping command names or allocation different sorts of memory. Both the library and the programs use some of these functions.
Now, there seems only two approaches to this setup. The first is to have the function stay in the library and for the program to call this function, just like all the other library functions. But this means the library has exposed for all other programs that link to it and that doesn’t really make a lot of sense.
The second method is to have the functions defined in both places, perhaps in a file that is linked with the program and the library. That seems to be duplicating the code in two different places. Namespace collision could be a problem but that easily fixed with using some unqiue prefix. I really don’t think having procfs_malloc, procfs_calloc and procfs_strdup are that useful.
I’m sure this sort of problem has been solved elsewhere. Has anyone else come across this? The functions are simple utility type functions such as malloc a block of memory, if there is a problem print to stderr.
I typically compile the shared functions into a separate static library or collection of objects. I then link it into both the program and the library. There is a small file size cost but it avoids symbol table and namespace pollution and eliminates the need to keep multiple copies of the sources. When compiling with gcc you can use the link symbol visibility stuff to prevent them from being visible in the library symbol table. See -fvisibikity=hidden and the related explicit visibility controls.
There is a third option you overlooked.
Put those functions on another library where they make sense, use that other library on both the program and library.
That means that, if there isn’t already a library where those functions make sense, you’ll create two libraries, what is a new kind of problem… But you are really exchanging problems here, not creating more of them.
It doesn’t seem like there is a perfectly great solution to this problem. I believe a semi-common solution is to move this type of function into a second library that sits on top of the first one. Kind of like you often have a “lowlevel” direct access library for functionality, and a second “higher level” library layered on top of it. But that’s just one data point.
I guess you might roll those common functions into a libfoo-private used by foo and libfoo.
This is done by by f.ex. metacity.
The danger ofcourse, is that there is no protection against a third-party using your private library (in the example of metacity, compiz is using the private library, and metacity didn’t gaurantee API/ABI stability in there…)
Maybe it would be possible to build a static library and link this into both foo and libfoo, but I’m not sure if this would work, or if the linker will be unhappy…
There’s other options. A variation on your first one, would be to consider those functions private to the project (as long as both the program and the library are part of that same project then everything would be fine), by not installing headers containing prototypes for those functions, maybe by using a different namespace (for example procfsprivate) and ideally by marking those as private symbols in your versioned symbols script (with something like PROCFSPRIVATE, instead of say PROCFS0).
Another option would be to make them function pointers that should be initialized by the program (ideally through another function), so then there’s only one implementation. But that might be annoying as all programs have to provide an implementation which might end up duplicating way more code and initialize them. Or provide a default implementation, which can be overridden by the calling program, this fixes the code duplication but brings back exposing stuff that you might not want to expose.
But in the end it all depends on the size of those functions, if they are simple wrappers, then probably none of this makes sense, and simple private inline functions might be the best, as you can share the source code, and the resulting binary will not see a significant size increase.
Having a shared library doesn’t require making it available for everyone to link against. If you just put it in /usr/lib/procps/ or similar and don’t give it a stable SONAME, that’s a pretty clear indication that it’s for private use only; if anyone else tries to use it then it will break hard for them quickly enough. man-db does this and it hasn’t been a problem for me.