C++ 什么是未定义的引用/未解决的外部符号错误?如何修复它?
什么是未定义的引用/未解决的外部符号错误?什么是常见的原因和如何修复/阻止它们?< /P> < P>编译C++程序发生在几个步骤中,如<强> 2.2 < /强>:< /P> 翻译语法规则的优先顺序由以下阶段规定[见脚注]C++ 什么是未定义的引用/未解决的外部符号错误?如何修复它?,c++,linker-errors,undefined-reference,c++-faq,unresolved-external,visual-studio,C++,Linker Errors,Undefined Reference,C++ Faq,Unresolved External,Visual Studio,什么是未定义的引用/未解决的外部符号错误?什么是常见的原因和如何修复/阻止它们?< /P> < P>编译C++程序发生在几个步骤中,如 2.2 < /强>:< /P> 翻译语法规则的优先顺序由以下阶段规定[见脚注] 物理源文件字符以实现定义的方式映射到基本源字符集 (为行尾指示器引入新行字符)如果 必要的。[剪报] 删除紧跟在新行字符后面的反斜杠字符(\)的每个实例,将物理源行拼接到 形成逻辑源行。[剪报] 源文件被分解为预处理标记(2.5)和空格字符序列(包括注释)。[剪报] 执行预处理指令,
g++ -o test objectFile1.o objectFile2.o -lLibraryName
指定的错误发生在编译的最后阶段,通常称为链接。这基本上意味着您将一组实现文件编译成了目标文件或库,现在您想让它们一起工作
g++ -o test objectFile1.o objectFile2.o -lLibraryName
假设您在a.cpp
中定义了符号a
。现在,b.cpp
声明并使用了该符号。在链接之前,它只是假设该符号是在某个地方定义的,但它并不关心在哪里。链接阶段负责查找符号并将其正确链接到b.cpp
(实际上是链接到使用它的对象或库)
如果您使用的是Microsoft Visual Studio,您将看到项目生成.lib
文件。其中包含导出符号表和导入符号表。导入的符号根据链接所针对的库进行解析,导出的符号为使用该.lib
(如果有)的库提供
其他编译器/平台也有类似的机制
常见的错误消息有错误LNK2001
、错误LNK1120
、错误LNK2019
对于Microsoft Visual Studio和对于GCC的符号名的引用未定义
守则:
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)" (?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
以及Microsoft Visual Studio的类似错误:
/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
常见原因包括:
未能链接到适当的库/对象文件或编译实现文件
通常,每个翻译单元将生成一个对象文件,其中包含在该翻译单元中定义的符号的定义。
要使用这些符号,必须针对这些对象文件进行链接
在gcc下,您可以指定要在命令行中链接在一起的所有对象文件,或者一起编译实现文件
g++ -o test objectFile1.o objectFile2.o -lLibraryName
这里的libraryName
只是库的简单名称,没有特定于平台的添加。例如,在Linux上,库文件通常称为libfoo.So
,但您只需编写-lfoo
。在Windows上,同一个文件可能被称为foo.lib
,但使用相同的参数。您可能必须使用-Lèdirectory›
添加可在其中找到这些文件的目录。确保不要在-l
或-l
后写空格
对于XCode:添加用户标题搜索路径->添加库搜索路径->将实际库引用拖放到项目文件夹中
在MSVS下,添加到项目中的文件会自动将其对象文件链接在一起,并生成lib
文件(常用)。要在单独的项目中使用这些符号,您需要
需要在项目设置中包含lib
文件。这是在项目属性的链接器部分,在Input->additionaldependencies
中完成的。(指向lib
文件的路径应为
添加到Linker->General->Additional Library Directories
)当使用随lib
文件提供的第三方库时,否则通常会导致错误
您还可能忘记将文件添加到编译中,在这种情况下,将不会生成目标文件。在gcc中,将文件添加到命令行。在MSVS中,将文件添加到项目中将使其自动编译(尽管文件可以,但是
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)
struct X
{
virtual ~X() = 0;
};
struct Y : X
{
~Y() {}
};
int main()
{
Y y;
}
//X::~X(){} //uncomment this line for successful definition
struct X
{
virtual void foo();
};
struct Y : X
{
void foo() {}
};
int main()
{
Y y; //linker error although there was no call to X::foo
}
struct X
{
virtual void foo() = 0;
};
struct A
{
~A();
};
A a; //destructor undefined
struct A
{
~A() {}
};
A::~A() {}
struct A
{
void foo();
};
void foo() {}
int main()
{
A a;
a.foo();
}
void A::foo() {}
struct X
{
static int x;
};
int main()
{
int x = X::x;
}
//int X::x; //uncomment this line to define X::x
template<class T>
struct X
{
void foo();
};
int main()
{
X<int> x;
x.foo();
}
//differentImplementationFile.cpp
template<class T>
void X<T>::foo()
{
}
void foo();
int main()
{
foo();
}
extern "C" void foo();
int main()
{
foo();
}
extern "C" void foo();
extern "C" {
#include "cheader.h"
}
#ifdef THIS_MODULE
#define DLLIMPEXP __declspec(dllexport)
#else
#define DLLIMPEXP __declspec(dllimport)
#endif
DLLIMPEXP void foo();
__declspec(dllexport) void foo();
__declspec(dllimport) void foo();
class DLLIMPEXP X
{
};
// 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
#pragma comment(lib, "libname.lib")
// 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
$ g++ src1.o src2.o -o prog
$ ./prog
123
// 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
.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:
; ...
$ 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
INPUT (libtbb.so.2)
cp libtbb.so.2 libtbb.so
int foo()
{
return 0;
}
void foo();
void bar()
{
foo();
}
template <typename T>
class Foo {
friend std::ostream& operator<< (std::ostream& os, const Foo<T>& a);
};
std::ostream& operator<< (std::ostream& os, const Foo<int>& a) {/*...*/}
// 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
}
template <typename T>
class Foo {
template <typename T1>
friend std::ostream& operator<<(std::ostream& os, const Foo<T1>& a);
// ...
};
template <typename T>
class Foo {
friend std::ostream& operator<<(std::ostream& os, const Foo& a)
{ /*...*/ }
// ...
};
#define UNICODE
#define _UNICODE
/DUNICODE /D_UNICODE
// header1.h
typedef int Number;
void foo(Number);
// header2.h
typedef float Number;
void foo(Number); // this only looks the same lexically
// 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(...);
}
#include "my_lib.h"
#include <stdio.h>
void hw(void)
{
puts("Hello World");
}
#ifndef MY_LIB_H
#define MT_LIB_H
extern void hw(void);
#endif
#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
$ 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
#include <zlib.h>
#include <stdio.h>
int main()
{
printf("%s\n",zlibVersion());
return 0;
}
$ gcc -c -o eg2.o eg2.c
$ 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
$ gcc -o eg2 $(pkg-config --libs zlib) eg2.o
eg2.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'
$ gcc -o eg1 eg1.o -L. -lmy_lib
$ ./eg1
Hello World
$ gcc -o eg2 eg2.o -lz
$ ./eg2
1.2.8
$ gcc -o eg2 eg2.o $(pkg-config --libs zlib)
$ ./eg2
1.2.8
$ gcc -o eg1 -L. -lmy_lib eg1.o
gcc -o eg2 -lz eg2.o
gcc -o eg2 $(pkg-config --libs zlib) eg2.o
gcc -o eg2 -lz eg2.o
gcc -o eg2 -lz eg2.o
$ gcc -o eg1 -I. -L. -lmy_lib eg1.c
$ gcc -I. -c -o eg1.o eg1.c
$ gcc -o eg1 -L. -lmy_lib eg1.o
/tmp/ccQk1tvs.o: In function `main'
eg1.o: In function `main':
// 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
}
extern const int test;
extern int test2;
#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
# -D shows (global) dynamic symbols that can be used from the outside of XXX.so
nm -D XXX.so | grep MY_SYMBOL
nm XXX.so
00000000000005a7 t HIDDEN_SYMBOL
00000000000005f8 T VISIBLE_SYMBOL
#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
>>> objdump -t XXXX.o | grep hidden
0000000000000000 g F .text 000000000000000b .hidden HIDDEN_SYMBOL1
000000000000000b g F .text 000000000000000b .hidden HIDDEN_SYMBOL2
#include "gum.h"
#include "foo.h"
int main()
{
gum();
foo f;
f.bar();
return 0;
}
#pragma once
struct foo {
void bar() const;
};
#pragma once
extern void gum();
#include "foo.h"
#include <iostream>
inline /* <- wrong! */ void foo::bar() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
#include "gum.h"
#include <iostream>
inline /* <- wrong! */ void gum()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
g++ -c main.cpp foo.cpp gum.cpp
$ g++ -o prog main.o foo.o gum.o
main.o: In function `main':
main.cpp:(.text+0x18): undefined reference to `gum()'
main.cpp:(.text+0x24): undefined reference to `foo::bar() const'
collect2: error: ld returned 1 exit status
#include "foo.h"
#include <iostream>
void foo::bar() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
#include "gum.h"
#include <iostream>
void gum()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
$ g++ -c main.cpp foo.cpp gum.cpp
imk@imk-Inspiron-7559:~/develop/so/scrap1$ g++ -o prog main.o foo.o gum.o
imk@imk-Inspiron-7559:~/develop/so/scrap1$ ./prog
void gum()
void foo::bar() const
#pragma once
#include <iostream>
struct foo {
void bar() const { // In-class definition is implicitly inline
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
// Alternatively...
#if 0
struct foo {
void bar() const;
};
inline void foo::bar() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
#endif
#pragma once
#include <iostream>
inline void gum() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
$ g++ -c main.cpp
$ g++ -o prog main.o
$ ./prog
void gum()
void foo::bar() const