cgccstatic-librariesldobjcopy

Make a C static library that only exposes the API


I have an old static library that includes some functions produced by a C auto-coder (Mathworks/Simulink). I have just made a new static library (that does totally different things from the old library) that uses a newer version of the auto-coder. I need to make an executable that links both these libraries. Unfortunately many of the helper functions generated by the auto-coder have the same name in the old and new libraries but their functionality has changed. These functions are not part of the API. Obviously when I try to link I get complaints that the same symbols appear in both libraries. The old library is untouchable, but I can mess with the new one.

The libraries are built with

gcc -c *.c  
ar -crs libwhatever.a *.o

and linked with

gcc main.o -L. -lold -lnew

My current solution is to look at all the symbol clashes given by gcc and rename the symbols in the new library using

objcopy --redefine-sym sym=sym_new libnew.a

This seems to work. My program links and behaves as expected. But I'm wondering if it is the right/best thing to do.

Ideally I'd like to make a libnew.a that only exposes the API functions and nothing else. That way I guarantee no symbol clashes when I try to link. Is this possible I cannot figure out how.

Please note that I have little previous experience in these matters. Also, if it's relevant/not obvious, I'm using Linux.

Edit

Below is a rather contrived minimal working example.

old/printOld.c:

#include "printOld.h"
#include <stdio.h>

void printOld()
{
  printStr();
}

void printStr()
{
  printf("Old\n");
}

old/printOld.h:

void printStr();

old/buildOld:

gcc -c printOld.c
ar -crs libold.a printOld.o

new/printNew.c:

#include "printNew.h"
#include <stdio.h>

void printNew()
{
  printStr();
}

void printStr()
{
  printf("New\n");
}

new/printNew.h:

void printStr();

new/buildNew:

gcc -c printNew.c
ar -crs libnew.a printNew.o

#objcopy --redefine-sym printStr=printStrNew libnew.a

main/main.c:

void printOld();
void printNew();

int main()
{
  printOld();
  printNew();

  return 0;
}

main/buildMain:

gcc main.c -L../old -L../new -lold -lnew

The linker error when I leave objcopy commented out is:

/usr/bin/ld: ../new/libnew.a(printNew.o): in function `printStr':
printNew.c:(.text+0x11): multiple definition of `printStr'; ../old/libold.a(printOld.o):printOld.c:(.text+0x11): first defined here
collect2: error: ld returned 1 exit status

The above example has the same kind of structure as the auto-generated code. I know that I can fix my problem by declaring the functions in the header files as static, but I'd rather not have to mess with the auto-generated code. It is very large and very unpleasant.


Solution

  • Use --keep-global-symbol=symbolname option with objcopy:

    objcopy --keep-global-symbol=printOld libold.a
    

    or

    objcopy --keep-global-symbols=api libold.a
    

    where api is a file with a list of API functions