কোন অপরিবর্তিত রেফারেন্স / অমীমাংসিত বাহ্যিক প্রতীক ত্রুটিটি কী এবং আমি কীভাবে এটি ঠিক করব?


1493

অপরিজ্ঞাত রেফারেন্স / অমীমাংসিত বাহ্যিক প্রতীক ত্রুটিগুলি কী কী? সাধারণ কারণগুলি কী কী এবং কীভাবে সেগুলি ঠিক করতে / প্রতিরোধ করবেন?

আপনার নিজের সম্পাদনা / যুক্ত করতে নির্দ্বিধায়


@ লুচিয়ানগ্রিগোর 'একটি উত্তর যুক্ত করতে নির্দ্বিধায় ' আপনি যদি অনুমতি দিতে চান তবে আমি আপনার প্রাথমিক উত্তরটি প্রাসঙ্গিক লিঙ্ক (আইএমএইচও) যুক্ত করতে পছন্দ করি।
ῥεῖ

19
একটি দরকারী উত্তর স্বীকার করার জন্য এই প্রশ্নটি খুব সাধারণ। আমি প্রশ্নটি নীচে না রেখে 1000+ খ্যাতিমান ব্যক্তিরা এ বিষয়ে মন্তব্য করে believe এরই মধ্যে আমি প্রচুর প্রশ্ন দেখতে পাচ্ছি যা বুদ্ধিমান এবং বন্ধ আমার কাছে খুব দরকারী very
আলবার্ট ভ্যান ডার হোর্স্ট

10
@ অ্যালবার্টভান্ডারহর্স্ট "একটি দরকারী উত্তর স্বীকার করার জন্য এই প্রশ্নটি খুব সাধারণ বিষয়" নীচের উত্তরগুলি কি কার্যকর নয়?
এলএফ

4
এগুলি কার্যকর হতে পারে, যেমন অনেক প্রশ্নের উত্তর যেমন খুব সাধারণ হিসাবে চিহ্নিত করা হয়।
অ্যালবার্ট ভ্যান ডার হোর্স্ট

1
আমি সবচেয়ে নতুন প্রজননযোগ্য উদাহরণটি এমন কিছু হিসাবে দেখতে চাই যা আমরা বেশিরভাগ নতুন ব্যবহারকারীদের কাছে সততার সাথে জিজ্ঞাসা করি। আমি এর দ্বারা কোনও অর্থ বোঝাতে চাই না, এটি ঠিক - আমরা আমাদের নিজের উপর চাপিয়ে দেওয়া বিধিগুলি অনুসরণ করার লোকদের আশা করতে পারি না।
ড্যানিলো

উত্তর:


848

একটি সি ++ প্রোগ্রাম সংকলনটি ২.২ (রেফারেন্সের জন্য কীথ থম্পসনের কাছে ক্রেডিট) দ্বারা নির্দিষ্ট করা হিসাবে কয়েকটি ধাপে সংঘটিত হয় :

অনুবাদের বাক্য গঠন নিয়মের মধ্যে প্রাধান্য নিম্নলিখিত ধাপগুলি দ্বারা নির্দিষ্ট করা হয়েছে [পাদটীকা দেখুন]

  1. শারীরিক উত্স ফাইলের অক্ষরগুলি ম্যাপ করা হয়, একটি প্রয়োগকরণ-সংজ্ঞায়িত পদ্ধতিতে, মূল উত্স অক্ষর সেটটিতে (প্রয়োজনীয় যদি প্রয়োজন হয় তবে লাইন সূচকগুলির জন্য নতুন-লাইন অক্ষর প্রবর্তন করা হবে)। [স্নিপ]
  2. তাত্ক্ষণিকভাবে একটি নতুন-রেখাযুক্ত অক্ষর (bac) এর ব্যাকস্ল্যাশ অক্ষরের প্রতিটি উদাহরণ মুছে ফেলা হবে, লজিকাল উত্স লাইনগুলি গঠনের জন্য দৈহিক উত্স লাইনগুলি বিভক্ত করে। [স্নিপ]
  3. উত্স ফাইলটি প্রোট্রোসেসিং টোকেনগুলি (2.5) এবং সাদা-স্থানের অক্ষরের ক্রম (মন্তব্য সহ )গুলিতে বিভক্ত হয়েছে। [স্নিপ]
  4. প্রাক-প্রসেসিং নির্দেশিকা কার্যকর করা হয়, ম্যাক্রো আমন্ত্রণগুলি প্রসারিত করা হয়, এবং_প্রেগমা অ্যানারি অপারেটর এক্সপ্রেশন কার্যকর করা হয়। [স্নিপ]
  5. প্রতিটি উত্স অক্ষর অক্ষর অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষর অক্ষর অক্ষর অক্ষর অক্ষর অক্ষর অক্ষর অক্ষর অক্ষর অক্ষরে অক্ষর রূপান্তরিত হয়; [স্নিপ]
  6. সংলগ্ন স্ট্রিং আক্ষরিক টোকেন সংক্ষিপ্ত হয়।
  7. টোকেনগুলি পৃথক করে সাদা-স্থানের অক্ষরগুলি আর তাত্পর্যপূর্ণ নয়। প্রতিটি প্রাক-প্রসেসিং টোকন টোকেনে রূপান্তরিত হয়। (2.7)। ফলস্বরূপ টোকেনগুলি সিনট্যাক্টিকাল এবং শব্দার্থবিজ্ঞানের সাথে বিশ্লেষণ করা হয় এবং অনুবাদ ইউনিট হিসাবে অনুবাদ করা হয়। [স্নিপ]
  8. অনুবাদকৃত অনুবাদ ইউনিট এবং ইনস্ট্যান্টেশন ইউনিটগুলি নীচে একত্রিত হয়েছে: [এসএনআইপি]
  9. সমস্ত বাহ্যিক সত্তার রেফারেন্সগুলি সমাধান করা হয়েছে। লাইব্রেরির উপাদানগুলি বর্তমান অনুবাদে সংজ্ঞায়িত নয় এমন সত্তাগুলির বাহ্যিক রেফারেন্সগুলি পূরণ করার জন্য লিঙ্কযুক্ত। এই জাতীয় সমস্ত অনুবাদক আউটপুট একটি প্রোগ্রামের ছবিতে সংগ্রহ করা হয় যা এর কার্যকর করার পরিবেশে কার্যকর করার জন্য প্রয়োজনীয় তথ্য ধারণ করে। (জোর আমার)

[পাদটীকা] বাস্তবায়নগুলি অবশ্যই এমন আচরণ করবে যেন এই পৃথক পর্যায়গুলি ঘটে, যদিও অনুশীলনে বিভিন্ন ধাপগুলি একসাথে ভাঁজ করা যেতে পারে।

সংকলনের এই শেষ পর্যায়ে নির্দিষ্ট ত্রুটিগুলি ঘটে থাকে, সাধারণত এটি লিঙ্কিং হিসাবে পরিচিত। এটির মূলত অর্থ এই যে আপনি বাস্তবায়ন ফাইলগুলির একগুচ্ছ অবজেক্ট ফাইল বা লাইব্রেরিতে সংকলন করেছেন এবং এখন আপনি তাদের একসাথে কাজ করতে চান।

বলে আপনি সংজ্ঞাটি সংজ্ঞায়িত aকরেছেন a.cpp। এখন, প্রতীক b.cpp ঘোষিত এবং এটি ব্যবহার। লিঙ্ক করার আগে, এটি সহজেই ধরে নেয় যে প্রতীকটি কোথাও সংজ্ঞায়িত হয়েছিল , তবে এটি এখনও কোথায় যত্নশীল নয়। লিঙ্কিং পর্বটি প্রতীকটি সন্ধান করার জন্য এবং এটির সাথে সঠিকভাবে লিঙ্ক করার জন্য দায়ী b.cpp(ভাল, আসলে এটি ব্যবহার করা অবজেক্ট বা লাইব্রেরিতে)।

আপনি যদি মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিও ব্যবহার করছেন তবে আপনি দেখতে পাবেন যে প্রকল্পগুলি .libফাইল উত্পন্ন করে। এর মধ্যে রফতানি চিহ্নগুলির একটি টেবিল এবং আমদানিকৃত চিহ্নগুলির একটি টেবিল রয়েছে। আমদানিকৃত প্রতীকগুলি আপনি যে লাইব্রেরির সাথে লিঙ্ক করেন তার বিপরীতে সমাধান করা হয় এবং রফতানি চিহ্নগুলি যে লাইব্রেরিগুলিতে .lib(যদি থাকে তবে) ব্যবহার করা হয়।

অন্যান্য সংকলক / প্ল্যাটফর্মগুলির জন্য অনুরূপ প্রক্রিয়া বিদ্যমান।

সাধারণ ত্রুটি বার্তা পাঠায় নি error LNK2001, error LNK1120, error LNK2019জন্য Microsoft ভিসুয়াল স্টুডিও এবং 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;
}

জিসিসির সাহায্যে নিম্নলিখিত ত্রুটিগুলি উত্পন্ন করবে :

