Предупреждение компоновщика "второе определение игнорируется" при включении двух библиотек с одинаковыми именами функций

контекст

Я работаю над проектом, предназначенным для отправки определенных команд на устройство. Каждое устройство может быть связано с DLL (например, deviceADll.h, deviceBDll.h), и я не программировал Dll, и я не могу изменять их каким-либо образом. Я отвечаю за интеграцию DeviceB в проект с минимальными изменениями в структуре проекта. Я знаю, что структура не может быть оптимальной и / или хорошо спроектированной, поэтому я готов принять предложение по этому вопросу в качестве последнего средства решения.

Поскольку устройства очень похожи, все функции Dll имеют одинаковое имя и часто один и тот же прототип.

Также из-за этого я создал родительский класс (Device_ts.h), от которого наследуются DeviceA_ts.h и DeviceB_ts.h (у меня также есть фабричный класс для устройств, но я не думаю, что он имеет отношение к моей проблеме),

проблема

Проблема возникает, когда я пытаюсь включить оба Dlls: проект компилируется, но я получаю

Warning 60 warning LNK4006: Connect@12 already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name

с последующим

Warning 61 warning LNK4006: __imp__Connect@12 already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name

и

Warning 62 warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name

Кто-нибудь сталкивался с подобной ситуацией? Должен ли я игнорировать эти предупреждения или я не смогу позвонить DeviceB.h функции, так как их определения игнорируются?

Я использую Visual Studio 2010, Device_ts.h Библиотека, которую я пишу, является статической библиотекой, и все параметры проекта (например, /MD, включают в себя каталоги, зависимости, MFC и т. д.) установлены правильно из того, что я нашел в своем исследовании этой проблемы.

Код

Код include и выглядит следующим образом (я покажу только одну из функций, вызывающих предупреждение, поскольку я получаю ту же ошибку для 50 функций):

DeviceADll.h

#ifndef DEVICEA_H__
#define DEVICEA_H__

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

namespace DeviceA
{
// some struct definition that don't cause the linker warnings
//...

// function definitions
extern "C" HANDLE PASCAL EXPORT Connect( HANDLE h_devA, const char *ip);
// ...
} // namespace DeviceA

DeviceBDll.h

#ifndef DEVICEB_H__
#define DEVICEB_H__

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

namespace DeviceB
{
// some struct definition that don't cause the linker warnings
//...

// function definitions
extern "C" HANDLE PASCAL EXPORT Connect( HANDLE h_devB, const char *ip);
// ...
} // namespace DeviceB

Device_ts.h

#ifndef DEVICE_FCT_H_
#define DEVICE_FCT_H_
#ifndef EXPORT
#define EXPORT
#endif

#if _MSC_VER > 1000
#pragma once
#endif

#include "DeviceADll.h"
#include "DeviceBDll.h"

class CDevice {
public:
    virtual BOOL Connect(char *ip_addr) = 0;
};
#endif DEVICE_FCT_H_

1 ответ

Решение

Это хороший вариант использования для ручной загрузки DLL, используя LoadLibrary() а также GetProcAddress(),

Вам придется управлять указателем на функцию для каждой функции, которая выглядит таким образом, что немного болезненно, но обход загрузки dll в ОС дает вам большую гибкость.

Также обратите внимание, что вам не нужно ссылаться на DLL при использовании этого метода, связывание DLL является 100% времени выполнения, и компоновщик не участвует вообще.

Вот пример:

typedef void (*connect_fn)(HANDLE, const char*);

connect_fn connect_a;
connect_fn connect_b;

int main()
{
  HINSTANCE dll_a = LoadLibrary("path_to_dll_a.dll");
  HINSTANCE dll_b = LoadLibrary("path_to_dll_b.dll");

  if (!dll_a || !dll_b) {
    return 1;
  }

  connect_a = (connect_fn)GetProcAddress(dll_a , "Connect");
  connect_b = (connect_fn)GetProcAddress(dll_b , "Connect");

  // connect_a and connect_b can now be used.
  return 0;
}

Изменить: По сути, я предлагаю вам относиться к DLL устройства как плагины, а не динамические библиотеки.

Другие вопросы по тегам