c++ - একটি অনির্ধারিত রেফারেন্স/অমীমাংসিত বহিরাগত প্রতীক ত্রুটি কি এবং আমি কিভাবে এটি ঠিক করতে পারি?




সি++ বই (20)

আপনার অন্তর্ভুক্ত পাথ ভিন্ন যখন

একটি হেডার ফাইল এবং এর সাথে সম্পর্কিত ভাগ লাইব্রেরি (.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এবং আপনার নিজের প্রোগ্রাম ব্যবহার করে আপনি শেষ হয়ে যান , তবে আপনার হ্যাকারটি হঠাৎ কী ঘটছে তা নিয়ে হঠাৎ করেই চলে যাবেন (pun intended)।

বাস্তব বিশ্বের এই ঘটতে পারে কিভাবে একটি উদাহরণ নীচের ব্যাখ্যা করা হয়।

একটি উদাহরণ সঙ্গে আরও সম্প্রসারণ

আমি দুটি প্রকল্প আছে: 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(), যখন প্রকৃতপক্ষে আপনি জানেন যে এটি সম্ভবত লাইব্রেরির দ্বারা রপ্তানি করা হচ্ছে। আপনি আপনার মাথা scratching ঘন্টা ব্যয় করতে পারে কি বিস্ময় ভুল হতে পারে। জিনিস হল, লিংক একটি ভিন্ন স্বাক্ষর দেখায় কারণ পরামিতি ধরনের সামান্য ভিন্ন। উদাহরণস্বরূপ, vec3কম্পাইলার যতদূর সংশ্লিষ্ট উভয় প্রকল্পে একটি ভিন্ন ধরনের। এটি ঘটতে পারে কারণ তারা দুটি সামান্য ভিন্ন ফাইলগুলি অন্তর্ভুক্ত করে (সম্ভবত ফাইলগুলি লাইব্রেরির দুটি ভিন্ন সংস্করণ থেকে আসে)।

সংযোগকারী ডিবাগিং

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

প্রক্রিয়া এই মত যায়:

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

[1] প্রকল্পের মাধ্যমে আমি উৎস ফাইলগুলির একটি সেট যা একটি লাইব্রেরি বা এক্সিকিউটেবল তৈরি করতে একসাথে লিঙ্কযুক্ত।

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

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

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


ক্লাস সদস্যগণ:

একটি বিশুদ্ধ virtual ধ্বংসকারী একটি বাস্তবায়ন প্রয়োজন।

একটি ধ্বংসকারী বিশুদ্ধ ঘোষণা এখনও আপনি এটি সংজ্ঞায়িত করা প্রয়োজন (একটি নিয়মিত ফাংশন বিপরীত):

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

এটি ঘটে কারণ কারণ বস্তুর ধ্বংসাত্মকভাবে ধ্বংস হয়ে গেলে বর্গ শ্রেণীর ধ্বংসকারীগুলিকে বলা হয়, সুতরাং একটি সংজ্ঞা প্রয়োজন।

virtual পদ্ধতি প্রয়োগ করা বা বিশুদ্ধ হিসাবে সংজ্ঞায়িত করা আবশ্যক।

এটি কোনও সংজ্ঞা ছাড়াই নন- virtual পদ্ধতির অনুরূপ, বিশুদ্ধ ঘোষণাটি একটি ডামি vtable তৈরি করে এবং যুক্ত করার ফাংশনটি ব্যবহার করে লিঙ্কার ত্রুটি পেতে পারে যুক্ত যুক্তির সাথে:

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

শ্রেণীকক্ষের ভিতরে অবিচ্ছেদ্য বা গণনার const static const ডেটা সদস্যের জন্য একটি const সরবরাহ করা যেতে পারে; যাইহোক, উপরের সদস্য হিসাবে এই সদস্যের উড-ব্যবহার এখনও একটি নামস্থান দশা সংজ্ঞা প্রয়োজন হবে। সি ++ 11 সমস্ত static const ডেটা সদস্যদের জন্য ক্লাসের ভিতরে শুরু করার অনুমতি দেয়।


কম্পাইলার / আইডিই একটি বাগ

আমি সম্প্রতি এই সমস্যা ছিল, এবং এটি ভিজ্যুয়াল স্টুডিও এক্সপ্রেস 2013 একটি বাগ ছিল পরিণত । আমি প্রকল্প থেকে একটি উৎস ফাইল মুছে ফেলতে এবং বাগ অতিক্রম করতে এটি পুনরায় যোগ করতে হয়েছিল।

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

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

টেমপ্লেট বন্ধুত্ব ...

একটি বন্ধু অপারেটর (বা ফাংশন) সঙ্গে একটি টেমপ্লেট টাইপ কোড স্নিপেট দেওয়া;

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

operator<<একটি অ-টেমপ্লেট ফাংশন হিসাবে ঘোষিত হচ্ছে। Tসঙ্গে ব্যবহৃত প্রতিটি টাইপ জন্য Foo, একটি অ-templated হতে হবে 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 জন্য উপলব্ধ নয়, কেবলমাত্র আর্গুমেন্ট নির্ভর অনুসন্ধানের জন্য, cppreference থেকে ;

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

টেমপ্লেট বন্ধুদের উপর cppreference এবং সি ++ 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)


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

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

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

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

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


