एक अपरिभाषित संदर्भ / अनसुलझे बाहरी प्रतीक त्रुटि क्या है और मैं इसे कैसे ठीक करूं?


1493

अपरिभाषित संदर्भ / अनसुलझे बाहरी प्रतीक त्रुटियां क्या हैं? सामान्य कारण क्या हैं और उन्हें कैसे ठीक करें / रोकें?

खुद को संपादित / जोड़ने के लिए स्वतंत्र महसूस करें।


@LuchianGrigore 'एक उत्तर जोड़ने के लिए स्वतंत्र महसूस करता हूं ' यदि आप अनुमति देना चाहते हैं तो मैं आपके प्राथमिक उत्तर में प्रासंगिक लिंक (IMHO) जोड़ना पसंद करता हूं।
atν 22:α ῥεῖ

19
यह प्रश्न एक उपयोगी उत्तर को स्वीकार करने के लिए बहुत सामान्य है। मैं इस सवाल पर नीचे टिप्पणी करने के बिना 1000 + प्रतिष्ठा लोगों की संख्या पर विश्वास नहीं कर सकता। इस बीच मैं बहुत सारे प्रश्न देखता हूं जो समझदार हैं और मेरे लिए बहुत उपयोगी हैं जो बंद हैं।
अल्बर्ट वैन डेर होर्स्ट

10
@AlbertvanderHorst "यह प्रश्न एक उपयोगी उत्तर को स्वीकार करने के लिए बहुत सामान्य है" क्या नीचे दिए गए उत्तर उपयोगी नहीं हैं?
एलएफ

4
वे उपयोगी हो सकते हैं, जैसे सवालों के कई जवाब हैं जो बहुत सामान्य रूप से चिह्नित किए गए हैं।
अल्बर्ट वैन डेर होर्स्ट

1
मैं न्यूनतम प्रतिलिपि प्रस्तुत करने योग्य उदाहरण को देखना चाहता हूं, जैसा कि हम सबसे नए उपयोगकर्ताओं से पूछते हैं, ईमानदारी से। मुझे इससे कोई मतलब नहीं है, यह सिर्फ है - हम लोगों से उन नियमों का पालन करने की उम्मीद नहीं कर सकते हैं जो हम खुद पर नहीं डालते हैं।
डेनिलो

जवाबों:


848

सी ++ प्रोग्राम का संकलन कई चरणों में होता है, जैसा कि 2.2 द्वारा निर्दिष्ट किया गया है (संदर्भ के लिए कीथ थॉम्पसन को क्रेडिट) :

अनुवाद के वाक्यविन्यास नियमों में पूर्ववर्तीता निम्नलिखित चरणों द्वारा निर्दिष्ट है [फुटनोट देखें]

  1. यदि आवश्यक हो, तो मूल स्रोत वर्ण सेट (एंड-ऑफ-लाइन संकेतक के लिए नए-पंक्ति वर्णों को लागू करने) के लिए भौतिक स्रोत फ़ाइल वर्णों को मैप किया जाता है। [कटाव]
  2. बैकस्लैश कैरेक्टर (\) के तुरंत बाद एक नई-लाइन कैरेक्टर को डिलीट करने का प्रत्येक उदाहरण, लॉजिकल सोर्स लाइनों को बनाने के लिए भौतिक स्रोत लाइनों को फैलाता है। [कटाव]
  3. स्रोत फ़ाइल को प्रीप्रोसेसिंग टोकन (2.5) और सफेद-अंतरिक्ष वर्णों के अनुक्रम (टिप्पणियों सहित) में विघटित किया जाता है। [कटाव]
  4. प्रीप्रोसेसिंग निर्देशों को निष्पादित किया जाता है, मैक्रो इनवोकेशन का विस्तार किया जाता है, और _Pragma यूनिरी ऑपरेटर एक्सप्रेशन निष्पादित किए जाते हैं। [कटाव]
  5. प्रत्येक स्रोत चरित्र एक चरित्र शाब्दिक या एक स्ट्रिंग शाब्दिक में सदस्य सेट करता है, साथ ही एक चरित्र शाब्दिक या गैर-कच्चे स्ट्रिंग शाब्दिक में प्रत्येक एस्केप अनुक्रम और सार्वभौमिक-चरित्र-नाम, निष्पादन वर्ण सेट के संबंधित सदस्य में परिवर्तित होता है; [कटाव]
  6. आसन्न स्ट्रिंग शाब्दिक टोकन समवर्ती होते हैं।
  7. टोकन को अलग करने वाले सफेद-अंतरिक्ष वर्ण अब महत्वपूर्ण नहीं हैं। प्रत्येक प्रीप्रोसेसिंग टोकन को टोकन में परिवर्तित किया जाता है। (2.7)। परिणामी टोकन को वाक्य रचना के रूप में क्रमबद्ध और शब्दार्थ रूप से विश्लेषित और अनुवादित किया जाता है। [कटाव]
  8. अनूदित अनुवाद इकाइयाँ और तात्कालिकता इकाइयाँ इस प्रकार हैं: [SNIP]
  9. सभी बाहरी निकाय संदर्भ हल किए गए हैं। वर्तमान अनुवाद में परिभाषित नहीं की गई संस्थाओं के लिए बाहरी संदर्भों को संतुष्ट करने के लिए लाइब्रेरी घटकों को जोड़ा जाता है। इस तरह के सभी अनुवादक आउटपुट को एक प्रोग्राम इमेज में एकत्र किया जाता है जिसमें निष्पादन निष्पादन के लिए आवश्यक जानकारी होती है। (जोर मेरा)

[फुटनोट] कार्यान्वयन को ऐसे व्यवहार करना चाहिए जैसे कि ये अलग-अलग चरण होते हैं, हालांकि व्यवहार में विभिन्न चरणों को एक साथ जोड़ दिया जा सकता है।

संकलन के इस अंतिम चरण के दौरान निर्दिष्ट त्रुटियां होती हैं, जिन्हें आमतौर पर लिंकिंग कहा जाता है। इसका मूल रूप से मतलब है कि आपने ऑब्जेक्ट फ़ाइलों या पुस्तकालयों में कार्यान्वयन फ़ाइलों का एक गुच्छा संकलित किया है और अब आप उन्हें एक साथ काम करना चाहते हैं।

कहते हैं कि आपने प्रतीक aको परिभाषित किया है a.cpp। अब, उस प्रतीक को b.cpp घोषित किया और उसका उपयोग किया। लिंक करने से पहले, यह माना जाता है कि वह प्रतीक कहीं परिभाषित किया गया था , लेकिन यह अभी तक परवाह नहीं करता है कि कहां है। लिंकिंग चरण प्रतीक को खोजने और इसे सही तरीके से जोड़ने के लिए ज़िम्मेदार है b.cpp(अच्छी तरह से, वास्तव में ऑब्जेक्ट या लाइब्रेरी जो इसका उपयोग करता है)।

यदि आप Microsoft Visual Studio का उपयोग कर रहे हैं, तो आप देखेंगे कि परियोजनाएँ .libफाइलें उत्पन्न करती हैं । इनमें निर्यात किए गए प्रतीकों की एक तालिका और आयातित प्रतीकों की एक तालिका है। आयात किए गए प्रतीकों को आपके द्वारा लिंक किए गए पुस्तकालयों के खिलाफ हल किया जाता है, और निर्यात किए गए प्रतीकों को उपयोग करने वाले पुस्तकालयों के लिए प्रदान किया जाता है.lib (यदि कोई हो) ।

इसी तरह के तंत्र अन्य संकलक / प्लेटफार्मों के लिए मौजूद हैं।

सामान्य त्रुटि संदेश हैं error LNK2001, error LNK1120, error LNK2019के लिए माइक्रोसॉफ्ट विजुअल स्टूडियो और undefined reference to symbolName के लिए जीसीसी

कोड:

struct X
{
   virtual void foo();
};
struct Y : X
{
   void foo() {}
};
struct A
{
   virtual ~A() = 0;
};
struct B: A
{
   virtual ~B(){}
};
extern int x;
void foo();
int main()
{
   x = 0;
   foo();
   Y y;
   B b;
}

GCC के साथ निम्नलिखित त्रुटियां उत्पन्न करेगा :

