Легко проверить наличие неразрешенных символов в общих библиотеках? - PullRequest
75 голосов
/ 24 октября 2009

Я пишу довольно большую библиотеку разделяемых объектов C ++ и столкнулся с небольшой проблемой, которая затрудняет отладку:

Если я определяю функцию / метод в заголовочном файле и забываю создать заглушку для нее (во время разработки), так как я создаю библиотеку общих объектов, а не исполняемый файл, при сообщении во время компиляции ошибок не возникает Я забыл реализовать эту функцию. Единственный способ узнать, что что-то не так, - это во время выполнения, когда в конце концов приложение, связывающееся с этой библиотекой, падает с ошибкой «неопределенный символ».

Я ищу простой способ проверить, есть ли у меня все символы, которые мне нужны во время компиляции, возможно, что-то, что я могу добавить в свой Makefile.

Одно из решений, которое я нашел, - это запустить скомпилированную библиотеку через nm -C -U, чтобы получить разобранный список всех неопределенных ссылок. Проблема в том, что это также дает список всех ссылок, которые есть в других библиотеках, таких как GLibC, которые, конечно, будут связаны с этой библиотекой, когда окончательное приложение будет собрано. Можно было бы использовать вывод от nm до grep через все мои заголовочные файлы и посмотреть, соответствует ли какое-нибудь из имен ... но это кажется безумным. Конечно, это не редкая проблема, и есть лучший способ ее решения?

Ответы [ 4 ]

85 голосов
/ 04 ноября 2009

Проверьте опцию компоновщика -z defs / --no-undefined. При создании общего объекта это приведет к сбою связи при наличии неразрешенных символов.

Если вы используете gcc для вызова компоновщика, вы будете использовать опцию компилятора -Wl для передачи опции компоновщику:

gcc -shared ... -Wl,-z,defs

В качестве примера рассмотрим следующий файл:

#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);
    }
}

Теперь, если вы встраиваете это в общий объект, это будет успешно:

> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded

Но если вы добавите -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
13 голосов
/ 27 октября 2009

В Linux (который вы, похоже, используете) ldd -r a.out должен дать вам именно тот ответ, который вы ищете.

ОБНОВЛЕНИЕ: тривиальный способ создания a.out для проверки:

 echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
 ldd -r ./a.out
8 голосов
/ 24 октября 2009

А как насчет тестового набора? Вы создаете фиктивные исполняемые файлы, которые ссылаются на нужные вам символы. Если связывание не удается, это означает, что интерфейс вашей библиотеки неполон.

3 голосов
/ 24 октября 2009

Однажды у меня была такая же проблема. Я разрабатывал компонентную модель на C ++, и, конечно, компоненты должны загружаться динамически во время выполнения. На ум приходят три решения, которые я применил:

  1. Потратьте некоторое время, чтобы определить систему сборки, которая способна компилироваться статически. Вы потратите некоторое время на его разработку, но это сэкономит вам много времени на обнаружение этих досадных ошибок времени выполнения.
  2. Сгруппируйте свои функции в хорошо известные и понятные разделы, чтобы вы могли группировать функции / заглушки, чтобы быть уверенными, что у каждой соответствующей функции есть заглушка. Если вы хорошо потратите время на документирование, вы можете написать сценарий, который проверяет определения (например, с помощью комментариев doxygen) и проверяет соответствующий файл .cpp.
  3. Выполните несколько тестовых исполняемых файлов, которые загружают один и тот же набор библиотек и задают флаг RTLD_NOW для dlopen (если вы используете * NIX). Они будут сигнализировать пропущенные символы.

Надеюсь, это поможет.

...