/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

এবং মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিও সহ একই ত্রুটি :

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
ডেভিড ড্রাইডডেল লিঙ্কারগুলি কীভাবে কাজ করে সে সম্পর্কে একটি দুর্দান্ত নিবন্ধ লিখেছিলেন: লিঙ্কার্সের কাছে বিগনার্স গাইড । এই প্রশ্নের মূল বিষয়বস্তু দেওয়া, আমি ভেবেছিলাম এটি কার্যকরভাবে প্রমাণিত হতে পারে।
প্রেসাকো

@ ট্যাঙ্কোরস্যামশ জিসিসি ব্যবহার করবেন? আরও সুনির্দিষ্ট হতে হবে MinGW।
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ক্লাস সংজ্ঞা মধ্যে ইন্টিগ্রাল বা গণনা টাইপের একটি ডেটা সদস্যের জন্য একটি ইনিশিয়ালাইজার সরবরাহ করা যেতে পারে ; তবে, এই সদস্যটির অদ্ভুত-ব্যবহারের জন্য উপরে বর্ণিত হিসাবে এখনও একটি নামের জায়গার স্কোপ সংজ্ঞা প্রয়োজন। সি ++ 11 সমস্ত static constডেটা সদস্যের জন্য বর্গের ভিতরে আরম্ভ করার অনুমতি দেয় ।


কেবল ভেবেছিলেন আপনি চাপ দিতে চাইতে পারেন যে দুটোই করা সম্ভব এবং ডর্টর আসলে ব্যতিক্রম নয়। (এটা প্রথম নজরে আপনার বাক্যে কথন থেকে সুস্পষ্ট নয়।)
Deduplicator

112

উপযুক্ত লাইব্রেরি / অবজেক্ট ফাইল বা বাস্তবায়ন ফাইল সংকলন ব্যর্থতা

সাধারণত, প্রতিটি অনুবাদ ইউনিট একটি অবজেক্ট ফাইল তৈরি করবে যা সেই অনুবাদ ইউনিটে সংজ্ঞায়িত চিহ্নগুলির সংজ্ঞা যুক্ত করে। এই চিহ্নগুলি ব্যবহার করতে, আপনাকে সেই অবজেক্ট ফাইলগুলির সাথে লিঙ্ক করতে হবে।

জিসিসি-র অধীনে আপনি কমান্ড লাইনের সাথে যুক্ত হওয়া সমস্ত অবজেক্ট ফাইলগুলি নির্দিষ্ট করতে পারবেন বা বাস্তবায়ন ফাইলগুলি একসাথে সংকলন করবেন।

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

libraryNameএখানে শুধু লাইব্রেরির খালি নাম প্ল্যাটফর্ম-নির্দিষ্ট সংযোজন ছাড়া। সুতরাং যেমন লিনাক্স লাইব্রেরিতে ফাইলগুলি সাধারণত বলা হয় libfoo.soতবে আপনি কেবল লিখতেন -lfoo। উইন্ডোজে একই ফাইলটি ডাকা হতে পারে foo.libতবে আপনি একই যুক্তিটি ব্যবহার করবেন। আপনাকে সেই ডিরেক্টরিটি যুক্ত করতে হবে যেখানে এই ফাইলগুলি ব্যবহার করে পাওয়া যাবে -L‹directory›-lবা পরে কোনও স্থান না লিখে নিশ্চিত করুন -L

জন্য উপর XCode : -> লাইব্রেরি অনুসন্ধানের পথ যুক্ত করুন - যোগ করুন ব্যবহারকারী শিরোলেখ অনুসন্ধান পথ> ড্র্যাগ এবং প্রকল্প ফোল্ডারের মধ্যে প্রকৃত গ্রন্থাগার রেফারেন্স ড্রপ।

এমএসভিএসের অধীনে কোনও প্রকল্পে যুক্ত হওয়া ফাইলগুলির সাথে স্বয়ংক্রিয়ভাবে তাদের অবজেক্ট ফাইলগুলি একসাথে যুক্ত থাকে এবং একটি libফাইল উত্পন্ন হয় (সাধারণ ব্যবহারে)। একটি পৃথক প্রকল্পে প্রতীকগুলি ব্যবহার করতে, আপনাকে libপ্রকল্পের সেটিংসে ফাইলগুলি অন্তর্ভুক্ত করতে হবে । এই প্রকল্পটি বৈশিষ্ট্য Linker অধ্যায় মধ্যে সম্পন্ন করা হয়, এ Input -> Additional Dependencies। ( libফাইলটিতে পাথ যুক্ত করা উচিত Linker -> General -> Additional Library Directories) কোনও তৃতীয় পক্ষের লাইব্রেরি যখন কোনও libফাইল সরবরাহ করা হয় তখন ব্যবহার না করার ফলে সাধারণত ত্রুটি হয়।

এটি এমনও হতে পারে যে আপনি সংকলনে ফাইল যুক্ত করতে ভুলে গেছেন, সেই ক্ষেত্রে অবজেক্ট ফাইলটি উত্পন্ন করা হবে না। ইন জিসিসি আপনি কমান্ড লাইন ফাইলগুলি যোগ চাই। ইন MSVS প্রকল্পের ফাইল যোগ করলে তা স্বয়ংক্রিয়ভাবে কম্পাইল (যদিও ফাইল করতে পারেন, ম্যানুয়ালি, স্বতন্ত্রভাবে বিল্ড থেকে বাদ দেওয়া) করতে হবে।

উইন্ডোজ প্রোগ্রামিং-এ, টেল-টেল সাইন যে আপনি কোনও প্রয়োজনীয় লাইব্রেরির সাথে লিঙ্ক করেননি তা হ'ল অমীমাংসিত প্রতীকটির নাম শুরু হয় __imp_। ডকুমেন্টেশনে ফাংশনের নামটি অনুসন্ধান করুন এবং এটিতে আপনার কোনও লাইব্রেরি ব্যবহার করা উচিত তা বলা উচিত। উদাহরণস্বরূপ, এমএসডিএন প্রতিটি ফাংশনের নীচে একটি বাক্সে "লাইব্রেরি" নামে একটি বিভাগে তথ্য রাখে।


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

আপনি যে ফাংশনটি প্রয়োগ করেছেন সেটি আপনার ঘোষিতটির সাথে ঠিক মেলে যাতে সাবধান হন Be উদাহরণস্বরূপ, আপনার সিভি-কোয়ালিফায়ার মিলতে পারে না:

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 অবশ্যই উপস্থিত হওয়া আবশ্যক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

সুতরাং আবার পুনরাবৃত্তি, যাতে শুরু করে ব্যাপার!


আমি কৌতূহলজনক বিষয়টি হ'ল আমার ক্ষেত্রে আমার কাছে একটি অবজেক্ট ফাইল ছিল যা একটি ভাগ করা লাইব্রেরির উপর নির্ভর করে। আমাকে মেকফিলটি সংশোধন করতে হবে এবং গ্রন্থাগারটি জিসিসি ৪.৮.৪ দিয়ে দেবিয়ানের পরে রাখতে হবে। সেন্টিস 6.৫-তে জিসিসি ৪.৪ সহ মেকফিল কোনও সমস্যা ছাড়াই কাজ করেছে।
মার্কো সুলা

74

একটি "অপরিজ্ঞাত রেফারেন্স / অমীমাংসিত বাহ্যিক প্রতীক" কী?

আমি "অপরিবর্তিত রেফারেন্স / অমীমাংসিত বাহ্যিক প্রতীক" কী তা বোঝানোর চেষ্টা করব।

দ্রষ্টব্য: আমি জি ++ এবং লিনাক্স ব্যবহার করি এবং সমস্ত উদাহরণ এটির জন্য

উদাহরণস্বরূপ আমাদের কিছু কোড রয়েছে

// 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

এটি ঘটেছে কারণ আমাদের স্থানীয়_ভার_নাম স্থির, অর্থাৎ এটি অন্যান্য মডিউলগুলির জন্য দৃশ্যমান নয়। এখন আরও গভীরভাবে। অনুবাদ পর্ব আউটপুট পান

$ 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

সুতরাং, আমরা দেখেছি স্থানীয়_ভার_নামের জন্য কোনও লেবেল নেই, এজন্য লিঙ্কার এটি খুঁজে পায় নি। তবে আমরা হ্যাকার :) এবং আমরা এটি ঠিক করতে পারি। আপনার পাঠ্য সম্পাদক এবং 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:
; ...

আমরা স্থানীয়_ভর_নামের দৃশ্যমানতা পরিবর্তন করেছি এবং এর মান 456789 তে সেট করেছি it এটি থেকে কোনও অবজেক্ট ফাইল তৈরি করার চেষ্টা করুন

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

ঠিক আছে, দেখুন পাঠ্য আউটপুট (প্রতীক)

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

এখন স্থানীয়_ভর_নামে বাইন্ড গ্লোবাল রয়েছে (লোকাল ছিল)

লিংক

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

এবং এটি চালান

$ ./prog 
123456789