/home/AbiSfw/ccvvuHoX.o: In function `main':
prog.cpp:(.text+0x10): undefined reference to `x'
prog.cpp:(.text+0x19): undefined reference to `foo()'
prog.cpp:(.text+0x2d): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
prog.cpp:(.text._ZN1BD1Ev[B::~B()]+0xb): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
prog.cpp:(.text._ZN1BD0Ev[B::~B()]+0x12): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1Y[typeinfo for Y]+0x8): undefined reference to `typeinfo for X'
/home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1B[typeinfo for B]+0x8): undefined reference to `typeinfo for A'
collect2: ld returned 1 exit status

और Microsoft विज़ुअल स्टूडियो के साथ ऐसी ही त्रुटियां :

1>test2.obj : error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)
1>test2.obj : error LNK2001: unresolved external symbol "int x" (?x@@3HA)
1>test2.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall A::~A(void)" (??1A@@UAE@XZ)
1>test2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall X::foo(void)" (?foo@X@@UAEXXZ)
1>...\test2.exe : fatal error LNK1120: 4 unresolved externals

सामान्य कारणों में शामिल हैं:


16
व्यक्तिगत रूप से, मुझे लगता है कि एमएस लिंकर त्रुटि संदेश जीसीसी त्रुटियों के समान ही पठनीय हैं। उनके पास अनसुलझे बाहरी के लिए मंगली और असम्बद्ध दोनों नामों को शामिल करने का भी लाभ है। समस्याग्रस्त नाम होने पर आपको यह देखने में मदद मिल सकती है कि आपको लाइब्रेरी या ऑब्जेक्ट फ़ाइलों को सीधे देखने की आवश्यकता है कि समस्या क्या हो सकती है (उदाहरण के लिए, एक कॉलिंग मिसमैच)। इसके अलावा, मुझे यकीन नहीं है कि एमएसवीसी के किस संस्करण ने यहां त्रुटियां पैदा कीं, लेकिन नए संस्करणों में फंक्शन का नाम (मेनग्लड और अनमैंगल्ड) शामिल है, जिसमें अनसुलझे बाहरी प्रतीक का जिक्र है।
माइकल बूर

5
डेविड ड्रिंसडेल ने लिंकर्स के काम करने के तरीके के बारे में एक शानदार लेख लिखा: बिगिनर्स गाइड टू लिंकर्स । इस प्रश्न के विषय को देखते हुए, मैंने सोचा कि यह उपयोगी साबित हो सकता है।
प्रातः

@TankorSmash gcc का उपयोग करें? अधिक सटीक होने के लिए न्यूनतम।
doug65536

1
@ ल्यूचियन अच्छा होगा यदि आप सही जोड़ते हैं, उपरोक्त त्रुटियों को ठीक करते हैं
फाल्गुन

177

कक्षा के सदस्य:

एक शुद्ध virtualविध्वंसक को एक कार्यान्वयन की आवश्यकता होती है।

एक विध्वंसक शुद्ध घोषित करने के बाद भी आपको इसे परिभाषित करने की आवश्यकता है (एक नियमित कार्य के विपरीत):

struct X
{
    virtual ~X() = 0;
};
struct Y : X
{
    ~Y() {}
};
int main()
{
    Y y;
}
//X::~X(){} //uncomment this line for successful definition

ऐसा इसलिए होता है क्योंकि बेस क्लास डिस्ट्रक्टर्स को कहा जाता है जब ऑब्जेक्ट को स्पष्ट रूप से नष्ट कर दिया जाता है, इसलिए एक परिभाषा की आवश्यकता होती है।

virtual विधियों को या तो लागू किया जाना चाहिए या शुद्ध रूप में परिभाषित किया जाना चाहिए।

यह virtualबिना किसी परिभाषा के गैर- तरीकों के समान है , अतिरिक्त तर्क के साथ कि शुद्ध घोषणा एक डमी व्यवहार्य बनाता है और आपको फ़ंक्शन का उपयोग किए बिना लिंकर त्रुटि मिल सकती है:

struct X
{
    virtual void foo();
};
struct Y : X
{
   void foo() {}
};
int main()
{
   Y y; //linker error although there was no call to X::foo
}

इसे काम करने के लिए, X::foo()शुद्ध घोषित करें :

struct X
{
    virtual void foo() = 0;
};

गैर- virtualवर्ग के सदस्य

कुछ सदस्यों को स्पष्ट रूप से उपयोग नहीं किए जाने पर भी परिभाषित करने की आवश्यकता है:

struct A
{ 
    ~A();
};

निम्नलिखित त्रुटि उत्पन्न करेगा:

A a;      //destructor undefined

कार्यान्वयन इनलाइन हो सकता है, वर्ग परिभाषा में ही:

struct A
{ 
    ~A() {}
};

या बाहर:

A::~A() {}

यदि कार्यान्वयन वर्ग परिभाषा के बाहर है, लेकिन शीर्ष लेख में, inlineएकाधिक परिभाषा को रोकने के लिए विधियों को चिह्नित किया जाना है।

यदि उपयोग किया जाता है तो सभी प्रयुक्त सदस्य विधियों को परिभाषित किया जाना चाहिए।

एक सामान्य गलती नाम को अर्हता प्राप्त करना भूल रही है:

struct A
{
   void foo();
};

void foo() {}

int main()
{
   A a;
   a.foo();
}

परिभाषा होनी चाहिए

void A::foo() {}

staticडेटा सदस्यों को एकल अनुवाद इकाई में कक्षा के बाहर परिभाषित किया जाना चाहिए :

struct X
{
    static int x;
};
int main()
{
    int x = X::x;
}
//int X::x; //uncomment this line to define X::x

static constवर्ग परिभाषा के भीतर अभिन्न या गणना के डेटा सदस्य के लिए एक इनिशाइज़र प्रदान किया जा सकता है ; हालाँकि, इस सदस्य के ओडीआर-उपयोग के लिए अभी भी ऊपर वर्णित एक नेमस्पेस स्कोप परिभाषा की आवश्यकता होगी। C ++ 11 सभी static constडेटा सदस्यों के लिए वर्ग के अंदर आरंभीकरण की अनुमति देता है ।


बस आपको लगता है कि आप तनाव करना चाहते हैं कि दोनों करना संभव है, और डोर वास्तव में अपवाद नहीं है। (यह पहली नज़र में आपके शब्दांकन से स्पष्ट नहीं है।)
डेडुप्लिकेटर

112

उपयुक्त पुस्तकालयों / ऑब्जेक्ट फ़ाइलों के खिलाफ लिंक करने या कार्यान्वयन फ़ाइलों को संकलित करने में विफलता

आमतौर पर, प्रत्येक अनुवाद इकाई एक ऑब्जेक्ट फ़ाइल उत्पन्न करेगी जिसमें उस अनुवाद इकाई में परिभाषित प्रतीकों की परिभाषाएँ शामिल हैं। उन प्रतीकों का उपयोग करने के लिए, आपको उन ऑब्जेक्ट फ़ाइलों के खिलाफ लिंक करना होगा।

जीसीसी के तहत आप सभी ऑब्जेक्ट फ़ाइलों को निर्दिष्ट करेंगे जिन्हें कमांड लाइन में एक साथ जोड़ा जाना है, या कार्यान्वयन फ़ाइलों को एक साथ संकलित करना है।

g++ -o test objectFile1.o objectFile2.o -lLibraryName

libraryNameयहाँ, बस पुस्तकालय के नंगे नाम है प्लेटफ़ॉर्म-विशिष्ट शब्दों के बिना भी। इसलिए उदाहरण के तौर पर लिनक्स लाइब्रेरी की फाइलों को आमतौर पर कहा जाता है libfoo.soलेकिन आप केवल लिखेंगे -lfoo। विंडोज़ पर उसी फ़ाइल को बुलाया जा सकता है foo.lib, लेकिन आप उसी तर्क का उपयोग करेंगे। आपको उस निर्देशिका को जोड़ना पड़ सकता है जहाँ उन फ़ाइलों का उपयोग करके पाया जा सकता है -L‹directory›। एक जगह के बाद -lया नहीं लिखना सुनिश्चित करें-L

के लिए XCode : -> लाइब्रेरी खोज पथ को जोड़ने - जोड़ें उपयोगकर्ता हैडर खोजें पथ> खींचें और परियोजना फ़ोल्डर में वास्तविक पुस्तकालय संदर्भ छोड़ देते हैं।

MSVS के तहत , किसी प्रोजेक्ट में जोड़ी गई फाइलें स्वचालित रूप से अपनी ऑब्जेक्ट फाइलों को एक साथ जोड़ देती हैं और एक libफाइल जेनरेट हो जाएगी (आम उपयोग में)। एक अलग प्रोजेक्ट में प्रतीकों का उपयोग करने के लिए, आपको libप्रोजेक्ट सेटिंग्स में फ़ाइलों को शामिल करना होगा। यह प्रोजेक्ट प्रॉपर्टीज के लिंकर सेक्शन में किया गया है Input -> Additional Dependencies। ( libफ़ाइल का पथ जोड़ा जाना चाहिए Linker -> General -> Additional Library Directories) जब किसी libफ़ाइल के साथ प्रदान की जाने वाली तृतीय-पक्ष लाइब्रेरी का उपयोग करते हैं , तो ऐसा करने में विफलता आमतौर पर त्रुटि का कारण बनती है।

यह भी हो सकता है कि आप फ़ाइल को संकलन में जोड़ना भूल जाएं, जिस स्थिति में ऑब्जेक्ट फ़ाइल उत्पन्न नहीं होगी। में जीसीसी आप आदेश पंक्ति में फ़ाइलें जोड़ने चाहते हैं। में MSVS परियोजना के लिए फ़ाइल जोड़ने यह यह स्वचालित रूप से संकलित (यद्यपि फ़ाइलों कर सकते हैं, मैन्युअल रूप से, व्यक्तिगत रूप से निर्माण से बाहर रखा जाना) कर देगा।

विंडोज प्रोग्रामिंग में, कहानी-कहानी का संकेत है कि आपने एक आवश्यक पुस्तकालय लिंक नहीं किया है कि अनसुलझे प्रतीक का नाम इसके साथ शुरू होता है __imp_। प्रलेखन में फ़ंक्शन का नाम देखें, और यह कहना चाहिए कि आपको किस लाइब्रेरी का उपयोग करने की आवश्यकता है। उदाहरण के लिए, MSDN प्रत्येक फ़ंक्शन के निचले भाग में "लाइब्रेरी" नामक एक बॉक्स में जानकारी रखता है।


1
यह अच्छा होगा यदि आप स्पष्ट रूप से gcc main.cइसके बजाय की सामान्य गलती को कवर कर सकते हैं gcc main.c other.c (जो शुरुआती अक्सर अपनी परियोजनाओं को बनाने से पहले ऐसा करते हैं। जैसे कि .o फाइलें)।
एमएम

101

घोषित किया गया लेकिन एक चर या फ़ंक्शन को परिभाषित नहीं किया गया।

एक विशिष्ट चर घोषणा है

extern int x;

जैसा कि यह केवल एक घोषणा है, एक एकल परिभाषा की आवश्यकता है। एक समान परिभाषा होगी:

int x;

उदाहरण के लिए, निम्नलिखित एक त्रुटि उत्पन्न करेगा:

extern int x;
int main()
{
    x = 0;
}
//int x; // uncomment this line for successful definition

इसी तरह की टिप्पणी कार्यों पर लागू होती है। किसी फ़ंक्शन को परिभाषित किए बिना घोषित करना त्रुटि की ओर जाता है:

void foo(); // declaration only
int main()
{
   foo();
}
//void foo() {} //uncomment this line for successful definition

सावधान रहें कि आप जिस फ़ंक्शन को लागू करते हैं, वह आपके द्वारा घोषित किए गए मैच से बिल्कुल मेल खाता है उदाहरण के लिए, आपके पास cv-क्वालिफायर बेमेल हो सकते हैं:

void foo(int& x);
int main()
{
   int x;
   foo(x);
}
void foo(const int& x) {} //different function, doesn't provide a definition
                          //for void foo(int& x)

बेमेल के अन्य उदाहरणों में शामिल हैं

  • एक नाम स्थान में घोषित फ़ंक्शन / चर, दूसरे में परिभाषित।
  • वर्ग सदस्य के रूप में घोषित फ़ंक्शन / चर, जिसे वैश्विक (या इसके विपरीत) के रूप में परिभाषित किया गया है।
  • फ़ंक्शन रिटर्न प्रकार, पैरामीटर संख्या और प्रकार, और कॉलिंग कन्वेंशन सभी बिल्कुल सहमत नहीं हैं।

कंपाइलर से त्रुटि संदेश आपको अक्सर उस चर या फ़ंक्शन की पूर्ण घोषणा देगा जो घोषित किया गया था लेकिन कभी भी परिभाषित नहीं किया गया था। आपके द्वारा प्रदान की गई परिभाषा से इसकी तुलना करें। सुनिश्चित करें कि हर विवरण मेल खाता हो।


वीएस में, हेडर में मौजूद सीपीपी फाइलों को सोर्स डायरेक्टरी में #includesनहीं जोड़ा जाता है, यह भी लापता परिभाषाओं की श्रेणी में आता है।
लॉरी स्टर्न

86

जिस क्रम में अन्योन्याश्रित लिंक्ड लाइब्रेरी निर्दिष्ट की गई है वह गलत है।

यदि पुस्तकालय एक-दूसरे पर निर्भर करते हैं, तो पुस्तकालय जिस क्रम से जुड़े होते हैं, वह क्रम चलता है। सामान्य तौर पर, यदि लाइब्रेरी लाइब्रेरी Aपर निर्भर करती है B, तो libA MUST पहले दिखाई देlibB को लिंकर झंडे में ।

उदाहरण के लिए:

// B.h
#ifndef B_H
#define B_H

struct B {
    B(int);
    int x;
};

#endif

// B.cpp
#include "B.h"
B::B(int xx) : x(xx) {}

// A.h
#include "B.h"

struct A {
    A(int x);
    B b;
};

// A.cpp
#include "A.h"

A::A(int x) : b(x) {}

// main.cpp
#include "A.h"

int main() {
    A a(5);
    return 0;
};

लाइब्रेरी बनाएँ:

$ g++ -c A.cpp
$ g++ -c B.cpp
$ ar rvs libA.a A.o 
ar: creating libA.a
a - A.o
$ ar rvs libB.a B.o 
ar: creating libB.a
a - B.o

संकलित करें:

$ g++ main.cpp -L. -lB -lA
./libA.a(A.o): In function `A::A(int)':
A.cpp:(.text+0x1c): undefined reference to `B::B(int)'
collect2: error: ld returned 1 exit status
$ g++ main.cpp -L. -lA -lB
$ ./a.out

तो फिर से दोहराने के लिए, आदेश बात करता है!


मुझे उत्सुक तथ्य यह है कि मेरे मामले में मेरे पास एक ऑब्जेक्ट फ़ाइल थी जो एक साझा लाइब्रेरी पर निर्भर करती है। मुझे मेकफिल को संशोधित करना था और डेबियन पर 4.8.4 जीसीसी के साथ पुस्तकालय के बाद पुस्तकालय को रखना था । Centos 6.5 पर gcc 4.4 के साथ Makefile ने बिना किसी समस्या के काम किया।
मार्को सुल

74

"अपरिभाषित संदर्भ / अनसुलझे बाहरी प्रतीक" क्या है

मैं यह समझाने की कोशिश करूंगा कि एक "अपरिभाषित संदर्भ / अनसुलझे बाहरी प्रतीक" क्या है।

नोट: मैं g ++ और लिनक्स का उपयोग करता हूं और इसके लिए सभी उदाहरण हैं

उदाहरण के लिए हमारे पास कुछ कोड हैं

// src1.cpp
void print();

static int local_var_name; // 'static' makes variable not visible for other modules
int global_var_name = 123;

int main()
{
    print();
    return 0;
}

तथा

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
//extern int local_var_name;

void print ()
{
    // printf("%d%d\n", global_var_name, local_var_name);
    printf("%d\n", global_var_name);
}

ऑब्जेक्ट फ़ाइलें बनाएँ

$ g++ -c src1.cpp -o src1.o
$ g++ -c src2.cpp -o src2.o

कोडांतरक चरण के बाद हमारे पास एक ऑब्जेक्ट फ़ाइल है, जिसमें निर्यात करने के लिए कोई भी प्रतीक हैं। प्रतीकों को देखो

$ readelf --symbols src1.o
  Num:    Value          Size Type    Bind   Vis      Ndx Name
     5: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 _ZL14local_var_name # [1]
     9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 global_var_name     # [2]

मैंने आउटपुट से कुछ पंक्तियों को अस्वीकार कर दिया है, क्योंकि वे कोई मायने नहीं रखते हैं

इसलिए, हम निर्यात करने के लिए प्रतीकों का पालन करते हैं।

[1] - this is our static (local) variable (important - Bind has a type "LOCAL")
[2] - this is our global variable

src2.cpp कुछ भी नहीं निर्यात करता है और हमने इसके कोई प्रतीक नहीं देखे हैं

हमारी ऑब्जेक्ट फ़ाइलों को लिंक करें

$ g++ src1.o src2.o -o prog

और इसे चलाएं

$ ./prog
123

लिंकर निर्यात किए गए प्रतीकों को देखता है और लिंक करता है। अब हम यहाँ की तरह src2.cpp में लाइनों को अनकैप करने की कोशिश करते हैं

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
extern int local_var_name;

void print ()
{
    printf("%d%d\n", global_var_name, local_var_name);
}

और एक वस्तु फ़ाइल का पुनर्निर्माण

$ g++ -c src2.cpp -o src2.o

ठीक है (कोई त्रुटि नहीं), क्योंकि हम केवल ऑब्जेक्ट फ़ाइल बनाते हैं, लिंकिंग अभी तक नहीं की गई है। लिंक करने का प्रयास करें

$ g++ src1.o src2.o -o prog
src2.o: In function `print()':
src2.cpp:(.text+0x6): undefined reference to `local_var_name'
collect2: error: ld returned 1 exit status

ऐसा इसलिए हुआ है क्योंकि हमारा local_var_name स्थिर है, अर्थात यह अन्य मॉड्यूल के लिए दृश्यमान नहीं है। अब और गहराई से। अनुवाद चरण आउटपुट प्राप्त करें

$ g++ -S src1.cpp -o src1.s

// src1.s
look src1.s

    .file   "src1.cpp"
    .local  _ZL14local_var_name
    .comm   _ZL14local_var_name,4,4
    .globl  global_var_name
    .data
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; assembler code, not interesting for us
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

इसलिए, हमने देखा है कि local_var_name के लिए कोई लेबल नहीं है, इसीलिए लिंकर को यह नहीं मिला है। लेकिन हम हैकर्स हैं :) और हम इसे ठीक कर सकते हैं। अपने टेक्स्ट एडिटर और परिवर्तन में src1.s खोलें

.local  _ZL14local_var_name
.comm   _ZL14local_var_name,4,4

सेवा

    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789

यानी आपको नीचे पसंद होना चाहिए

    .file   "src1.cpp"
    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789
    .globl  global_var_name
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; ...

हमने local_var_name की दृश्यता को बदल दिया है और इसके मूल्य को 456789 पर सेट किया है। इससे एक ऑब्जेक्ट फ़ाइल बनाने का प्रयास करें

$ g++ -c src1.s -o src2.o

ठीक है, वाचिक आउटपुट (प्रतीक) देखें

$ readelf --symbols src1.o
8: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 local_var_name

अब local_var_name में Bind GLOBAL है (LOCAL था)

संपर्क

$ g++ src1.o src2.o -o prog

और इसे चलाएं

$ ./prog 
123456789

ठीक है, हम इसे हैक करते हैं :)

इसलिए, परिणामस्वरूप - एक "अपरिभाषित संदर्भ / अनसुलझे बाहरी प्रतीक त्रुटि" तब होता है जब लिंकर ऑब्जेक्ट फ़ाइलों में वैश्विक प्रतीकों को नहीं पा सकता है।


71

प्रतीकों को C प्रोग्राम में परिभाषित किया गया और C ++ कोड में उपयोग किया गया।

फ़ंक्शन (या चर) void foo()को C प्रोग्राम में परिभाषित किया गया था और आप इसे C ++ प्रोग्राम में उपयोग करने का प्रयास करते हैं:

void foo();
int main()
{
    foo();
}

C ++ लिंकर को नामों की मांग की जाती है, इसलिए आपको फ़ंक्शन को इस तरह घोषित करना होगा:

extern "C" void foo();
int main()
{
    foo();
}

समान रूप से, C प्रोग्राम में परिभाषित होने के बजाय, फ़ंक्शन (या चर) void foo()C ++ में परिभाषित किया गया था, लेकिन C लिंकेज के साथ:

extern "C" void foo();

और आप इसे C ++ लिंकेज के साथ C ++ प्रोग्राम में उपयोग करने का प्रयास करते हैं।

यदि एक संपूर्ण लाइब्रेरी को हेडर फ़ाइल में शामिल किया गया है (और सी कोड के रूप में संकलित किया गया था); शामिल करने की आवश्यकता इस प्रकार होगी;

extern "C" {
    #include "cheader.h"
}

5
या इसके विपरीत, यदि आप एक सी लाइब्रेरी विकसित करते हैं, तो एक अच्छा नियम हेडर फ़ाइल (ओं) को सभी निर्यात किए गए घोषणाओं के साथ #ifdef __cplusplus [\n] extern"C" { [\n] #endifऔर #ifdef __cplusplus [\n] } [\n] #endif( [\n]वास्तविक कैरिज रिटर्न होने के नाते ) संरक्षित करना है, लेकिन मैं इसे टिप्पणी में ठीक से नहीं लिख सकता हूं।
बेंटॉय 13

जैसा कि ऊपर की टिप्पणी में, '
मिक्सिंग

वास्तव में मेरी मदद की! यह मेरा मामला था जब मैंने इस प्रश्न के लिए देखा
नाइटहॉफ़रिज़ोन

यह तब भी हो सकता है जब आप अपने साधारण C ++ हेडर फ़ाइल को एक्सटर्नल C : से घिरे दुर्घटना में शामिल करते हैं extern "C" { #include <myCppHeader.h> }
कॉमफ्रीक

68

यदि अन्य सभी विफल रहता है, तो recompile।

मैं हाल ही में दृश्य स्टूडियो 2012 में एक अनसुलझे बाहरी त्रुटि से छुटकारा पाने में सक्षम था, जो कि आपत्तिजनक फ़ाइल को पुनः प्राप्त कर रहा था। जब मैंने दोबारा बनाया, तो त्रुटि दूर हो गई।

यह आमतौर पर तब होता है जब दो (या अधिक) पुस्तकालयों में चक्रीय निर्भरता होती है। लाइब्रेरी ए बीलिब में प्रतीकों का उपयोग करने का प्रयास करती है और पुस्तकालय बी एलिब से प्रतीकों का उपयोग करने का प्रयास करता है। के साथ शुरू करने के लिए मौजूद नहीं है। जब आप A को संकलित करने का प्रयास करते हैं, तो लिंक चरण विफल हो जाएगा क्योंकि यह B.lib नहीं ढूँढ सकता है। A.lib उत्पन्न होगा, लेकिन कोई dll नहीं। आप फिर बी को संकलित करते हैं, जो बीलिब को सफल और उत्पन्न करेगा। ए-री का संकलन अब काम करेगा क्योंकि बी.लिब अब मिल गया है।


1
सही - यह तब होता है जब पुस्तकालयों में चक्रीय निर्भरता होती है।
लुचियन ग्रिगोर

1
मैंने आपके उत्तर पर विस्तार किया और मुख्य एक में जुड़ा। धन्यवाद।
लुचियन ग्रिगोर

57

मॉड्यूल / डीएल (संकलक विशिष्ट) में गलत तरीके से आयात / निर्यात करने के तरीके / कक्षाएं।

MSVS का उपयोग __declspec(dllexport)और निर्यात करने और आयात करने के लिए आपको कौन से प्रतीकों को निर्दिष्ट करना है __declspec(dllimport)

यह दोहरी कार्यक्षमता आमतौर पर एक मैक्रो के उपयोग के माध्यम से प्राप्त की जाती है:

#ifdef THIS_MODULE
#define DLLIMPEXP __declspec(dllexport)
#else
#define DLLIMPEXP __declspec(dllimport)
#endif

मैक्रो THIS_MODULEकेवल उस मॉड्यूल में परिभाषित किया जाएगा जो फ़ंक्शन को निर्यात करता है। इस तरह से, घोषणा:

DLLIMPEXP void foo();

तक फैलता है

__declspec(dllexport) void foo();

और संकलक फ़ंक्शन को निर्यात करने के लिए कहता है, क्योंकि वर्तमान मॉड्यूल में इसकी परिभाषा है। जब एक अलग मॉड्यूल में घोषणा शामिल है, तो इसका विस्तार होगा

__declspec(dllimport) void foo();

और संकलक को बताता है कि परिभाषा आपके द्वारा लिंक किए गए पुस्तकालयों में से एक में है (यह भी देखें) 1 ) )।

आप आयात / निर्यात वर्गों का अनुकरण कर सकते हैं:

class DLLIMPEXP X
{
};

2
पूर्ण होने के लिए, इस उत्तर में जीसीसी visibilityऔर विंडोज की .defफाइलों का उल्लेख होना चाहिए , क्योंकि ये प्रतीक नाम और उपस्थिति को भी प्रभावित करते हैं।
रुबेंब

@rubenvb मैंने .defउम्र में फ़ाइलों का उपयोग नहीं किया है। एक उत्तर जोड़ने या इसे संपादित करने के लिए स्वतंत्र महसूस करें।
लुचियन ग्रिगोर

57

यह सबसे भ्रामक त्रुटि संदेशों में से एक है जो प्रत्येक VC ++ प्रोग्रामर ने समय और फिर से देखा है। पहले चीजों को स्पष्ट करते हैं।

A. प्रतीक क्या है? संक्षेप में, एक प्रतीक एक नाम है। यह एक चर नाम, एक फ़ंक्शन नाम, एक क्लास नाम, एक टाइपडेफ़ नाम या उन नामों और संकेतों को छोड़कर कुछ भी हो सकता है जो C ++ भाषा के हैं। यह एक निर्भरता पुस्तकालय (किसी अन्य उपयोगकर्ता द्वारा परिभाषित) द्वारा परिभाषित या पेश किया गया उपयोगकर्ता है।

B. बाहरी क्या है? VC ++ में, प्रत्येक स्रोत फ़ाइल (.cpp, .c, आदि) को अनुवाद इकाई माना जाता है, संकलक एक समय में एक इकाई संकलित करता है, और वर्तमान अनुवाद इकाई के लिए एक ऑब्जेक्ट फ़ाइल (.obj) उत्पन्न करता है। (ध्यान दें कि शामिल की गई प्रत्येक हेडर फ़ाइल इस स्रोत फ़ाइल को प्रीप्रोसेस किया जाएगा और इस अनुवाद इकाई के हिस्से के रूप में माना जाएगा) अनुवाद इकाई के भीतर सब कुछ आंतरिक माना जाता है, बाकी सब कुछ बाहरी माना जाता है। C ++ में, आप जैसे कीवर्ड का उपयोग करके एक बाहरी प्रतीक को संदर्भित कर सकते हैं extern,__declspec (dllimport) और इसी तरह।

C. "संकल्प" क्या है? रिज़ॉल्यूशन एक लिंकिंग-टाइम टर्म है। लिंकिंग-टाइम में, लिंकर ऑब्जेक्ट फ़ाइलों में हर प्रतीक के लिए बाहरी परिभाषा खोजने का प्रयास करता है जो आंतरिक रूप से इसकी परिभाषा नहीं पा सकते हैं। इस खोज प्रक्रिया का दायरा इसमें शामिल है:

  • सभी ऑब्जेक्ट फ़ाइलें जो संकलन समय में उत्पन्न हुईं
  • सभी पुस्तकालय (.लिब) जो या तो स्पष्ट रूप से या अंतर्निहित रूप से इस भवन अनुप्रयोग की अतिरिक्त निर्भरता के रूप में निर्दिष्ट हैं।

इस खोज प्रक्रिया को संकल्प कहा जाता है।

डी। आखिर, अनारक्षित बाहरी प्रतीक क्यों? यदि लिंकर बाहरी प्रतीक के लिए बाहरी परिभाषा नहीं पा सकता है जिसकी आंतरिक रूप से कोई परिभाषा नहीं है, तो यह एक अनारक्षित बाहरी प्रतीक त्रुटि की रिपोर्ट करता है।

ई। LNK2019 के संभावित कारण : अनारक्षित बाहरी प्रतीक त्रुटि। हम पहले से ही जानते हैं कि यह त्रुटि बाहरी चिह्न की परिभाषा को खोजने में विफल लिंकर के कारण है, संभावित कारणों को निम्नानुसार हल किया जा सकता है:

  1. परिभाषा मौजूद है

उदाहरण के लिए, यदि हमारे पास एक फ़ंक्शन है जिसे फू कहा जाता है। a.cpp में परिभाषित किया गया है:

int foo()
{
    return 0;
}

B.cpp में हम फ़ंक्शन फू को कॉल करना चाहते हैं, इसलिए हम जोड़ते हैं

void foo();

घोषणा समारोह foo (), और एक अन्य समारोह शरीर में इसे कहते हैं, का कहना है bar():

void bar()
{
    foo();
}

अब जब आप इस कोड का निर्माण करते हैं, तो आपको LNK2019 त्रुटि की शिकायत होगी कि फू एक अनसुलझा प्रतीक है। इस मामले में, हम जानते हैं कि foo () की परिभाषा a.cpp में है, लेकिन हम जिसे कॉल कर रहे हैं (अलग रिटर्न वैल्यू) से अलग है। यह मामला है कि परिभाषा मौजूद है।

  1. परिभाषा मौजूद नहीं है

यदि हम किसी लाइब्रेरी में कुछ फ़ंक्शन को कॉल करना चाहते हैं, लेकिन आयात लाइब्रेरी को Project | Properties | Configuration Properties | Linker | Input | Additional Dependencyआपकी प्रोजेक्ट सेटिंग की अतिरिक्त निर्भरता सूची (इसमें से सेट ) में नहीं जोड़ा गया है । अब लिंकर LNK2019 की रिपोर्ट करेगा क्योंकि वर्तमान खोज क्षेत्र में परिभाषा मौजूद नहीं है।


1
व्यवस्थित व्याख्या के लिए धन्यवाद। मैं इसे पढ़ने के बाद अन्य उत्तरों को समझ सकता हूं।
DISPLAYNAME

55

टेम्पलेट कार्यान्वयन दिखाई नहीं दे रहे हैं।

विशिष्ट टेम्प्लेट की सभी परिभाषाएँ उन सभी अनुवाद इकाइयों के लिए दृश्यमान होनी चाहिए जो उनका उपयोग करती हैं। इसका मतलब है कि आप किसी टेम्पलेट की परिभाषा को कार्यान्वयन फ़ाइल में अलग नहीं कर सकते। यदि आपको कार्यान्वयन को अलग करना होगा, तो सामान्य वर्कअराउंड में एक implफ़ाइल होती है जिसे आप हेडर के अंत में शामिल करते हैं जो टेम्पलेट की घोषणा करता है। एक सामान्य स्थिति है:

template<class T>
struct X
{
    void foo();
};

int main()
{
    X<int> x;
    x.foo();
}

//differentImplementationFile.cpp
template<class T>
void X<T>::foo()
{
}

इसे ठीक करने के लिए, आपको परिभाषा को स्थानांतरित करना होगा X::foo हेडर फ़ाइल या इसका उपयोग करने वाली अनुवाद इकाई को दिखाई देने वाली कुछ जगह ।

कार्यान्वयन फ़ाइल में विशिष्ट टेम्पलेट लागू किए जा सकते हैं और कार्यान्वयन दिखाई नहीं देता है, लेकिन विशेषज्ञता को पहले घोषित किया जाना चाहिए।

आगे की व्याख्या और एक अन्य संभावित समाधान (स्पष्ट तात्कालिकता) के लिए यह प्रश्न और उत्तर देखें


1
"टेम्प्लेट को हेडर में परिभाषित किया जाना चाहिए" के बारे में और जानकारी stackoverflow.com/questions/495021
प्लाज़्मा एचएच

41

अपरिभाषित संदर्भ WinMain@16या समान 'असामान्य' main() प्रविष्टि बिंदु संदर्भ (विशेषकर के लिए))।

आप अपनी वास्तविक IDE के साथ सही प्रोजेक्ट प्रकार चुनने में चूक गए होंगे। आईडीई आमतौर पर उपयोग int main(int argc, char** argv);किए जाने वाले हस्ताक्षर के बजाय इस तरह के प्रवेश बिंदु फ़ंक्शन (उदाहरण के लिए ऊपर दिए गए अनुपलब्ध संदर्भ में निर्दिष्ट) के लिए उदाहरण के लिए विंडोज एप्लीकेशन परियोजनाओं को बांधना चाह सकता है ।

यदि आपका आईडीई प्लेन कंसोल प्रोजेक्ट्स का समर्थन करता है, तो आप विंडोज़ एप्लिकेशन प्रोजेक्ट के बजाय इस प्रोजेक्ट प्रकार को चुनना चाह सकते हैं।


यहाँ case1 और case2 एक से अधिक विस्तार में संभाला असली दुनिया समस्या।


2
मदद नहीं कर सकता, लेकिन इस सवाल और इस तथ्य को इंगित करता हूं कि यह अक्सर होने के बजाय मुख्य कार्य नहीं होने के कारण होता है WinMain। मान्य C ++ प्रोग्रामों की आवश्यकता है main
क्रिस

36

यदि आप तृतीय पक्ष पुस्तकालयों का उपयोग कर रहे हैं, तो सुनिश्चित करें कि आपके पास सही 32/64 बिट बायनेरी हैं


34

Microsoft #pragmaलिंक समय पर सही लायब्रेरी का संदर्भ देता है;

#pragma comment(lib, "libname.lib")

पुस्तकालय की निर्देशिका सहित पुस्तकालय पथ के अलावा, यह पुस्तकालय का पूरा नाम होना चाहिए।


34

विजुअल स्टूडियो नुगेट पैकेज को नए टूलसेट संस्करण के लिए अद्यतन करने की आवश्यकता है

मुझे सिर्फ यह समस्या Visual Studio 2013 के साथ libpng को जोड़ने की कोशिश कर रही थी। समस्या यह है कि पैकेज फ़ाइल में केवल Visual Studio 2010 और 2012 के लिए लाइब्रेरी थी।

सही समाधान यह है कि डेवलपर को एक अद्यतन पैकेज जारी करने और फिर अपग्रेड करने की उम्मीद है, लेकिन इसने मेरे लिए VS2013 के लिए एक अतिरिक्त सेटिंग में हैक करके, VS2012 लाइब्रेरी फ़ाइलों की ओर इशारा करते हुए काम किया।

मैंने सभी अनुभागों की नकल करके उस फ़ाइल packagesको ढूंढकर packagename\build\native\packagename.targetsऔर उसके अंदर ( समाधान की निर्देशिका के अंदर फ़ोल्डर में) पैकेज संपादित किया v110। मैं बदल v110करने v120में हालत क्षेत्रों केवल सभी के रूप में फ़ाइल नाम रास्तों को छोड़ने के लिए बहुत सावधान किया जा रहा है v110। इसने दृश्य स्टूडियो 2013 को 2012 के लिए पुस्तकालयों से जोड़ने की अनुमति दी, और इस मामले में, इसने काम किया।


1
यह अति विशिष्ट लगता है - शायद एक नया धागा इस उत्तर के लिए एक बेहतर स्थान होगा।
लुचियन ग्रिगोर

3
@LuchianGrigore: मैं यहां पोस्ट करना चाहता था क्योंकि यह प्रश्न वास्तव में यह मुद्दा था, लेकिन इसे इस प्रश्न के डुप्लिकेट के रूप में चिह्नित किया गया था इसलिए मैं वहां इसका उत्तर नहीं दे सका। इसलिए मैंने इसके बजाय यहां अपना जवाब पोस्ट किया।
मालवीयस

उस प्रश्न का पहले से ही स्वीकृत उत्तर है। इसे डुप्लिकेट के रूप में चिह्नित किया गया है क्योंकि सामान्य कारण ऊपर सूचीबद्ध है। यदि लाइब्रेरी में शामिल हर समस्या के लिए हमारे पास एक उत्तर होता तो क्या होता?
लुचियन ग्रिगोर

6
@LuchianGrigore: यह समस्या किसी लाइब्रेरी के लिए विशिष्ट नहीं है, यह विजुअल स्टूडियो के पैकेज प्रबंधन प्रणाली का उपयोग करके सभी पुस्तकालयों को प्रभावित करती है। मैं सिर्फ दूसरे प्रश्न को खोजने के लिए हुआ क्योंकि हम दोनों को libpng की समस्या थी। मुझे libxml2, libiconv और glew के लिए भी यही समस्या थी (उसी समाधान के साथ)। यह सवाल विजुअल स्टूडियो के पैकेज मैनेजमेंट सिस्टम की समस्या के बारे में है, और मेरा उत्तर इसका कारण बताता है और वर्कअराउंड प्रदान करता है। किसी ने बस "अनसुलझे बाहरी" को देखा और यह मान लिया कि यह एक मानक लिंकर समस्या है जब यह वास्तव में एक पैकेज प्रबंधन समस्या है।
माल्वेनस

34

मान लीजिए कि आपके पास c ++ में लिखी गई एक बड़ी परियोजना है, जिसमें एक हजार .cpp फाइलें और एक .h फाइलें हैं। और मान लीजिए कि यह परियोजना दस स्थैतिक पुस्तकालयों पर भी निर्भर करती है। मान लीजिए कि हम विंडोज पर हैं और हम विजुअल स्टूडियो 20xx में अपना प्रोजेक्ट बनाते हैं। जब आप संपूर्ण समाधान संकलित करने के लिए Ctrl + F7 Visual Studio दबाते हैं (मान लें कि हमारे पास समाधान में सिर्फ एक परियोजना है)

संकलन का अर्थ क्या है?

  • Visual Studio फ़ाइल .vcxproj में खोज करता है और प्रत्येक फ़ाइल को संकलित करना शुरू करता है जिसमें एक्सटेंशन .cpp होता है। संकलन का क्रम अपरिभाषित है। तो आपको यह नहीं मानना ​​चाहिए कि फ़ाइल main.cpp पहले संकलित है
  • अगर .cpp फाइलें उन प्रतीकों को खोजने के लिए अतिरिक्त .h फ़ाइलों पर निर्भर करती हैं, जो फ़ाइल में परिभाषित नहीं भी हो सकती हैं या नहीं
  • यदि एक .cpp फ़ाइल मौजूद है जिसमें संकलक को एक प्रतीक नहीं मिल रहा है, तो संकलक समय त्रुटि संदेश उठाता है प्रतीक x नहीं पाया जा सकता है
  • एक्सटेंशन .cpp के साथ प्रत्येक फ़ाइल के लिए एक ऑब्जेक्ट फ़ाइल बनाई जाती है .o और विज़ुअल स्टूडियो भी ProjectName.Cpp.Clean.txt नामक फ़ाइल में आउटपुट लिखते हैं जिसमें सभी ऑब्जेक्ट फ़ाइलें होती हैं जिन्हें लिंकर द्वारा संसाधित किया जाना चाहिए।

संकलन का दूसरा चरण लिंकर द्वारा किया जाता है। लिकर को सभी ऑब्जेक्ट फ़ाइल को मर्ज करना चाहिए और अंत में आउटपुट का निर्माण करना चाहिए (जो एक निष्पादन योग्य या पुस्तकालय हो सकता है)

एक परियोजना को जोड़ने में कदम

  • सभी ऑब्जेक्ट फ़ाइलों को पार्स करें और उस परिभाषा को खोजें जो केवल हेडर में घोषित की गई थी (उदाहरण के लिए: किसी कक्षा की एक विधि का कोड जैसा कि पिछले उत्तरों में बताया गया है, या किसी स्थिर चर के प्रारंभ का आयोजन करता है जो किसी वर्ग के अंदर सदस्य है)
  • यदि एक प्रतीक वस्तु फ़ाइलों में नहीं पाया जा सकता है, तो वह अतिरिक्त पुस्तकालयों में भी खोजा जाता है। परियोजना कॉन्फ़िगरेशन गुणों में एक नया पुस्तकालय जोड़ने के लिए -> VC ++ निर्देशिकाएँ -> लाइब्रेरी निर्देशिकाएँ और यहां आपने पुस्तकालयों और कॉन्फ़िगरेशन गुणों की खोज के लिए अतिरिक्त फ़ोल्डर निर्दिष्ट किया -> लिंकर -> पुस्तकालय का नाम निर्दिष्ट करने के लिए इनपुट । -यदि लिंकर को वह प्रतीक नहीं मिल रहा है जो आप एक में लिखते हैं। तो वह एक लिंकर समय त्रुटि उठाता है जो ध्वनि की तरह लग सकता है error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)

अवलोकन

  1. एक बार जब लिंकर को एक प्रतीक मिल जाता है तो वह इसके लिए अन्य पुस्तकालयों में नहीं खोजता है
  2. पुस्तकालयों को जोड़ने का क्रम मायने रखता है
  3. यदि लिंकर को एक स्थिर पुस्तकालय में एक बाहरी प्रतीक मिलता है, तो वह परियोजना के आउटपुट में प्रतीक को शामिल करता है। फिर भी, यदि पुस्तकालय साझा (गतिशील) है तो वह कोड (प्रतीकों) को आउटपुट में शामिल नहीं करता है, लेकिन रन-टाइम क्रैश हो सकता है पाए जाते हैं

इस तरह की त्रुटि को कैसे हल करें

संकलक समय त्रुटि:

  • सुनिश्चित करें कि आप अपना c ++ प्रोजेक्ट सिंटेक्टिकल सही लिखें।

लिंकर टाइम एरर

  • अपने सभी प्रतीक को परिभाषित करें जिसे आप अपनी हेडर फ़ाइलों में घोषित करते हैं
  • #pragma onceसंकलक को एक हेडर शामिल न करने देने के लिए उपयोग करें यदि यह पहले से ही वर्तमान .cpp में शामिल है जो संकलित हैं
  • सुनिश्चित करें कि आपकी बाहरी लाइब्रेरी में ऐसे प्रतीक नहीं हैं जो आपके हेडर फ़ाइलों में परिभाषित किए गए अन्य प्रतीकों के साथ संघर्ष में प्रवेश कर सकते हैं
  • जब आप यह सुनिश्चित करने के लिए टेम्प्लेट का उपयोग करते हैं कि आप हेडर फ़ाइल में प्रत्येक टेम्प्लेट फ़ंक्शन की परिभाषा शामिल करते हैं, तो कंपाइलर किसी भी इंस्टेंटिएशन के लिए उपयुक्त कोड उत्पन्न करने की अनुमति देता है।

क्या आपका जवाब दृश्य स्टूडियो के लिए विशिष्ट नहीं है? प्रश्न किसी भी आईडीई / संकलक उपकरण को निर्दिष्ट नहीं करता है, इसलिए यह आपके उत्तर को गैर-दृश्य-स्टूडियो भाग के लिए बेकार बनाता है।
विक्टर पोल्वॉय

आप सही हे । लेकिन संकलन / लिंकिंग की प्रत्येक आईडीई प्रक्रिया में हर प्रक्रिया को थोड़ा अलग तरीके से किया जा रहा है। लेकिन फाइलों को बिल्कुल एक ही तरह से संसाधित किया जाता है (यहां तक ​​कि जी + + वही काम करता है जब यह झंडे को पार्स करता है ..)

समस्या वास्तव में आईडीई के बारे में नहीं है, लेकिन समस्याओं को जोड़ने के लिए एक उत्तर के बारे में है। लिंकिंग समस्याएं IDE से संबंधित नहीं हैं बल्कि कंपाइलर और बिल्ड प्रक्रिया से संबंधित हैं।
विक्टर पोलेवॉय

हां.लेकिन बिल्ड / लिंकिंग की प्रक्रिया g ++ / विज़ुअल स्टूडियो (VS के लिए Microsoft द्वारा प्रदान किया गया कंपाइलर) / ग्रहण / नेट बीन्स पर उसी तरह से किया जा रहा है

29

कंपाइलर / आईडीई में एक बग

मुझे हाल ही में यह समस्या हुई थी, और यह दृश्य स्टूडियो एक्सप्रेस 2013 में एक बग था । मुझे प्रोजेक्ट से एक स्रोत फ़ाइल को निकालना था और बग को दूर करने के लिए इसे फिर से जोड़ना था।

यदि आप मानते हैं कि यह कंपाइलर / IDE में बग हो सकता है, तो प्रयास करने के चरण:

  • प्रोजेक्ट को साफ करें (कुछ आईडीई के पास ऐसा करने का विकल्प है, आप ऑब्जेक्ट फ़ाइलों को हटाकर मैन्युअल रूप से भी कर सकते हैं)
  • मूल से सभी स्रोत कोड की नकल करते हुए, एक नया प्रोजेक्ट शुरू करने का प्रयास करें।

5
यह मानते हुए कि आपके उपकरण टूट गए हैं, सबसे अधिक संभावना है कि आप सच्चे कारण से दूर जा रहे हैं। यह केवल इतनी अधिक संभावना है कि आपने संकलक की तुलना में गलती की है जिससे आपकी समस्या हुई। अपने समाधान को साफ करना या अपने बिल्ड कॉन्फ़िगरेशन को फिर से बनाना, त्रुटियों को ठीक कर सकता है, लेकिन इसका मतलब यह नहीं है कि कंपाइलर में कोई बग है। लिंक किया गया "यह पता चला कि यह एक बग था" Microsoft द्वारा पुष्टि नहीं की गई है और प्रतिलिपि प्रस्तुत करने योग्य नहीं है।
JDiMatteo

4
@JDiMatteo इस सवाल पर 21 जवाब हैं और इसलिए उत्तर की एक महत्वपूर्ण राशि एक "संभावना" समाधान नहीं होने जा रहा है। यदि आप उन सभी उत्तरों को खारिज कर देते हैं जो आपकी संभावना सीमा से नीचे हैं, तो यह पृष्ठ प्रभावी रूप से बेकार हो जाता है क्योंकि अधिकांश आम मामले वैसे भी आसानी से देखे जा सकते हैं।
डेवलपर

27

त्रुटि का निदान करने में सहायता के लिए लिंकर का उपयोग करें

अधिकांश आधुनिक लिंकर्स में एक क्रिया विकल्प शामिल होता है जो अलग-अलग डिग्री तक प्रिंट करता है;

  • लिंक मंगलाचरण (कमांड लाइन),
  • लाइब्रेरियों को लिंक चरण में शामिल करने पर डेटा,
  • पुस्तकालयों का स्थान,
  • उपयोग किए गए खोज पथ।

Gcc और clang के लिए; आप आम तौर पर जोड़ना होगा -v -Wl,--verboseया -v -Wl,-vकमांड लाइन करने के लिए। अधिक विवरण यहां मिल सकता है;

MSVC के लिए, /VERBOSE(विशेष रूप से /VERBOSE:LIB) लिंक कमांड लाइन में जोड़ा जाता है।


26

लिंक्ड .लिब फ़ाइल .dll से संबंधित है

मेरी भी यही समस्या थी। मान लीजिए कि मेरे पास MyProject और TestProject प्रोजेक्ट हैं। मैंने MyProject के लिए lib फाइल को TestProject में प्रभावी रूप से जोड़ा था। हालाँकि, इस lib फ़ाइल को MyLject के लिए DLL के रूप में निर्मित किया गया था। इसके अलावा, मेरे पास MyProject में सभी तरीकों के लिए स्रोत कोड नहीं था, लेकिन केवल DLL के प्रवेश बिंदुओं तक पहुंच है।

समस्या को हल करने के लिए, मैंने MyProject को LIB के रूप में बनाया, और TestProject को इस .lib फ़ाइल से जोड़ा (i जनरेट हुई .lib फ़ाइल को TestProject फ़ोल्डर में पेस्ट करें)। मैं फिर एक DLL के रूप में फिर से MyProject का निर्माण कर सकता हूं। यह संकलित किया जा रहा है क्योंकि टेस्टप्रोजेक्ट से जुड़ी लीब में माईप्रोजेक्ट की कक्षाओं में सभी विधियों के लिए कोड होता है।


25

चूँकि लोगों को इस प्रश्न के लिए निर्देशित किया जा रहा है जब यह लिंकर त्रुटियों की बात आती है मैं इसे यहाँ जोड़ने जा रहा हूँ।

जीसीसी 5.2.0 के साथ लिंकर त्रुटियों का एक संभावित कारण यह है कि अब एक नया libstdc ++ लाइब्रेरी ABI डिफ़ॉल्ट रूप से चुना गया है।

यदि आपको std :: __ cxx11 नाम स्थान या टैग [abi: cxx11] में प्रतीकों के अपरिभाषित संदर्भों के बारे में लिंकर त्रुटियां मिलती हैं, तो यह संभवतः इंगित करता है कि आप _GLIBCXX_USE_CXX11_ABI के लिए विभिन्न मानों के साथ संकलित ऑब्जेक्ट फ़ाइलों को एक साथ जोड़ने का प्रयास कर रहे हैं। मैक्रो। यह आमतौर पर तीसरे पक्ष के पुस्तकालय से लिंक करते समय होता है जिसे जीसीसी के पुराने संस्करण के साथ संकलित किया गया था। अगर नए ABI के साथ थर्ड-पार्टी लाइब्रेरी का पुनर्निर्माण नहीं किया जा सकता है, तो आपको पुराने ABI के साथ अपने कोड को फिर से जोड़ना होगा।

इसलिए अगर आपको 5.1.0 के बाद जीसीसी में स्विच करते समय अचानक लिंकर की त्रुटियां आती हैं, तो यह जांचने की चीज होगी।


20

GNU ld के आसपास एक आवरण जो लिंकर स्क्रिप्ट का समर्थन नहीं करता है

कुछ .so फाइलें वास्तव में GNU ld linker स्क्रिप्ट हैं , जैसे libtbb.so फाइल इस के लिए एक ASCII टेक्स्ट फाइल है:

INPUT (libtbb.so.2)

कुछ और जटिल बिल्ड इसका समर्थन नहीं कर सकते हैं। उदाहरण के लिए, यदि आप संकलक विकल्पों में -v शामिल करते हैं, तो आप देख सकते हैं कि लिंक करने के लिए पुस्तकालयों की वर्बोज़ आउटपुट सूची में मेनविन gcc रैपर mwdip डिस्क्स लिंकर स्क्रिप्ट कमांड फ़ाइलें। चारों ओर एक साधारण काम लिंकर स्क्रिप्ट इनपुट कमांड को बदलने के लिए है। इसके बजाय फ़ाइल की एक प्रति (या एक सिमलिंक) के साथ फाइल करें, जैसे

cp libtbb.so.2 libtbb.so

या -l तर्क को .so के पूर्ण पथ से प्रतिस्थापित कर सकते हैं, जैसे कि -ltbbdo के बजाय/home/foo/tbb-4.3/linux/lib/intel64/gcc4.4/libtbb.so.2


20

आपका लिंकेज ऑब्जेक्ट फ़ाइलों से पहले पुस्तकालयों की खपत करता है जो उन्हें संदर्भित करता है

  • आप अपने कार्यक्रम को जीसीसी टूलकिन के साथ संकलित करने और जोड़ने की कोशिश कर रहे हैं।
  • आपका लिंकेज सभी आवश्यक पुस्तकालयों और पुस्तकालय खोज पथों को निर्दिष्ट करता है
  • यदि पर libfooनिर्भर करता है libbar, तो आपका लिंकेज सही तरीके libfooसे पहले रखता है libbar
  • आपका लिंक undefined reference to कुछ त्रुटियों के साथ विफल हो जाता है
  • लेकिन आपके द्वारा की गई हेडर फाइलों में सभी अपरिभाषित कुछ s घोषित किए #includeजाते हैं और वास्तव में उन पुस्तकालयों में परिभाषित होते हैं जिन्हें आप लिंक कर रहे हैं।

उदाहरण सी में हैं। वे समान रूप से अच्छी तरह से सी ++ हो सकते हैं

आपके द्वारा बनाए गए स्थिर पुस्तकालय में शामिल एक न्यूनतम उदाहरण

my_lib.c

#include "my_lib.h"
#include <stdio.h>

void hw(void)
{
    puts("Hello World");
}

my_lib.h

#ifndef MY_LIB_H
#define MT_LIB_H

extern void hw(void);

#endif

eg1.c

#include <my_lib.h>

int main()
{
    hw();
    return 0;
}

आप अपनी स्थैतिक लाइब्रेरी का निर्माण करते हैं:

$ gcc -c -o my_lib.o my_lib.c
$ ar rcs libmy_lib.a my_lib.o

आप अपना कार्यक्रम संकलित करें:

$ gcc -I. -c -o eg1.o eg1.c

आप इसे जोड़ने libmy_lib.aऔर विफल करने का प्रयास करते हैं:

$ gcc -o eg1 -L. -lmy_lib eg1.o 
eg1.o: In function `main':
eg1.c:(.text+0x5): undefined reference to `hw'
collect2: error: ld returned 1 exit status

एक ही परिणाम यदि आप एक चरण में संकलित और लिंक करते हैं, जैसे:

$ gcc -o eg1 -I. -L. -lmy_lib eg1.c
/tmp/ccQk1tvs.o: In function `main':
eg1.c:(.text+0x5): undefined reference to `hw'
collect2: error: ld returned 1 exit status

एक साझा प्रणाली पुस्तकालय, संपीड़न पुस्तकालय में शामिल एक न्यूनतम उदाहरण libz

eg2.c

#include <zlib.h>
#include <stdio.h>

int main()
{
    printf("%s\n",zlibVersion());
    return 0;
}

अपना कार्यक्रम संकलित करें:

$ gcc -c -o eg2.o eg2.c

अपने प्रोग्राम को जोड़ने libzऔर विफल करने का प्रयास करें :

$ gcc -o eg2 -lz eg2.o 
eg2.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'
collect2: error: ld returned 1 exit status

यदि आप संकलित करते हैं और एक ही बार में लिंक करते हैं:

$ gcc -o eg2 -I. -lz eg2.c
/tmp/ccxCiGn7.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'
collect2: error: ld returned 1 exit status

और उदाहरण 2 में एक भिन्नता शामिल है pkg-config:

$ gcc -o eg2 $(pkg-config --libs zlib) eg2.o 
eg2.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'

आप क्या गलत कर रहे हैं?

ऑब्जेक्ट फ़ाइलों और पुस्तकालयों के अनुक्रम में आप अपने प्रोग्राम को बनाने के लिए लिंक करना चाहते हैं, आप ऑब्जेक्ट फ़ाइलों से पहले पुस्तकालयों को रख रहे हैं जो उन्हें संदर्भित करते हैं। आपको इसके बाद पुस्तकालयों को रखने की आवश्यकता है उन ऑब्जेक्ट फ़ाइलों के जो उन्हें संदर्भित करते हैं।

लिंक उदाहरण 1 सही ढंग से:

$ gcc -o eg1 eg1.o -L. -lmy_lib

सफलता:

$ ./eg1 
Hello World

लिंक उदाहरण 2 सही ढंग से:

$ gcc -o eg2 eg2.o -lz

सफलता:

$ ./eg2 
1.2.8

उदाहरण 2 pkg-configविविधता को सही ढंग से लिंक करें :

$ gcc -o eg2 eg2.o $(pkg-config --libs zlib) 
$ ./eg2
1.2.8

स्पष्टीकरण

पढ़ना यहाँ से वैकल्पिक है

डिफ़ॉल्ट रूप से, आपके डिस्ट्रो पर जीसीसी द्वारा उत्पन्न एक लिंकेज कमांड, कमांडलाइन अनुक्रम में बाएं से दाएं लिंकेज में फाइलों का उपभोग करता है। जब यह पता चलता है कि एक फ़ाइल किसी चीज़ को संदर्भित करती है और इसके लिए परिभाषा नहीं होती है, तो आगे दाईं ओर फ़ाइलों में परिभाषा की खोज की जाएगी। यदि यह अंततः एक परिभाषा पाता है, तो संदर्भ हल हो जाता है। यदि कोई संदर्भ अंत में अनसुलझे रहते हैं, तो लिंकेज विफल हो जाता है: लिंकर पीछे की ओर नहीं खोजता है।

सबसे पहले, उदाहरण 1 , स्थैतिक पुस्तकालय के साथmy_lib.a

एक स्थिर पुस्तकालय ऑब्जेक्ट फ़ाइलों का एक अनुक्रमित संग्रह है। जब लिंकर -lmy_libलिंकेज अनुक्रम में पाता है और यह पता लगाता है कि यह स्थैतिक पुस्तकालय को संदर्भित करता है ./libmy_lib.a, तो यह जानना चाहता है कि क्या आपके प्रोग्राम को ऑब्जेक्ट फ़ाइलों में से किसी की आवश्यकता है libmy_lib.a

libmy_lib.aअर्थात् में केवल ऑब्जेक्ट फ़ाइल है , my_lib.oऔर वहाँ केवल एक चीज में परिभाषित है my_lib.o, अर्थात् कार्य hw

लिंकर यह तय करेगा कि आपके कार्यक्रम की जरूरत my_lib.oहै और केवल अगर यह पहले से ही जानता है कि आपके कार्यक्रम को संदर्भित करता है hw, तो एक या एक से अधिक ऑब्जेक्ट फ़ाइलों में यह पहले से ही प्रोग्राम में जोड़ा गया है, और यह कि पहले से ही जोड़ा गया ऑब्जेक्ट फ़ाइलों में से कोई भी शामिल नहीं है के लिए परिभाषा hw

यदि यह सच है, तो लिंकर my_lib.oपुस्तकालय से एक प्रति निकालेगा और आपके कार्यक्रम में जोड़ देगा। फिर, आपके कार्यक्रम में एक परिभाषा है hw, इसलिए इसके संदर्भ हलhw किए जाते हैं ।

जब आप प्रोग्राम को लिंक करने का प्रयास करते हैं जैसे:

$ gcc -o eg1 -L. -lmy_lib eg1.o

लिंकर प्रोग्राम को देखता है जब यह जोड़ा नहीं है । क्योंकि उस बिंदु पर, यह नहीं देखा है । आपका कार्यक्रम अभी तक के सभी संदर्भ पड़ता है नहीं : यह अभी तक कोई भी संदर्भ नहीं है सब पर है, क्योंकि सभी संदर्भों को यह बनाता है में हैं ।eg1.o -lmy_libeg1.ohweg1.o

इसलिए लिंकर my_lib.oकार्यक्रम में शामिल नहीं होता है और इसका कोई और उपयोग नहीं है libmy_lib.a

अगला, इसे पाता है eg1.o, और इसे प्रोग्राम होने के लिए जोड़ता है। लिंकेज अनुक्रम में एक ऑब्जेक्ट फ़ाइल को हमेशा प्रोग्राम में जोड़ा जाता है। अब, कार्यक्रम एक संदर्भ बनाता है hw, और इसमें परिभाषा नहीं होती है hw; लेकिन लिंकेज अनुक्रम में कुछ भी नहीं बचा है जो लापता परिभाषा प्रदान कर सकता है। संदर्भ अनसुलझेhw समाप्त होता है , और लिंकेज विफल हो जाता है।

साझा पुस्तकालय के साथ दूसरा, उदाहरण 2libz

एक साझा लाइब्रेरी ऑब्जेक्ट फ़ाइलों या इसके जैसे कुछ का संग्रह नहीं है। यह एक प्रोग्राम की तरह बहुत अधिक है, जिसमें कोई mainफ़ंक्शन नहीं है और इसके बजाय यह परिभाषित करने वाले कई अन्य प्रतीकों को उजागर करता है, ताकि अन्य प्रोग्राम रनटाइम के दौरान उनका उपयोग कर सकें।

कई Linux distros आज उनके जीसीसी toolchain ताकि उसके भाषा ड्राइवरों (कॉन्फ़िगर gcc, g++, gfortranआदि) प्रणाली लिंकर (हिदायत ldएक पर लिंक साझा पुस्तकालयों के लिए) के रूप में जरूरी आधार। आपको उन विकृतियों में से एक मिला है।

इसका मतलब यह है कि जब लिंकर -lzलिंकेज अनुक्रम में पाता है, और यह पता लगाता है कि यह साझा लाइब्रेरी (कहता है) को संदर्भित करता है /usr/lib/x86_64-linux-gnu/libz.so, तो यह जानना चाहता है कि क्या आपके प्रोग्राम में शामिल किए गए किसी भी संदर्भ को अभी तक परिभाषित नहीं किया गया है, इसकी परिभाषाएं हैं द्वारा निर्यात किया गयाlibz

अगर यह सच है, तो लिंकर बाहर किसी भी हिस्सा को कॉपी नहीं करेगा libzऔर उन्हें आपके प्रोग्राम में जोड़ देगा; इसके बजाय, यह सिर्फ आपके प्रोग्राम के कोड को डॉक्टर करेगा ताकि: -

  • रनटाइम के दौरान, सिस्टम प्रोग्राम लोडर libzआपके प्रोग्राम की एक ही प्रक्रिया में एक कॉपी लोड करेगा जब भी यह आपके प्रोग्राम की एक कॉपी लोड करता है, इसे चलाने के लिए।

  • रनटाइम के दौरान, जब भी आपका प्रोग्राम किसी ऐसी चीज़ को संदर्भित करता है, जिसे उस परिभाषित किया जाता है libz, तो संदर्भ libzउसी प्रक्रिया की कॉपी द्वारा निर्यात की गई परिभाषा का उपयोग करता है।

आपका कार्यक्रम केवल एक चीज को संदर्भित करना चाहता है जिसकी एक परिभाषा है libzजिसका निर्यात किया जाता है , अर्थात् फ़ंक्शन zlibVersion, जिसे केवल एक बार, में संदर्भित किया जाता है eg2.c। यदि लिंकर आपके कार्यक्रम में उस संदर्भ को जोड़ता है, और फिर द्वारा निर्यात की गई परिभाषा पाता है libz, तो संदर्भ हल हो जाता है

लेकिन जब आप प्रोग्राम को लिंक करने का प्रयास करते हैं जैसे:

gcc -o eg2 -lz eg2.o

घटनाओं का क्रम ठीक उसी तरह से गलत है जैसे उदाहरण 1। जिस बिंदु पर जब लिंकर को पता चलता है -lz, तो कार्यक्रम में किसी भी चीज का कोई संदर्भ नहीं होता है : वे सभी अंदर हैं eg2.o, जो अभी तक नहीं देखा गया है। तो लिंकर यह तय करता है कि इसका कोई उपयोग नहीं है libz। जब यह पहुंचता है eg2.o, तो इसे प्रोग्राम में जोड़ता है, और फिर इसका अपरिभाषित संदर्भ होता है zlibVersion, लिंकेज अनुक्रम समाप्त हो जाता है; वह संदर्भ अनसुलझा है, और लिंकेज विफल है।

अंत में, pkg-configउदाहरण 2 की भिन्नता का अब स्पष्ट स्पष्टीकरण है। शेल-विस्तार के बाद:

gcc -o eg2 $(pkg-config --libs zlib) eg2.o

हो जाता है:

gcc -o eg2 -lz eg2.o

जो सिर्फ 2 उदाहरण फिर से है।

मैं उदाहरण 1 में समस्या को पुन: पेश कर सकता हूं, लेकिन उदाहरण 2 में नहीं

लिंकेज:

gcc -o eg2 -lz eg2.o

तुम्हारे लिए ठीक काम करता है!

(या: लिंकेज ने आपके लिए ठीक काम किया, कहते हैं, फेडोरा 23, लेकिन उबंटू 16.04 पर विफल रहता है)

ऐसा इसलिए है क्योंकि डिस्ट्रॉ जिस पर लिंकेज काम करता है, उनमें से एक है जो अपने जीसीसी टूलकिन को साझा पुस्तकालयों को आवश्यकतानुसार जोड़ने के लिए कॉन्फ़िगर नहीं करता है ।

दिन में, यूनिक्स जैसी प्रणालियों के लिए विभिन्न नियमों द्वारा स्थिर और साझा पुस्तकालयों को जोड़ना सामान्य था। एक सीक्वेंस सीक्वेंस में स्टेटिक लाइब्रेरीज़ को उदाहरण 1 में बताए गए आवश्यक आधार पर लिंक किया गया था , लेकिन साझा लाइब्रेरी को बिना शर्त लिंक किया गया था।

यह व्यवहार लिंकटाइम पर किफायती है क्योंकि लिंक करने वाले को यह विचार करने की आवश्यकता नहीं है कि प्रोग्राम द्वारा साझा लाइब्रेरी की आवश्यकता है: यदि यह एक साझा लाइब्रेरी है, तो इसे लिंक करें। और अधिकांश लिंकेज में अधिकांश लाइब्रेरी साझा लाइब्रेरी हैं। लेकिन इसके नुकसान भी हैं: -

  • यह रनटाइम में अनौपचारिक है , क्योंकि यह साझा पुस्तकालयों को एक कार्यक्रम के साथ लोड किए जाने का कारण बन सकता है, भले ही उनकी आवश्यकता न हो।

  • स्थिर और साझा पुस्तकालयों के लिए अलग-अलग लिंकेज नियम अनुभवहीन प्रोग्रामर को भ्रमित कर सकते हैं, जो यह नहीं जान सकते हैं कि -lfooउनके लिंकेज में /some/where/libfoo.aया तो समाधान करने जा रहे हैं या नहीं /some/where/libfoo.so, और वैसे भी साझा और स्थिर पुस्तकालयों के बीच अंतर को समझ नहीं सकते हैं।

इस व्यापार बंद के कारण आज विद्वतापूर्ण स्थिति पैदा हो गई है। कुछ पुस्तकालयों ने साझा पुस्तकालयों के लिए अपने जीसीसी लिंकेज नियमों को बदल दिया है ताकि सभी पुस्तकालयों के लिए आवश्यक सिद्धांत लागू हो। कुछ डिस्ट्रॉर्स पुराने तरीके से अटक गए हैं।

अगर मुझे उसी समय संकलन और लिंक भी मिल जाता है, तो भी मुझे यह समस्या क्यों आती है?

अगर मैं बस:

$ gcc -o eg1 -I. -L. -lmy_lib eg1.c

निश्चित रूप से जीसीसी को eg1.cपहले संकलित करना है , और फिर परिणामी ऑब्जेक्ट फ़ाइल के साथ लिंक करना है libmy_lib.a। तो यह कैसे पता नहीं चल सकता है कि लिंक करते समय ऑब्जेक्ट फ़ाइल की आवश्यकता है?

क्योंकि एकल कमांड के साथ संकलन और लिंक करना लिंकेज अनुक्रम के क्रम को नहीं बदलता है।

जब आप ऊपर कमांड चलाते हैं, gccतो यह पता लगाते हैं कि आप संकलन + लिंकेज चाहते हैं। तो पर्दे के पीछे, यह एक संकलन कमांड उत्पन्न करता है, और इसे चलाता है, फिर एक लिंकेज कमांड उत्पन्न करता है, और इसे चलाता है, जैसे कि आपने दो कमांड चलाए थे:

$ gcc -I. -c -o eg1.o eg1.c
$ gcc -o eg1 -L. -lmy_lib eg1.o

तो कड़ी में विफल रहता है अगर आप बस के रूप में यह होता है है उन दो आदेशों को चलाने के। विफलता में आपको केवल इतना ही अंतर दिखाई देता है कि जीसीसी ने संकलन + लिंक मामले में एक अस्थायी ऑब्जेक्ट फ़ाइल उत्पन्न की है, क्योंकि आप इसे उपयोग करने के लिए नहीं कह रहे हैं eg1.o। हम देखते हैं:

/tmp/ccQk1tvs.o: In function `main'

