-2

I'm compiling and archiving a library (call it libbar.a). The key translation units in that library use a function void foo() defined (non-statically) in a foo.cpp which also gets compiled and put in the library.

I want to avoid this void foo() clashing with other symbols elsewhere in my codebase (which uses that library). Now, you could say - just don't include a header which declares void foo(); but - what if I actually do use the same void foo() elsewhere? Even though it's more efficient to just have it once in my entire codebase, I actually want whoever uses the library to be oblivious to the implementation detail of void foo() being used internally. So - I want for nobody to be able to look up that symbol in libbar.a, but for the code within libbar.a to still be able to use it.

How can I achieve this?

Notes:

  • The code (both for foo and my library) is C and/or C++. Answers assuming it's C-only or C++-only are also relevant.
  • I realize that if I change the name (e.g. to void bar_foo()), or put void foo() into a namespace, that could have the desired effect. But I need to not do that, i.e. I need to keep using the same code for void foo() with no changes. I'm only willing to change things in library code which uses void foo() and in the build mechanism.
  • I'm working with gcc on Linux; I'm hoping something which works with clang or is compiler-agnostic, though. I also automate my build with CMake, but don't bother writing CMake code - just say what you want the build system to do in general terms.
Stargateur
  • 24,473
  • 8
  • 65
  • 91
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • What happens if you put your precious `foo()` in a separate static library and link it to you `libbar.a`? – Innokentiy Alaytsev May 01 '18 at 11:09
  • 4
    This is rather pointless question because you are essentially asking "how can I avoid name clashes without using unique names". – user7860670 May 01 '18 at 11:10
  • 1
    I don't think it is possible for `ar` format static libraries. For `.so` format dynamic libraries (and for Windows DLLs) you can control which symbols are exported. – Ian Abbott May 01 '18 at 11:15
  • I think while building library you need to give a option to linker to strip out foo from exported symbols – code707 May 01 '18 at 11:16
  • Use namespaces and build the classes using `bridge design pattern` where the objects' interfaces are separated from their implementations. – seccpur May 01 '18 at 11:19
  • @InnokentiyAlaytsev: I don't want to burden people who use `libbar.a` to also link `libfoo.a`. I don't even want them to have to know I use `foo()`. – einpoklum May 01 '18 at 11:27
  • @setia_: But do I even use the linker when building the library? Don't I just use `ar` typically? – einpoklum May 01 '18 at 11:28
  • @seccpur: I'm not sure I follow. If you're suggesting I change the `foo()` code - that's not an option for various reasons. I can only wrap it. – einpoklum May 01 '18 at 11:29
  • @einpoklum: In bridge pattern, the implementation will be detached from the interface and header definitions, hence no change require in foo() practically, – seccpur May 01 '18 at 11:32
  • @seccpur: I still don't see how this resolves my problem. `void foo()` is a symbol exported from `libbar.a`. While that's the case, it can't be linked with any user code that also has a compiled object with `void foo()`. Sorry for being dense, please spell it out for me... – einpoklum May 01 '18 at 11:34
  • Easy solution: wait till C++20 modules :) – Passer By May 01 '18 at 11:50
  • @PasserBy: How so? The code for `void foo()` remains as-is, so I have `void foo()` exported from an object file. How would I now avoid it being exported from the static library by using modules anywhere? – einpoklum May 01 '18 at 11:56
  • Your libbar doesn't need to reexport libfoo's stuff – Passer By May 01 '18 at 11:57
  • @PasserBy: What do you mean by "re-export"? The library is typically created by `ar libbar.a foo.o something_else.o`. – einpoklum May 01 '18 at 12:01
  • Your tag are incorrect, tag C and C++ is incorrect here and make your question too broad, if you want tag a language tag only one. I recommand you to tag the compiler you use too, as this question is about symbol, and this has nothing to do the a particular language. Answer you for all existing compiler would make question too broad too. I think what you ask is impossible. – Stargateur May 01 '18 at 12:18
  • @Stargateur I do not understand why there are some many downvote. How can the user (@einpoklum) can know that ? Yes his question should explain the used toolchain, it will help to answer to the question... – benjarobin May 01 '18 at 12:26
  • @benjarobin I would [edit] the question myself but OP clearly specified "The question is about C and/or C++ code." in the question. It would vandalism the question if I do it myself. And I can't guess what compiler OP use. "I do not understand all of the downvote" I write a comment for explain my downvote however I only speak for myself. "Yes this question should explain the toolchain use" exactly so you did understand my previous comment and you agree with me. This question is unlikely going to have a good answer if the OP don't improve it. Question is unclear and too broad. – Stargateur May 01 '18 at 12:32
  • Namespaces. Use them. – n. m. could be an AI May 01 '18 at 13:02
  • @n.m.: Like I said in a note - I can't change the code of `foo()`. I need to change the visibility of the object. – einpoklum May 01 '18 at 13:14
  • Regarding this new information, I **really** think that neither C and C++ tag are correct. – Stargateur May 01 '18 at 13:17
  • 1
    @einpoklum You clearly say you can't touch the source code, C and C++ are about code problem, not about compiling and linking. Have you look the link provide by benjarobin, I think it would probably answer your question https://stackoverflow.com/a/6940389/7076153 – Stargateur May 01 '18 at 13:32
  • @Stargateur: Well, I can touch my own library's source code; but - fair enough. – einpoklum May 01 '18 at 14:11
  • @einpoklum Don't take it personally or whatever , I'm not "in war" with you, but as I say you should add what compiler/toolchain you use, add for example [tag:clang] or [tag:gcc], and maybe add [tag:makefile] or [tag:cmake]. Didn't the answer in the link fix your problem ? If not I don't understand your question/problem. – Stargateur May 01 '18 at 14:15
  • The question as it stands now is about programming languages, i.e. source code. If you cannot change source code, you are not dealing with a programming language. Retag. You may or may not be able to play dirty games by modifying object files in an architecture- and OS-specific way. – n. m. could be an AI May 01 '18 at 15:11