ঠিক আছে, আমরা এটি হ্যাক :)

সুতরাং, ফলস্বরূপ - লিঙ্কার যখন অবজেক্ট ফাইলগুলিতে গ্লোবাল প্রতীকগুলি খুঁজে না পায় তখন একটি "অপরিজ্ঞাত রেফারেন্স / অমীমাংসিত বাহ্যিক প্রতীক ত্রুটি" ঘটে যায়।


71

প্রতীকগুলি একটি সি প্রোগ্রামে সংজ্ঞায়িত করা হয়েছিল এবং সি ++ কোডে ব্যবহৃত হয়েছিল।

ফাংশন (বা ভেরিয়েবল) void foo()একটি সি প্রোগ্রামে সংজ্ঞায়িত করা হয়েছিল এবং আপনি এটি সি ++ প্রোগ্রামে ব্যবহার করার চেষ্টা করছেন:

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

সি ++ লিঙ্কার নামগুলি ম্যাঙ্গেল হওয়ার প্রত্যাশা করে, তাই আপনাকে ফাংশনটি এই হিসাবে ঘোষণা করতে হবে:

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

সমানভাবে, কোনও সি প্রোগ্রামে সংজ্ঞায়িত হওয়ার পরিবর্তে ফাংশনটি (বা ভেরিয়েবল) void foo()সি ++ এ সংজ্ঞায়িত করা হয়েছিল তবে সি সংযোগের সাথে:

extern "C" void foo();

এবং আপনি এটি সি ++ লিঙ্কেজ সহ কোনও সি ++ প্রোগ্রামে ব্যবহার করার চেষ্টা করছেন।

যদি একটি সম্পূর্ণ লাইব্রেরি একটি শিরোলেখ ফাইলটিতে অন্তর্ভুক্ত থাকে (এবং এটি সি কোড হিসাবে সংকলিত ছিল); অন্তর্ভুক্ত নিম্নলিখিত হিসাবে করা প্রয়োজন হবে;

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

5
বা বিপরীতভাবে, আপনি যদি একটি সি লাইব্রেরি বিকাশ করেন তবে একটি দুর্দান্ত নিয়ম হ'ল ফাইল (গুলি) রক্ষা করা সমস্ত রফতানি ঘোষণাকে ঘিরে #ifdef __cplusplus [\n] extern"C" { [\n] #endifএবং #ifdef __cplusplus [\n] } [\n] #endif( [\n]সত্যিকারের ক্যারেজ রিটার্ন হওয়া সত্ত্বেও আমি মন্তব্যটিতে এটি সঠিকভাবে লিখতে পারি না) রক্ষা করি।
বেন্টয় 13

উপরের মতামত হিসাবে, 'মিশ্র-ভাষা শিরোনাম
জানব্রি

সত্যিই আমাকে সাহায্য করেছে! এটি আমার ক্ষেত্রে যখন আমি এই প্রশ্নের সন্ধান
করলাম

এই ঘটতে পারে যদি আপনি দ্বারা বেষ্টিত দৃর্ঘটনায় আপনার সাধারণ সি ++ হেডার ফাইলের অন্তর্ভুক্ত extern সি : extern "C" { #include <myCppHeader.h> }
কমফ্রিচ

68

অন্য সব যদি ব্যর্থ হয় তবে পুনরায় কম্পাইল করুন।

আমি সম্প্রতি আপত্তিজনক ফাইলটি পুনরায় সংশোধন করে ভিজ্যুয়াল স্টুডিও ২০১২ সালে একটি অমীমাংসিত বাহ্যিক ত্রুটি থেকে মুক্তি পেতে সক্ষম হয়েছি। আমি যখন পুনর্নির্মাণ করি তখন ত্রুটিটি চলে যায়।

এটি সাধারণত ঘটে যখন দুটি (বা আরও) লাইব্রেরিতে একটি চক্রীয় নির্ভরতা থাকে। লাইব্রেরি একটি বিলিবে প্রতীক ব্যবহার করার চেষ্টা করে এবং লাইব্রেরি বি এলিব থেকে প্রতীক ব্যবহার করার চেষ্টা করে। কোনটিই দিয়ে শুরু করার অস্তিত্ব নেই। আপনি যখন এটিকে সংকলনের চেষ্টা করবেন, লিঙ্ক পদক্ষেপটি ব্যর্থ হবে কারণ এটি বিলিবকে খুঁজে পাচ্ছে না। 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();

এবং বর্তমান সংযোজনটির সংজ্ঞা রয়েছে বলে সংযোগকারীটিকে ফাংশনটি রফতানি করতে বলে tells যখন কোনও ভিন্ন মডিউলে ঘোষণাটি অন্তর্ভুক্ত করা হয় তখন এটি প্রসারিত হবে

__declspec(dllimport) void foo();

এবং সংকলককে বলে যে সংজ্ঞাটি আপনি যে লাইব্রেরির সাথে সংযুক্ত করেছেন সেগুলির মধ্যে একটিতে রয়েছে (এছাড়াও দেখুন 1 )।

আপনি আমদানি / রফতানি ক্লাসগুলি সমান করতে পারেন:

class DLLIMPEXP X
{
};

2
সম্পূর্ণ হওয়ার জন্য, এই উত্তরে জিসিসি visibilityএবং উইন্ডোজ .defফাইলগুলি উল্লেখ করা উচিত , কারণ এগুলি প্রতীকের নাম এবং উপস্থিতিকেও প্রভাবিত করে।
রুবেনভবি

@ রুবেনভ আমি .defযুগে যুগে ফাইল ব্যবহার করি নি n't একটি উত্তর যুক্ত করতে বা এটি সম্পাদনা করতে নির্দ্বিধায়।
লুচিয়ান গ্রিগোর

57

এটি প্রতিটি ভিসি ++ প্রোগ্রামাররা আবার সময় এবং সময় দেখেছিল এমন একটি বিভ্রান্তিকর ত্রুটি বার্তা। প্রথমে বিষয়গুলি পরিষ্কার করে নেওয়া যাক।

উ: প্রতীক কী? সংক্ষেপে, একটি প্রতীক একটি নাম। এটি একটি চলক নাম, একটি ফাংশন নাম, শ্রেণীর নাম, একটি টাইপডেফ নাম বা সি ++ ভাষার অন্তর্ভুক্ত names নাম এবং চিহ্নগুলি বাদে কিছু হতে পারে। এটি নির্ভরতা গ্রন্থাগার (অন্য ব্যবহারকারী-সংজ্ঞায়িত) দ্বারা ব্যবহারকারী সংজ্ঞায়িত বা প্রবর্তিত।

খ। বাহ্যিক কী? ভিসি ++ এ, প্রতিটি উত্স ফাইল (.cpp, .c, ইত্যাদি) অনুবাদ ইউনিট হিসাবে বিবেচিত হয়, সংকলকটি একবারে একটি ইউনিট সংকলন করে এবং বর্তমান অনুবাদ ইউনিটের জন্য একটি অবজেক্ট ফাইল (.obj) উত্পন্ন করে। (দ্রষ্টব্য যে এই উত্স ফাইলটি অন্তর্ভুক্ত প্রতিটি শিরোনাম ফাইল প্রাক প্রসেসড হবে এবং এই অনুবাদ ইউনিটের অংশ হিসাবে বিবেচিত হবে) অনুবাদ ইউনিটের মধ্যে থাকা সমস্ত কিছুকে অভ্যন্তরীণ হিসাবে বিবেচনা করা হয়, অন্য সমস্ত কিছুই বাহ্যিক হিসাবে বিবেচিত হয়। C ++ তোমার মতোই কীওয়ার্ড ব্যবহার করে একটি বহিস্থিত প্রতীক উল্লেখ থাকতে পারে extern, __declspec (dllimport)ইত্যাদি।

গ। "সংকল্প" কি? সমাধান একটি সংযোগ-সময় শব্দ term লিঙ্কিং-টাইমে, লিঙ্কার বস্তু ফাইলগুলিতে প্রতিটি চিহ্নের জন্য বাহ্যিক সংজ্ঞাটি অনুসন্ধান করার চেষ্টা করে যা অভ্যন্তরীণভাবে তার সংজ্ঞাটি খুঁজে পায় না। এই অনুসন্ধানের প্রক্রিয়াটির সুযোগগুলি সহ:

  • সংকলনের সময় উত্পন্ন সমস্ত বস্তু ফাইল
  • সমস্ত লাইব্রেরি (.lib) যা স্পষ্টভাবে বা স্পষ্টভাবে এই বিল্ডিং অ্যাপ্লিকেশনটির অতিরিক্ত নির্ভরতা হিসাবে নির্দিষ্ট করা হয়েছে।

এই অনুসন্ধানের প্রক্রিয়াটিকে সংকল্প বলে।

D. অবশেষে, কেন অমীমাংসিত বাহ্যিক প্রতীক? যদি লিঙ্কার কোনও প্রতীকের জন্য বাহ্যিক সংজ্ঞাটি খুঁজে না পায় যার অভ্যন্তরীণ কোনও সংজ্ঞা নেই, তবে এটি একটি অমীমাংসিত বহিরাগত প্রতীক ত্রুটির প্রতিবেদন করে।

E. LNK2019 এর সম্ভাব্য কারণগুলি : অমীমাংসিত বাহ্যিক প্রতীক ত্রুটি। আমরা ইতিমধ্যে জানি যে এই ত্রুটিটি লিঙ্কার বাহ্যিক চিহ্নগুলির সংজ্ঞা পেতে ব্যর্থ হওয়ার কারণে হয়েছে, সম্ভাব্য কারণগুলি এইভাবে সাজানো যেতে পারে:

  1. সংজ্ঞা বিদ্যমান

উদাহরণস্বরূপ, যদি আমাদের a.cpp এ সংজ্ঞায়িত foo নামে একটি ফাংশন থাকে:

int foo()
{
    return 0;
}

বি সি পি পি-তে আমরা ফাংশন ফু বলতে চাই, তাই আমরা যুক্ত করি

void foo();

ফাংশন foo () ঘোষণা করতে এবং অন্য ফাংশন বডিতে এটি কল করতে, বলুন bar():

void bar()
{
    foo();
}

এখন আপনি এই কোডটি তৈরি করার সময় আপনি fo একটি অমীমাংসিত প্রতীক হিসাবে অভিযোগ করে একটি LNK2019 ত্রুটি পাবেন। এই ক্ষেত্রে, আমরা জানি যে foo () এর a.cpp এ এর ​​সংজ্ঞা রয়েছে তবে আমরা যে কল করছি তার থেকে আলাদা (পৃথক ফেরতের মান)। এই সংজ্ঞাটি বিদ্যমান যে ক্ষেত্রে।

  1. সংজ্ঞা বিদ্যমান নেই

আমরা যদি কোনও গ্রন্থাগারে কিছু ফাংশন কল করতে চাই তবে আমদানি গ্রন্থাগারটি Project | Properties | Configuration Properties | Linker | Input | Additional Dependencyআপনার প্রকল্পের সেটিংয়ের অতিরিক্ত নির্ভরতা তালিকায় (সেট করা :) এ যুক্ত হয় না । এখন সংযোগকারী একটি LNK2019 প্রতিবেদন করবে যেহেতু বর্তমান অনুসন্ধানের সুযোগে সংজ্ঞাটি বিদ্যমান নেই।


1
পদ্ধতিগত ব্যাখ্যার জন্য আপনাকে ধন্যবাদ। আমি এই উত্তরটি পড়ার পরে এখানে অন্যান্য উত্তরগুলি বুঝতে পারি।
ডিসপ্লেনেম

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
PlasmaHH

41

অপরিবর্তিত রেফারেন্স WinMain@16বা অনুরূপ 'অস্বাভাবিক' main() এন্ট্রি পয়েন্ট রেফারেন্স (বিশেষত জন্য))।