के बजाय:

eg1.o: In function `main':

यह सभी देखें

जिस क्रम में अन्योन्याश्रित लिंक्ड लाइब्रेरी निर्दिष्ट की गई है वह गलत है

गलत क्रम में अन्योन्याश्रित पुस्तकालयों लाना सिर्फ एक तरीका है जिसमें आप फ़ाइलों को प्राप्त कर सकते हैं की जरूरत है जो फ़ाइलें से संबंध में बाद में आने वाले चीजों की परिभाषा प्रदान परिभाषाएँ। ऑब्जेक्ट फाइल्स के सामने लाइब्रेरियों को रखना जो उन्हें संदर्भित करते हैं, वही गलती करने का एक और तरीका है।


18

मित्रतापूर्ण टेम्पलेट ...

एक दोस्त ऑपरेटर (या फ़ंक्शन) के साथ टेम्पलेट प्रकार के कोड स्निपेट को देखते हुए;

template <typename T>
class Foo {
    friend std::ostream& operator<< (std::ostream& os, const Foo<T>& a);
};

operator<<एक गैर टेम्पलेट समारोह के रूप में घोषित किया जा रहा है। Tसाथ उपयोग किए जाने वाले हर प्रकार के लिए Foo, गैर-अस्थायी होना चाहिए operator<<। उदाहरण के लिए, यदि कोई प्रकार Foo<int>घोषित किया गया है, तो निम्नानुसार एक ऑपरेटर कार्यान्वयन होना चाहिए;

std::ostream& operator<< (std::ostream& os, const Foo<int>& a) {/*...*/}

चूंकि इसे लागू नहीं किया गया है, लिंकर इसे खोजने में विफल रहता है और परिणाम में त्रुटि होती है।

इसे ठीक करने के लिए, आप Fooटाइप करने से पहले एक टेम्प्लेट ऑपरेटर की घोषणा कर सकते हैं और फिर एक मित्र के रूप में घोषित कर सकते हैं , उपयुक्त तात्कालिकता। वाक्य-विन्यास थोड़ा अजीब है, लेकिन निम्नानुसार है;

// forward declare the Foo
template <typename>
class Foo;

// forward declare the operator <<
template <typename T>
std::ostream& operator<<(std::ostream&, const Foo<T>&);

template <typename T>
class Foo {
    friend std::ostream& operator<< <>(std::ostream& os, const Foo<T>& a);
    // note the required <>        ^^^^
    // ...
};

template <typename T>
std::ostream& operator<<(std::ostream&, const Foo<T>&)
{
  // ... implement the operator
}

उपरोक्त कोड ऑपरेटर की मित्रता को उसी तात्कालिकता तक सीमित करता है Foo, अर्थात operator<< <int>तात्कालिकता के निजी सदस्यों तक पहुँचने के लिए सीमित है Foo<int>

विकल्पों में शामिल हैं;

  • टेम्प्लेट्स के सभी इंस्टालेशन को बढ़ाने के लिए दोस्ती की अनुमति;

    template <typename T>
    class Foo {
        template <typename T1>
        friend std::ostream& operator<<(std::ostream& os, const Foo<T1>& a);
        // ...
    };
  • या, operator<<कक्षा परिभाषा के अंदर इनलाइन के लिए कार्यान्वयन किया जा सकता है;

    template <typename T>
    class Foo {
        friend std::ostream& operator<<(std::ostream& os, const Foo& a)
        { /*...*/ }
        // ...
    };

ध्यान दें , जब ऑपरेटर (या फ़ंक्शन) की घोषणा केवल कक्षा में दिखाई देती है, तो नाम "सामान्य" लुकअप के लिए उपलब्ध नहीं है, केवल तर्क निर्भर लुकअप के लिए, cppreference से ;

क्लास या क्लास टेम्प्लेट X के भीतर एक मित्र घोषणा में घोषित पहला नाम X के नामस्थान को संलग्न करने वाले अंतरतम का सदस्य बन जाता है, लेकिन देखने के लिए सुलभ नहीं है (तर्क-निर्भर लुकअप को छोड़कर जो X को मानता है) जब तक कि नाम स्थान के दायरे में मिलान की घोषणा नहीं होती है प्रदान की ...

Cppreference और C ++ FAQ में टेम्पलेट दोस्तों पर आगे पढ़ना है ।

ऊपर दी गई तकनीकों को दिखाने वाली कोड लिस्टिंग


असफल कोड नमूने के साइड नोट के रूप में; g ++ इस बारे में चेतावनी देता है

warning: friend declaration 'std::ostream& operator<<(...)' declares a non-template function [-Wnon-template-friend]

note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)


16

जब आपके शामिल पथ अलग होते हैं

जब एक हेडर फ़ाइल और उससे जुड़ी साझा लाइब्रेरी (.lib फ़ाइल) सिंक से बाहर जाती हैं, तो लिंकर त्रुटियां हो सकती हैं। मुझे समझाने दो।

लिंकर कैसे काम करते हैं? लिंकर उनके हस्ताक्षर की तुलना करके अपनी परिभाषा (साझा पुस्तकालय में) के साथ एक फ़ंक्शन घोषणा (हेडर में घोषित) से मेल खाता है। यदि लिंकर को पूरी तरह से मेल खाने वाली फ़ंक्शन परिभाषा नहीं मिलती है, तो आप एक लिंकर त्रुटि प्राप्त कर सकते हैं।

क्या घोषणा और परिभाषा से मेल खाते हुए भी अभी भी एक लिंकर त्रुटि प्राप्त करना संभव है? हाँ! वे स्रोत कोड में समान दिख सकते हैं, लेकिन यह वास्तव में इस बात पर निर्भर करता है कि संकलक क्या देखता है। अनिवार्य रूप से आप इस तरह की स्थिति को समाप्त कर सकते हैं:

// header1.h
typedef int Number;
void foo(Number);

// header2.h
typedef float Number;
void foo(Number); // this only looks the same lexically

ध्यान दें कि भले ही दोनों फ़ंक्शन घोषणा स्रोत कोड में समान दिखते हैं, लेकिन वे संकलक के अनुसार वास्तव में भिन्न हैं।

आप पूछ सकते हैं कि इस तरह की स्थिति में कोई कैसे समाप्त होता है? पाठ्यक्रम के पथ शामिल करें ! यदि साझा किए गए पुस्तकालय को संकलित करते समय, पथ शामिल होता है header1.hऔर आप header2.hअपने स्वयं के कार्यक्रम का उपयोग करते हुए समाप्त हो जाते हैं , तो आपको अपने हेडर को यह सोचकर छोड़ दिया जाएगा कि क्या हुआ (दंडित उद्देश्य)।

वास्तविक दुनिया में यह कैसे हो सकता है इसका एक उदाहरण नीचे दिया गया है।

एक उदाहरण के साथ आगे विस्तार

मेरे पास दो प्रोजेक्ट हैं: graphics.libऔर main.exe। दोनों परियोजनाएं निर्भर करती हैं common_math.h। मान लीजिए कि पुस्तकालय निम्नलिखित समारोह का निर्यात करता है:

// graphics.lib    
#include "common_math.h" 

void draw(vec3 p) { ... } // vec3 comes from common_math.h

और फिर आप आगे बढ़ते हैं और लाइब्रेरी को अपने प्रोजेक्ट में शामिल करते हैं।

// main.exe
#include "other/common_math.h"
#include "graphics.h"

int main() {
    draw(...);
}

बूम! आपको एक लिंकर त्रुटि मिलती है और आपको पता नहीं है कि यह क्यों विफल हो रहा है। कारण यह है कि सामान्य पुस्तकालय में एक ही शामिल के विभिन्न संस्करणों का उपयोग किया जाता है common_math.h(मैंने उदाहरण में इसे एक अलग पथ को शामिल करके स्पष्ट किया है, लेकिन यह हमेशा इतना स्पष्ट नहीं हो सकता है। हो सकता है कि संकलक सेटिंग में शामिल पथ अलग हो) ।

इस उदाहरण में ध्यान दें, लिंकर आपको बताएगा कि यह नहीं मिल सकता है draw(), जब वास्तविकता में आप जानते हैं कि यह स्पष्ट रूप से पुस्तकालय द्वारा निर्यात किया जा रहा है। आप अपने सिर को खरोंचते हुए घंटों बिता सकते हैं कि क्या गलत हुआ। बात यह है, लिंकर एक अलग हस्ताक्षर देखता है क्योंकि पैरामीटर प्रकार थोड़ा अलग हैं। उदाहरण में, vec3दोनों परियोजनाओं में एक अलग प्रकार है जहां तक ​​संकलक का संबंध है। ऐसा इसलिए हो सकता है क्योंकि वे दो अलग-अलग फाइलों में शामिल हैं (शायद लाइब्रेरी के दो अलग-अलग संस्करणों से आने वाली फाइलें शामिल हैं)।

लिंकर को डीबग करना

DUMPBIN आपका दोस्त है, यदि आप Visual Studio का उपयोग कर रहे हैं। मुझे यकीन है कि अन्य संकलक के पास अन्य समान उपकरण हैं।

प्रक्रिया इस प्रकार है:

  1. लिंकर त्रुटि में दिए गए अजीब आम नाम पर ध्यान दें। (उदा। ड्रा @ ग्राफिक्स @ XYZ)।
  2. पुस्तकालय से निर्यात किए गए प्रतीकों को एक पाठ फ़ाइल में डंप करें।
  3. रुचि के निर्यात किए गए प्रतीक की खोज करें, और ध्यान दें कि मांगे गए नाम अलग हैं।
  4. ध्यान दें कि आम के नाम अलग-अलग क्यों समाप्त हुए। आप देख पाएंगे कि पैरामीटर प्रकार भिन्न हैं, भले ही वे स्रोत कोड में समान दिखें।
  5. कारण वे अलग हैं। ऊपर दिए गए उदाहरण में, वे भिन्न हैं क्योंकि अलग-अलग फ़ाइलों में शामिल हैं।

[१] परियोजना से मेरा मतलब है स्रोत फ़ाइलों का एक सेट जो एक पुस्तकालय या एक निष्पादन योग्य बनाने के लिए एक साथ जुड़े हुए हैं।

EDIT 1: समझने के लिए आसान होने के लिए पहले खंड को फिर से लिखें। अगर कुछ और तय करना है तो कृपया मुझे नीचे कमेंट करके बताएं। धन्यवाद!


15

असंगत UNICODEपरिभाषाएँ

एक Windows UNICODE बिल्ड TCHARआदि के साथ परिभाषित किया जा रहा है wchar_tआदि के रूप में बनाया गया है । जब के UNICODEरूप में परिभाषित के साथ निर्माण के TCHARरूप में परिभाषित नहीं के रूप में charआदि इन UNICODEऔर _UNICODEपरिभाषित सभी " T" स्ट्रिंग प्रकार को प्रभावित ; LPTSTR, LPCTSTRऔर उनके एल्क।

UNICODEपरिभाषित किए गए प्रोजेक्ट के साथ एक लाइब्रेरी का निर्माण करना और इसे एक ऐसी परियोजना में जोड़ने का प्रयास करना, जहां UNICODEपरिभाषित नहीं किया गया है, लिंकर त्रुटियों का परिणाम होगा क्योंकि परिभाषा में एक बेमेल होगा TCHAR; charबनाम wchar_t

त्रुटि में आमतौर पर एक फ़ंक्शन शामिल होता है charया एक wchar_tव्युत्पन्न प्रकार के साथ, ये शामिल हो सकते हैं std::basic_string<>आदि। कोड में प्रभावित फ़ंक्शन के माध्यम से ब्राउज़ करते समय, अक्सर एक संदर्भ TCHARया std::basic_string<TCHAR>आदि होगा। यह एक कथा-कहानी का संकेत है कि कोड मूल रूप से एक UNICODE और एक मल्टी-बाइट कैरेक्टर (या "संकीर्ण") दोनों के लिए बनाया गया था ।

इसे ठीक करने के लिए, UNICODE(और _UNICODE) की सुसंगत परिभाषा के साथ सभी आवश्यक पुस्तकालयों और परियोजनाओं का निर्माण करें ।

  1. यह या तो के साथ किया जा सकता है;

    #define UNICODE
    #define _UNICODE
  2. या परियोजना सेटिंग्स में;

    प्रोजेक्ट गुण> सामान्य> प्रोजेक्ट डिफॉल्ट> चरित्र सेट

  3. या कमांड लाइन पर;

    /DUNICODE /D_UNICODE

विकल्प के रूप में अच्छी तरह से लागू है, अगर UNICODE का उपयोग करने का इरादा नहीं है, तो सुनिश्चित करें कि परिभाषित सेट नहीं हैं, और / या मल्टी-कैरेक्टर सेटिंग का उपयोग परियोजनाओं में किया जाता है और लगातार लागू किया जाता है।

"रिलीज़" और "डीबग" के बीच संगत होना न भूलें।


14

स्वच्छ और पुनर्निर्माण

बिल्ड का "क्लीन" "डेड वुड" को हटा सकता है जिसे पिछले बिल्ड, फेल बिल्ड, अधूरे बिल्ड और अन्य बिल्ड सिस्टम से संबंधित बिल्ड मसलों के आसपास छोड़ दिया जा सकता है।

सामान्य तौर पर आईडीई या बिल्ड में "क्लीन" फ़ंक्शन के कुछ रूप शामिल होंगे, लेकिन यह सही तरीके से कॉन्फ़िगर नहीं किया जा सकता है (जैसे मैन्युअल मेकाइल में) या विफल हो सकता है (जैसे मध्यवर्ती या परिणामी बायनेरी केवल-पढ़ने के लिए हैं)।

एक बार "क्लीन" पूरा हो जाने के बाद, सत्यापित करें कि "क्लीन" सफल हो गया है और सभी जेनरेट की गई इंटरमीडिएट फाइल (उदाहरण के लिए स्वचालित मेफाइल) को सफलतापूर्वक हटा दिया गया है।

इस प्रक्रिया को अंतिम उपाय के रूप में देखा जा सकता है, लेकिन अक्सर यह एक अच्छा पहला कदम होता है ; खासकर यदि त्रुटि से संबंधित कोड हाल ही में जोड़ा गया है (या तो स्थानीय रूप से या स्रोत भंडार से)।


10

constचर घोषणाओं / परिभाषाओं में "बाहरी" गुम (केवल C ++)

C से आने वाले लोगों के लिए यह आश्चर्य की बात हो सकती है कि C ++ में वैश्विक constचर में आंतरिक (या स्थिर) लिंकेज है। सी में यह मामला नहीं था, क्योंकि सभी वैश्विक चर स्पष्ट रूप से हैं extern(यानी जब staticकीवर्ड गायब है)।

उदाहरण:

// file1.cpp
const int test = 5;    // in C++ same as "static const int test = 5"
int test2 = 5;

// file2.cpp
extern const int test;
extern int test2;

void foo()
{
 int x = test;   // linker error in C++ , no error in C
 int y = test2;  // no problem
}

हेडर फ़ाइल का उपयोग करना सही होगा और इसे file2.cpp और file1.cpp में शामिल करना होगा

extern const int test;
extern int test2;

वैकल्पिक रूप से कोई भी constस्पष्ट रूप से file1.cpp में चर की घोषणा कर सकता हैextern


8

हालांकि यह कई स्वीकृत उत्तरों के साथ एक बहुत पुराना प्रश्न है, मैं एक अस्पष्ट हल करने के लिए साझा करना चाहूंगा "अपरिभाषित संदर्भ" त्रुटि ।

पुस्तकालयों के विभिन्न संस्करण

मैं संदर्भित करने के लिए एक उपनाम का उपयोग कर रहा था std::filesystem::path: फ़ाइल सिस्टम मानक लाइब्रेरी में C ++ 17 के बाद से है, लेकिन मेरे प्रोग्राम को C ++ 14 में भी संकलन करने की आवश्यकता है, इसलिए मैंने एक परिवर्तनशील उपनाम का उपयोग करने का निर्णय लिया:

#if (defined _GLIBCXX_EXPERIMENTAL_FILESYSTEM) //is the included filesystem library experimental? (C++14 and newer: <experimental/filesystem>)
using path_t = std::experimental::filesystem::path;
#elif (defined _GLIBCXX_FILESYSTEM) //not experimental (C++17 and newer: <filesystem>)
using path_t = std::filesystem::path;
#endif

मान लीजिए कि मेरे पास तीन फाइलें हैं: main.cpp, file.h, file.cpp:

  • file.h # में शामिल है < प्रयोगात्मक :: filesystem > और ऊपर कोड है
  • file.cpp , file.h का कार्यान्वयन, # शामिल करें " file.h "
  • main.cpp # में < filesystem > और " file.h " शामिल हैं

मुख्य पुस्तकालयों में प्रयुक्त विभिन्न पुस्तकालयों पर ध्यान दें और file.h. चूंकि main.cpp # "include'd file.h <के बाद" फाइल सिस्टम >, फाइल सिस्टम के संस्करण का उपयोग किया था सी ++ 17 एक । मैं निम्नलिखित आदेशों के साथ कार्यक्रम को संकलित करता था:

$ g++ -g -std=c++17 -c main.cpp-> main.cpp को main.o
$ में g++ -g -std=c++17 -c file.cppसंकलित करता है -> file.cpp और file.h को file.o
$ में संकलित करता है g++ -g -std=c++17 -o executable main.o file.o -lstdc++fs-> main.o और file.o लिंक जोड़ता है

इस तरह किसी भी समारोह file.o में निहित और main.o में प्रयोग किया जाता है कि आवश्यकpath_t दे दी है "अपरिभाषित संदर्भ" त्रुटियों क्योंकि main.o करने के लिए भेजा std::filesystem::pathलेकिन file.o लिए std::experimental::filesystem::path

संकल्प

इसे ठीक करने के लिए मुझे बस <प्रायोगिक :: filesystem> को file.h में <filesystem> में बदलने की आवश्यकता थी ।


5

साझा पुस्तकालयों के खिलाफ लिंक करते समय, सुनिश्चित करें कि उपयोग किए गए प्रतीकों को छिपाया नहीं गया है।

जीसीसी का डिफ़ॉल्ट व्यवहार यह है कि सभी प्रतीक दिखाई देते हैं। हालाँकि, जब अनुवाद इकाइयाँ विकल्प के साथ निर्मित होती हैं -fvisibility=hidden, __attribute__ ((visibility ("default")))तो परिणामी साझा की गई वस्तु में केवल कार्य / चिह्न ही बाहरी होते हैं।

आप यह देख सकते हैं कि आपके द्वारा खोजे जा रहे प्रतीक क्या आह्वान द्वारा बाहरी हैं:

# -D shows (global) dynamic symbols that can be used from the outside of XXX.so
nm -D XXX.so | grep MY_SYMBOL 

छिपे हुए / स्थानीय प्रतीकों को nmलोअरकेस प्रतीक प्रकार के साथ दिखाया गया है , उदाहरण के tलिए कोड-सेक्शन के लिए `T के बजाय:

