How to apply -fvisibility option to symbols in static libraries?

Solution 1:

Simply pass -Wl,--exclude-libs,ALL to gcc

This will tell the linker to transform all the symbols in the static libraries to hidden.

--exclude-libs also accepts a list of archives (i.e. static library names) for finer granularity on which libraries to hide symbols from.

Note: this will only work in systems using GNU binutils (e.g. Linux) or with a linker supporting --exclude-libs (e.g. it won't work with OSX's ld64)

Solution 2:

Basically, visibility is handled during linking, and the linker doesn't seem impose it on static archives. A related question (though not a duplicate) was asked on SO here.

What I would advise you to do is to replace your linking stage: gcc -shared -o mylib.so foo.o libbar.a into a two stages process where you get back the object files:

  • ar x libbar.a (possibly into a suitable, empty directory)
  • gcc -fvisibility=hidden -shared -o mylib.so foo.o tempdir/*.o

Solution 3:

This is an answer to the problem for OS X.

The Mac ld doesn't support --exclude-libs, but it does support -exported_symbol sym and it does apply this to object files in static libraries. And when you're filtering to a public API, the whitelist is small enough to spell it out.

I ended up with the following in my Makefile to generate a -Wl,-exported_symbol,_api_func_1 flag for each exported symbol:

SYMBOLS   = api_func_1 api_func_2 api_func_3 api_func_4
SYMBOLS   += api_func_5 # add more as necessary
COMMA     = ,
LDFLAGS   += $(addprefix -Wl$(COMMA)-exported_symbol$(COMMA)_,$(SYMBOLS))

# ...

libmyapi.so: # ...
    $(CC) -shared -o $@ ... $(LDFLAGS)

Then you can if-gate between this version of the flags and the GNU ld version after detecting which linker the system has.