আপনি আপনার প্রকৃত IDE সহ সঠিক প্রকল্পের প্রকারটি বেছে নিতে ভুলে গেছেন। আইডিই সাধারণত ব্যবহৃত int main(int argc, char** argv);স্বাক্ষরের পরিবর্তে যেমন উইন্ডোজ অ্যাপ্লিকেশন প্রকল্পগুলিকে এন্ট্রি পয়েন্ট ফাংশনে (উপরের নিখোঁজ রেফারেন্সে উল্লিখিত) বাঁধাই করতে পারে ।

আপনার আইডিই যদি সমতল কনসোল প্রকল্পগুলিকে সমর্থন করে তবে আপনি উইন্ডোজ অ্যাপ্লিকেশন প্রকল্পের পরিবর্তে এই প্রকল্পের ধরণটি চয়ন করতে পারেন।


এখানে বাস্তব কেস সমস্যা থেকে কেস 1 এবং কেস 2 আরও বিশদে পরিচালনা করা হয়েছে ।


2
সাহায্যের কিন্তু উল্লেখ করতে পারি, এই প্রশ্ন এবং সত্য যে এই আরো প্রায়ই হচ্ছে না চেয়ে সব সময়ে কোন প্রধান ফাংশন থাকার দ্বারা ঘটিত হয় WinMain। বৈধ সি ++ প্রোগ্রামগুলির একটি প্রয়োজন main
ক্রিস

36

এছাড়াও আপনি যদি তৃতীয় পক্ষের লাইব্রেরি ব্যবহার করছেন তবে আপনার কাছে সঠিক 32/64 বিট বাইনারি রয়েছে তা নিশ্চিত করুন


34

মাইক্রোসফ্ট #pragmaলিঙ্ক সময়ে সঠিক লাইব্রেরি উল্লেখ করার জন্য একটি প্রস্তাব দেয়;

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

লাইব্রেরির ডিরেক্টরি সহ লাইব্রেরির পাথ ছাড়াও এটি লাইব্রেরির পুরো নাম হওয়া উচিত।


34

নতুন টুলসেট সংস্করণে ভিজ্যুয়াল স্টুডিও নুগেট প্যাকেজ আপডেট করা দরকার

আমার কেবলমাত্র ভিজ্যুয়াল স্টুডিও 2013 এর সাথে লিবিপং লিঙ্ক করার চেষ্টা করার সময় এই সমস্যা হয়েছিল The সমস্যাটি হ'ল প্যাকেজ ফাইলে কেবল ভিজ্যুয়াল স্টুডিও 2010 এবং 2012 এর জন্য লাইব্রেরি ছিল।

সঠিক সমাধানটি আশা করা যায় বিকাশকারী একটি আপডেট হওয়া প্যাকেজ প্রকাশ করে তারপরে আপগ্রেড করে তবে এটি ভিএস2013 এর জন্য অতিরিক্ত সেটিং হ্যাক করে আমার পক্ষে কাজ করেছে, ভিএস ২০১২ লাইব্রেরি ফাইলগুলিতে ইঙ্গিত করে।

আমি সমস্ত বিভাগটি অনুলিপি করে সেই ফাইলটি packagesসন্ধান করে packagename\build\native\packagename.targetsএবং এর ভিতরে প্যাকেজটি ( সমাধানের ডিরেক্টরিতে থাকা ফোল্ডারে) সম্পাদনা করেছি v110। আমি পরিবর্তন v110করতে v120অবস্থায় ক্ষেত্র শুধুমাত্র সব ফাইলের নাম পাথ ত্যাগ করার খুব সতর্কতা অবলম্বন হচ্ছে v110। এটি কেবলমাত্র ভিজ্যুয়াল স্টুডিও 2013 কে 2012 এর লাইব্রেরিতে লিঙ্ক করার অনুমতি দিয়েছে এবং এই ক্ষেত্রে এটি কাজ করেছে।


1
এটি অত্যধিক নির্দিষ্ট বলে মনে হচ্ছে - সম্ভবত একটি নতুন থ্রেড এই উত্তরের জন্য আরও ভাল জায়গা হবে।
লুচিয়ান গ্রিগোর

3
@ লুচিয়ানগ্রিগোর: আমি এখানে পোস্ট করতে চাইছিলাম কারণ এই প্রশ্নটি হুবহু এই সমস্যাটি ছিল, তবে এটি এই প্রশ্নের সদৃশ হিসাবে চিহ্নিত হয়েছিল তাই আমি সেখানে উত্তর দিতে পারিনি। সুতরাং আমি এখানে পরিবর্তে আমার উত্তর পোস্ট।
মালভাইনাস

এই প্রশ্নের ইতিমধ্যে একটি স্বীকৃত উত্তর রয়েছে। এটি সদৃশ হিসাবে চিহ্নিত হয়েছে কারণ সাধারণ কারণ উপরে তালিকাবদ্ধ রয়েছে। অন্তর্ভুক্ত নেই এমন একটি লাইব্রেরির প্রতিটি সমস্যার জন্য যদি আমাদের এখানে উত্তর থাকে তবে কী হবে?
লুচিয়ান গ্রিগোর

6
@ লুচিয়ানগ্রিগোর: এই সমস্যাটি কোনও লাইব্রেরির জন্য নির্দিষ্ট নয়, এটি ভিজ্যুয়াল স্টুডিওর প্যাকেজ ম্যানেজমেন্ট সিস্টেম ব্যবহার করে সমস্ত লাইব্রেরিগুলিকে প্রভাবিত করে। আমি কেবলমাত্র অন্য প্রশ্নটি খুঁজতে গিয়েছিলাম কারণ আমাদের দুজনেরই লিবিপং সমস্যা ছিল। LibxML2, libiconv এবং glew এর জন্যও আমার একই সমস্যা (একই সমাধান সহ) ছিল। এই প্রশ্নটি ভিজ্যুয়াল স্টুডিওর প্যাকেজ ম্যানেজমেন্ট সিস্টেমের সাথে সমস্যা সম্পর্কিত এবং আমার উত্তরটির কারণ ব্যাখ্যা করে এবং একটি কার্যপ্রণালী সরবরাহ করে। কেউ সবেমাত্র "অমীমাংসিত বাহ্যিক" দেখেছেন এবং ধরে নিয়েছেন যে এটি আসলে একটি লিঙ্কার সমস্যা যখন এটি আসলে প্যাকেজ পরিচালনার সমস্যা।
মালভাইনাস

