Сбит с толку неразрешенной ошибкой внешнего символа
-
20-09-2019 - |
Вопрос
Я пытаюсь создать библиотеку-оболочку с помощью компилятора VC ++.
ErlDriver.c
#define __WIN32__
#define DLL_EXPORT __declspec(dllexport)
#include "erl_driver.h"
DLL_EXPORT int _driver_output(ErlDrvPort port, char *buf, int len) {
return driver_output(port, buf, len);
}
build.летучая мышь
cl /I%ERL_DRIVER_H% /LD /MD ErlDriver.c
Когда я пытаюсь создать это, я получаю следующую ошибку компоновщика:
ErlDriver.obj :ошибка LNK2019:неразрешенный внешний символ _WinDynDriverCallbacks, на который ссылается функция __driver_output
erl_win_dyn_driver.h (включено в erl_driver.h)
typedef struct {
WDD_FTYPE(driver_output) *driver_output;
// a ton more of those
} TWinDynDriverCallbacks;
extern TWinDynDriverCallbacks WinDynDriverCallbacks;
#define driver_output (WinDynDriverCallbacks.driver_output)
Итак, как вы можете видеть, WinDynDriverCallbacks - это определенный объявлено.
Тогда что может быть причиной ошибки компоновщика?
Решение
Существует тонкая разница между "объявлением" чего-либо и "определением" этого в C или C ++.Когда вы объявляете его, он сообщает компилятору, что определенный символ будет определен где-то еще - это может позволить коду использовать этот символ без необходимости видеть фактическое определение.Вам все равно придется определить символ где-нибудь в коде, на который дана ссылка, иначе вы получите сообщение об ошибке, которое видите.
Например, это объявление символа WinDynDriverCallbacks
:
extern TWinDynDriverCallbacks WinDynDriverCallbacks;
В вашем коде есть это объявление - оно позволяет коду, использующему символ, успешно компилироваться (но не связываться).
Вам нужно где-то добавить определение:
TWinDynDriverCallbacks WinDynDriverCallbacks;
Определение должно быть где-то в файле исходного кода (обычно не в заголовочном файле).Это указывает компилятору выделить место в объектном коде для этого объекта и позволяет программе успешно выполнить связывание.
Другие советы
Нет, это не определено (по крайней мере, в том, что вы процитировали).Это объявлено.Ключевое слово "extern" означает "определение этого символа появляется в другом модуле компиляции (исходном файле)". Вам необходимо установить связь с объектным файлом (или библиотекой), созданным в результате компиляции исходного файла, который определяет этот символ.
У меня возникла очень похожая проблема с созданием NIF в Windows.Неразрешенный внешний символ _WinDynNifCallbacks.Оказывается, это определяется макрокомандой ERL_NIF_INIT, и в моем случае весь макрос должен был быть заключен во внешний блок C.
т.е. это не удалось
extern "C" ERL_NIF_INIT(...)
пока это удавалось
extern "C"
{
ERL_NIF_INIT(...)
}
Я сильно подозреваю, что эта проблема связана с той же проблемой, но с макрокомандой DRIVER_INIT для драйвера порта erlang.
Driver_Init - это основной цикл, который объявляет "TWinDynDriverCallbacks WinDynDriverCallbacks;" но он правильно объявлен в многострочном определении для driver_init .Вам не нужно будет оборачивать его во внешнюю букву "c".
поскольку эта тема возникала около миллиона раз при попытке настроить мой драйвер порта barebones erlang, я скажу это здесь.Я работаю над книгой Джо Армстронга "Программирование на эрланге", глава 12 "Методы взаимодействия".Используя erl5.9 и vs2010.
Код в книге содержал упущение и ошибку в example1_lib.c.Хотя ошибка, скорее всего, связана с изменением возраста книги по сравнению с версией erlang.
Необходимо установить (#define WIN32) в самом верху example1_lib.c в противном случае erlang по умолчанию использовал все параметры Linux.
Во-вторых, необходимо изменить (int bufflen) на (ErlDrvSizeT bufflen) в example_drv_output.
После этого он стал чистым.