Я пытаюсь построить проект в Visual Studio 2012, который использует GnuTLS. Я скачал последнюю официальную сборку Windows с веб-сайт, и создал библиотеку ссылок, запустив lib /def:libgnutls-28.def
в каталоге bin создайте командную строку Visual Studio.
После добавления typedef long ssize_t
, код компилируется нормально, но связывание завершается ошибкой со следующей ошибкой:
source_file.obj : error LNK2001: unresolved external symbol _gnutls_free
C:\Path\to\executable.exe : fatal error LNK1120: 1 unresolved externals
я звоню gnutls_free
освободить часть памяти, выделенной и возвращенной библиотекой. Если я удалю звонок gnutls_free
проект успешно связан. При условии gnutls_free
это просто глобальная переменная (содержащая указатель на функцию), экспортируемая библиотекой, я не уверен, почему доступ к ней приводит к неразрешенной ссылке на другой символ. Я подтвердил, что gnutls_free
не является #define
к чему угодно.
В качестве теста я попытался сделать gnutls_free_function test = gnutls_free;
что также приводит к ошибке ссылки. Бег grep -w -r _gnutls_free .
на исходный код GnuTLS ничего не возвращает, поэтому я в растерянности.
Любые идеи для получения этой работы будет принята с благодарностью.
РЕДАКТИРОВАТЬ:
Добавление __declspec(dllimport)
к декларации gnutls_free
в gnutls.h
позволяет ссылку на успех. Есть ли способ сделать это без поддержки пользовательской версии файла заголовка?
Похоже, не существует способа, чтобы компоновщик или библиотека импорта автоматически разыменовывали указатель IAT на элемент данных так же, как это делается для функций (с помощью небольшой функции батута, которая статически связана с модулем, импортирующим функцию). , __declspec(dllimport)
Атрибут сообщает компилятору о необходимости разыменования, чтобы он мог вставлять код для неявного выполнения разыменования указателя IAT. Это позволяет получить доступ к экспортированным данным, а для функций позволяет компилятору вызывать импортированную функцию посредством косвенного вызова через указатель IAT, а не путем вызова функции батута.
Посмотрите пару статей Рэймонда Чена о dllimport
для хорошего объяснения того, что происходит для вызовов функций (к сожалению, он не обсуждал импорт данных):
Компоновщик MS или библиотека импорта не имеют механизма, который помог бы компилятору получать импортированные данные «наивным» способом — компилятору требуется __delcspec(dllimport)
намек на то, что требуется дополнительная разыменование через IAT. В любом случае, смысл всего этого в том, что кажется, что нет способа импортировать данные, кроме как с помощью __declspec(dllimport)
приписывать.
Если вы хотите избежать изменения gnutls
распределение (которое я могу понять), вот один довольно несовершенный обходной путь:
Вы можете создать небольшой объектный файл, который не содержит ничего, кроме простой оболочки для gnutls_free()
; поскольку gnutls_free()
имеет интерфейс без реальных зависимостей, вы можете иметь необходимые декларации «жестко» вместо того, чтобы включать gnutls.h
:
typedef void (*gnutls_free_function) (void *);
__declspec(dllimport) extern gnutls_free_function gnutls_free;
void xgnutls_free(void* p)
{
gnutls_free(p);
}
Ваш код звонка xgnutls_free()
вместо gnutls_free()
,
Не очень хорошее решение — требует, чтобы ваш код вызывал оболочку (так что это не очень хорошо, если вы включаете сторонний код, который может зависеть от gnutls_free()
), но это может быть достаточно хорошо.
Других решений пока нет …