1 Answers1

2

If you compile the library non statically (create a .so or a .dll), this is possible. You can choose the symbol that you want to export: Basically you hide all symbol and add an attribut to the public symbol.

You can achive that with this kind of MACRO:

#ifdef BUILD_STATIC_LIB
# define LIB_EXPORT
#elif (defined BUILD_DYN_LIB)
# if (defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)
#  ifdef __GNUC__    
#   define LIB_EXPORT  __cdecl __attribute__((dllexport))
#  else
#   define LIB_EXPORT  __cdecl __declspec(dllexport)
#  endif
# else
#  define LIB_EXPORT  __attribute__ ((visibility ("default")))
# endif
#else
# if (defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)
#  ifdef __GNUC__
#   define LIB_EXPORT  __cdecl
#  else
#   define LIB_EXPORT  __declspec(dllexport)
#  endif
# else
#  define LIB_EXPORT
# endif
#endif

Prepand to all public symbol the MACRO LIB_EXPORT, and build the source code with -DBUILD_DYN_LIB. And on Linux, add the linker flag -fvisibility=hidden

But if you want to achieve this with a static library (.a), well the only proper way is to put every private function in a namespace...

Also using a static library can be "dangerous": If your application provides the same symbol that it's provided in the static library, the linker will not warn (at least by default), the application will be linked/created. The linker will choose the symbol from the application and not from the static library.

If you could, you can patch all symbol of libbar.a using the trick described here : https://stackoverflow.com/a/6940389/808101

In your application, if you need to use a symbol (a function) from the "patched" libbar.a, you will have to prepend to the symbol name what you specified in --prefix-symbols

benjarobin
  • 4,410
  • 27
  • 21
  • I kind of guessed there's more flexibility when building dynamic libraries, but +1 nonetheless. Also, I'm willing to settle for a "non-proper" way... – einpoklum May 01 '18 at 11:32
  • 1
    @einpoklum I added a note to try to explain what's happen if the same symbol is in the static library and in the application code – benjarobin May 01 '18 at 11:48
  • 1
    I may have found a solution: https://stackoverflow.com/questions/10157680/how-can-i-get-gcc-to-add-a-prefix-to-all-symbol-names – benjarobin May 01 '18 at 12:09