শেয়ারকৃত লাইব্রেরিগুলির সাথে লিঙ্ক করার সময়, ব্যবহৃত চিহ্নগুলি লুকানো নেই তা নিশ্চিত করুন।

জি সি সি এর ডিফল্ট আচরণ সব প্রতীক দৃশ্যমান হয়। যাইহোক, যখন অনুবাদ ইউনিটগুলি বিকল্পের সাথে তৈরি করা হয়, তখন -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`কোড-সেকশনের জন্য` টি পরিবর্তে:

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(){
  ...
}

যা উইন্ডোজ / MSVC-version এর সাথে সামঞ্জস্যপূর্ণ:

#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

অসঙ্গতি UNICODEসংজ্ঞা

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

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

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

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

  1. এই উভয় সঙ্গে সম্পন্ন করা যেতে পারে;

    #define UNICODE
    #define _UNICODE
  2. অথবা প্রকল্প সেটিংস মধ্যে;

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

  3. অথবা কমান্ড লাইনের উপর;

    /DUNICODE /D_UNICODE

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

"রিলিজ" এবং "ডিবাগ" এর সাথে সামঞ্জস্যপূর্ণ হতে ভুলবেন না।


ঘোষিত কিন্তু একটি পরিবর্তনশীল বা ফাংশন সংজ্ঞায়িত না।

একটি সাধারণ পরিবর্তনশীল ঘোষণা

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

আপনি যে ফাংশনটি বাস্তবায়ন করেছেন তা অবশ্যই সতর্কতার সাথে মেলে এমন সতর্কতা অবলম্বন করুন। উদাহরণস্বরূপ, আপনি বিচ্ছিন্ন সিভি-যোগ্যতা থাকতে পারে:

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)

বিচ্ছিন্নতা অন্যান্য উদাহরণ অন্তর্ভুক্ত

  • ফাংশন / পরিবর্তনশীল অন্য নামে সংজ্ঞায়িত একটি নামস্থান ঘোষণা।
  • ফাংশন / পরিবর্তনশীল শ্রেণী সদস্য হিসাবে ঘোষিত, গ্লোবাল (বা বিপরীত) হিসাবে সংজ্ঞায়িত।
  • ফাংশন ফেরত টাইপ, পরামিতি সংখ্যা এবং ধরনের, এবং কলিং কনভেনশন সব ঠিকমত না।

কম্পাইলার থেকে ত্রুটি বার্তাটি আপনাকে ভেরিয়েবল বা ফাংশনটির পূর্ণ ঘোষণা দেবে যা ঘোষণা করা হয়েছিল তবে কখনও সংজ্ঞায়িত করা হয়নি। আপনার প্রদত্ত সংজ্ঞাটি ঘনিষ্ঠভাবে তুলনা করুন। প্রতিটি বিস্তারিত ম্যাচ নিশ্চিত করুন।


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

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

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

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

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

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

extern "C" void foo();

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

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

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

ভুলভাবে আমদানি / মোডুলস / DLL (কম্পাইলার নির্দিষ্ট) জুড়ে ক্লাস / এক্সপোর্ট পদ্ধতি।

__Declspec __declspec(dllexport) এবং __declspec(dllimport) ব্যবহার করে এক্সপোর্ট এবং আমদানি করতে কোন প্রতীকগুলি নির্দিষ্ট করার জন্য MSVS আপনাকে প্রয়োজন।

এই ডুয়াল কার্যকারিতা সাধারণত ম্যাক্রোর ব্যবহার মাধ্যমে প্রাপ্ত হয়:

