Я пишу довольно большую библиотеку общих объектов C ++ и столкнулся с небольшой проблемой, которая затрудняет отладку:
Если я определяю функцию / метод в файле заголовка и забываю создать для него заглушку (во время разработки), поскольку я создаю как библиотеку общих объектов, а не исполняемый файл, во время компиляции не появляются ошибки, сообщающие мне, что у меня есть забыл реализовать эту функцию. Единственный способ узнать, что что-то не так, - это во время выполнения, когда в конечном итоге приложение, связывающееся с этой библиотекой, падает с ошибкой «неопределенный символ».
Я ищу простой способ проверить, есть ли у меня все символы, которые мне нужны, во время компиляции, возможно, что-то, что я могу добавить в свой Makefile.
Одно из решений, которое я придумал, - это запустить скомпилированную библиотеку, nm -C -U
чтобы получить разобранный список всех неопределенных ссылок. Проблема в том, что здесь также появляется список всех ссылок, которые находятся в других библиотеках, таких как GLibC, которые, конечно, будут связаны вместе с этой библиотекой, когда окончательное приложение будет собрано. Можно было бы использовать вывод nm
to для grep
всех моих файлов заголовков и посмотреть, соответствует ли какое-либо из имен .. но это кажется безумным. Конечно, это не редкость, и есть способ лучше ее решить?
источник
nm -C -u
спас меня несколько раз! (обратите внимание на строчные буквы-u
в моей системе.) Оставляю этот комментарий здесь, чтобы я мог найти его в следующий раз, когда он мне понадобится.Ответы:
Проверьте опцию компоновщика
-z defs
/--no-undefined
. При создании общего объекта это приведет к сбою ссылки, если есть неразрешенные символы.Если вы используете gcc для вызова компоновщика, вы будете использовать параметр компилятора,
-Wl
чтобы передать параметр компоновщику:В качестве примера рассмотрим следующий файл:
#include <stdio.h> void forgot_to_define(FILE *fp); void doit(const char *filename) { FILE *fp = fopen(filename, "r"); if (fp != NULL) { forgot_to_define(fp); fclose(fp); } }
Теперь, если вы встроите это в общий объект, все получится:
Но если вы добавите
-z defs
, ссылка не будет работать и сообщит вам о пропавшем символе:> gcc -shared -fPIC -o libsilly.so silly.c -Wl,-z,defs && echo succeeded || echo failed /tmp/cccIwwbn.o: In function `doit': silly.c:(.text+0x2c): undefined reference to `forgot_to_define' collect2: ld returned 1 exit status failed
источник
-Bsymbolic
их в командную строку компоновщика. Даже еслиforgot_to_define
теперь он существует в библиотеке благодаря-z
проверке, исполняемый файл все равно может переопределить его своим собственным определением, и собственные определения библиотеки перейдут на это переопределение;-Bsymbolic
заставляет вещи так, чтобы собственные определения библиотеки ее функций переходили в ее функции.// forgot_to_define(fp);
он не сообщит об ошибкеВ Linux (который, похоже, вы используете)
ldd -r a.out
должен дать вам именно тот ответ, который вы ищете.ОБНОВЛЕНИЕ: тривиальный способ создания,
a.out
по которому можно проверить:echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so ldd -r ./a.out
источник
А как насчет набора тестов? Вы создаете фиктивные исполняемые файлы, которые ссылаются на нужные вам символы. Если связывание не удалось, это означает, что интерфейс вашей библиотеки неполный.
источник
Однажды у меня была такая же проблема. Я разрабатывал компонентную модель на C ++, и, конечно же, компоненты должны загружаться во время выполнения динамически. На ум приходят три решения, которые я применил:
Надеюсь, это поможет.
источник