包含两个具有相同函数名称的库时,链接器警告“忽略第二个定义”

MDL*_*MDL 3 c++ dll visual-studio linker-warning

语境

我正在开发一个旨在向设备发送某些命令的项目。每个设备都可以与一个 dll 连接(例如 deviceADll.h、deviceBDll.h),并且这些 Dll 不是由我编写的,我也不能以任何方式修改它们。我负责将DeviceB集成到项目中,对项目结构进行最小的更改。我知道该结构可能不是最佳的和/或设计良好的,因此我愿意接受有关该问题的建议作为最后的解决方案。

由于设备非常相似,因此所有 Dll 函数都具有相同的名称,并且通常具有相同的原型。

也正因为如此,我创建了一个父类(Device_ts.h),DeviceA_ts.h和DeviceB_ts.h继承自该父类(我也有一个设备的工厂类,但我认为它与我的问题无关) 。

问题

当我尝试包含两个 Dll 时出现问题:项目编译,但我得到一个

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 等)都是根据我在这个问题的研究中发现的内容正确设置的。

代码

包含和代码如下所示(我将仅显示导致警告的函数之一,因为我在 50 个函数上遇到了相同的错误):

设备ADll.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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

设备_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_
Run Code Online (Sandbox Code Playgroud)

小智 5

这是手动 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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:基本上,我建议您将设备 DLL 视为插件,而不是动态库。