#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
{
};

স্বতঃস্ফূর্ত সংযুক্ত লাইব্রেরি নির্দিষ্ট করা হয় যাতে ক্রম ভুল।

লাইব্রেরিগুলি একে অপরকে নির্ভর করে যদি লাইব্রেরিগুলি ডিওইএসের সাথে সম্পর্কিত হয়। সাধারণভাবে, যদি লাইব্রেরী 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

তাই আবার পুনরাবৃত্তি, আদেশ ব্যাপার!


একটি সি ++ প্রোগ্রাম কম্পাইল করা কয়েকটি ধাপে সঞ্চালিত হয়, যেমন 2.2 অনুসারে উল্লেখ করা হয়েছে (রেফারেন্সের জন্য কিথ থম্পসনকে ক্রেডিট) :

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

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

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

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

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

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

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

সাধারণ ত্রুটি বার্তাগুলি error LNK2001 error LNK1120 , মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিওর জন্য error LNK2019 এবং জি सीसीের জন্য প্রতীক নামের undefined reference to

কোড:

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

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

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

সাধারণ কারণ অন্তর্ভুক্ত:

  • যথাযথ লাইব্রেরি / বস্তু ফাইলের বিরুদ্ধে সংযোগ স্থাপন বা বাস্তবায়ন ফাইল সংকলন ব্যর্থ
  • ঘোষণা এবং অনির্ধারিত পরিবর্তনশীল বা ফাংশন।
  • ক্লাস টাইপ সদস্যদের সঙ্গে সাধারণ সমস্যা
  • টেমপ্লেট বাস্তবায়ন দৃশ্যমান নয়।
  • প্রতীক একটি সি প্রোগ্রামে সংজ্ঞায়িত এবং সি ++ কোড ব্যবহার করা হয়।
  • ভুলভাবে আমদানি / মডিউল / ডিল জুড়ে পদ্ধতি / ক্লাস রপ্তানি। (এমএসভিএস নির্দিষ্ট)
  • বিজ্ঞপ্তি লাইব্রেরি নির্ভরতা
  • 'WinMain @ 16' এর অনির্দিষ্ট রেফারেন্স
  • স্বতন্ত্র লাইব্রেরি অর্ডার
  • একই নাম একাধিক উৎস ফাইল
  • #Pragma (মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিও) ব্যবহার করার সময়।
  • টেমপ্লেট বন্ধুদের সঙ্গে সমস্যা
  • অসঙ্গতিহীন UNICODE সংজ্ঞা

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

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

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

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

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

এই অনুসন্ধান প্রক্রিয়া সমাধান বলা হয়।

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

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

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

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

int foo()
{
    return 0;
}

B.cpp আমরা ফাংশন foo কল করতে চান, তাই আমরা যোগ

void foo();

ফাংশন ঘোষণা foo (), এবং অন্য ফাংশন শরীরের মধ্যে কল, bar() :

void bar()
{
    foo();
}

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

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

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


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

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

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


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

কিছু .so ফাইল আসলে GNU ld লিঙ্কার স্ক্রিপ্ট হয় , যেমন libtbb.so ফাইলটি এই সামগ্রী সহ একটি ASCII পাঠ্য ফাইল:

INPUT (libtbb.so.2)

কিছু জটিল জটিল এই সমর্থন করতে পারে না। উদাহরণস্বরূপ, যদি আপনি কম্পাইলার বিকল্পগুলিতে -v অন্তর্ভুক্ত করেন, তবে আপনি দেখতে পারেন যে মইনউইন gcc wrapper mwdip discards লিঙ্কার স্ক্রিপ্ট কমান্ড ফাইলগুলি লাইব্রেরিগুলির লিখিত শব্দের লিখিত শব্দের লিস্টে রয়েছে। লিংক স্ক্রিপ্ট ইনপুট কমান্ডটি প্রতিস্থাপন করা প্রায় সহজ কাজ পরিবর্তে ফাইল (অথবা একটি symlink) ফাইল একটি কপি সঙ্গে ফাইল, উদাহরণস্বরূপ

cp libtbb.so.2 libtbb.so

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


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

আমি সম্প্রতি আপত্তিজনক ফাইল recompiling দ্বারা ভিসুয়াল স্টুডিও 2012 সালে একটি অমীমাংসিত বহিরাগত ত্রুটি পরিত্রাণ পেতে সক্ষম হয়েছিল। যখন আমি পুনরায় নির্মিত, ত্রুটি চলে গেছে।

