2010-02-11 42 views
3

我正在努力讓rLog在Windows下作爲一個DLL來構建,並且我得到了與rlog命名空間中一些全局符號相關的未定義符號錯誤。特別是這些在RLogChannel.cpp:如何在命名空間中正確使用extern?

namespace rlog { 
... 
    RLogChannel *_RLDebugChannel = GetGlobalChannel("debug", Log_Debug); 
    RLogChannel *_RLInfoChannel = GetGlobalChannel("info", Log_Info); 
    RLogChannel *_RLWarningChannel = GetGlobalChannel("warning", Log_Warning); 
    RLogChannel *_RLErrorChannel = GetGlobalChannel("error", Log_Error); 
... 
}; 

我認爲這個問題是:1)他們沒有出口,2)他們不是在頭部聲明所以其他的事情可以訪問它們。所以我加了__declspec(dllexport)的(通過RLOG_DECL宏)給他們,並在標題中,放:

namespace rlog { 
... 
    RLOG_DECL extern RLogChannel *_RLDebugChannel; 
    RLOG_DECL extern RLogChannel *_RLInfoChannel; 
    RLOG_DECL extern RLogChannel *_RLWarningChannel; 
    RLOG_DECL extern RLogChannel *_RLErrorChannel; 
... 
}; 

但無論怎樣我RLogChannel.cpp聲明變量,我得到一個重新定義的錯誤,儘管我將他們排在頭上......這樣做的正確方法是什麼?似乎它應該是直截了當的,但我不能完全包圍它。

編輯:錯誤信息

Error 12 error C2086: 'rlog::RLogChannel *rlog::_RLDebugChannel' : redefinition rlog-1.4\rlog\RLogChannel.cpp 45 rlog 

(同樣爲所有4個符號)

編輯:我不知道發生了什麼,代碼是完全以前一樣,但現在它會編譯(感覺就像MSVC的怪異...),不幸的是,鏈接到我的庫時,符號仍然顯示爲未解決的問題

+1

所以它的格式比我更好一點什麼上面更新了確切的錯誤信息 – 2010-02-11 21:06:13

+0

?可以在這裏發佈。 – 2010-02-11 21:21:26

+0

好像是一些重要的東西NT已被排除在問題之外。您能否提供一個簡潔而完整的測試用例(例如,我可以傳遞給編譯器的一個文件),從而導致此錯誤? – 2010-02-11 22:07:55

回答

1

解決此問題的一種方法是在一個位置和標題中定義一次。 但是,如果您只是將所有定義轉換爲標題,則最終會出現多重定義問題。

解決方案是這樣的。假設文件名爲rlog.c & rlog.h

--- (rlog.h) --- 
#ifdef RLOG_DEFINES 
#define EXTERN 
#else 
#define EXTERN extern 
#endif 


namespace rlog { 
... 
    RLOG_DECL EXTERN RLogChannel *_RLDebugChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLInfoChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLWarningChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLErrorChannel; 
... 
}; 


--- (rlog.c) --- 
#define RLOG_DEFINES 
#include "rlog.h" 

... 

--- (other .c files) --- 
#include "rlog.h" 

這種解決方案的優點是,由於定義在項目中只定義了一次,你永遠不會讓他們不同步的相互你只需要在一個地方改變它們。想象一下,如果你定義一個變量爲long,但是在extern定義中它被聲明爲short?你可能會出現意想不到的副作用。所以這樣做有助於防止這些類型的問題。

希望有所幫助。

+0

他已經說過他在cpp文件中定義了一次,並在頭文件中聲明瞭它們。 – Potatoswatter 2010-02-11 22:00:32

+0

當我這樣做時,我仍然遇到多個定義錯誤...... – 2010-02-11 22:01:46

+0

在.c文件中定義它們的常規解決方案也意味着它們只在項目中定義過一次。包含來自該文件的頭文件(包含聲明)可以確保您沒有意外的不匹配,因爲編譯器會在出現錯誤時給出錯誤。簡而言之,我認爲你所提供的代碼沒有優勢,但它有更復雜的缺點,並且沒有遵循正常的慣例。 – 2010-02-11 22:03:27

1

我認爲馬特非常接近。我曾面臨這個問題一段時間去和正確的(和最便攜的解決方案是這樣的:

--- (rlog.h) --- 
#ifdef RLOG_DEFINES 
#define RLOG_DECL __declspec(dllexport) 
#else 
#define RLOG_DECL __declspec(dllimport) 
#endif 


namespace rlog { 
... 
    RLOG_DECL extern RLogChannel *_RLDebugChannel; 
    RLOG_DECL extern RLogChannel *_RLInfoChannel; 
    RLOG_DECL extern RLogChannel *_RLWarningChannel; 
    RLOG_DECL extern RLogChannel *_RLErrorChannel; 
... 
}; 


--- (rlog.c) --- 
#define RLOG_DEFINES 
#include "rlog.h" 

namespace rlog { 
... 
    __declspec(dllexport) RLogChannel *_RLDebugChannel = GetGlobalChannel("debug", Log_Debug); 
    __declspec(dllexport) RLogChannel *_RLInfoChannel = GetGlobalChannel("info", Log_Info); 
    __declspec(dllexport) RLogChannel *_RLWarningChannel = GetGlobalChannel("warning", Log_Warning); 
    __declspec(dllexport) RLogChannel *_RLErrorChannel = GetGlobalChannel("error", Log_Error); 
... 
}; 


--- (other .c files) --- 
#include "rlog.h" 

規則很簡單,當您編譯提供DLLEXPORT必須在兩個符號聲明和定義相匹配的dll。在另一方面,當外界使用您的庫 - 它必須出現它爲dllimport符號

問候, 馬切伊·雅布隆斯基