سؤال

أحاول إنشاء مكتبة مجمعة باستخدام مترجم 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.bat

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;

يجب أن ينتقل التعريف إلى ملف التعليمات البرمجية المصدر في مكان ما (وليس بشكل عام في ملف رأس).يخبر هذا المترجم بتخصيص مساحة في كود الكائن لهذا الكائن ويسمح للبرنامج بالارتباط بنجاح.

نصائح أخرى

لا، لم يتم تعريفه (على الأقل فيما نقلته).لقد تم الإعلان عنه.تعني الكلمة الرئيسية "الخارجي" "تعريف هذا الرمز في وحدة تجميع أخرى (ملف المصدر)." يجب أن تربط ملف الكائن (أو المكتبة) المنتجة من تجميع الملف المصدر الذي يحدد هذا الرمز.

لقد واجهت مشكلة مشابهة جدًا في إنشاء NIF على نظام التشغيل Windows.لم يتم حل الرمز الخارجي _WinDynNifCallbacks.تبين أن هذا يتم تعريفه بواسطة الماكرو ERL_NIF_INIT وفي حالتي يلزم وضع الماكرو بالكامل في كتلة C خارجية.

أي فشل هذا

extern "C" ERL_NIF_INIT(...)

بينما نجح هذا

extern "C"
{
   ERL_NIF_INIT(...)
}

أظن بشدة أن هذه المشكلة ترجع إلى نفس المشكلة ولكن مع الماكرو DRIVER_INIT لبرنامج تشغيل منفذ erlang.

Driver_init هي الحلقة الرئيسية التي تعلن "TwindyndriverCallbackss WindyndriverCallbacks ؛" ولكن تم الإعلان عنها بشكل صحيح في الخط المتعدد تحديد Driver_init.لا يجب أن تحتاج إلى تغليفه بحرف "c" الخارجي.

نظرًا لأن هذا الموضوع قد ظهر حوالي مليون مرة أثناء محاولتي إعداد برنامج تشغيل منفذ Erlang المجرد الخاص بي، فسوف أقول هذا هنا.أنا أعمل على كتاب إرلانج للبرمجة لجو أرمسترونج، الفصل 12 من تقنيات التواصل.باستخدام erl5.9 و vs2010.

الكود الموجود في الكتاب به إغفال وخطأ في example1_lib.c.على الرغم من أن الخطأ يرجع على الأرجح إلى عمر الكتاب مقابل تغييرات إصدار erlang.

مطلوب لضبط (#define WIN32) في الجزء العلوي من example1_lib.c وإلا فإن erlang سيختار جميع خيارات Linux بشكل افتراضي.

ثانيًا، يلزم تغيير (int bufflen) إلى (ErlDrvSizeT bufflen) في example_drv_output.

بعد ذلك بنيت نظيفة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top