Hiding non-API symbols in library

726 views Asked by At

Suppose I have a library foo which consists of the modules foo and util and has the following source tree:

foo/
    foo.c
    foo.h
    util.c
    util.h

The public API of the library is defined in foo.h and all global identifiers are properly prefixed with foo_ or util_. The module util is only used by foo. To prevent name clashes with other modules named util I want to create a (static) library in which only identifiers from module foo are visible. How can I do this?

Edit: I have searched the internet quite extensively but surprisingly this seems to be one of those unsolved problems in computer science.

3

There are 3 answers

0
August Karlstrom On BEST ANSWER

Before each variable and function declaration in util.h, define a macro constant which renames the declared identifier by adding the library prefix foo_, for instance

#define util_x foo_util_x
extern int util_x;   

#define util_f foo_util_f
void util_f(void);

...

With these definitions in place, no other parts of the code need to be changed, and all global symbols in the object file util.o will be prefixed with foo_. This means that name collisions are less likely to occur.

4
Myst On

There are probably other possible approaches, but here's one:

You might consider including the file util.c within foo.c and making all the util functions / globals static. i.e.:

#include "util.c"
// ...

This works the same as *.h files, it simply ports the whole source into foo.c, nesting util.c and making all the static data available.

When I do this, I rename the file to .inc (i.e. util.c => util.inc)...

#include "util.inc"
// ...

...it's an older convention I picked up somewhere, though it might conflict with assembler files, so you'll have to use your own discretion.

EDIT

Another approach might require linker specific directives. For example, this SO answer details GNU's ld to achieve this goal. There are other approaches as well, listed in that same thread.

0
ephemient On

The following is GCC-specific.

You can mark each utility function with

__attribute__((visibility ("hidden")))

which will prevent it from being linked to from another shared object.

You can apply this to a series of declarations by surrounding them with

#pragma GCC visibility push(hidden)
/* ... */
#pragma GCC visibility pop

or use -fvisibility=hidden when compiling the object, which applies to declarations without an explicit visibility (e.g. neither __attribute__((visibility)) nor #pragma GCC visibility).