Question

We have a huge codebase with multiple dependencies (like tinyxml, fft stuff, etc), templates, ... in C/C++, all of which is wrapped neatly behind a very simple C interface.

Building a dynamic library for OSX was just fine, because we could easily strip all unwanted symbols from the library (using strip -S -x) leaving only the wanted C interface and hiding all the C++ classes / templates / dependencies / ... So in the end the only symbols exported/visible are our API calls: OUR_LIBNAME_FUNC1, OUR_LIBNAME_FUNC2 etc etc

However, we now want to do the same for an iOS static lib and we are running out of ideas. Is there any way to hide all the un-needed/wanted symbols without reverting to a big mess of code-amalgamation, rewriting code, objdump-ing, obfuscation...? Especially for the external libs that might be reused by others and which will then result in multiple symbol definitions!

After a lot of research ( mostly stack overflow :-) ) I am kind of becoming hopeless...

greets

Was it helpful?

Solution 2

Answering my own question: in the end we resorted to an anonymous namespace and code amalgamation.

I.e. all the cpp/c code was amalgamated into on big C file using a large and relatively complex/ugly python script. All the functions in the CPP file were wrapped in an anonymous namespace, leaving only the exported functions outside of the namespace.

After that doing a strip -S -x on the library cleared out most of the junk.

I.e.

/************** AMALGAMATED CPP FILE **************/

/************** STD HEADERS **************/
#include "OurLibraryHeader.h"
#include <cmath>
#include <string>
// more standard includes here and includes that aren't possible to do in the anonymous namespace

/************** AMALGAM **************/
namespace {
#include "OneofOurheaders1.h"
#include "OneofOurheaders2.h"
#include "SomeExternalLib.h"

/************************* OneofOurImplementations.cpp *************************/
// included literally

/************************* OneofOurImplementations2.cpp *************************/
// included literally

// etc
}

int OneOfOurLibraryFunctions()
{
}

// etc

This is rather filthy but it gets the job done. I'm sure there are nicer ways to do this with some LLVM trickery...

  • Bram

OTHER TIPS

OK, I just spent a lot of time doing something similar to this. This is non-perfect, but this worked well enough for our purposes.

  1. Put your C api top level entry points in one file, "c_api.c".
  2. Create a file "c_api.symbols" with the name of each entry point on a line by itself with the "_" that the linker adds
  3. Use the linker to pre-link your api to your internal libraries

Something like this:

% cat c_api.c
#include "libA.h"
#include "libB.h"
#include "libC.h"

void init()
{
    libA_startup();
}

void run()
{
    libB_execute(libA_context());
}

void stop()
{
    libA_shutdown();
    libB_end();
    libC_log();
}
% cat c_api.symbols
_init
_run
_stop
% cc -c a_api.c
% ld -x -r c_api.o libA.a libB.a libC.a -exported_symbols_list c_api.symbols -o c_api_hidden.o
% ar r c_api.a c_api_hidden.o
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top