2017-08-18 11 views
2

デバイスに特定のコマンドを送信するために設計されたプロジェクトに取り組んでコンテキストリンカは、同じ関数名

イムを持つ2つのライブラリを含む「無視2番目の定義」を警告します。各デバイスはdll(例えばdeviceADll.h、deviceBDll.h)とインターフェースすることができ、Dllは私によってプログラミングされていないし、何らかの形でそれらを変更することもできない。私は、プロジェクトの構造を最小限に変更して、DeviceBをプロジェクトに統合する役割を担っています。私はその構造が最適ではなく、そして/またはうまく設計されていない可能性があることを知っているので、私は最後の手段としてその問題に関する提案をしたいと思っています。

デバイスは非常に似ているので、すべてのDll関数は同じ名前であり、多くの場合同じプロトタイプです。

このため、私はDeviceA_ts.hとDeviceB_ts.hが継承している親クラス(Device_ts.h)を作成しました(私はDevicesクラスのファクトリクラスも持っていますが、私の問題に)。

私は両方のDLLを含めるしようとすると、問題

は、問題が発生します。プロジェクトはコンパイルが、私は

Warning 61 warning LNK4006: [email protected] already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name

続い

Warning 60 warning LNK4006: [email protected] 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_ 
+0

あなたは 'DeviceADll'および/または' DeviceBDll'の静的にリンクされたバージョンへのアクセスを持っていますか?そうであれば、自分自身で2つのDLLを作成することができます。それぞれはデバイスライブラリの1つにリンクし、衝突しないシンボルのみをエクスポートします。 – Frank

+0

DLLは別のチームによって開発されているので、彼らは、DLLのように、将来のバージョンでは、それぞれの新しいリリースで書き換えする必要はありませんとして滞在する必要があります。通常はそれほど悪くはありませんが、これらのファイルはそれぞれ5000行ですので、実際には理想的ではありません –

+0

オフトピック:これらの2重の下線に注意してください。ダブルアンダースコアの識別子は、ライブラリの実装で使用するために予約されています。 – user4581301

答えて

2

これはLoadLibrary()GetProcAddress()を使用して、手動DLLのローディングのための良好なユースケースです。

あなたは各関数の関数ポインタを管理する必要がありますが、痛みのビットであるこのように、見上げたが、OSの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を扱う示唆

は、ここでの例です。

+0

あなたの答えをありがとう。私は、Dllのロードは「実行時」に行われ、コンパイル時には実行されないことを知っています。ライブラリ(Device_ts.h)は静的ライブラリなので、Dllもロードできますか?また、関連する子クラス(DeviceA_ts.hとDeviceB_ts.h)に各Dllをロードする必要がありますね。 –

+0

@Maxダンラプラス「通常」のDLLの使用時には、(DLLの読み込み時にOSが提出されるアドレステーブルが構築されている)、コンパイル時に行わいくつかの部分的なリンクが依然としてあります。コンパイル時にDLLをリンクすることでこれを参照します。 – Frank

+0

各クラスにロードする限り、それは多くの要素に依存する設計上の決定です。たとえば、すべてのdllに同じシンボルがある場合、そのコンストラクタでDLLパスを受け取り、各デバイスに注入依存として渡す一般的な 'DeviceType'クラスを作成します。 – Frank