නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේත දෝෂ මොනවාද? පොදු හේතු මොනවාද සහ ඒවා නිවැරදි කරන්නේ / වළක්වා ගන්නේ කෙසේද?
ඔබේම සංස්කරණය කිරීමට / එකතු කිරීමට නිදහස් වන්න.
නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේත දෝෂ මොනවාද? පොදු හේතු මොනවාද සහ ඒවා නිවැරදි කරන්නේ / වළක්වා ගන්නේ කෙසේද?
ඔබේම සංස්කරණය කිරීමට / එකතු කිරීමට නිදහස් වන්න.
Answers:
2.2 හි නිශ්චිතව දක්වා ඇති පරිදි C ++ වැඩසටහනක් සම්පාදනය කිරීම පියවර කිහිපයකින් සිදු වේ (යොමු කිරීම සඳහා කීත් තොම්සන්ට බැර) :
පරිවර්තන සින්ටැක්ස් රීති අතර ප්රමුඛතාවය පහත දැක්වෙන අදියරයන් මගින් නියම කරනු ලැබේ [පාදසටහන බලන්න] .
- අවශ්ය නම් භෞතික ප්රභව ගොනු අක්ෂර ක්රියාත්මක කිරීම-නිර්වචනය කර ඇති පරිදි මූලික මූලාශ්ර අක්ෂර කට්ටලයට (අවශ්ය රේඛා දර්ශකයන් සඳහා නව රේඛා අක්ෂර හඳුන්වා දීම) සිතියම් ගත කරනු ලැබේ. [SNIP]
- බැක්ස්ලෑෂ් අක්ෂරයක (\) සෑම අවස්ථාවකම වහාම නව රේඛා අක්ෂරයක් මකා දමනු ලැබේ. [SNIP]
- ප්රභව ගොනුව පෙර සැකසුම් ටෝකන (2.5) සහ සුදු-අවකාශ අක්ෂර අනුපිළිවෙලට (අදහස් ඇතුළුව) දිරාපත් වේ. [SNIP]
- පෙර සැකසුම් විධානයන් ක්රියාත්මක කරනු ලැබේ, සාර්ව ආයාචනා පුළුල් වේ, සහ _ප්රාග්මා ඒකීය ක්රියාකරු ප්රකාශන ක්රියාත්මක වේ. [SNIP]
- සෑම ප්රභව අක්ෂර කට්ටලයකම වචනානුසාරයෙන් හෝ වචනාර්ථයෙන් වචනාර්ථයෙන්, මෙන්ම එක් එක් ගැලවීමේ අනුක්රමය සහ විශ්වීය-චරිත-නාමයක් අක්ෂර වචනාර්ථයෙන් හෝ අමු නොවන වචන වචනාර්ථයෙන් ක්රියාත්මක වන අක්ෂර කට්ටලයේ අනුරූප සාමාජිකයා බවට පරිවර්තනය වේ; [SNIP]
- යාබද නූල් වචනාර්ථ ටෝකන සංයුක්ත වේ.
- ටෝකන වෙන් කරන සුදු-අවකාශ අක්ෂර තවදුරටත් වැදගත් නොවේ. සෑම පෙර සැකසුම් ටෝකනයක්ම ටෝකනයක් බවට පරිවර්තනය වේ. (2.7). එහි ප්රති ing ලයක් ලෙස ටෝකන කෘතිමව හා අර්ථාන්විතව විශ්ලේෂණය කර පරිවර්තන ඒකකයක් ලෙස පරිවර්තනය කරනු ලැබේ. [SNIP]
- පරිවර්තන පරිවර්තන ඒකක සහ ක්ෂණික ඒකක පහත පරිදි සංයුක්ත වේ: [SNIP]
- සියලුම බාහිර ආයතන යොමු කිරීම් විසඳනු ලැබේ. වර්තමාන පරිවර්තනයේ අර්ථ දක්වා නැති ආයතන සඳහා බාහිර යොමු කිරීම් තෘප්තිමත් කිරීම සඳහා පුස්තකාල සංරචක සම්බන්ධ කර ඇත. එවැනි සියලු පරිවර්තක ප්රතිදානය වැඩසටහන් ක්රියාත්මක කිරීම සඳහා එහි ක්රියාකාරී පරිසරය තුළ ක්රියාත්මක කිරීමට අවශ්ය තොරතුරු අඩංගු වේ. (අවධාරණය මගේ)
[පාදසටහන] ප්රායෝගිකව විවිධ අවධීන් එකට නැමිය හැකි වුවද, ක්රියාත්මක කිරීම් මෙම වෙනම අදියරයන් මෙන් හැසිරිය යුතුය.
නිශ්චිත දෝෂයන් සම්පාදනය කිරීමේ මෙම අවසාන අදියරේදී සිදු වේ. මූලික වශයෙන් අදහස් කරන්නේ ඔබ ක්රියාත්මක කිරීමේ ලිපිගොනු සමූහයක් වස්තු ලිපිගොනු හෝ පුස්තකාලවලට සම්පාදනය කර ඇති අතර දැන් ඔබට ඒවා එකට වැඩ කිරීමට අවශ්ය බවයි.
ඔබ සංකේතය අර්ථ කියන්න a
තුළ a.cpp
. දැන්, එම සංකේතය b.cpp
ප්රකාශ කර එය භාවිතා කර ඇත. සම්බන්ධ වීමට පෙර, එය සරලව උපකල්පනය කරන්නේ එම සංකේතය කොතැනක හෝ අර්ථ දක්වා ඇති බවයි , නමුත් එය තවමත් කොතැනදැයි ගණන් ගන්නේ නැත. සම්බන්ධක අවධිය සංකේතය සොයා ගැනීම සහ එය නිවැරදිව සම්බන්ධ කිරීම සඳහා වගකීම දරයි b.cpp
(හොඳයි, ඇත්ත වශයෙන්ම එය භාවිතා කරන වස්තුවට හෝ පුස්තකාලයට).
ඔබ මයික්රොසොෆ්ට් විෂුවල් ස්ටුඩියෝ භාවිතා කරන්නේ නම්, ව්යාපෘති මඟින් .lib
ගොනු ජනනය කරන බව ඔබට පෙනෙනු ඇත. මේවායේ අපනයනය කළ සංකේත වගුවක් සහ ආනයනික සංකේත වගුවක් අඩංගු වේ. ආනයනය කරන ලද සංකේත ඔබ සම්බන්ධ කරන පුස්තකාලවලට එරෙහිව විසඳනු ලබන අතර, අපනයනය කරන ලද සංකේත භාවිතා කරනු ලබන පුස්තකාල සඳහා ලබා දී ඇත .lib
(ඇත්නම්).
වෙනත් සම්පාදකයින් / වේදිකා සඳහා සමාන යාන්ත්රණ පවතී.
පොදු වැරැද්ද පණිවිඩ error LNK2001
, error LNK1120
, error LNK2019
සඳහා මයික්රොසොෆ්ට් විෂුවල් ස්ටුඩියෝ සහ undefined reference to
symbolName සඳහා ගල්ෆ් .
කේතය:
struct X
{
virtual void foo();
};
struct Y : X
{
void foo() {}
};
struct A
{
virtual ~A() = 0;
};
struct B: A
{
virtual ~B(){}
};
extern int x;
void foo();
int main()
{
x = 0;
foo();
Y y;
B b;
}
GCC සමඟ පහත දෝෂ ජනනය කරනු ඇත :
/home/AbiSfw/ccvvuHoX.o: In function `main':
prog.cpp:(.text+0x10): undefined reference to `x'
prog.cpp:(.text+0x19): undefined reference to `foo()'
prog.cpp:(.text+0x2d): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
prog.cpp:(.text._ZN1BD1Ev[B::~B()]+0xb): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
prog.cpp:(.text._ZN1BD0Ev[B::~B()]+0x12): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1Y[typeinfo for Y]+0x8): undefined reference to `typeinfo for X'
/home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1B[typeinfo for B]+0x8): undefined reference to `typeinfo for A'
collect2: ld returned 1 exit status
සහ Microsoft Visual Studio සමඟ සමාන දෝෂ :
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
පොදු හේතු අතර:
#pragma
(මයික්රොසොෆ්ට් විෂුවල් ස්ටුඩියෝ) භාවිතා කරන විට .lib දිගුව ඇතුළත් කිරීම හෝ නොකිරීම.UNICODE
නිර්වචනvirtual
විනාශ කරන්නෙකුට ක්රියාත්මක කිරීමක් අවශ්ය වේ.ඩිස්ට්රැක්ටර් පිරිසිදු යැයි ප්රකාශ කිරීම සඳහා ඔබට එය නිර්වචනය කිරීමට අවශ්ය වේ (සාමාන්ය ශ්රිතයක් මෙන් නොව):
struct X
{
virtual ~X() = 0;
};
struct Y : X
{
~Y() {}
};
int main()
{
Y y;
}
//X::~X(){} //uncomment this line for successful definition
මෙය සිදුවන්නේ වස්තුව ව්යංගයෙන් විනාශ වූ විට මූලික පංති විනාශ කරන්නන් ලෙස හැඳින්වෙන නිසා අර්ථ දැක්වීමක් අවශ්ය වේ.
virtual
ක්රම ක්රියාත්මක කළ යුතුය, නැතහොත් නිර්මල ලෙස අර්ථ දැක්විය යුතුය.virtual
නිර්වචනයක් නොමැති ක්රමවේදයන්ට මෙය සමාන වන අතර, පිරිසිදු ප්රකාශය ව්යාජ වෑටියක් ජනනය කරන අතර ශ්රිතය භාවිතා නොකර සම්බන්ධක දෝෂය ඔබට ලැබෙනු ඇත.
struct X
{
virtual void foo();
};
struct Y : X
{
void foo() {}
};
int main()
{
Y y; //linker error although there was no call to X::foo
}
මෙය ක්රියාත්මක වීමට X::foo()
නම් පිරිසිදු යැයි ප්රකාශ කරන්න :
struct X
{
virtual void foo() = 0;
};
virtual
පංති නොවන සාමාජිකයන්සමහර සාමාජිකයන් පැහැදිලිව භාවිතා නොකළද අර්ථ දැක්විය යුතුය:
struct A
{
~A();
};
පහත දැක්වෙන්නේ දෝෂයකි:
A a; //destructor undefined
පන්ති අර්ථ දැක්වීම තුළම ක්රියාත්මක කිරීම පේළිගත කළ හැකිය:
struct A
{
~A() {}
};
හෝ පිටත:
A::~A() {}
ක්රියාත්මක කිරීම පන්ති අර්ථ දැක්වීමෙන් පිටත නම්, නමුත් ශීර්ෂයක, inline
බහු අර්ථ දැක්වීමක් වැළැක්වීම සඳහා ක්රම සලකුණු කළ යුතුය .
භාවිතා කරන සියලුම සාමාජික ක්රම භාවිතා කරන්නේ නම් නිර්වචනය කළ යුතුය.
struct A
{
void foo();
};
void foo() {}
int main()
{
A a;
a.foo();
}
අර්ථ දැක්වීම විය යුතුය
void A::foo() {}
static
තනි පරිවර්තන ඒකකයකින් දත්ත සාමාජිකයින් පන්තියෙන් පිටත අර්ථ දැක්විය යුතුය :struct X
{
static int x;
};
int main()
{
int x = X::x;
}
//int X::x; //uncomment this line to define X::x
static
const
පංති අර්ථ දැක්වීම තුළ සමෝධානික හෝ ගණන් කිරීමේ වර්ගයේ දත්ත සාමාජිකයෙකු සඳහා ආරම්භකයක් සැපයිය හැකිය ; කෙසේ වෙතත්, මෙම සාමාජිකයාගේ අමුතු භාවිතය සඳහා ඉහත විස්තර කර ඇති පරිදි නාම අවකාශ විෂය පථයේ අර්ථ දැක්වීමක් අවශ්ය වේ. C ++ 11 සියලුම static const
දත්ත සාමාජිකයින් සඳහා පන්තිය තුළ ආරම්භ කිරීමට ඉඩ දෙයි .
පොදුවේ ගත් කල, සෑම පරිවර්තන ඒකකයක්ම එම පරිවර්තන ඒකකයේ අර්ථ දක්වා ඇති සංකේතවල අර්ථ දැක්වීම් අඩංගු වස්තු ගොනුවක් ජනනය කරනු ඇත. එම සංකේත භාවිතා කිරීම සඳහා, ඔබ එම වස්තු ලිපිගොනු සමඟ සම්බන්ධ විය යුතුය.
Gcc යටතේ ඔබ විධාන රේඛාවේ එකට සම්බන්ධ කළ යුතු සියලුම වස්තු ගොනු නියම කරනු ඇත, නැතහොත් ක්රියාත්මක කිරීමේ ගොනු එකට සම්පාදනය කරන්න.
g++ -o test objectFile1.o objectFile2.o -lLibraryName
මෙම libraryName
මෙතන වේදිකාවක්-විශේෂිත එකතු තොරව, පුස්තකාලය පමණක් හිස් නාමය වේ. එබැවින් උදා: ලිනක්ස් පුස්තකාල ලිපිගොනු සාමාන්යයෙන් හැඳින්වුවද libfoo.so
ඔබ ලියන්නේ එය පමණි -lfoo
. වින්ඩෝස් හි එම ගොනුවම හැඳින්විය හැක foo.lib
, නමුත් ඔබ එකම තර්කය භාවිතා කරයි. ඔබට එම ගොනු භාවිතයෙන් සොයාගත හැකි නාමාවලිය එක් කිරීමට සිදු විය හැකිය -L‹directory›
. පසු -l
හෝ පසුව ඉඩක් ලිවීමට වග බලා ගන්න -L
.
සඳහා XCode : -> පුස්තකාල සොයන්න පාත් එකතු -> ඇද ව්යාපෘතිය ෆෝල්ඩරයේ සැබෑ පුස්තකාල යොමු අතහැර පරිශීලක ශීර්ෂකය සොයන්න පථ එක් කරන්න.
MSVS යටතේ , ව්යාපෘතියකට එකතු කරන ලද ගොනු ස්වයංක්රීයව ඒවායේ වස්තු ලිපිගොනු එකට සම්බන්ධ කර ඇති අතර lib
ගොනුවක් ජනනය වේ (පොදු භාවිතයේදී). වෙනම ව්යාපෘතියක සංකේත භාවිතා කිරීමට, ඔබට lib
ව්යාපෘති සැකසුම් තුළ ගොනු ඇතුළත් කළ යුතුය. මෙය සිදු කරනු ලබන්නේ ව්යාපෘති ගුණාංගවල ලින්කර් කොටසේ ය Input -> Additional Dependencies
. ( lib
ගොනුව සඳහා මාර්ගය එක් කළ යුතුය Linker -> General -> Additional Library Directories
) ගොනුවක් ලබා දී ඇති තෙවන පාර්ශවීය පුස්තකාලයක් භාවිතා කරන විට lib
, එසේ කිරීමට අපොහොසත් වීම සාමාන්යයෙන් දෝෂයට හේතු වේ.
ගොනුව සම්පාදනයට එක් කිරීමට ඔබට අමතක වීම ද සිදුවිය හැකිය, එවැනි අවස්ථාවකදී වස්තු ගොනුව ජනනය නොවේ. දී gcc ඔබ විධාන රේඛාව තුල ඇති ගොනු එක් කරන්න කැමතියි. දී MSVS ගොනුව ව්යාපෘතිය එකතු එය (ගොනු වුවත්, අතින්, තනි තනිව ගොඩ නැඟීමට බැහැර කළ හැකි) ගිණුම ස්වංක්රීයව එය සකස් කර දෙනු ඇත.
වින්ඩෝස් ක්රමලේඛනයේදී, ඔබ අවශ්ය පුස්තකාලයක් සම්බන්ධ නොකළ බව පැවසීමේ ලකුණ වන්නේ නොවිසඳුනු සංකේතයේ නම ආරම්භ __imp_
වීමයි. ප්රලේඛනයේ ඇති ශ්රිතයේ නම සොයා බලන්න, එවිට ඔබ භාවිතා කළ යුත්තේ කුමන පුස්තකාලයද යන්න එහි සඳහන් විය යුතුය. උදාහරණයක් ලෙස, MSDN විසින් එක් එක් ශ්රිතයේ පතුලේ ඇති කොටුවක තොරතුරු “පුස්තකාලය” යනුවෙන් හැඳින්වෙන කොටසක තබයි.
gcc main.c
වෙනුවට පොදු වැරැද්ද ඔබට පැහැදිලිව ආවරණය කළ හැකි නම් හොඳයි gcc main.c other.c
(.o ගොනු සෑදීමට තරම් ඔවුන්ගේ ව්යාපෘති විශාල වීමට පෙර ආරම්භකයින් බොහෝ විට කරන්නේ).
සාමාන්ය විචල්ය ප්රකාශයකි
extern int x;
මෙය ප්රකාශයක් පමණක් බැවින් තනි අර්ථ දැක්වීමක් අවශ්ය වේ. අනුරූප අර්ථ දැක්වීමක් වනුයේ:
int x;
උදාහරණයක් ලෙස, පහත දැක්වෙන්නේ දෝෂයක් ජනනය කරයි:
extern int x;
int main()
{
x = 0;
}
//int x; // uncomment this line for successful definition
කාර්යයන් සඳහා සමාන අදහස් අදාළ වේ. ශ්රිතයක් නිර්වචනය නොකර එය ප්රකාශ කිරීම දෝෂයට තුඩු දෙයි:
void foo(); // declaration only
int main()
{
foo();
}
//void foo() {} //uncomment this line for successful definition
ඔබ ක්රියාත්මක කරන කාර්යය ඔබ ප්රකාශ කළ ක්රියාවට හරියටම ගැලපෙන බවට වග බලා ගන්න. උදාහරණයක් ලෙස, ඔබට නොගැලපෙන cv- සුදුසුකම් තිබිය හැකිය:
void foo(int& x);
int main()
{
int x;
foo(x);
}
void foo(const int& x) {} //different function, doesn't provide a definition
//for void foo(int& x)
නොගැලපීම් සඳහා වෙනත් උදාහරණ ඇතුළත් වේ
සම්පාදකයාගේ දෝෂ පණිවිඩය බොහෝ විට ප්රකාශිත නමුත් කිසි විටෙක නිර්වචනය නොකළ විචල්යය හෝ ශ්රිතය පිළිබඳ සම්පූර්ණ ප්රකාශය ඔබට ලබා දෙනු ඇත. ඔබ ලබා දුන් අර්ථ දැක්වීමට එය සමීපව සසඳන්න. සෑම විස්තරයක්ම ගැලපෙන බවට වග බලා ගන්න.
#includes
නොකළ ශීර්ෂයට ගැලපෙන සීපීපී ගොනු ද නැතිවූ අර්ථ දැක්වීම් ගණයට අයත් වේ.
පුස්තකාල එකිනෙකට රඳා පවතින්නේ නම් පුස්තකාල සම්බන්ධ වන අනුපිළිවෙල වැදගත් වේ. පොදුවේ ගත් කල, පුස්තකාලය පුස්තකාලය 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
ඒ නිසා නැවත වරක් නැවත නැවත කිරීමට, නියෝගය වේද කාරණය!
"නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේතය" යනු කුමක්ද?
"නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේතය" යනු කුමක්දැයි පැහැදිලි කිරීමට මම උත්සාහ කරමි.
සටහන: මම g ++ සහ ලිනක්ස් භාවිතා කරන අතර සියලු උදාහරණ ඒ සඳහා වේ
උදාහරණයක් ලෙස අපට කේතයක් තිබේ
// src1.cpp
void print();
static int local_var_name; // 'static' makes variable not visible for other modules
int global_var_name = 123;
int main()
{
print();
return 0;
}
සහ
// src2.cpp
extern "C" int printf (const char*, ...);
extern int global_var_name;
//extern int local_var_name;
void print ()
{
// printf("%d%d\n", global_var_name, local_var_name);
printf("%d\n", global_var_name);
}
වස්තු ගොනු සාදන්න
$ g++ -c src1.cpp -o src1.o
$ g++ -c src2.cpp -o src2.o
එකලස් කිරීමේ අදියරෙන් පසු අප සතුව වස්තු ගොනුවක් ඇත, එහි අපනයනය සඳහා ඕනෑම සංකේත අඩංගු වේ. සංකේත දෙස බලන්න
$ readelf --symbols src1.o
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 _ZL14local_var_name # [1]
9: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 global_var_name # [2]
ප්රතිදානයෙන් සමහර පේළි මම ප්රතික්ෂේප කර ඇත්තෙමි
එබැවින්, අපනයනය සඳහා පහත දැක්වෙන සංකේත අපට පෙනේ.
[1] - this is our static (local) variable (important - Bind has a type "LOCAL")
[2] - this is our global variable
src2.cpp කිසිවක් අපනයනය නොකරන අතර එහි සංකේත කිසිවක් අප දැක නැත
අපගේ වස්තු ගොනු සම්බන්ධ කරන්න
$ g++ src1.o src2.o -o prog
එය ක්රියාත්මක කරන්න
$ ./prog
123
ලින්කර් අපනයනය කළ සංකේත දැක එය සම්බන්ධ කරයි. දැන් අපි මෙහි මෙන් src2.cpp හි රේඛා නොගැලපීමට උත්සාහ කරමු
// src2.cpp
extern "C" int printf (const char*, ...);
extern int global_var_name;
extern int local_var_name;
void print ()
{
printf("%d%d\n", global_var_name, local_var_name);
}
වස්තු ගොනුවක් නැවත ගොඩනඟන්න
$ g++ -c src2.cpp -o src2.o
හරි (දෝෂ නැත), අපි වස්තු ගොනුවක් පමණක් සාදන නිසා, සම්බන්ධ කිරීම තවමත් සිදු කර නොමැත. සම්බන්ධ කිරීමට උත්සාහ කරන්න
$ g++ src1.o src2.o -o prog
src2.o: In function `print()':
src2.cpp:(.text+0x6): undefined reference to `local_var_name'
collect2: error: ld returned 1 exit status
එය සිදුවී ඇත්තේ අපගේ local_var_name ස්ථිතික නිසා, එනම් එය වෙනත් මොඩියුල සඳහා නොපෙනේ. දැන් වඩාත් ගැඹුරින්. පරිවර්තන අදියර ප්රතිදානය ලබා ගන්න
$ g++ -S src1.cpp -o src1.s
// src1.s
look src1.s
.file "src1.cpp"
.local _ZL14local_var_name
.comm _ZL14local_var_name,4,4
.globl global_var_name
.data
.align 4
.type global_var_name, @object
.size global_var_name, 4
global_var_name:
.long 123
.text
.globl main
.type main, @function
main:
; assembler code, not interesting for us
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
එබැවින්, local_var_name සඳහා ලේබලයක් නොමැති බව අපි දැක ඇත්තෙමු, ඒ නිසා සම්බන්ධකය එය සොයා නොගත්තේය. නමුත් අපි හැකර්වරු :) අපට එය නිවැරදි කළ හැකිය. ඔබේ පෙළ සංස්කාරකයේ src1.s විවෘත කර වෙනස් කරන්න
.local _ZL14local_var_name
.comm _ZL14local_var_name,4,4
වෙත
.globl local_var_name
.data
.align 4
.type local_var_name, @object
.size local_var_name, 4
local_var_name:
.long 456789
එනම් ඔබට පහත පරිදි තිබිය යුතුය
.file "src1.cpp"
.globl local_var_name
.data
.align 4
.type local_var_name, @object
.size local_var_name, 4
local_var_name:
.long 456789
.globl global_var_name
.align 4
.type global_var_name, @object
.size global_var_name, 4
global_var_name:
.long 123
.text
.globl main
.type main, @function
main:
; ...
අපි local_var_name හි දෘශ්යතාව වෙනස් කර එහි අගය 456789 ලෙස සකසා ඇත. එයින් වස්තු ගොනුවක් තැනීමට උත්සාහ කරන්න
$ g++ -c src1.s -o src2.o
හරි, කියවීමේ ප්රතිදානය බලන්න (සංකේත)
$ readelf --symbols src1.o
8: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 local_var_name
දැන් local_var_name හි බන්ධන GLOBAL ඇත (LOCAL විය)
සබැඳිය
$ g++ src1.o src2.o -o prog
එය ක්රියාත්මක කරන්න
$ ./prog
123456789
හරි, අපි එය හැක් කරනවා :)
එබැවින්, ප්රති result ලයක් ලෙස - වස්තු ලිපිගොනු තුළ සම්බන්ධකයට ගෝලීය සංකේත සොයාගත නොහැකි වූ විට “නිර්වචනය නොකළ යොමු / නොවිසඳුනු බාහිර සංකේත දෝෂයක්” සිදු වේ.
ශ්රිතය (හෝ විචල්යය) void foo()
සී වැඩසටහනක අර්ථ දක්වා ඇති අතර ඔබ එය සී ++ වැඩසටහනක භාවිතා කිරීමට උත්සාහ කරයි:
void foo();
int main()
{
foo();
}
C ++ සම්බන්ධකය මඟින් නම් අඹරනු ඇතැයි අපේක්ෂා කරයි, එබැවින් ඔබ ශ්රිතය මෙසේ ප්රකාශ කළ යුතුය:
extern "C" void foo();
int main()
{
foo();
}
ඒ හා සමානව, C වැඩසටහනක අර්ථ දැක්වීම වෙනුවට, ශ්රිතය (හෝ විචල්යය) void foo()
C ++ වලින් අර්ථ දක්වා ඇති නමුත් C සම්බන්ධතාවය සමඟ:
extern "C" void foo();
ඔබ එය C ++ සම්බන්ධතාවයක් සහිත C ++ වැඩසටහනක භාවිතා කිරීමට උත්සාහ කරයි.
සම්පූර්ණ පුස්තකාලයක් ශීර්ෂ ගොනුවකට ඇතුළත් කර ඇත්නම් (එය සී කේතය ලෙස සම්පාදනය කරන ලදි); ඇතුළත් කිරීම පහත පරිදි විය යුතුය;
extern "C" {
#include "cheader.h"
}
#ifdef __cplusplus [\n] extern"C" { [\n] #endif
සහ සැබෑ කරත්ත ආපසු පැමිණීම ) සහ ශීර්ෂ ගොනුව (ය) ආරක්ෂා කර ගැනීමයි . #ifdef __cplusplus [\n] } [\n] #endif
[\n]
extern "C" { #include <myCppHeader.h> }
.
අනෙක් සියල්ල අසමත් වුවහොත් නැවත සකස් කරන්න.
විෂුවල් ස්ටුඩියෝ 2012 හි නොවිසඳුණු බාහිර දෝෂයක් ඉවත් කිරීමට මට මෑතකදී හැකි වූයේ වැරදි කළ ගොනුව නැවත සකස් කිරීමෙනි. මම නැවත ගොඩනඟන විට දෝෂය පහව ගියේය.
මෙය සාමාන්යයෙන් සිදුවන්නේ පුස්තකාල දෙකක් (හෝ වැඩි ගණනක්) චක්රීය යැපීමක් ඇති විටය. පුස්තකාලය B.lib සහ පුස්තකාල B හි සංකේත භාවිතා කිරීමට උත්සාහ කරයි A.lib වෙතින් සංකේත භාවිතා කිරීමට උත්සාහ කරයි. ආරම්භ කිරීමට දෙකම නොපවතී. ඔබ A සම්පාදනය කිරීමට උත්සාහ කරන විට, B.lib සොයාගත නොහැකි නිසා සම්බන්ධක පියවර අසාර්ථක වේ. A.lib ජනනය වනු ඇත, නමුත් dll නැත. එවිට ඔබ B සම්පාදනය කරයි, එය සාර්ථක වන අතර B.lib ජනනය කරයි. A නැවත සම්පාදනය කිරීම දැන් ක්රියාත්මක වන්නේ B.lib දැන් සොයාගෙන ඇති බැවිනි.
MSVS භාවිතා අපනයන හා ආනයන කිරීමට වූ සංකේත නියම කිරීමට ඔබ අවශ්ය __declspec(dllexport)
හා__declspec(dllimport)
.
මෙම ද්විත්ව ක්රියාකාරිත්වය සාමාන්යයෙන් ලබා ගන්නේ සාර්ව භාවිතයෙන් ය:
#ifdef THIS_MODULE
#define DLLIMPEXP __declspec(dllexport)
#else
#define DLLIMPEXP __declspec(dllimport)
#endif
සාර්ව THIS_MODULE
අර්ථ දැක්වෙන්නේ ශ්රිතය අපනයනය කරන මොඩියුලය තුළ පමණි. ඒ ආකාරයෙන්, ප්රකාශය:
DLLIMPEXP void foo();
දක්වා පුළුල් වේ
__declspec(dllexport) void foo();
වත්මන් මොඩියුලය එහි අර්ථ දැක්වීම අඩංගු බැවින් ශ්රිතය අපනයනය කිරීමට සම්පාදකයාට පවසයි. ප්රකාශය වෙනත් මොඩියුලයකට ඇතුළත් කළ විට එය පුළුල් වේ
__declspec(dllimport) void foo();
නිර්වචනය ඔබ සම්බන්ධ කළ එක් පුස්තකාලයක ඇති බව සම්පාදකයාට පවසයි ( 1 ද බලන්න ) ).
ඔබට ආනයන / අපනයන පන්ති සමාන කළ හැකිය:
class DLLIMPEXP X
{
};
visibility
සහ වින්ඩෝස් .def
ගොනු සඳහන් කළ යුතුය , මේවා සංකේත නාමයට සහ පැවැත්මට ද බලපෑම් කරයි.
.def
අවුරුදු ගණනාවක් තිස්සේ ලිපිගොනු භාවිතා කර නැත . පිළිතුරක් එක් කිරීමට හෝ මෙය සංස්කරණය කිරීමට නිදහස් වන්න.
විශේෂීකරණය නොකළ සැකිලි ඒවායේ අර්ථ දැක්වීම් ඒවා භාවිතා කරන සියලුම පරිවර්තන ඒකකවලට දැකිය යුතුය. එයින් අදහස් කරන්නේ ඔබට අච්චුවක අර්ථ දැක්වීම ක්රියාත්මක කිරීමේ ගොනුවකට වෙන් කළ නොහැකි බවයි. ඔබ ක්රියාත්මක කිරීම වෙන් කළ යුතු නම්, සාමාන්ය විසඳුම වන්නේ 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
ශීර්ෂ ගොනුවට හෝ එය භාවිතා කරන පරිවර්තන ඒකකයට පෙනෙන ස්ථානයකට ගෙන යා යුතුය .
විශේෂිත සැකිලි ක්රියාත්මක කිරීමේ ගොනුවක ක්රියාත්මක කළ හැකි අතර ක්රියාත්මක කිරීම දෘශ්යමාන විය යුතු නැත, නමුත් විශේෂීකරණය කලින් ප්රකාශයට පත් කළ යුතුය.
වැඩිදුර පැහැදිලි කිරීම සහ තවත් විසඳුමක් සඳහා (පැහැදිලි ක්ෂණිකකරණය) මෙම ප්රශ්නය සහ පිළිතුර බලන්න .
මෙය සෑම VC ++ ක්රමලේඛකයෙක්ම කාලය හා වේලාව නැවත දැක ඇති ව්යාකූල දෝෂ පණිවිඩ වලින් එකකි. අපි මුලින්ම කරුණු පැහැදිලි කර ගනිමු.
පිළිතුර - සංකේතය යනු කුමක්ද? කෙටියෙන් කිවහොත්, සංකේතයක් යනු නමකි. එය විචල්ය නාමයක්, ශ්රිත නාමයක්, පන්ති නාමයක්, යතුරු ලියනය කළ නමක් හෝ සී ++ භාෂාවට අයත් නම් සහ සං signs ා හැර වෙනත් දෙයක් විය හැකිය. එය පරිශීලක පරායත්ත පුස්තකාලයක් මගින් නිර්වචනය කර හෝ හඳුන්වා දී ඇත (තවත් පරිශීලක අර්ථ දැක්වීමක්).
B. බාහිර යනු කුමක්ද?
VC ++ හි, සෑම ප්රභව ගොනුවක්ම (.cpp, .c, ආදිය) පරිවර්තන ඒකකයක් ලෙස සලකනු ලැබේ, සම්පාදකයා වරකට එක් ඒකකයක් සම්පාදනය කරයි, සහ වර්තමාන පරිවර්තන ඒකකය සඳහා එක් වස්තු ගොනුවක් (.obj) ජනනය කරයි. (මෙම ප්රභව ගොනුව ඇතුළත් කර ඇති සෑම ශීර්ෂ ගොනුවක්ම පෙර සැකසූ බවත් මෙම පරිවර්තන ඒකකයේ කොටසක් ලෙස සලකනු ඇති බවත් සලකන්න) පරිවර්තන ඒකකයක් තුළ ඇති සියල්ල අභ්යන්තර ලෙස සලකනු ලැබේ, අනෙක් සියල්ල බාහිර ලෙස සැලකේ. C ++, ඔබ වැනි මූල පද භාවිතා කරමින් බාහිර සංකේතයක් අදාල විය හැක extern
, __declspec (dllimport)
සහ යනාදි.
C. “අධිෂ්” ානය ”යනු කුමක්ද? විසඳීම යනු සම්බන්ධක-කාලීන යෙදුමකි. සම්බන්ධක වේලාවේදී, සම්බන්ධකය එහි සංකේතය අභ්යන්තරව සොයාගත නොහැකි වස්තු ලිපිගොනු වල සෑම සංකේතයක් සඳහාම බාහිර අර්ථ දැක්වීම සොයා ගැනීමට උත්සාහ කරයි. මෙම සෙවීමේ ක්රියාවලියේ විෂය පථය:
මෙම සෙවීමේ ක්රියාවලිය විසදුම ලෙස හැඳින්වේ.
D. අවසාන වශයෙන්, නොවිසඳුනු බාහිර සංකේතය ඇයි? අභ්යන්තරව අර්ථ දැක්වීමක් නොමැති සංකේතයක් සඳහා සම්බන්ධකයට බාහිර අර්ථ දැක්වීම සොයාගත නොහැකි නම්, එය නොවිසඳුනු බාහිර සංකේත දෝෂයක් වාර්තා කරයි.
E. LNK2019 සඳහා විය හැකි හේතු : නොවිසඳුනු බාහිර සංකේත දෝෂයකි. මෙම දෝෂය සම්බන්ධකය බාහිර සංකේතවල අර්ථ දැක්වීම සොයා ගැනීමට අපොහොසත් වීම නිසා බව අපි දැනටමත් දනිමු, විය හැකි හේතු පහත පරිදි වර්ග කළ හැකිය:
උදාහරණයක් ලෙස, අපට a.cpp හි අර්ථ දක්වා ඇති foo නම් ශ්රිතයක් තිබේ නම්:
int foo()
{
return 0;
}
B.cpp හි අපට ශ්රිතය foo ලෙස හැඳින්වීමට අවශ්ය බැවින් අපි එකතු කරමු
void foo();
foo () ශ්රිතය ප්රකාශ කිරීමට සහ එය වෙනත් ශ්රිත ආයතනයකට අමතන්න bar()
:
void bar()
{
foo();
}
දැන් ඔබ මෙම කේතය ගොඩනඟන විට foo නොවිසඳුනු සංකේතයක් බවට පැමිණිලි කරමින් ඔබට LNK2019 දෝෂයක් ලැබෙනු ඇත. මෙම අවස්ථාවෙහිදී, foo () හි අර්ථ දැක්වීම a.cpp හි ඇති බව අපි දනිමු, නමුත් අප අමතන ක්රමයට වඩා වෙනස් (වෙනස් ප්රතිලාභ අගය). අර්ථ දැක්වීම පවතින අවස්ථාව මෙයයි.
අපට පුස්තකාලයක සමහර කාර්යයන් ඇමතීමට අවශ්ය නම්, නමුත් ආනයන පුස්තකාලය Project | Properties | Configuration Properties | Linker | Input | Additional Dependency
ඔබේ ව්යාපෘති සැකසුමෙහි අතිරේක පරායත්තතා ලැයිස්තුවට (:) සිට සකසා ඇත ) එකතු නොවේ . වර්තමාන සෙවුම් විෂය පථය තුළ අර්ථ දැක්වීම නොපවතින බැවින් දැන් සම්බන්ධකය LNK2019 වාර්තා කරයි.
නිර්වචනය නොකළ WinMain@16
හෝ ඊට සමාන 'අසාමාන්ය' main()
පිවිසුම් ලක්ෂ්ය යොමුව (විශේෂයෙන්දෘශ්ය චිත්රාගාරය).
ඔබගේ සත්ය IDE සමඟ නිවැරදි ව්යාපෘති වර්ගය තෝරා ගැනීමට ඔබට මග හැරී ඇත. බහුලව භාවිතා වන int main(int argc, char** argv);
අත්සන වෙනුවට වින්ඩෝස් යෙදුම් ව්යාපෘති එවැනි පිවිසුම් ලක්ෂ්ය ශ්රිතයට (ඉහත අස්ථානගතව ඇති සඳහනෙහි දක්වා ඇති පරිදි) බැඳීමට IDE ට අවශ්ය විය හැකිය .
ඔබේ IDE සරල කොන්සෝල ව්යාපෘති සඳහා සහය දක්වන්නේ නම් , වින්ඩෝස් යෙදුම් ව්යාපෘතියක් වෙනුවට මෙම ව්යාපෘති වර්ගය තෝරා ගැනීමට ඔබට අවශ්ය විය හැකිය.
මෙන්න case1 සහ case2සැබෑ ලෝක ගැටලුවකින් වඩාත් විස්තරාත්මකව හසුරුවන .
WinMain
. වලංගු C ++ වැඩසටහන් සඳහා a අවශ්ය වේ main
.
නව මෙවලම් කට්ටල අනුවාදය සඳහා දෘශ්ය ස්ටුඩියෝ නුජෙට් පැකේජය යාවත්කාලීන කළ යුතුය
මට මේ ගැටලුව තිබුනේ විෂුවල් ස්ටුඩියෝ 2013 සමඟ libpng සම්බන්ධ කිරීමට උත්සාහ කිරීමෙනි. ගැටළුව වන්නේ පැකේජ ගොනුවේ තිබුණේ විෂුවල් ස්ටුඩියෝ 2010 සහ 2012 සඳහා පුස්තකාල පමණි.
නිවැරදි විසඳුම නම් සංවර්ධකයා විසින් යාවත්කාලීන කරන ලද පැකේජයක් නිකුත් කර යාවත්කාලීන කරනු ඇතැයි අපේක්ෂා කිරීමයි, නමුත් එය VS2013 සඳහා අතිරේක සැකසුමක අනවසරයෙන් ඇතුළුවී VS2012 පුස්තකාල ලිපිගොනු වෙත යොමු කිරීම මට වැඩ කළේය.
මම පැකේජය සංස්කරණය කළේ ( packages
විසඳුමේ නාමාවලිය තුළ ඇති ෆෝල්ඩරයේ) packagename\build\native\packagename.targets
එම ගොනුව සොයා ගැනීමෙන් සහ ඇතුළත, සියලුම v110
කොටස් පිටපත් කිරීමෙනි . මම වෙනස් v110
කිරීමට v120
ඇති තත්ත්වය ක්ෂේත්ර පමණක් සියලු ලෙස ගොනු නාමය මාර්ග හැර ඉතා ප්රවේසම් වීම v110
. මෙය හුදෙක් විෂුවල් ස්ටුඩියෝ 2013 සඳහා 2012 සඳහා පුස්තකාල සමඟ සම්බන්ධ වීමට ඉඩ දී ඇති අතර මේ අවස්ථාවේ දී එය ක්රියාත්මක විය.
ඔබ සතුව c ++ හි ලියා ඇති විශාල ව්යාපෘතියක් තිබේ. එහි .cpp ගොනු දහසක් සහ .h ගොනු දහසක් ඇත. තවද අපි කියමු ව්යාපෘතිය ස්ථිතික පුස්තකාල දහයක් මත රඳා පවතී. අපි කියමු අපි වින්ඩෝස් වල සිටින අතර අපගේ ව්යාපෘතිය විෂුවල් ස්ටුඩියෝ 20xx හි ගොඩනඟමු. සම්පූර්ණ විසඳුම සම්පාදනය කිරීම ආරම්භ කිරීම සඳහා ඔබ Ctrl + F7 විෂුවල් ස්ටුඩියෝව එබූ විට (අපට විසඳුමේ ඇත්තේ එක් ව්යාපෘතියක් යැයි සිතමු)
සම්පාදනය කිරීමේ තේරුම කුමක්ද?
සම්පාදනය කිරීමේ දෙවන පියවර ලින්කර් විසින් සිදු කරනු ලැබේ. ලින්කර් විසින් සියලු වස්තු ගොනුව ඒකාබද්ධ කොට අවසානයේ ප්රතිදානය ගොඩනගා ගත යුතුය (එය ක්රියාත්මක කළ හැකි හෝ පුස්තකාලයක් විය හැකිය)
ව්යාපෘතියක් සම්බන්ධ කිරීමේ පියවර
error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)
නිරීක්ෂණය
මේ ආකාරයේ දෝෂයක් විසඳන්නේ කෙසේද?
සම්පාදක කාල දෝෂය:
සම්බන්ධක කාල දෝෂය
#pragma once
සම්පාදනය කර ඇති වත්මන් .cpp හි දැනටමත් එක් ශීර්ෂයක් ඇතුළත් කර ඇත්නම් සම්පාදකයාට ඉඩ නොදීමට භාවිතා කරන්නමට මෑතකදී මෙම ගැටලුව ඇති වූ අතර එය දෘශ්ය ස්ටුඩියෝ එක්ස්ප්රස් 2013 හි දෝෂයක් බව පෙනී ගියේය . ව්යාපෘතියෙන් ප්රභව ගොනුවක් ඉවත් කර දෝෂය මඟහරවා ගැනීම සඳහා එය නැවත එක් කිරීමට මට සිදු විය.
එය සම්පාදක / IDE හි දෝෂයක් විය හැකි යැයි ඔබ විශ්වාස කරන්නේ නම් උත්සාහ කිරීමට පියවර:
බොහෝ නූතන සම්බන්ධකයන්ට විවිධ මට්ටම් වලට මුද්රණය වන වාචික විකල්පයක් ඇතුළත් ය;
Gcc සහ clang සඳහා; ඔබ සාමාන්යයෙන් එකතු කරන -v -Wl,--verbose
හෝ -v -Wl,-v
විධාන රේඛාවේ කිරීමට. වැඩි විස්තර මෙහි සොයාගත හැකිය;
MSVC සඳහා, /VERBOSE
(විශේෂයෙන් /VERBOSE:LIB
) සම්බන්ධක විධාන රේඛාවට එකතු කරනු ලැබේ.
/VERBOSE
සම්බන්ධක විකල්පයේ MSDN පිටුව .සම්බන්ධිත .lib ගොනුව .dll සමඟ සම්බන්ධ වේ
මටත් ඒ ප්රශ්නයම තිබුණා. මට MyProject සහ TestProject ව්යාපෘති ඇති බව පවසන්න. මම MyProject සඳහා වන lib ගොනුව TestProject සමඟ effectively ලදායී ලෙස සම්බන්ධ කර ඇත්තෙමි. කෙසේ වෙතත්, MyProject සඳහා DLL ගොඩනගා ඇති බැවින් මෙම lib ගොනුව නිපදවන ලදී. එසේම, MyProject හි සියලුම ක්රම සඳහා ප්රභව කේත මා සතුව නොතිබුණි, නමුත් DLL හි පිවිසුම් ස්ථාන වෙත ප්රවේශ වීම පමණි.
ගැටළුව විසඳීම සඳහා, මම MyProject එක LIB ලෙස ගොඩනඟා, TestProject මෙම .lib ගොනුවට සම්බන්ධ කළෙමි (මම උත්පාදනය කළ .lib ගොනුව TestProject ෆෝල්ඩරයට පිටපත් කරමි). මට නැවත ඩීඑල්එල් ලෙස MyProject ගොඩනගා ගත හැකිය. ටෙස්ට් ප්රොජෙක්ට් සම්බන්ධ කර ඇති ලිබයට මයිප්රොජෙක්ට් හි පන්තිවල සියලුම ක්රම සඳහා කේත අඩංගු බැවින් එය සම්පාදනය වේ.
සම්බන්ධක දෝෂ සම්බන්ධයෙන් මිනිසුන් මෙම ප්රශ්නයට යොමු වී ඇති බවක් පෙනෙන්නට ඇති හෙයින් මම මෙය මෙහි එක් කිරීමට යන්නෙමි.
GCC 5.2.0 සමඟ සම්බන්ධක දෝෂ ඇතිවිය හැකි එක් හේතුවක් නම් නව libstdc ++ පුස්තකාල ABI දැන් පෙරනිමියෙන් තෝරා ගැනීමයි.
Std :: __ cxx11 නාම අවකාශය හෝ [abi: cxx11] ටැගය ඇතුළත් වන සංකේත සඳහා නිර්වචනය නොකළ යොමු කිරීම් පිළිබඳ සම්බන්ධක දෝෂ ඔබට ලැබුනේ නම්, එවිට බොහෝ විට ඇඟවෙන්නේ _GLIBCXX_USE_CXX11_ABI සඳහා විවිධ අගයන් සමඟ සම්පාදනය කරන ලද වස්තු ගොනු එකට සම්බන්ධ කිරීමට ඔබ උත්සාහ කරන බවයි. සාර්ව. මෙය සාමාන්යයෙන් සිදුවන්නේ GCC හි පැරණි අනුවාදයක් සමඟ සම්පාදනය කරන ලද තෙවන පාර්ශවීය පුස්තකාලයකට සම්බන්ධ වන විට ය. තෙවන පාර්ශවීය පුස්තකාලය නව ABI සමඟ නැවත ගොඩනඟා ගත නොහැකි නම්, ඔබේ කේතය පැරණි ABI සමඟ නැවත සකස් කිරීමට ඔබට අවශ්ය වනු ඇත.
5.1.0 න් පසු GCC වෙත මාරුවීමේදී ඔබට හදිසියේම සම්බන්ධක දෝෂ ඇති වුවහොත් මෙය පරීක්ෂා කර බැලිය යුතු කරුණකි.
libfoo
මත රඳා පවතී libbar
නම් ඔබගේ සම්බන්ධතාවය නිවැරදිව තබන, libfoo
පෙර libbar
.undefined reference to
යම් දෝෂයකින් අසමත් වේ .#include
අතර ඇත්ත වශයෙන්ම ඔබ සම්බන්ධ කරන පුස්තකාලවල අර්ථ දක්වා ඇත.උදාහරණ සී හි ඇත. ඒවා සමානවම සී ++ විය හැකිය
my_lib.c
#include "my_lib.h"
#include <stdio.h>
void hw(void)
{
puts("Hello World");
}
my_lib.h
#ifndef MY_LIB_H
#define MT_LIB_H
extern void hw(void);
#endif
eg1.c
#include <my_lib.h>
int main()
{
hw();
return 0;
}
ඔබ ඔබේ ස්ථිතික පුස්තකාලය සාදයි:
$ gcc -c -o my_lib.o my_lib.c
$ ar rcs libmy_lib.a my_lib.o
ඔබ ඔබේ වැඩසටහන සම්පාදනය කරයි:
$ gcc -I. -c -o eg1.o eg1.c
ඔබ එය සමඟ සම්බන්ධ වීමට උත්සාහ කර libmy_lib.a
අසමත් වේ:
$ gcc -o eg1 -L. -lmy_lib eg1.o
eg1.o: In function `main':
eg1.c:(.text+0x5): undefined reference to `hw'
collect2: error: ld returned 1 exit status
ඔබ එක් පියවරක් සම්පාදනය කර සම්බන්ධ කරන්නේ නම් එකම ප්රති result ලය, වැනි:
$ 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
මෙතැන් සිට කියවීම අත්යවශ්ය නොවේ .
පෙරනිමියෙන්, ඔබේ ඩිස්ට්රෝ හි GCC විසින් ජනනය කරන ලද සම්බන්ධක විධානයක්, සම්බන්ධකයේ ඇති ලිපිගොනු වමේ සිට දකුණට විධාන රේඛා අනුපිළිවෙලින් පරිභෝජනය කරයි. ගොනුවක් යනු යම් දෙයකට යොමු වන බව සොයාගත් විට සඳහා අර්ථ දැක්වීමක් නොමැති , තව දුරටත් දකුණට ඇති ලිපිගොනු වල අර්ථ දැක්වීමක් සෙවීම. එය අවසානයේ අර්ථ දැක්වීමක් සොයා ගන්නේ නම්, යොමු කිරීම විසඳනු ලැබේ. කිසියම් යොමු කිරීමක් අවසානයේ නොවිසඳී පවතින්නේ නම්, සම්බන්ධතාවය අසමත් වේ: සම්බන්ධකය පසුපසට සොයන්නේ නැත.
පළමුව, උදාහරණ 1 , ස්ථිතික පුස්තකාලය සමඟmy_lib.a
ස්ථිතික පුස්තකාලයක් යනු වස්තු ලිපිගොනු සුචිගත කරන ලද ලේඛනාගාරයකි. -lmy_lib
සම්බන්ධක අනුක්රමය තුළ සම්බන්ධකය සොයාගත් විට මෙය ස්ථිතික පුස්තකාලයට යොමු වන බව දැනගත් විට ./libmy_lib.a
, එය ඔබගේ වැඩසටහනට කිසියම් වස්තු ලිපිගොනු අවශ්ය දැයි දැන ගැනීමට අවශ්ය වේ libmy_lib.a
.
එහි ඇත්තේ වස්තු ගොනුවක් පමණි libmy_lib.a
, එනම් my_lib.o
අර්ථ දැක්වෙන්නේ එක් දෙයක් පමණි my_lib.o
, එනම් ශ්රිතයයිhw
.
ඔබේ වැඩසටහනට my_lib.o
එය දැනටමත් වැඩසටහනට hw
එකතු කර ඇති වස්තු ලිපිගොනු එකක් හෝ වැඩි ගණනක් ගැන සඳහන් කර ඇති බවත් , එය දැනටමත් එකතු කර ඇති වස්තු ලිපිගොනු කිසිවක් අඩංගු නොවන බවත් ඔබේ වැඩසටහනට අවශ්ය බව සම්බන්ධකය තීරණය කරයි . සඳහා අර්ථ දැක්වීම hw
.
එය සත්ය නම්, සම්බන්ධකය my_lib.o
පුස්තකාලයෙන් පිටපතක් ලබා ගෙන එය ඔබේ වැඩසටහනට එක් කරයි. එවිට, ඔබේ වැඩසටහන සඳහා අර්ථ දැක්වීමක් අඩංගු වේ hw
, එබැවින් එහි යොමු hw
කිරීම් නිරාකරණය වේ.
ඔබ වැඩසටහන සම්බන්ධ කිරීමට උත්සාහ කරන විට:
$ gcc -o eg1 -L. -lmy_lib eg1.o
එය දකින විට
සම්බන්ධකය වැඩසටහනට එකතු කර නැත . මන්දයත් එම අවස්ථාවේදී එය දැක නැති බැවිනි . ඔබගේ වැඩසටහන තවමත් කිසිදු යොමු කරන්නේ නැහැ : එය තවම යොමු කරන්නේ නැහැ සියලු දී සියලු යොමු එය වර්ගයන් ඇති නිසා, .eg1.o
-lmy_lib
eg1.o
hw
eg1.o
එබැවින් සම්බන්ධකය my_lib.o
වැඩසටහනට එකතු නොකරන අතර වැඩිදුර භාවිතයක් නොමැත libmy_lib.a
.
ඊළඟට, එය සොයා ගන්නා eg1.o
අතර එය වැඩසටහනක් ලෙස එකතු කරයි. සම්බන්ධක අනුපිළිවෙලෙහි වස්තු ගොනුවක් සෑම විටම වැඩසටහනට එකතු වේ. දැන්, වැඩසටහන යොමු කිරීමක් කරයි hw
, සහ එහි අර්ථ දැක්වීමක් අඩංගු නොවේ hw
; නමුත් සම්බන්ධක අනුක්රමය තුළ අස්ථානගත වූ අර්ථ දැක්වීමක් සැපයිය හැකි කිසිවක් නොමැත. යොමු කිරීම නොවිසඳීhw
අවසන් වන අතර සම්බන්ධතාවය අසමත් වේ.
දෙවනුව, උදාහරණ 2 , හවුල් පුස්තකාලය සමඟlibz
හවුල් පුස්තකාලයක් යනු වස්තු ලිපිගොනු හෝ ඒ හා සමාන කිසිවක් නොවේ. එය බොහෝ විට ශ්රිතයක් නොමැති වැඩසටහනකට සමාන වන අතර main
ඒ වෙනුවට එය අර්ථ දක්වන වෙනත් සංකේත කිහිපයක් නිරාවරණය කරයි, එවිට වෙනත් වැඩසටහන් වලට ඒවා ක්රියාත්මක වේලාවේදී භාවිතා කළ හැකිය.
බොහෝ ලිනක්ස් distros අද ඔවුන්ගේ ගල්ෆ් toolchain එහි භාෂාව රියදුරන් (එබැවින් මාන gcc
, g++
, gfortran
ආදිය) මෙම පද්ධතිය linker උපදෙස් ලබා ( ld
) සම්බන්ධ කිරීමට මත පුස්තකාල හවුල් වැනි අවශ්ය පදනම. ඔබට එම ඩිස්ට්රෝ වලින් එකක් තිබේ.
මෙයින් අදහස් කරන්නේ -lz
සම්බන්ධක අනුක්රමය තුළ සම්බන්ධකය සොයාගත් විට සහ මෙය හවුල් පුස්තකාලයට (කියන්න) /usr/lib/x86_64-linux-gnu/libz.so
යොමු වූ විට, එය ඔබගේ වැඩසටහනට එකතු කර ඇති කිසියම් සඳහනක් තවමත් අර්ථ දක්වා නොමැතිද යන්න දැන ගැනීමට අවශ්ය බව ය. විසින් අපනයනය කරන ලදිlibz
බව සැබෑ නම්, ඊට linker ඇත නොහැකි අතරින් කුමන හෝ කුට්ටි පිටපත් 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 යි.
සම්බන්ධතාවය:
gcc -o eg2 -lz eg2.o
ඔබට හොඳින් වැඩ කරයි!
(හෝ: එම සම්බන්ධතාවය ඔබට ෆෙඩෝරා 23 හි හොඳට වැඩ කළ නමුත් උබුන්ටු 16.04 හි අසමත් වේ)
එයට හේතුව, සම්බන්ධතාවය ක්රියාත්මක වන ඩිස්ට්රෝ එක එහි GCC මෙවලම් කට්ටලය අවශ්ය පරිදි හවුල් පුස්තකාල සම්බන්ධ කිරීම සඳහා වින්යාස නොකරන එකකි . .
යුනික්ස් වැනි පද්ධති ස්ථිතික හා බෙදාගත් පුස්තකාල විවිධ නීති රීති වලට සම්බන්ධ කිරීම සාමාන්ය දෙයක් විය. උදාහරණ 1 හි විස්තර කර ඇති පරිදි සම්බන්ධක අනුපිළිවෙලක ස්ථිතික පුස්තකාල අවශ්ය පරිදි සම්බන්ධ කර ඇත , නමුත් හවුල් පුස්තකාල කොන්දේසි විරහිතව සම්බන්ධ කර ඇත.
මෙම හැසිරීම සම්බන්ධක වේලාවේදී ලාභදායී වන්නේ වැඩසටහනට හවුල් පුස්තකාලයක් අවශ්ය දැයි සම්බන්ධකයට සිතා බැලිය යුතු නැති බැවිනි: එය හවුල් පුස්තකාලයක් නම් එය සම්බන්ධ කරන්න. බොහෝ සම්බන්ධතා වල ඇති පුස්තකාල බොහෝමයක් හවුල් පුස්තකාල වේ. නමුත් අවාසි ද ඇත: -
එය අපහරණය වේ ධාවන එය ඔවුන්ට අවශ්ය වන්නේ නැත පවා නම් පුස්තකයන් වැඩසටහනක් සමග පැටවිය කිරීමට හේතු නිසා.
ස්ථිතික හා පුස්තකයන් සඳහා විවිධ සම්බන්ධතාවය නිසාම නීති නොදැන සිටි යන්න inexpert වැඩසටහන්කරුවන්, දීමට අපහසුය -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':
එකිනෙකට පරායත්ත සම්බන්ධිත පුස්තකාල නියම කර ඇති අනුපිළිවෙල වැරදිය
එකිනෙකට පරායත්ත පුස්තකාල වැරදි අනුපිළිවෙලට තැබීම ඔබට අර්ථ දැක්වීම් සපයන ලිපිගොනු වලට වඩා සම්බන්ධතාවයේ පසුව එන දේවල් පිළිබඳ අර්ථ දැක්වීම් අවශ්ය ගොනු ලබා ගත හැකි එක් ක්රමයකි . පුස්තකාල ඒවා යොමු කරන වස්තු ලිපිගොනු ඉදිරියේ තැබීම එකම වැරැද්ද කිරීමේ තවත් ක්රමයකි.
සම්බන්ධක ස්ක්රිප්ට් සඳහා සහය නොදක්වන GNU ld වටා එතීම
සමහර .so ගොනු ඇත්ත වශයෙන්ම GNU ld සම්බන්ධක ස්ක්රිප්ට් වේ , උදා: libtbb.so ගොනුව මෙම අන්තර්ගතයන් සහිත ASCII පෙළ ගොනුවකි:
INPUT (libtbb.so.2)
තවත් සමහර සංකීර්ණ ගොඩනැඟිලි මෙයට සහාය නොදක්වයි. උදාහරණයක් ලෙස, ඔබ සම්පාදක විකල්පයන්හි -v ඇතුළත් කළහොත්, සම්බන්ධ වීමට ඇති පුස්තකාලවල වාචික ප්රතිදාන ලැයිස්තුවේ ප්රධාන ලින්ක් ස්ක්රිප්ට් විධාන ලිපිගොනු ඉවතලන බව ඔබට පෙනේ . සම්බන්ධක ස්ක්රිප්ට් ආදාන විධානය ප්රතිස්ථාපනය කිරීම සරල වැඩකි. ගොනුවේ පිටපතක් සහිත ගොනුවක් (හෝ සිම්ලින්ක්), උදා
cp libtbb.so.2 libtbb.so
හෝ ඔබ වෙනුවට උදාහරණ, .ඒ සම්පූර්ණ මාර්ගය සමඟ -L තර්කය වෙනුවට හැකි -ltbb
කරන්නද/home/foo/tbb-4.3/linux/lib/intel64/gcc4.4/libtbb.so.2
මිතුරු ක්රියාකරුවෙකු (හෝ ශ්රිතය) සමඟ අච්චු වර්ගයක කේත ස්නිපටය ලබා දී ඇත;
template <typename T>
class Foo {
friend std::ostream& operator<< (std::ostream& os, const Foo<T>& a);
};
මෙම operator<<
A-සැකිල්ල නොවන ශ්රිතයක් ලෙස ප්රකාශයට පත් කොට ඇත. T
භාවිතා කරන සෑම වර්ගයක් සඳහාම Foo
, සැකිලි රහිත විය යුතුය operator<<
. උදාහරණයක් ලෙස, Foo<int>
ප්රකාශිත වර්ගයක් තිබේ නම් , පහත පරිදි ක්රියාකරු ක්රියාත්මක කිරීමක් තිබිය යුතුය;
std::ostream& operator<< (std::ostream& os, const Foo<int>& a) {/*...*/}
එය ක්රියාත්මක නොවන බැවින්, සම්බන්ධකය එය සොයා ගැනීමට අපොහොසත් වන අතර එහි ප්රති results ලය දෝෂයකි.
මෙය නිවැරදි කිරීම සඳහා, ඔබට Foo
ටයිප් කිරීමට පෙර අච්චු ක්රියාකරුවෙකු ප්රකාශයට පත් කළ හැකි අතර පසුව සුදුසු මිතුරෙකු ලෙස ප්රකාශ කළ හැකිය. වාක්ය ඛණ්ඩය ටිකක් අමුතුයි, නමුත් පහත පරිදි පෙනේ;
// forward declare the Foo
template <typename>
class Foo;
// forward declare the operator <<
template <typename T>
std::ostream& operator<<(std::ostream&, const Foo<T>&);
template <typename T>
class Foo {
friend std::ostream& operator<< <>(std::ostream& os, const Foo<T>& a);
// note the required <> ^^^^
// ...
};
template <typename T>
std::ostream& operator<<(std::ostream&, const Foo<T>&)
{
// ... implement the operator
}
ඉහත කේතය මඟින් ක්රියාකරුගේ මිත්රත්වය අනුරූපී ක්ෂණිකකරණයට සීමා කරයි Foo
, එනම් operator<< <int>
ක්ෂණිකකරණය ක්ෂණිකකරණයේ පෞද්ගලික සාමාජිකයින්ට ප්රවේශ වීම සඳහා සීමා වේ Foo<int>
.
විකල්ප ඇතුළත්;
පහත දැක්වෙන පරිදි, සැකිලි වල සියලු අවස්ථා දක්වා මිත්රත්වයට ඉඩ දීම;
template <typename T>
class Foo {
template <typename T1>
friend std::ostream& operator<<(std::ostream& os, const Foo<T1>& a);
// ...
};
නැතහොත්, operator<<
පන්ති අර්ථ දැක්වීම තුළ ඇතුළත ක්රියාත්මක කළ හැකිය;
template <typename T>
class Foo {
friend std::ostream& operator<<(std::ostream& os, const Foo& a)
{ /*...*/ }
// ...
};
සටහන , ක්රියාකරු (හෝ කාර්යය) ප්රකාශයට පත් පමණක් පන්තියේ ප්රකාශ වන විට, එම නම, "සාමාන්ය" විමසුම්, තර්කය රඳා බැලීම සඳහා පමණක් ලබා ගත හැකි නොවේ cppreference ;
පංතියේ හෝ පන්තියේ අච්චුව තුළ මිතුරු ප්රකාශයක මුලින් ප්රකාශයට පත් කරන ලද නමක් X හි අභ්යන්තරයේ ඇති නාම අවකාශයේ සාමාජිකයෙකු බවට පත්වේ, නමුත් නාම අවකාශයේ විෂය පථයට ගැලපෙන ප්රකාශයක් මිස, බැලීමට (X ලෙස සලකන තර්ක-රඳා පවතින විමසුම හැර) බැලීමට ප්රවේශ විය නොහැක. සපයා ඇත ...
Cppreference සහ C ++ නිති අසන ප්රශ්න වලදී අච්චු මිතුරන් පිළිබඳ වැඩිදුර කියවීමක් ඇත .
ඉහත ක්රමෝපායන් පෙන්වන කේත ලැයිස්තුගත කිරීම .
අසමත් වූ කේත සාම්පලයට පැති සටහනක් ලෙස; 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)
ශීර්ෂ ගොනුවක් සහ ඒ හා සම්බන්ධ හවුල් පුස්තකාලය (.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 අරමුණ).
සැබෑ ලෝකයේ මෙය සිදුවිය හැකි ආකාරය පිළිබඳ උදාහරණයක් පහත විස්තර කෙරේ.
මට ව්යාපෘති දෙකක් තිබේ: graphics.lib
සහ main.exe
. ව්යාපෘති දෙකම රඳා පවතී common_math.h
. පුස්තකාලය පහත ශ්රිතය අපනයනය කරයි යැයි සිතමු:
// graphics.lib
#include "common_math.h"
void draw(vec3 p) { ... } // vec3 comes from common_math.h
ඉන්පසු ඔබ ඉදිරියට ගොස් පුස්තකාලය ඔබේම ව්යාපෘතියකට ඇතුළත් කරන්න.
// main.exe
#include "other/common_math.h"
#include "graphics.h"
int main() {
draw(...);
}
උත්පාතය! ඔබට සම්බන්ධක දෝෂයක් ඇති අතර එය අසමත් වන්නේ මන්දැයි ඔබට අදහසක් නැත. හේතුව, පොදු පුස්තකාලය එකම ඇතුළත් විවිධ අනුවාදයන් භාවිතා කිරීමයි common_math.h
(මම වෙනත් උදාහරණයකින් මෙහි උදාහරණයෙන් පැහැදිලි කර ඇත්තෙමි, නමුත් එය සැමවිටම එතරම් පැහැදිලිව පෙනෙන්නට නොතිබිය හැකිය. සමහර විට ඇතුළත් කිරීමේ මාර්ගය සම්පාදක සැකසුම් තුළ වෙනස් වේ) .
මෙම උදාහරණයේ සටහන් කරන්න, එය සොයාගත නොහැකි බව සම්බන්ධකය ඔබට කියනු draw()
ඇත, යථාර්ථයේ දී ඔබ එය පැහැදිලිවම පුස්තකාලයෙන් අපනයනය කරන බව ඔබ දන්නා විට. වැරැද්ද කුමක්දැයි කල්පනා කරමින් ඔබේ හිස සීරීමට ඔබට පැය ගණනක් ගත කළ හැකිය. කාරණය වන්නේ, පරාමිති වර්ග තරමක් වෙනස් බැවින් සම්බන්ධකය වෙනස් අත්සනක් දකී. උදාහරණයේ දී, vec3
සම්පාදකයා සැලකිලිමත් වන පරිදි ව්යාපෘති දෙකෙහිම වෙනස් වර්ගයකි. මෙය සිදුවිය හැක්කේ ඒවා තරමක් වෙනස් ගොනු දෙකකින් පැමිණීම නිසා විය හැකිය (සමහර විට ඇතුළත් කළ හැකි ලිපිගොනු පුස්තකාලයේ විවිධ අනුවාද දෙකකින් පැමිණේ).
ඔබ විෂුවල් ස්ටුඩියෝ භාවිතා කරන්නේ නම් ඩම්ප්බින් ඔබේ මිතුරා ය. මට විශ්වාසයි වෙනත් සම්පාදකයින්ට වෙනත් සමාන මෙවලම් ඇති බව.
ක්රියාවලිය මේ ආකාරයට ය:
[1] ව්යාපෘතිය අනුව මා අදහස් කරන්නේ පුස්තකාලයක් හෝ ක්රියාත්මක කළ හැකි එකක් නිෂ්පාදනය කිරීම සඳහා එකට සම්බන්ධ කර ඇති ප්රභව ගොනු සමූහයකි.
සංස්කරණය 1: තේරුම් ගැනීමට පහසු වන පරිදි පළමු කොටස නැවත ලියන්න. වෙනත් දෙයක් නිවැරදි කිරීමට අවශ්ය දැයි මට දන්වන්න කරුණාකර පහත අදහස් දක්වන්න. ස්තූතියි!
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>
යනාදිය සිදුවනු ඇත . මෙය කේතය මුලින් අදහස් කළේ යුනිකෝඩ් සහ බහු-බයිට් අක්ෂර (හෝ “පටු”) ගොඩනැගීම සඳහා ය. .
මෙය නිවැරදි කිරීම සඳහා, UNICODE
(සහ _UNICODE
) පිළිබඳ නිශ්චිත අර්ථ දැක්වීමකින් අවශ්ය සියලුම පුස්තකාල සහ ව්යාපෘති ගොඩනඟන්න .
මෙය එක්කෝ කළ හැකිය;
#define UNICODE
#define _UNICODE
හෝ ව්යාපෘති සැකසුම් තුළ;
ව්යාපෘති ගුණාංග> සාමාන්ය> ව්යාපෘති පෙරනිමි> අක්ෂර කට්ටලය
හෝ විධාන රේඛාවේ;
/DUNICODE /D_UNICODE
විකල්පය ද අදාළ වේ, යුනිකෝඩ් භාවිතා කිරීමට අදහස් නොකරන්නේ නම්, නිර්වචන සකසා නොමැති බවට වග බලා ගන්න, සහ / හෝ බහු අක්ෂර සැකසුම ව්යාපෘතිවල භාවිතා වන අතර නිරන්තරයෙන් අදාළ වේ.
"මුදා හැරීම" සහ "නිදොස්කරණය" ගොඩනැගීම් අතර අනුකූල වීමට අමතක නොකරන්න.
ගොඩනැඟිල්ලේ “පිරිසිදු” කිරීමකට පෙර ගොඩනැඟිලි, අසාර්ථක ගොඩනැඟිලි, අසම්පූර්ණ ගොඩනැඟිලි සහ වෙනත් ගොඩනැඟිලි පද්ධතියට සම්බන්ධ ගොඩනැගිලි ගැටළු වලින් ඉතිරිව ඇති “මළ දැව” ඉවත් කළ හැකිය.
පොදුවේ ගත් කල, IDE හෝ ගොඩනැගීමට යම් ආකාරයක “පිරිසිදු” ශ්රිතයක් ඇතුළත් වේ, නමුත් මෙය නිවැරදිව වින්යාස කර නොතිබිය හැකිය (උදා: අතින් සාදන ලද ගොනුවක) හෝ අසමත් විය හැකිය (උදා: අතරමැදි හෝ ප්රති ant ල ද්විමය කියවීමට පමණි).
"පිරිසිදු" සම්පුර්ණ වූ පසු, "පිරිසිදු" සාර්ථක වී ඇති බවත්, ජනනය කරන ලද අතරමැදි ගොනුව (උදා: ස්වයංක්රීය මේක්ෆයිල්) සාර්ථකව ඉවත් කර ඇති බවත් තහවුරු කරන්න.
මෙම ක්රියාවලිය අවසාන නිකේතනයක් ලෙස දැකිය හැකි නමුත් බොහෝ විට එය හොඳ පළමු පියවරකි ; විශේෂයෙන් දෝෂයට අදාළ කේතය මෑතකදී එකතු කර ඇත්නම් (දේශීයව හෝ ප්රභව ගබඩාවෙන්).
const
විචල්ය ප්රකාශන / අර්ථ දැක්වීම්වල "බාහිර" අස්ථානගත වී ඇත (C ++ පමණි)C වෙතින් පැමිණෙන පුද්ගලයින් සඳහා C ++ ගෝලීය const
විචල්යයන්ට අභ්යන්තර (හෝ ස්ථිතික) සම්බන්ධතාවයක් තිබීම පුදුමයක් විය හැකිය . C හි මෙය එසේ නොවේ, මන්ද සියලු ගෝලීය විචල්යයන් ව්යංගයෙන් 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
මෙය පිළිගත් බහුවිධ පිළිතුරු සහිත තරමක් පැරණි ප්රශ්න වුවද, අපැහැදිලි “නිර්වචනය නොකළ සඳහනක්” දෝෂය නිරාකරණය කරන්නේ කෙසේදැයි බෙදා ගැනීමට මම කැමතියි .
මම යොමු කිරීමට අන්වර්ථයක් භාවිතා කළෙමි std::filesystem::path
: ගොනු පද්ධතිය C ++ 17 සිට සම්මත පුස්තකාලයේ ඇත, නමුත් මගේ වැඩසටහනට C ++ 14 ද සම්පාදනය කිරීමට අවශ්ය විය, එබැවින් විචල්ය අන්වර්ථයක් භාවිතා කිරීමට මම තීරණය කළෙමි:
#if (defined _GLIBCXX_EXPERIMENTAL_FILESYSTEM) //is the included filesystem library experimental? (C++14 and newer: <experimental/filesystem>)
using path_t = std::experimental::filesystem::path;
#elif (defined _GLIBCXX_FILESYSTEM) //not experimental (C++17 and newer: <filesystem>)
using path_t = std::filesystem::path;
#endif
මට ලිපිගොනු තුනක් ඇති බව කියමු: main.cpp, file.h, file.cpp:
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.o කිරීමට file.cpp හා file.h සම්පාදනය
$ 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
.
මෙය නිවැරදි කිරීම සඳහා මට අවශ්ය වූයේ <පර්යේෂණාත්මක :: ගොනු පද්ධතිය> file.h හි <filesystem> ලෙස වෙනස් කිරීමයි.
Gcc හි පෙරනිමි හැසිරීම නම් සියලු සංකේත දෘශ්යමාන වීමයි. කෙසේ වෙතත්, පරිවර්තන ඒකක විකල්පයක් සහිතව ගොඩනඟා ඇති විට, එහි ප්රති shared ලයක් ලෙස බෙදාගත් වස්තුවෙහි බාහිර වන්නේ -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
(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
දෘශ්යතාව පිළිබඳ වැඩි විස්තර 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
විවිධ ගෘහ නිර්මාණ
ඔබට මෙවැනි පණිවිඩයක් දැකිය හැකිය:
library machine type 'x64' conflicts with target machine type 'X86'
එවැනි අවස්ථාවක, එයින් අදහස් කරන්නේ පවතින සංකේත ඔබ සම්පාදනය කරන මෝස්තරයට වඩා වෙනස් ගෘහ නිර්මාණ ශිල්පයක් සඳහා බවයි.
විෂුවල් ස්ටුඩියෝ හි, මෙය වැරදි "වේදිකාව" නිසා වන අතර, ඔබට සුදුසු එකක් තෝරා ගැනීමට හෝ පුස්තකාලයේ නිසි අනුවාදය ස්ථාපනය කිරීමට අවශ්ය වේ.
ලිනක්ස් හි, එය වැරදි පුස්තකාල ෆෝල්ඩරයක් නිසා විය හැකිය ( නිදසුනක් lib
වෙනුවට භාවිතා කිරීම lib64
).
MacOS හි, ගෘහ නිර්මාණ දෙකම එකම ගොනුවක නැව්ගත කිරීමේ විකල්පයක් ඇත. සමහර විට සබැඳිය අනුවාද දෙකම එහි තිබිය යුතු යැයි අපේක්ෂා කරයි, නමුත් එකක් පමණි. එය පුස්තකාලය ලබා ගන්නා වැරදි lib
/ lib64
ෆෝල්ඩරයේ ගැටළුවක් ද විය හැකිය .