Видимость символов C в статических архивах

#c #gcc #linker #visibility #symbols

#c #gcc #компоновщик #видимость #символы

Вопрос:

У меня есть файлы foo.c bar.c и baz.c, а также код-оболочка myfn.c, определяющий функцию myfn(), которая использует код и данные из этих других файлов.

Я хотел бы создать что-то вроде объектного файла или архива, myfn.o или libmyfn.a, чтобы myfn() можно было сделать доступным для других проектов, не экспортируя также загрузку символов из {foo, bar,baz}.o .

Как правильно это сделать в Linux / gcc? Спасибо.


Обновление: я нашел один способ сделать это. Изначально я должен был подчеркнуть, что речь идет о статических архивах, а не о DSO. В любом случае, рецепт:

  1. #define PUBLIC __attribute__ ((visibility("default"))) затем отметьте myfn() как PUBLIC in myfn.c . Больше ничего не отмечайте PUBLIC .

  2. Скомпилируйте объекты с gcc -c foo.c bar.c baz.c myfn.c -fvisibility=hidden помощью , которая помечает все как скрытые, за исключением myfn() .

  3. Создайте удобный архив, используя ld переключатель частичного связывания: ld -r foo.o bar.o baz.o myfn.o -o libmyfn.a

  4. Локализуйте все, что не PUBLIC было таким: objcopy --localize-hidden libmyfn.a

  5. Теперь nm говорится myfn , что это единственный глобальный символ, libmyfn.a и последующее связывание с другими программами работает просто отлично: gcc -o main main.c -L. -lmyfn (здесь программа вызывает myfn() ; если он попытается вызвать foo() , компиляция завершится неудачей).

Если я использую ar вместо ld -r на шаге 3, то компиляция завершается с ошибкой на шаге 5: я предполагаю ar , что он не связан foo с etc myfn и больше не может, как только эти функции будут локализованы, тогда ld -r как разрешает ссылку до ее локализации.

Я бы приветствовал любой ответ, который подтверждает, что это «правильный» способ, или описывает более простой способ достижения того же.

Комментарии:

1. Правильным способом было бы найти литературу или учебное пособие по созданию библиотек.

2. Сделай мне одолжение, отправив это в качестве ответа, Юджин, чтобы я мог проголосовать против него. Спасибо.

Ответ №1:

К сожалению, привязка C для глобальных файлов — это все или ничего, в том смысле, что глобальные файлы всех модулей будут доступны в libmyfn.a окончательном списке внешних символов.

gcc tool chain предлагает расширение, которое позволяет скрывать символы от внешних пользователей, делая их доступными для других единиц перевода в вашей библиотеке:

foo.h:

 void foo();
  

foo.c:

 void foo() __attribute__ ((visibility ("hidden")));
  

myfn.h:

 void myfn();
  

myfn.c:

 #include <stdio.h>
#include "foo.h"

void myfn() {
    printf("calling foo...n");
    foo();
    printf("calling foo again...n");
    foo();
}
  

Для удобства переносимости вам, вероятно, было бы полезно создать макрос для __attribute__ ((visibility ("hidden"))) и поместить его в условный блок компиляции, обусловленный gcc .

Кроме того, Linux предлагает утилиту called strip , которая позволяет удалять некоторые символы из скомпилированных объектных файлов. Опции -N и -K позволяют идентифицировать отдельные символы, которые вы хотите сохранить или удалить.

Комментарии:

1. Кажется, это ответ, наиболее близкий к моему первоначальному, не очень хорошо сформулированному вопросу. Возможно, вы могли бы еще раз взглянуть на вопрос, который я отредактировал, и сообщить мне, что вы думаете о предлагаемом решении?

2. @PythonAteMyHamster Ваш новый подход к маркировке некоторых функций общедоступными и удалению всего остального выглядит правильно.

3. Я дам ему час, но если никто не опубликует ничего лучшего, тогда вы получите галочку с правильным ответом.

Ответ №2:

Начните с этого, чтобы создать статическую библиотеку

 gcc -c -O2 foo.c bar.c baz.c myfn.c
ar av libmyfunctions.a foo.o bar.o baz.o myfn.o
  

Компилируйте и соединяйте с другими программами, такими как:

 gcc -O2 program.c -lmyfunctions -o myprogram
  

Теперь у libmyfunctions.a вас в конечном итоге будет дополнительный материал из источника, который не требуется кодом в myfn.c, но компоновщик должен выполнить разумную работу по удалению этого при создании окончательной программы.

Комментарии:

1. Спасибо, Селби, но этот «дополнительный материал» был именно той проблемой, которую я пытался устранить, когда задавал вопрос!

2. Компоновщик удалит неиспользуемый объектный код для вас. Но если вы пытаетесь минимизировать размер вашего . файл библиотеки, тогда вам понадобится пользовательская сборка. (например #define LIBRARY_BUILD 1 , и затем код, не предназначенный для сборки, находится в разделах #ifndef LIBRARY_BUILD .

3. Селби, речь шла не о контроле того, какой объектный код извлекает компоновщик, а об ограничении видимости символов в libmyfn.a только теми, которые представляют API (а не все другие функции, реализующие API). Мой обновленный пост теперь показывает один из способов достижения того, чего я хотел. Все равно спасибо.

Ответ №3:

Предположим, что myfn.c имеет функцию myfun(), которую вы хотите использовать в других трех файлах foo.c, bar.c и baz.c

Теперь создайте общую библиотеку из кода в myfn.c, а именно libmyf.a

Используйте вызов этой функции myfun() в трех других файлах. Объявите функцию как extern в этих файлах. Теперь вы можете создать объектный код этих файлов и связать файл libmyf.a на этапе компоновки.

Обратитесь к следующей ссылке для использования разделяемых библиотек.

http://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html

Комментарии:

1. Спасибо Pankaj, но я в основном знаю, как создавать библиотеки; чего я не знал, так это как управлять видимостью символов. Думаю, теперь я понял.

2. gcc.gnu.org/wiki/Visibility Приведенная выше страница подтверждает ваше решение, а также предоставляет другой метод с использованием #pragmas.