4

I have a C library in an archive file, clib.a. I've written a C++ wrapper for it, cpp.o, and would like to use this as a static library:

ar cTrvs cppwrap.a clib.a cpp.o

Code which links to this won't be able to use the stuff from clib.a directly unless the correct header is included. However, if someone coincidentally creates an appropriate prototype -- e.g. void myCoincidentallyNamedGlobalFunction() -- I'm concerned which definition of myCoincidentallyNamedGlobalFunction will apply.

Since the symbols from clib.a only need to be accessed in cpp.o, and not anything linked to cppwrap.a, is there a way to completely hide them so that there is no possible collision (so even including the clib header would fail)?

CodeClown42
  • 11,194
  • 1
  • 32
  • 67
  • Is `clib.o` something you're building yourself, or a monolithic binary you're handed by someone else that you want to wrap? – Jeff May 15 '14 at 13:14
  • @Jeff I'm building it, yes. – CodeClown42 May 15 '14 at 13:26
  • 1
    So you have a couple options then, I think. You can hide methods/variables you don't want to export in anonymous namespaces, which is probably the cleanest way, or you can manually `strip -N` or `objcopy -N` symbols you don't want exposed from your final distributed library. – Jeff May 15 '14 at 13:27
  • OK, this might be dumb, but could he put clib.o in its own library, scrub the names and then archive that into cppwrap.a ? – Jiminion May 15 '14 at 13:33
  • OK, maybe not totally dumb, as Jeff thinks the same thing. I though symbol stripping mostly applied to debugging though.... – Jiminion May 15 '14 at 13:34
  • @Jeff If so I don't see it (multiple questions). It could be phrased *"How can I link `cpp.o` to `clib.o` in `cppwrap.a` without exporting the symbols in `clib.o` via `cppwrap.a`?"* `clib.o` is actually an archive itself (`clib.a`), if that makes any difference (I've edited the question to this effect) – CodeClown42 May 15 '14 at 13:39
  • @Jeff - you're right, this doesn't apply here. Removing. – Andy May 15 '14 at 13:43

1 Answers1

3

You can manually remove unneeded symbols on the final combined library:

$ objcopy -N foo cppwrap.a (remove symbol)

Or, if you need the symbols but want to make sure that external users can't get to them:

$ objcopy -L bar cppwrap.a (localize symbol)

Or, if a symbol in clib.a must be visible by something in cpp.o but you don't want it to be used by anyone else:

$ objcopy -W baz cppwrap.a (weaken symbol)

In this case, collisions with symbols from other object files/libraries will defer to their usage, even though the symbol will still be visible. To obscure things further or to reduce chances of even a deferential collision, you can also use:

$ objcopy --redefine-sym old=new cppwrap.a

An anonymous namespace may help in some cases, but not if there's functionality that your wrapper needs but is trying to hide from external users.

Jeff
  • 3,475
  • 4
  • 26
  • 35
  • The `namespace` solution will of course make it impossible for the functions in `cpp.o` to call the functions in `clib.o`. – Some programmer dude May 15 '14 at 13:43
  • `objcopy` returns *"not stripping symbol 'baz' because it is named in a relocation"*. Unless I misunderstand your example, using a namespace is no good since A) the code compiled into `clib.o` is C code, B) I don't want to have to modify clib at all, I just want to blackbox it completely inside the archive. – CodeClown42 May 15 '14 at 13:48
  • Right, it wasn't clear to me at first whether she needed to simply obscure superfluous symbols or is trying to ensure that core functionality can only be accessed through the cpp.o symbol names. – Jeff May 15 '14 at 13:49
  • @goldilocks OK, I think I see where you are a bit better now. Try `objcopy -L baz cppwrap.a` to localize a symbol. – Jeff May 15 '14 at 13:50
  • Hmmph. `objcopy -L baz` sounds right to me but then says, `whereX/whereX/clib.o: No such file or directory` although `ar -t cppwrap.a` lists `clib.o` and `whereX/clib.o` is created-- maybe that is a separate dilemma to do with `ar -T` ? :\ – CodeClown42 May 15 '14 at 13:56
  • OK, as kind of a hack you can try `objcopy -W baz clib.a` before you `ar` it together. This keeps the symbol global but flags it as "weak", such that colliding symbols in later links will override it by default. – Jeff May 15 '14 at 13:59
  • Works for me -- you should mention that in the answer (I was ignorant of `objcopy` until now, it seems the right approach in context). Thx. – CodeClown42 May 15 '14 at 14:06
  • Glad my solution works for you, but I'm not sure that it's really the cleanest possible. If you are building both `clib.a` and the wrappers, you might want to endeavor to actually build the individual `.o` components with their respective C++ wrapper symbols so that you can truly remove the C symbols, rather than obscure or weakening them. – Jeff May 15 '14 at 14:23