nm XXX.so
00000000000005a7 t HIDDEN_SYMBOL
00000000000005f8 T VISIBLE_SYMBOL

आप नामों को गिराने nmके विकल्प के साथ भी उपयोग कर सकते हैं -C(यदि C ++ का उपयोग किया गया था)।

विंडोज-डीएलएस के समान, एक सार्वजनिक कार्यों को परिभाषित के साथ चिह्नित करेगा, उदाहरण के लिए DLL_PUBLICपरिभाषित:

#define DLL_PUBLIC __attribute__ ((visibility ("default")))

DLL_PUBLIC int my_public_function(){
  ...
}

जो मोटे तौर पर विंडोज / MSVC- संस्करण से मेल खाती है:

#ifdef BUILDING_DLL
    #define DLL_PUBLIC __declspec(dllexport) 
#else
    #define DLL_PUBLIC __declspec(dllimport) 
#endif

दृश्यता के बारे में अधिक जानकारी gcc विकि पर देखी जा सकती है।


जब एक अनुवाद इकाई को संकलित किया जाता -fvisibility=hiddenहै जिसके परिणामस्वरूप प्रतीकों में अभी भी बाहरी लिंकेज होता है (ऊपरी केस प्रतीक प्रकार के साथ दिखाया जाता है nm) और इसका उपयोग बिना किसी बाहरी समस्या के बाहरी लिंकेज के लिए किया जा सकता है, यदि ऑब्जेक्ट फाइलें एक स्टैटिक लाइब्रेरी का हिस्सा बन जाती हैं। लिंकेज तभी स्थानीय हो जाता है जब ऑब्जेक्ट फाइल्स को एक साझा लाइब्रेरी में लिंक किया जाता है।