এটি সাধারণত ঘটে যখন দুটি (বা আরো) লাইব্রেরিগুলিতে একটি চক্র নির্ভরতা থাকে। লাইব্রেরি B.lib এবং লাইব্রেরিতে সি চিহ্ন ব্যবহার করার চেষ্টা A.lib থেকে প্রতীক ব্যবহার করার চেষ্টা করে। সঙ্গে বন্ধ শুরু অস্তিত্ব নেই। যখন আপনি A সংকলন করার চেষ্টা করেন, লিঙ্ক পদক্ষেপটি ব্যর্থ হবে কারণ এটি BLib খুঁজে পাচ্ছে না। এলিব তৈরি করা হবে, কিন্তু কোন ডিল। তারপর আপনি B কম্পাইল করুন যা সফল হবে এবং BLib তৈরি করবে। পুনঃ কম্পাইলিং A এখন কাজ করবে কারণ বিলি এখন পাওয়া যায়।


বিভিন্ন আর্কিটেকচার

আপনি একটি বার্তা দেখতে পারেন:

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

এই ক্ষেত্রে, এর মানে হল যে উপলব্ধ প্রতীকগুলি আপনি যে কম্পাইল করছেন তার চেয়ে ভিন্ন আর্কিটেকচারের জন্য।

ভিজ্যুয়াল স্টুডিওতে, এটি ভুল "প্ল্যাটফর্ম" এর কারণে, এবং আপনাকে অবশ্যই সঠিক বাছাইটি বা লাইব্রেরির যথাযথ সংস্করণটি ইনস্টল করতে হবে।

লিনাক্স, এটি (ব্যবহার ভুল গ্রন্থাগার ফোল্ডারের কারণে হতে পারে libপরিবর্তে lib64উদাহরণস্বরূপ)।

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


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

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

সঠিক সমাধান বিকাশকারী একটি আপডেট হওয়া প্যাকেজটি প্রকাশ করে এবং তারপরে আপগ্রেড করার আশা করা হয়, তবে এটি VS2013 এর জন্য অতিরিক্ত সেটিংসে হ্যাকিংয়ের মাধ্যমে আমার জন্য কাজ করেছে, VS2012 লাইব্রেরি ফাইলগুলিতে নির্দেশ করে।

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


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

GCC 5.2.0 এর সাথে লিঙ্কার ত্রুটিগুলির একটি সম্ভাব্য কারণ হল একটি নতুন libstdc ++ লাইব্রেরি ABI এখন ডিফল্টভাবে নির্বাচিত হয়েছে।

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

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


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

সংকলন মানে কি?

  • ভিসুয়াল স্টুডিও অনুসন্ধান .vcxproj ফাইলে অনুসন্ধান করুন এবং এক্সটেনশন। Cpp প্রতিটি ফাইল কম্পাইল শুরু করুন। সংকলন আদেশটি অনির্ধারিত। তাই আপনাকে প্রথমে ধরে নিতে হবে না যে ফাইলটি main.cpp প্রথম সংকলিত হয়
  • যদি .cpp ফাইলগুলি অতিরিক্ত। এইচ ফাইলগুলিতে নির্ভর করে তবে প্রতীকগুলি খুঁজে পেতে পারে যা ফাইল। Cpp
  • যদি একটি .cpp ফাইল উপস্থিত থাকে তবে সংকলকটি একটি প্রতীক খুঁজে পায়নি, একটি কম্পাইলার সময় ত্রুটি বার্তা উত্থাপন করে প্রতীক x পাওয়া যায় নি
  • এক্সটেনশন সহ প্রতিটি ফাইলের জন্য .cpp একটি বস্তু ফাইল তৈরি করা হয় .o এবং ভিজ্যুয়াল স্টুডিওও ProjectName.Cpp.Clean.txt নামে একটি ফাইলের আউটপুট লিখেছে যার মধ্যে সমস্ত বস্তু ফাইল রয়েছে যা লিঙ্কার দ্বারা প্রক্রিয়া করতে হবে।

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

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

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

পর্যবেক্ষণ

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

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

কম্পাইলার সময় ত্রুটি:

  • আপনি আপনার সি ++ প্রকল্প সিনট্যাক্টিক সঠিক লিখতে ভুলবেন না।

সংযোগকারী সময় ত্রুটি

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




unresolved-external