34

ধরুন আপনার সি ++ তে একটি বড় প্রকল্প লেখা আছে যার হাজার হাজার .cpp ফাইল এবং হাজার হাজার .h ফাইল রয়েছে nd এবং ধরা যাক প্রকল্পটি দশটি স্ট্যাটিক লাইব্রেরির উপরও নির্ভর করে। আসুন আমরা উইন্ডোতে রয়েছি এবং আমরা ভিজ্যুয়াল স্টুডিও 20XX এ আমাদের প্রকল্পটি তৈরি করি। পুরো সমাধানটি সংকলন শুরু করতে আপনি যখন Ctrl + F7 ভিজ্যুয়াল স্টুডিও টিপেন (ধরুন আমাদের সমাধানে কেবল একটি প্রকল্প আছে)

সংকলনের অর্থ কী?

  • .Vcxproj ফাইলটিতে ভিজ্যুয়াল স্টুডিও অনুসন্ধান করুন এবং প্রতিটি ফাইলের সংকলন শুরু করুন যার এক্সটেনশন .cpp রয়েছে। সংকলনের অর্ডার অপরিজ্ঞাত o সুতরাং আপনাকে অবশ্যই ধরে নিতে হবে না যে ফাইলটি মূল সিপিপি প্রথমে সংকলিত হয়েছে
  • .Cpp ফাইলগুলি .cpp ফাইলটিতে সংজ্ঞায়িত বা নাও হতে পারে এমন প্রতীকগুলি খুঁজে পেতে অতিরিক্ত .h ফাইলের উপর নির্ভর করে
  • যদি একটি .cpp ফাইল উপস্থিত থাকে যেখানে সংকলকটি একটি প্রতীকটি খুঁজে পায় না, একটি সংকলক সময় ত্রুটি বার্তা উত্সাহিত করে সিম্বল এক্স পাওয়া যায়নি could
  • এক্সটেনশন সহ প্রতিটি ফাইলের জন্য .cpp একটি অবজেক্ট ফাইল উত্পন্ন হয় .o এবং ভিজ্যুয়াল স্টুডিওতে প্রজেক্টনাম.সিপ্প.ক্লিয়েন.টেক্সট নামে একটি ফাইল আউটপুট লেখায় যা লিঙ্কার দ্বারা প্রক্রিয়া করা আবশ্যক সমস্ত অবজেক্ট ফাইল ধারণ করে।

সংকলনের দ্বিতীয় ধাপটি লিঙ্কার দ্বারা সম্পন্ন হয় L লিঙ্কারকে সমস্ত অবজেক্ট ফাইলটি মার্জ করে শেষ পর্যন্ত আউটপুট তৈরি করতে হবে (যা এক্সিকিউটেবল বা একটি লাইব্রেরি হতে পারে)

একটি প্রকল্পের লিঙ্কে পদক্ষেপ

  • সমস্ত বস্তুর ফাইলগুলি পার্স করুন এবং সংজ্ঞাটি কেবলমাত্র শিরোনামে ঘোষিত হয়েছিল (যেমন: পূর্ববর্তী উত্তরে উল্লিখিত শ্রেণীর একটি পদ্ধতির কোড, বা স্ট্যাটিক ভেরিয়েবলের সূচনা যা কোনও শ্রেণীর অভ্যন্তরে সদস্য) ইভেন্টটি আবিষ্কার করুন)
  • যদি কোনও প্রতীক অবজেক্ট ফাইলে পাওয়া না যায় তবে তিনি অতিরিক্ত লাইব্রেরিতেও অনুসন্ধান করা হয়। কোনও প্রকল্পে একটি নতুন লাইব্রেরি যুক্ত করার জন্য কনফিগারেশন বৈশিষ্ট্য -> ভিসি ++ ডিরেক্টরি -> লাইব্রেরি ডিরেক্টরি এবং এখানে আপনি লাইব্রেরি এবং কনফিগারেশন বৈশিষ্ট্য অনুসন্ধান করার জন্য অতিরিক্ত ফোল্ডার নির্দিষ্ট করেছেন -> লিঙ্কার -> গ্রন্থাগারের নাম নির্দিষ্ট করার জন্য ইনপুট । -যদি লিঙ্কার প্রতীকটি খুঁজে না পেয়ে থাকে যা আপনি একটিতে লিখেছেন। সিপিপি তিনি একটি লিঙ্কারের সময় ত্রুটি উত্থাপন করেন যা এর মতো শোনাচ্ছে error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)

পর্যবেক্ষণ

  1. লিঙ্কার একবার একটি প্রতীক খুঁজে পেলে সে এর জন্য অন্যান্য লাইব্রেরিতে অনুসন্ধান করে না
  2. লাইব্রেরিগুলি সংযুক্ত করার ক্রমটি বিবেচনা করে
  3. যদি লিঙ্কার একটি স্থিত লাইব্রেরিতে একটি বাহ্যিক প্রতীক খুঁজে পান তবে তিনি প্রকল্পের আউটপুটে প্রতীকটি অন্তর্ভুক্ত করেন H তবে, লাইব্রেরিটি ভাগ করা থাকলে (গতিশীল) তিনি আউটপুটে কোড (চিহ্নগুলি) অন্তর্ভুক্ত করেন না, তবে রান-টাইম ক্রাশ হতে পারে ঘটা

এই ধরণের ত্রুটি কীভাবে সমাধান করবেন

সংকলক সময় ত্রুটি:

  • নিশ্চিত হয়ে নিন যে আপনি আপনার সি ++ প্রকল্প সিনট্যাক্টিক্যাল সঠিক লিখেছেন।

লিঙ্কারের সময় ত্রুটি

  • আপনার সমস্ত চিহ্নকে সংজ্ঞা দিন যা আপনি আপনার শিরোনাম ফাইলগুলিতে ঘোষণা করেন
  • #pragma onceসংকলককে একটি শিরোনাম অন্তর্ভুক্ত না করার জন্য ব্যবহার করুন যদি এটি ইতিমধ্যে বর্তমান .cpp অন্তর্ভুক্ত থাকে যা সংকলিত হয়
  • আপনার বাহ্যিক গ্রন্থাগারে এমন চিহ্ন নেই যা আপনার শিরোনাম ফাইলগুলিতে সংজ্ঞায়িত অন্যান্য চিহ্নগুলির সাথে বিরোধে প্রবেশ করতে পারে তা নিশ্চিত করুন
  • আপনি যখন টেম্পলেটটি ব্যবহার করেন তা নিশ্চিত করার জন্য যে কোনও সংস্থার জন্য কম্পাইলারকে উপযুক্ত কোড উত্পন্ন করার অনুমতি দেওয়ার জন্য আপনি প্রতিটি টেম্পলেট ফাংশনটির সংজ্ঞা শিরক ফাইলে অন্তর্ভুক্ত করেছেন।

আপনার উত্তরটি কি ভিজ্যুয়াল স্টুডিওর জন্য নির্দিষ্ট নয়? প্রশ্নটি কোনও আইডিই / সংকলক সরঞ্জাম নির্দিষ্ট করে না তাই এটি আপনার উত্তর অ-ভিজ্যুয়াল-স্টুডিও অংশের জন্য অকেজো করে।
ভিক্টর পোলেভয়

তুমি ঠিক বলছো . তবে প্রতিটি আইডিই সংকলন / লিঙ্কিংয়ের প্রতিটি প্রক্রিয়া কিছুটা আলাদাভাবে করা হচ্ছে

সমস্যাটি আসলে আইডিই নিয়ে নয়, সমস্যা সংযোগের জন্য একটি উত্তর সম্পর্কে। লিঙ্কিংয়ের সমস্যাগুলি আইডিই সম্পর্কিত নয় তবে সংকলক এবং বিল্ড প্রক্রিয়া সম্পর্কিত।
ভিক্টর পোলেভয়

হ্যাঁ। তবে বিল্ডিং / লিঙ্কিং প্রক্রিয়াটি জি ++ / ভিজ্যুয়াল স্টুডিওতে করা হচ্ছে (মাইক্রোসফ্ট দ্বারা ভিএস এর জন্য সরবরাহিত সংকলক) / গ্রহন / নেট

29

সংকলক / আইডিইতে একটি বাগ

আমার সম্প্রতি এই সমস্যা হয়েছিল এবং এটি ভিজ্যুয়াল স্টুডিও এক্সপ্রেস 2013-এ একটি বাগ ছিল was । আমাকে প্রকল্প থেকে একটি উত্স ফাইল সরিয়ে ফেলা হয়েছে এবং বাগটি কাটিয়ে উঠতে আবার যুক্ত করতে হয়েছিল।

