Как применить параметр -fvisibility к символам в статических библиотеках?

У меня есть проект общей библиотеки, который построен из 4 статических библиотек (.a) и одного файла объекта (.o). Я пытаюсь добавить параметр -fvisibility=hidden, чтобы ограничить символы в выводе только теми, которые я помечаю в источнике с помощью __attribute__.

Я добавил параметр -fvisibility=hidden в параметры компиляции для проекта .so (который охватывает файл .o) и для проектов .a.

Символы в объектном файле, как и ожидалось, удаляются из окончательного .so. Однако символы из проектов .a все еще находятся в окончательном файле .so. Добавление параметра -fvisibility=hidden к команде ссылки .so не имеет никакого эффекта.

Что я делаю неправильно?

Моя цель здесь - удалить из .so все символы, кроме функций интерфейса к библиотеке.

РЕДАКТИРОВАТЬ: я на самом деле использовал карту версий, чтобы решить эту проблему. Однако это требует постоянного обслуживания скрипта версии по мере изменения внешних символов. Принятый ответ дает лучшее представление.


person Steve Fallows    schedule 08.02.2010    source источник
comment
Платформа не упоминается, но решение для этого под iOS / OS X см. stackoverflow.com/a/18949281/316487   -  person bleater    schedule 30.07.2015


Ответы (3)


По сути, видимость обрабатывается во время компоновки, и компоновщик, похоже, не навязывает ее статическим архивам. Связанный вопрос (хотя и не повторяющийся) был задан здесь.

Я бы посоветовал вам заменить стадию связывания: gcc -shared -o mylib.so foo.o libbar.a на двухэтапный процесс, в котором вы получаете обратно объектные файлы:

  • ar x libbar.a (возможно, в подходящий пустой каталог)
  • gcc -fvisibility=hidden -shared -o mylib.so foo.o tempdir/*.o
person F'x    schedule 12.02.2010
comment
Хорошая идея. Соответствует тому, что я узнал экспериментально. Может попробовать позже. - person Steve Fallows; 12.02.2010
comment
Я просто хотел бы уточнить, где правильное место для добавления -fvisibility=hidden. Согласно GCC Visibility Wiki в разделе Как использовать новую поддержку видимости C ++ указано, что измените вашу систему make, чтобы передавать -fvisibility = hidden каждому вызову GCC, компилирующего исходный файл.. Поэтому мне было интересно, действительно ли вам нужно устанавливать флаг видимости при создании объекта so. - person McLeary; 25.09.2018
comment
В чем будет разница между -fvisibility=hidden и -s? - person ar2015; 25.09.2018
comment
Можно ли восстановить архив без экспорта? В основном получение статической библиотеки .a из * .o, которая не будет втягивать экспорт при компоновке в разделяемой библиотеке? - person ceztko; 08.04.2020

Просто передайте -Wl,--exclude-libs,ALL в gcc

Это скажет компоновщику преобразовать все символы в статических библиотеках в скрытые.

--exclude-libs также принимает список архивов (т. Е. Статических имен библиотек) для более точной детализации, от каких библиотек нужно скрывать символы.

Примечание: это будет работать только в системах, использующих GNU binutils (например, Linux) или с компоновщиком, поддерживающим --exclude-libs (например, он не будет работать с OSX ld64)

person fons    schedule 13.02.2013
comment
Большое вам спасибо! Я использую это вместе с -fvisibility = hidden и выборочно экспортирую только общедоступный API (IMO только подход с использованием белых списков является разумным, особенно когда речь идет о статических библиотеках, внешних по отношению к проекту). Возможно, если вы сможете добавить несколько тегов, будущие сотрудники Google будут вам благодарны. - person dashesy; 28.02.2013
comment
Я считаю, что это -Wl, - exclude-libs = ALL (замените вторую запятую на =) - person Nathan Monteleone; 04.07.2013
comment
К сожалению, это не работает в Mac OS, поскольку ld не знает эту опцию в Mac OS. - person rsp1984; 06.08.2014
comment
Кроме того, --exclude-libs применим только к статическим библиотекам, но не к динамическим библиотекам. - person Manish Shukla; 10.10.2014
comment
@ManishShukla Вопрос конкретно о статических библиотеках - person fons; 10.10.2014
comment
Я заметил, что это не будет надежно исключать символы при компиляции с оптимизацией времени компоновки. - person Alexey B.; 21.02.2019
comment
Это так мне помогло, что я потратил много времени, пытаясь скрыть ненужные символы, а также имел дело с ошибками компилятора, которые в некоторых случаях не устанавливали видимость правильно. Но это вместе с visibility = hidden просто исправляет ситуацию и заставляет работать должным образом. Я не совсем уверен, почему это не поведение по умолчанию для разделяемых библиотек. - person jozols; 30.04.2019
comment
Это очень хороший ответ, но тот факт, что этот переключатель в настоящее время недоступен в MacOSX, является большим ограничением. Иногда статические зависимости сторонних разработчиков втягивают кучу нежелательных символов, и часто их компиляция без экспорта требует модификации исходного кода. Можно ли просто удалить экспортированные символы из архива статической библиотеки (.a)? Если да, то как? - person ceztko; 08.04.2020

Это ответ на проблему для OS X.

Mac ld не поддерживает --exclude-libs, но поддерживает -exported_symbol sym и применяет к объектным файлам в статических библиотеках. И когда вы фильтруете общедоступный API, белый список достаточно мал, чтобы его можно было подробно описать.

В моем Makefile я получил следующее, чтобы сгенерировать флаг -Wl,-exported_symbol,_api_func_1 для каждого экспортированного символа:

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)

Затем вы можете использовать if-gate между этой версией флагов и версией GNU ld после определения, какой компоновщик есть в системе.

person Riking    schedule 30.05.2018
comment
@Mecki В чем разница между нормальным -l и -hidden-l? - person Danra; 11.03.2021
comment
@Danra -l экспортирует символы в зависимости от их видимости. OP сказал, что он сделал все символы скрытыми по умолчанию с помощью -fvisibility=hidden, поэтому -l не будет экспортировать их по умолчанию. Если вы хотите экспортировать их, вам нужно использовать -reexport-l, который всегда будет экспортировать символы, независимо от видимости. Аналогом является -hidden-l, который никогда не будет экспортировать символы, независимо от видимости. Я признаю, что мой комментарий плохо сформулирован, извините за это. - person Mecki; 11.03.2021
comment
Итак, в macOS, чтобы избежать повторного экспорта символов видимости статической библиотеки по умолчанию из исполняемого файла, связанного с библиотекой, следует использовать -hidden-l? (при условии, что не указаны ручные -exported_symbols и т.п.) - person Danra; 11.03.2021