ऑब्जेक्ट फ़ाइल में कौन से प्रतीक छिपे हैं यह जानने के लिए:

>>> objdump -t XXXX.o | grep hidden
0000000000000000 g     F .text  000000000000000b .hidden HIDDEN_SYMBOL1
000000000000000b g     F .text  000000000000000b .hidden HIDDEN_SYMBOL2

आपको बाहरी प्रतीकों का उपयोग करना nm -CDया nm -gCDदेखना चाहिए । जीसीसी विकि पर दृश्यता भी देखें ।
jww

2

विभिन्न आर्किटेक्चर

आप एक संदेश देख सकते हैं जैसे:

library machine type 'x64' conflicts with target machine type 'X86'

उस स्थिति में, इसका मतलब है कि उपलब्ध प्रतीक आपके द्वारा संकलित किए जाने वाले की तुलना में एक अलग वास्तुकला के लिए हैं।

विज़ुअल स्टूडियो पर, यह गलत "प्लेटफ़ॉर्म" के कारण है, और आपको या तो उचित एक का चयन करना होगा या लाइब्रेरी का उचित संस्करण स्थापित करना होगा।

लिनक्स पर, यह गलत लाइब्रेरी फ़ोल्डर ( उदाहरण libके lib64लिए उपयोग करने के बजाय ) के कारण हो सकता है ।

MacOS पर, एक ही फाइल में दोनों आर्किटेक्चर को शिपिंग करने का विकल्प है। यह हो सकता है कि लिंक को दोनों संस्करणों के होने की उम्मीद है, लेकिन केवल एक ही है। यह गलत lib/ lib64फ़ोल्डर के साथ एक मुद्दा भी हो सकता है जहां पुस्तकालय उठाया जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.