যদি আপনি বিশ্বাস করেন যে এটি সংকলক / আইডিইতে বাগ হতে পারে তবে চেষ্টা করার পদক্ষেপগুলি:

  • প্রকল্পটি সাফ করুন (কিছু আইডিইগুলির কাছে এটি করার বিকল্প রয়েছে, আপনি বস্তুর ফাইলগুলি মুছে ফেলে ম্যানুয়ালিও এটি করতে পারেন)
  • আসলটি থেকে সমস্ত উত্স কোড অনুলিপি করে একটি নতুন প্রকল্প শুরু করার চেষ্টা করুন।

5
আপনার সরঞ্জামগুলি নষ্ট হয়ে গেছে বিশ্বাস করে সম্ভবত আপনাকে আসল কারণ থেকে দূরে সরিয়ে নিয়ে যেতে হবে। এটি এত বেশি সম্ভাবনা রয়েছে যে কোনও সংকলক আপনার সমস্যার কারণ হিসাবে আপনি একটি ভুল করেছেন। আপনার সমাধানটি পরিষ্কার করা বা আপনার বিল্ড কনফিগারেশনটি পুনরায় তৈরি করা বিল্ড ত্রুটিগুলি ঠিক করতে পারে তবে এর অর্থ এই নয় যে সংকলকটিতে একটি বাগ রয়েছে। লিঙ্কযুক্ত "পরিণত হয়েছিল এটি একটি বাগ ছিল" মাইক্রোসফ্ট দ্বারা নিশ্চিত নয় এবং পুনরুত্পাদনযোগ্য নয়।
জেডিম্যাটটিও

4
@ জেডিম্যাটটিও এই প্রশ্নের 21 টি উত্তর রয়েছে এবং অতএব উল্লেখযোগ্য পরিমাণে উত্তর "সম্ভাব্য" সমাধান হতে চলেছে না। আপনি যদি আপনার মতামত প্রান্তিকের নীচে থাকা সমস্ত উত্তরগুলি খারিজ করেন তবে এই পৃষ্ঠাটি কার্যকরভাবে অকেজো হয়ে যায় কারণ বেশিরভাগ সাধারণ ক্ষেত্রে যেভাবেই সহজেই চিহ্নিত করা যায়।
developerbmw

27

ত্রুটি নির্ণয়ে সহায়তা করতে লিংক ব্যবহার করুন

বেশিরভাগ আধুনিক লিকারগুলিতে একটি ভার্বোস বিকল্প অন্তর্ভুক্ত থাকে যা বিভিন্ন ডিগ্রীতে প্রিন্ট করে;

  • লিঙ্ক আহ্বান (কমান্ড লাইন),
  • লিঙ্ক স্টেজে কি লাইব্রেরি অন্তর্ভুক্ত রয়েছে তার ডেটা,
  • গ্রন্থাগারের অবস্থান,
  • ব্যবহৃত পাথ অনুসন্ধান করুন।

জিসিসি এবং ঝনঝন জন্য; আপনি সাধারণত যুক্ত -v -Wl,--verboseবা -v -Wl,-vকমান্ড লাইনে যোগ করতে হবে । আরো বিস্তারিত এখানে পাওয়া যাবে;

এমএসভিসির জন্য, /VERBOSE(বিশেষত /VERBOSE:LIB) লিঙ্ক কমান্ড লাইনে যুক্ত করা হয়েছে।


26

লিঙ্কযুক্ত .lib ফাইল একটি .dll এর সাথে সম্পর্কিত

আমারও একই প্রশ্ন ছিল. বলুন আমার কাছে মাইপ্রজেক্ট এবং টেস্টপ্রজেক্ট রয়েছে। আমি মাইপ্রজেক্টের জন্য lib ফাইলটিকে কার্যকরভাবে টেস্টপ্রজেক্টের সাথে সংযুক্ত করেছি। যাইহোক, এই লিব ফাইলটি মাইপ্রজেক্টটি নির্মিত হওয়ার জন্য ডিএলএল হিসাবে তৈরি করা হয়েছিল। এছাড়াও, আমি মাইপ্রজেক্টে সমস্ত পদ্ধতির সোর্স কোডটি ধারণ করে নি, তবে কেবলমাত্র ডিএলএল-এর প্রবেশ পয়েন্টগুলিতে অ্যাক্সেস করেছি।

সমস্যাটি সমাধান করার জন্য, আমি মাইপ্রজেক্টকে এলআইবি হিসাবে তৈরি করেছি এবং টেস্টপ্রজেক্টটিকে এই .lib ফাইলের সাথে সংযুক্ত করেছি (আমি উত্পন্ন .lib ফাইলটিকে টেস্টপ্রজেক্ট ফোল্ডারে আটকানো কপি করি)। আমি তখন আবার ডিএলএল হিসাবে মাইপ্রজেক্টটি তৈরি করতে পারি can টেস্টপ্রজেক্টটি যে লিবে লিঙ্কযুক্ত তা মাইপ্রজেক্টের ক্লাসে সমস্ত পদ্ধতির কোড ধারণ করে এটি সংকলন করে চলেছে।


25

যেহেতু লিঙ্কার ত্রুটিগুলি আসে তখন লোকেরা এই প্রশ্নের দিকে পরিচালিত বলে মনে হয় আমি এটি এখানে যুক্ত করতে যাচ্ছি।

জিসিসি 5.2.0 এর সাথে লিঙ্কার ত্রুটির একটি সম্ভাব্য কারণ হ'ল একটি নতুন libstdc ++ লাইব্রেরি এখন ডিফল্টরূপে বেছে নেওয়া হয়েছে।

যদি আপনি স্ট্যান্ডার্ড :: __ সিএক্সএক্সএল 11 নামপঞ্জী বা ট্যাগ [আবি: সিএক্সএক্স 11]-তে টাইপের সাথে সংযুক্ত চিহ্নগুলির অপরিবর্তিত রেফারেন্স সম্পর্কে লিঙ্কার ত্রুটি পেয়ে থাকেন তবে সম্ভবত এটি ইঙ্গিত দেয় যে আপনি _GLIBCXX_USE_CXX11_ABI এর জন্য বিভিন্ন মানের সাথে সংকলিত অবজেক্ট ফাইলগুলি একসাথে যুক্ত করার চেষ্টা করছেন indicates ম্যাক্রো। এটি সাধারণত তৃতীয় পক্ষের লাইব্রেরির সাথে সংযোগ করার সময় ঘটে যা জিসিসির একটি পুরানো সংস্করণ দিয়ে সংকলিত হয়েছিল। যদি তৃতীয় পক্ষের লাইব্রেরিটি নতুন এবিআই দিয়ে পুনর্নির্মাণ করা না যায় তবে আপনাকে পুরানো এবিআইয়ের সাথে আপনার কোডটি পুনরায় সংকলন করতে হবে।

সুতরাং আপনি যদি 5.1.0 এর পরে কোনও জিসিসিতে স্যুইচ করার সময় হঠাৎ লিঙ্কার ত্রুটিগুলি পান তবে এটি চেক আউট করার বিষয় হবে।


20

GNU ld এর চারপাশে একটি মোড়ক যা লিঙ্কার স্ক্রিপ্টগুলি সমর্থন করে না

কিছু .so ফাইলগুলি আসলে জিএনইউ এলডি লিঙ্কার স্ক্রিপ্ট হয় , যেমন libtbb.so ফাইল এই বিষয়বস্তু সহ একটি ASCII পাঠ্য ফাইল:

INPUT (libtbb.so.2)

আরও কিছু জটিল বিল্ড এটি সমর্থন নাও করতে পারে। উদাহরণস্বরূপ, আপনি যদি সংকলক বিকল্পগুলিতে -v অন্তর্ভুক্ত করেন তবে আপনি দেখতে পারেন যে মেইনউইন জিসিসি র‌্যাপার এমডুভিপ লিঙ্কারে লিখিতভাবে ভার্জ বোতাম আউটপুট তালিকার মধ্যে লিঙ্কার স্ক্রিপ্ট কমান্ড ফাইলগুলি বাতিল করে দেয় around চারপাশে একটি সহজ কাজ হল লিঙ্কার স্ক্রিপ্ট ইনপুট কমান্ড প্রতিস্থাপন করা around পরিবর্তে ফাইলের একটি অনুলিপি (বা একটি সিমলিংক) সহ ফাইল করুন, যেমন

cp libtbb.so.2 libtbb.so

অথবা আপনি .l এর পুরো পথ দিয়ে -l যুক্তিটি প্রতিস্থাপন করতে পারেন, যেমন -ltbbনা করে/home/foo/tbb-4.3/linux/lib/intel64/gcc4.4/libtbb.so.2


20

