1

I recently had to face a fairly complex issue regarding lib management, but I would be very surprised to be the first one.

Let's imagine you are creating a library (static or dynamic) called lib1 in C. Inside lib1 are a few functions that are exposed through an API, and a few other ones which remain private.

Ideally, the private functions would be static. Unfortunately, let's assume one of the source files, called extmod.c, come from another project, and it would be beneficial to keep it unmodified. Therefore, it becomes unpractical to static the functions it defines.

As a consequence, all the functions defined into extmod are present into lib1 ABI, but not the API, since the relevant *.h is not shipped. So no one notice.

Unfortunately, at later stage, someone wants to link both lib1 and another lib2 which also includes extmod. It results in a linking error, due to duplicate definitions.

In C++, the answer to this problem would be a simple namespace. In C, we are less lucky.

There are a few solutions to this problem, but I would like to probe if anyone believes to have found an efficient and non-invasive way. By "non-invasive", I mean a method which avoids if possible to modify extmod.c.

Among the possible workaround, there is the possibility to change all definitions from extmod.c using a different prefix, effectively emulating namespace. Or the possibility to put the content of extmod.c into extmod.h and static everything. Both method do extensively modify extmod though ...

Note that I've looked at this previous answer, but it doesn't address this specific concern.

Community
  • 1
  • 1
Cyan
  • 13,248
  • 8
  • 43
  • 78
  • You don't really need to modify the file by hand, I mean not function by function, I would use `libclang` probably the python bindings and create a new file from the source of `extmod.c` where all functions are static. – Iharob Al Asimi Jun 26 '15 at 01:45
  • It's not that simple. If functions inside `extmod.c` are made blindly static, not even the library can access them. So it would require additionnal transformations, such as transferring the content of the `.c` into the `.h`, and there your start to inherit a lot more problems, such as naming collisions, unused static code, and so on .... – Cyan Jun 26 '15 at 18:46

3 Answers3

4

You could implement your 'different prefix' solution by excluding extmod.c from your your build and instead treating it as header file in a way. Use the C pre-processor to effectively modify the file without actually modifying it. For example if extmod.c contains:

void print_hello()
{
   printf("hello!");
}

Exclude this file from your build and add one called ns_extmod.c. The content of this file should look like this:

#define print_hello ns_print_hello
#include "extmod.c"

On compilation, print_hello will be renamed to ns_print_hello by the C pre-processor but the original file will remain intact.

Alternatively, IF AND ONLY IF the function are not called internally by extmod.c, it might work to use the preprocessor to make them static in the same way:

#define print_hello static print_hello
#include "extmod.c"

This should work for you assuming you have control over the build process.

Shawn Rakowski
  • 5,644
  • 2
  • 27
  • 29
  • OK, I'm trying to fully grasp your suggestion, since it seems on good track. Especially I like that it seems to not require modifying initial files. So now let's assume that we have a file `ns_extmod_c` which, as you suggest, contain a bunch of macro translated symbol names and then includes `extmod.c`. I guess that a similar transformation must be applied to the `extmod.h` file too, so that prototype definitions coincide. You last comment on `static` is less clear to me... – Cyan Jun 26 '15 at 19:00
  • Well, thinking again about it, it seems better to introduce the translating macro at `.h` level. Since the `.h` is included, definitions are automatically transferred to `.c`. Even better, calling programs including the `.h` also get the benefit of the translation for free, so no need to change this side of the code either. Looks like a good win from all side. Now onto practicing ... – Cyan Jun 26 '15 at 19:09
  • OK, so if we also want to not touch the `.h`, it's necessary to define both a `ns_extmod.c` and a `ns_extmod.h`, and they become the versions called by the user program. The other idea is like @harshad : translated symbol names are into a `.h` which _is included by_ `extmod.h`, and all new names are automatically transferred. But it requires to change one line of code within `extmod.h`. Not a big deal if you ask me, but then it becomes easy to make a mistake in a future update : not modifying `extmod.h` to `#include "ns_extmod.h"` results in original names used gain, creating name collisions. – Cyan Jun 26 '15 at 19:17
  • The last comment about making them static doesn't make a much sense come to think of it, but I think you are on the right track now! :-) – Shawn Rakowski Jun 26 '15 at 22:37
2

One way you can do prefixing without actually editing extmod.c is as follows:

Create a new header file extmod_prefix.h as:

#ifndef EXTMOD_PREFIX_H
#define EXTMOD_PREFIX_H

#ifdef LIB1
#define PREFIX lib1_
#else
#ifdef LIB2
#define PREFIX lib2_
#endif
#endif

#define function_in_extmod PREFIX##function_in_extmod
/* Do this for all the functions in extmod.c */

#endif

Include this file in extmod.h and define LIB1 in lib1's build process and LIB2 in lib2.

This way, all the functions in extmod.c will be prefixed by lib1_ in lib1 and lib2_ in lib2.

  • This is a very good idea. Ultimately, I will nonetheless prefer @Shwany method, which is extremely close to the one you suggest. The major difference is that the user program includes the alternate `ns_extmod.h` and compile the alternate `ns_extmod.c` instead of the original ones. The major benefit is long term : in a long time in the future, someone will update `extmod` with a newer version, and may not be aware that it needs to modify a single line within `extmod.h` to call the translated named. It results in a silent issue : original names are now used again, and no one notice, until ... – Cyan Jun 26 '15 at 19:22
2

Here's the answer (in the form of a question). The relevant portion:

objcopy --prefix-symbols allows me to prefix all symbols exported by an object file / static library.

user3386109
  • 34,287
  • 7
  • 49
  • 68
  • It's a good point. Now, using objcopy also adds one more dependency to the build chain. – Cyan Jun 28 '15 at 11:29