#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. В любом случае, рецепт:
-
#define PUBLIC __attribute__ ((visibility("default")))
затем отметьтеmyfn()
какPUBLIC
inmyfn.c
. Больше ничего не отмечайтеPUBLIC
. -
Скомпилируйте объекты с
gcc -c foo.c bar.c baz.c myfn.c -fvisibility=hidden
помощью , которая помечает все как скрытые, за исключениемmyfn()
. -
Создайте удобный архив, используя
ld
переключатель частичного связывания:ld -r foo.o bar.o baz.o myfn.o -o libmyfn.a
-
Локализуйте все, что не
PUBLIC
было таким:objcopy --localize-hidden libmyfn.a
-
Теперь
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
, и затем код, не предназначенный для сборки, находится в разделах #ifndefLIBRARY_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.