আপনার লিঙ্কেজটি তাদের উল্লেখ করা অবজেক্ট ফাইলগুলির আগে গ্রন্থাগারগুলি গ্রাস করে

  • আপনি জিসিসি সরঞ্জামচেইনের সাথে আপনার প্রোগ্রামটি সংকলন এবং লিঙ্ক করার চেষ্টা করছেন।
  • আপনার লিঙ্কেজ সমস্ত প্রয়োজনীয় লাইব্রেরি এবং গ্রন্থাগার অনুসন্ধানের পাথ নির্দিষ্ট করে
  • যদি libfooনির্ভর করে libbarতবে আপনার লিঙ্কেজটি সঠিকভাবে libfooআগে রাখে libbar
  • আপনার লিঙ্কেজ undefined reference to কিছু ত্রুটির সাথে ব্যর্থ হয় ।
  • আপনার সমস্ত হেডার ফাইলগুলিতে সমস্ত অপরিজ্ঞাত কিছু ঘোষিত হয় #includeএবং আপনি যে লাইব্রেরিগুলিতে সংযুক্ত হন তা প্রকৃতপক্ষে সংজ্ঞায়িত হয়।

উদাহরণ সি তে রয়েছে তারা সমানভাবে সি ++ হতে পারে be

একটি স্ট্যাটিক লাইব্রেরি জড়িত একটি ন্যূনতম উদাহরণ যা আপনি নিজেকে তৈরি করেছিলেন

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

ব্যাখ্যা

পড়া এখানে থেকে isচ্ছিক

ডিফল্টরূপে, জিসিসি দ্বারা উত্পাদিত একটি লিংকেজ কমান্ড, আপনার ডিস্ট্রোতে, লিঙ্কেজে থাকা ফাইলগুলি বাম থেকে ডানদিকে কমান্ডলাইন অনুক্রমে গ্রাস করে। যখন এটি দেখতে পেল যে কোনও ফাইল কোনও কিছুকে বোঝায় কোনও এবং এর সংজ্ঞা নেই, তখন ডানে আরও ফাইলগুলিতে একটি সংজ্ঞা অনুসন্ধান করবেন। যদি শেষ পর্যন্ত এটি একটি সংজ্ঞা খুঁজে পায়, তবে রেফারেন্সটি সমাধান হয়ে যায়। যদি কোনও রেফারেন্স শেষে অমীমাংসিত থাকে, লিঙ্কেজ ব্যর্থ হয়: লিঙ্কার পিছন দিকে সন্ধান করে না।

স্থির লাইব্রেরি সহ প্রথম, উদাহরণ 1my_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

linker যোগ করেনি eg1.o প্রোগ্রাম যখন এটি সূচিত -lmy_lib। কারণ যে সময়ে, এটি দেখা যায় নি eg1.o। তোমার প্রোগ্রাম এখনো কোনো রেফারেন্স মনে করার কারণ নাই hw: এটা এখনো কোনো রেফারেন্স দেখা যায় না সব সময়ে , কারণ সমস্ত রেফারেন্স এটা তোলে হয় eg1.o

সুতরাং লিঙ্কারটি my_lib.oপ্রোগ্রামটিতে যুক্ত হয় না এবং এর জন্য আর কোনও ব্যবহার নেই libmy_lib.a

এরপরে এটি সন্ধান করে eg1.oএবং এটি প্রোগ্রাম হিসাবে যুক্ত করে। লিঙ্কেজ সিকোয়েন্সের একটি অবজেক্ট ফাইল সর্বদা প্রোগ্রামে যুক্ত করা হয়। এখন, প্রোগ্রামটি একটি রেফারেন্স দেয় hwএবং এর কোনও সংজ্ঞা থাকে না hw; তবে লিঙ্কেজ সিকোয়েন্সে এমন কিছুই অবশিষ্ট নেই যা অনুপস্থিত সংজ্ঞাটি সরবরাহ করতে পারে। অমীমাংসিত হয়ে hwশেষ হয়ে যায় এবং সংযোগ ব্যর্থ হয়।

দ্বিতীয়, ভাগ করা লাইব্রেরি সহ উদাহরণ 2libz

একটি ভাগ করা লাইব্রেরি অবজেক্ট ফাইল বা এর মতো কোনও কিছুর সংরক্ষণাগার নয়। এটি অনেকটা এমন একটি প্রোগ্রামের মতো যার কোনও mainফাংশন নেই এবং পরিবর্তে এটি সংজ্ঞায়িত করা একাধিক অন্যান্য প্রতীক প্রকাশ করে, যাতে অন্যান্য প্রোগ্রামগুলি রানটাইমে এগুলি ব্যবহার করতে পারে।

অনেক লিনাক্স ডিস্ট্রো আজকে তাদের জিসিসি টুলচেইন যাতে তার ভাষা ড্রাইভার (কনফিগার gcc, g++, gfortranইত্যাদি) সিস্টেম linker (নির্দেশ 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. মুহুর্তে মত ঠিক একই ভাবে ভুল যখন linker খুঁজে বের করে -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

অবশ্যই gcc কে eg1.cপ্রথমে সংকলন করতে হবে , এবং তারপরে ফলাফলযুক্ত অবজেক্ট ফাইলটি লিঙ্ক করতে হবে libmy_lib.a। সুতরাং এটি কীভাবে জানতে পারে না যে লিংকটি করার সময় অবজেক্ট ফাইলটি প্রয়োজন?

কারণ একটি একক কমান্ডের সাথে সংকলন এবং সংযোগ লিঙ্কেজ ক্রমের ক্রম পরিবর্তন করে না।

আপনি যখন উপরের কমান্ডটি চালাবেন, তখন এটি নির্ধারণ করুন gccযে আপনি সংকলন + লিঙ্কেজ চান। পর্দার অন্তরালে এটি একটি সংকলন কমান্ড তৈরি করে এবং এটি চালায়, তারপরে একটি লিঙ্কেজ কমান্ড তৈরি করে এবং এটি চালায়, যেন আপনি দুটি কমান্ড চালিয়েছেন:

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

তাই দুটো ঘটনার ব্যর্থ আপনি ঠিক যেমন এটা আছে না ঐ দুই কমান্ড চালানো। ব্যর্থতায় আপনি যে পার্থক্যটি লক্ষ্য করছেন তা হ'ল gcc কম্পাইল + লিঙ্কের ক্ষেত্রে একটি অস্থায়ী অবজেক্ট ফাইল তৈরি করেছে, কারণ আপনি এটি ব্যবহার করতে বলছেন না 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)
        { /*...*/ }
        // ...
    };

দ্রষ্টব্য , যখন অপারেটরের ঘোষণাপত্র (বা ফাংশন) কেবল ক্লাসে উপস্থিত হয়, নামটি "সাধারণ" অনুসন্ধানের জন্য পাওয়া যায় না, কেবল যুক্তি নির্ভর নির্ভর অনুসন্ধানের জন্য, সিপ্রেফারেন্স থেকে ;

শ্রেণি বা শ্রেণীর টেম্পলেটর মধ্যে বন্ধুত্বের ঘোষণার মধ্যে প্রথমে ঘোষিত একটি নাম এক্স এর অন্তর্নিহিত সংলগ্ন নেমস্পেসের সদস্য হয়ে যায় তবে নাম অবস্থানের স্কোপের সাথে ম্যাচিং ডিক্লেয়ারেশন না থাকলে অনুসন্ধানের জন্য (যুক্তি-নির্ভর লুকে বাদ দেওয়া যা এক্সকে বিবেচনা করে) অ্যাক্সেসযোগ্য নয় unless প্ ...

Cppreferences এবং 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(আমি উদাহরণটিতে এখানে একটি পৃথক পথ অন্তর্ভুক্ত করে স্পষ্ট করে দিয়েছি তবে এটি সর্বদা এতটা সুস্পষ্ট নাও হতে পারে Maybe সংকলক সেটিংসে অন্তর্ভুক্ত পথটি পৃথক হতে পারে) ।

এই উদাহরণে নোট করুন, লিঙ্কারটি আপনাকে বলবে এটি এটি খুঁজে পায়নি draw(), যখন বাস্তবে আপনি জানেন যে এটি অবশ্যই লাইব্রেরি দ্বারা রফতানি করা হচ্ছে। কী ভুল হয়েছে তা ভেবে আপনি আপনার মাথা আঁচড়ান কয়েক ঘন্টা ব্যয় করতে পারেন। জিনিসটি হল, লিঙ্কারটি একটি আলাদা স্বাক্ষর দেখায় কারণ প্যারামিটারের ধরনগুলি কিছুটা আলাদা। উদাহরণস্বরূপ, vec3উভয় প্রকল্পের মধ্যে যেমন কম্পাইলারের সাথে সম্পর্কিত হয় তবে তা আলাদা। এটি ঘটতে পারে কারণ তারা দুটি সামান্য আলাদা ফাইলগুলি অন্তর্ভুক্ত করে আসে (সম্ভবত ফাইলগুলি লাইব্রেরির দুটি পৃথক সংস্করণ থেকে আসে)।

লিঙ্কারটি ডিবাগ করা হচ্ছে

ডুম্পবিন আপনার বন্ধু, যদি আপনি ভিজুয়াল স্টুডিও ব্যবহার করেন। আমি নিশ্চিত যে অন্যান্য সংকলকগুলির কাছে অন্যান্য অনুরূপ সরঞ্জাম রয়েছে।

প্রক্রিয়াটি এরকম হয়:

  1. লিঙ্কার ত্রুটিতে দেওয়া অদ্ভুত ম্যাঙ্গলেড নামটি নোট করুন। (উদাঃ @ গ্রাফিক্স @ এক্সওয়াইজেড আঁকুন)।
  2. পাঠ্য ফাইলে লাইব্রেরি থেকে রফতানি করা প্রতীকগুলি ফেলে দিন।
  3. আগ্রহের রফতানি প্রতীকটি সন্ধান করুন এবং লক্ষ্য করুন যে ম্যাংলেড নামটি আলাদা।
  4. কেন ম্যাংলেড নামগুলি আলাদা হয়ে গেল সেদিকে মনোযোগ দিন। উত্সের কোডটিতে একই দেখতে প্যারামিটারের ধরনগুলি দেখতে দেখতে আপনি দেখতে সক্ষম হবেন।
  5. কেন তারা আলাদা হয় কারণ। উপরে বর্ণিত উদাহরণে, ফাইলগুলি অন্তর্ভুক্ত করার কারণে এগুলি পৃথক।

[1] প্রকল্পের দ্বারা আমার অর্থ উত্স ফাইলগুলির একটি সেট যা একটি লাইব্রেরি বা এক্সিকিউটেবল উত্পাদন করতে একসাথে যুক্ত linked

সম্পাদনা 1: বুঝতে সহজ হতে প্রথম বিভাগটি পুনরায় লিখেছেন। অন্য কিছু ঠিক করার দরকার আছে কিনা তা জানতে দয়া করে নীচে মন্তব্য করুন। ধন্যবাদ!


15

অসামঞ্জস্য UNICODEসংজ্ঞা

একটি উইন্ডোজ ইউনিকোড বিল্ড সঙ্গে নির্মিত হয় TCHARইত্যাদি হিসাবে সংজ্ঞায়িত করা হচ্ছে wchar_tসঙ্গে বিল্ডিং না কখন ইত্যাদি UNICODEসঙ্গে বিল্ড হিসাবে সংজ্ঞায়িত TCHARহিসাবে সংজ্ঞায়িত করা charইত্যাদি.এই UNICODEএবং _UNICODEসংজ্ঞায়িত সব প্রভাবিত " T" STRING ধরনের ; LPTSTR, LPCTSTRএবং তাদের এলক

UNICODEসংজ্ঞায়িত করে একটি লাইব্রেরি তৈরি করা এবং এটি এমন কোনও প্রকল্পে সংযুক্ত করার চেষ্টা করা যেখানে UNICODEসংজ্ঞায়িত করা হয়নি, যার ফলে সংযোগকারী ত্রুটি ঘটবে কারণ সংজ্ঞাতে কোনও মিল নেই TCHAR; charবনাম wchar_t

ত্রুটিটি সাধারণত একটি ফাংশনকে একটি মান charবা wchar_tউত্পন্ন প্রকারের সাথে অন্তর্ভুক্ত করে, এতে std::basic_string<>এগুলিও অন্তর্ভুক্ত থাকতে পারে । কোডে প্রভাবিত ক্রিয়াকলাপটি ব্রাউজ করার সময়, প্রায়শই এখানে TCHARবা এর উল্লেখ পাওয়া যায় std::basic_string<TCHAR>This এটি একটি কথিত চিহ্ন যা কোডটি মূলত একটি ইউনিকোডে এবং মাল্টি-বাইট অক্ষর (বা "সংকীর্ণ") উভয়ের জন্যই তৈরি করা হয়েছিল sign ।

এটি সংশোধন করার জন্য, UNICODE(এবং _UNICODE) এর ধারাবাহিক সংজ্ঞা সহ প্রয়োজনীয় সমস্ত গ্রন্থাগার এবং প্রকল্পগুলি তৈরি করুন ।

  1. এটি হয় সঙ্গে করা যেতে পারে;

    #define UNICODE
    #define _UNICODE
  2. বা প্রকল্পের সেটিংসে;

    প্রকল্পের বৈশিষ্ট্য> সাধারণ> প্রকল্পের ডিফল্ট> অক্ষর সেট

  3. বা কমান্ড লাইনে;

    /DUNICODE /D_UNICODE

বিকল্পটি প্রযোজ্য, যদি ইউনিকোড ব্যবহারের উদ্দেশ্যে না হয় তবে নিশ্চিত করুন যে সংজ্ঞাগুলি সেট করা নেই এবং / অথবা মাল্টি-ক্যারেক্টর সেটিং প্রকল্পগুলিতে ব্যবহৃত হয়েছে এবং ধারাবাহিকভাবে প্রয়োগ করা হয়েছে।

"রিলিজ" এবং "ডিবাগ" পাশাপাশি তৈরির মধ্যেও সামঞ্জস্য রাখতে ভুলবেন না।


14

পরিষ্কার এবং পুনর্নির্মাণ

বিল্ডটির একটি "পরিষ্কার" পূর্ববর্তী বিল্ডগুলি, ব্যর্থ বিল্ডস, অসম্পূর্ণ বিল্ডস এবং অন্যান্য বিল্ড সিস্টেম সম্পর্কিত বিল্ড সংক্রান্ত সমস্যাগুলি থেকে পড়ে থাকা "মৃত কাঠ" সরিয়ে ফেলতে পারে।

সাধারণভাবে আইডিই বা বিল্ডের মধ্যে কিছু ধরণের "ক্লিন" ফাংশন অন্তর্ভুক্ত থাকে তবে এটি সঠিকভাবে কনফিগার করা যায় না (যেমন ম্যানুয়াল মেকফাইলে) বা ব্যর্থ হতে পারে (যেমন মধ্যবর্তী বা ফলস্বরূপ দ্বিপদী কেবল পঠনযোগ্য)।

একবার "ক্লিন" শেষ হয়ে গেলে, পরীক্ষা করুন যে "ক্লিন" সফল হয়েছে এবং সমস্ত উত্পন্ন ইন্টারমিডিয়েট ফাইল (যেমন একটি স্বয়ংক্রিয় মেকফিল) সফলভাবে মুছে ফেলা হয়েছে।

এই প্রক্রিয়াটি একটি চূড়ান্ত অবলম্বন হিসাবে দেখা যেতে পারে, তবে প্রায়শই এটি প্রথম প্রথম পদক্ষেপ ; বিশেষত যদি ত্রুটির সাথে সম্পর্কিত কোডটি সম্প্রতি যুক্ত করা হয়েছে (হয় স্থানীয়ভাবে বা উত্স সংগ্রহস্থল থেকে)।


10

constপরিবর্তনীয় ঘোষণা / সংজ্ঞাগুলিতে "বাহ্যিক" অনুপস্থিত (কেবলমাত্র 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: ফাইল সিস্টেমটি সি ++ 17 সাল থেকে স্ট্যান্ডার্ড লাইব্রেরিতে রয়েছে তবে আমার প্রোগ্রামটি সি ++ 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 # এর < পরীক্ষামূলক :: ফাইল সিস্টেম > অন্তর্ভুক্ত রয়েছে এবং উপরের কোডটি রয়েছে
  • file.cpp , file.h এর বাস্তবায়ন, # এর " file.h " অন্তর্ভুক্ত
  • main.cpp # এর < ফাইল সিস্টেম > এবং " file.h " অন্তর্ভুক্ত রয়েছে

Main.cpp এবং file.h. এ ব্যবহৃত বিভিন্ন লাইব্রেরি নোট করুন। যেহেতু main.cpp # < ফাইল সিস্টেম > এর পরে " file.h " অন্তর্ভুক্ত করেছে , তাই সেখানে ব্যবহৃত ফাইল সিস্টেমের সংস্করণটি C ++ 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

সমাধান

এটি ঠিক করার জন্য আমার কেবলমাত্র ফাইল পরীক্ষায় <পরীক্ষামূলক :: ফাইল সিস্টেম> পরিবর্তন করতে হবে <ফাইলসিসটাম> এ


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(যদি সি ++ ব্যবহার করা হত)।

উইন্ডোজ-ডেলসের অনুরূপ, কোনও একটি সংজ্ঞায়িত জনসাধারণের কার্যাদি চিহ্নিত করবে, উদাহরণস্বরূপ DLL_PUBLIC:

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

DLL_PUBLIC int my_public_function(){
  ...
}

যা মোটামুটি উইন্ডোজ / এমএসভিসি-সংস্করণের সাথে মিলে যায়:

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

দৃশ্যমানতা সম্পর্কে আরও তথ্য জিসিসি উইকিতে পাওয়া যাবে।


যখন কোনও অনুবাদ ইউনিট -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 উদাহরণস্বরূপ )।

ম্যাকোজে, একই ফাইলে উভয় আর্কিটেকচার শিপিংয়ের বিকল্প রয়েছে। এটি লিঙ্কটি উভয় সংস্করণ থাকবে বলে আশাবাদী, তবে কেবল একটি। এটি লাইব্রেরিটি বাছাই করা হয়েছে এমন ভুল lib/ lib64ফোল্ডারের ক্ষেত্রেও সমস্যা হতে পারে ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.