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
The macro THIS_MODULE would only be defined in the module that exports the function. That way, the declaration:
DLLIMPEXP void foo();
expands to
__declspec(dllexport) void foo();
and tells the compiler to export the function, as the current module contains its definition. When including the declaration in a different module, it would expand to
__declspec(dllimport) void foo();
and tells the compiler that the definition is in one of the libraries you linked against (also see1)).
This is one of most confusing error messages that every VC++ programmers have seen time and time again. Let’s make things clarity first.
**A. What is symbol?**In short, a symbol is a name. It can be a variable name, a function name, a class name, a typedef name, or anything except those names and signs that belong to C++ language. It is user defined or introduced by a dependency library (another user-defined).
**B. What is external?**In VC++, every source file (.cpp,.c,etc.) is considered as a translation unit, the compiler compiles one unit at a time, and generate one object file(.obj) for the current translation unit. (Note that every header file that this source file included will be preprocessed and will be considered as part of this translation unit)Everything within a translation unit is considered as internal, everything else is considered as external. In C++, you may reference an external symbol by using keywords like extern, __declspec (dllimport) and so on.
**C. What is “resolve”?**Resolve is a linking-time term. In linking-time, linker attempts to find the external definition for every symbol in object files that cannot find its definition internally. The scope of this searching process including:
All object files that generated in compiling time
All libraries (.lib) that are either explicitly or implicitly specified as additional dependencies of this building application.
This searching process is called resolve.
**D. Finally, why Unresolved External Symbol?**If the linker cannot find the external definition for a symbol that has no definition internally, it reports an Unresolved External Symbol error.
E. Possible causes of LNK2019: Unresolved External Symbol error. We already know that this error is due to the linker failed to find the definition of external symbols, the possible causes can be sorted as:
Definition exists
For example, if we have a function called foo defined in a.cpp:
int foo()
{
return 0;
}
In b.cpp we want to call function foo, so we add
void foo();
to declare function foo(), and call it in another function body, say bar():
void bar()
{
foo();
}
Now when you build this code you will get a LNK2019 error complaining that foo is an unresolved symbol. In this case, we know that foo() has its definition in a.cpp, but different from the one we are calling(different return value). This is the case that definition exists.
Definition does not exist
If we want to call some functions in a library, but the import library is not added into the additional dependency list (set from: Project | Properties | Configuration Properties | Linker | Input | Additional Dependency) of your project setting. Now the linker will report a LNK2019 since the definition does not exist in current searching scope.
Unspecialized templates must have their definitions visible to all translation units that use them. That means you can't separate the definition of a template to an implementation file. If you must separate the implementation, the usual workaround is to have an impl file which you include at the end of the header that declares the template. A common situation is:
To fix this, you must move the definition of X::foo to the header file or some place visible to the translation unit that uses it.
Specialized templates can be implemented in an implementation file and the implementation doesn't have to be visible, but the specialization must be previously declared.
For further explanation and another possible solution (explicit instantiation) see this question and answer.
I was recently able to get rid of an unresolved external error in Visual Studio 2012 just by recompiling the offending file. When I re-built, the error went away.
This usually happens when two (or more) libraries have a cyclic dependency. Library A attempts to use symbols in B.lib and library B attempts to use symbols from A.lib. Neither exist to start off with. When you attempt to compile A, the link step will fail because it can't find B.lib. A.lib will be generated, but no dll. You then compile B, which will succeed and generate B.lib. Re-compiling A will now work because B.lib is now found.
what is an "undefined reference/unresolved external symbol"
I'll try to explain what is an "undefined reference/unresolved external symbol". note: i use g++ and Linux and all examples is for it
For example we have some code
// 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;
}
and
// 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);
}
After the assembler phase we have an object file, which contains any symbols to export. Look at the symbols
$ 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]
I've rejected some lines from output, because they do not matter
So, we see follow symbols to export.
[1] - this is our static (local) variable (important - Bind has a type "LOCAL")
[2] - this is our global variable
src2.cpp exports nothing and we have seen no its symbols
Link our object files
$ g++ src1.o src2.o -o prog
and run it
$ ./prog
123
Linker sees exported symbols and links it. Now we try to uncomment lines in src2.cpp like here
// 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);
}
and rebuild an object file
$ g++ -c src2.cpp -o src2.o
OK (no errors), because we only build object file, linking is not done yet. Try to link
$ 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
It has happened because our local_var_name is static, i.e. it is not visible for other modules. Now more deeply. Get the translation phase output
So, we've seen there is no label for local_var_name, that's why linker hasn't found it. But we are hackers :) and we can fix it. Open src1.s in your text editor and change
The order in which interdependent linked libraries are specified is wrong.
The order in which libraries are linked DOES matter if the libraries depend on each other. In general, if library A depends on library B, then libAMUSTappear before libB in the linker flags.
For example:
// 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;
};
Create the libraries:
$ 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
Compile:
$ 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
Declared but did not define a variable or function.
A typical variable declaration is
extern int x;
As this is only a declaration, asingle definitionis needed. A corresponding definition would be:
int x;
For example, the following would generate an error:
extern int x;
int main()
{
x = 0;
}
//int x; // uncomment this line for successful definition
Similar remarks apply to functions. Declaring a function without defining it leads to the error:
void foo(); // declaration only
int main()
{
foo();
}
//void foo() {} //uncomment this line for successful definition
Be careful that the function you implement exactly matches the one you declared. For example, you may have mismatched cv-qualifiers:
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)
Other examples of mismatches include
Function/variable declared in one namespace, defined in another.
Function/variable declared as class member, defined as global (or vice versa).
Function return type, parameter number and types, and calling convention do not all exactly agree.
The error message from the compiler will often give you the full declaration of the variable or function that was declared but never defined. Compare it closely to the definition you provided. Make sure every detail matches.
29条答案
按热度按时间yv5phkfx16#
编译C++程序分几个步骤进行,如2.2(credits to Keith Thompson for the reference)所指定:
翻译的语法规则之间的优先顺序由以下阶段*[见脚注]*规定。
1.如有必要,以实现定义的方式将物理源文件字符Map到基本源字符集(引入换行符作为行尾指示符)。[剪报]
1.删除紧跟换行符的反斜杠字符()的每个示例,拼接物理源行以形成逻辑源行。[剪报]
1.源文件被分解为预处理标记(2.5)和空白字符序列(包括注解)。[剪报]
1.执行预处理指令,展开宏调用,执行_Pragma一元运算符表达式。[剪报]
1.将字符文字或字符串文字中的每个源字符集成员,以及字符文字或非原始字符串文字中的每个转义序列和通用字符名称转换为执行字符集的相应成员;[Snip]
1.连接相邻的字符串文字标记。
1.空格字符分隔令牌不再重要。每个预处理令牌被转换为令牌。(2.7)。得到的标记被作为翻译单位进行句法和语义分析和翻译。[剪报]
1.翻译后的翻译单元和示例化单元组合如下:[Snip]
1.解析所有外部实体引用。链接库组件以满足对未在当前转换中定义的实体的外部参照。所有这样的翻译器输出都被收集到一个程序映像中,其中包含在其执行环境中执行所需的信息。(重点挖掘)
指定的错误发生在编译的最后阶段,通常称为链接。这基本上意味着您将一组实现文件编译成目标文件或库,现在您想让它们协同工作。
假设您在
a.cpp
中定义了符号a
。现在,b.cpp
声明了该符号并使用了它。在链接之前,它简单地假设该符号是在某个地方定义的,但它并不关心在哪里定义的。链接阶段负责查找符号并将其正确链接到b.cpp
(实际上是链接到使用它的对象或库)。如果您使用的是Microsoft Visual Studio,您将看到项目生成
.lib
文件。其中包含一个导出符号表和一个导入符号表。导入的符号将根据链接所针对的库进行解析,并为使用该.lib
(如果有)的库提供导出的符号。对于其他编译器/平台也存在类似的机制。
常见的错误信息有:Microsoft Visual Studio的
error LNK2001
、error LNK1120
、error LNK2019
;GCC的undefined reference to
symbol Name。代码:
GCC会产生如下错误:
Microsoft Visual Studio也有类似的错误:
常见原因包括:
#pragma
(Microsoft Visual Studio)UNICODE
definitionswlp8pajw17#
微软提供了一个
#pragma
来在链接时引用正确的库;除了包括库目录的库路径外,这还应该是库的全名。
7vux5j2d18#
另外,如果您使用的是第三方库,请确保您拥有正确的32/64位二进制文件
xkftehaa19#
未定义对
WinMain@16
或类似“不寻常”main()
入口点引用的引用**(尤其是对于visual-studio)。您可能没有使用实际的IDE选择正确的项目类型。例如,IDE可能希望将Windows应用程序项目绑定到这样的入口点函数(如上面缺失的引用中所指定的),而不是通常使用的
int main(int argc, char**argv);
签名。如果您的IDE支持普通控制台项目,您可能希望选择此项目类型,而不是Windows应用程序项目。
下面是一个“真实世界”问题中更详细地处理的案例1和case2。
gojuced720#
Incorrectly importing/exporting methods/classes across modules/dll (compiler specific).
MSVS requires you to specify which symbols to export and import using
__declspec(dllexport)
and__declspec(dllimport)
.This dual functionality is usually obtained through the use of a macro:
The macro
THIS_MODULE
would only be defined in the module that exports the function. That way, the declaration:expands to
and tells the compiler to export the function, as the current module contains its definition. When including the declaration in a different module, it would expand to
and tells the compiler that the definition is in one of the libraries you linked against (also see1)).
You can similary import/export classes:
wfsdck3021#
This is one of most confusing error messages that every VC++ programmers have seen time and time again. Let’s make things clarity first.
**A. What is symbol?**In short, a symbol is a name. It can be a variable name, a function name, a class name, a typedef name, or anything except those names and signs that belong to C++ language. It is user defined or introduced by a dependency library (another user-defined).
**B. What is external?**In VC++, every source file (.cpp,.c,etc.) is considered as a translation unit, the compiler compiles one unit at a time, and generate one object file(.obj) for the current translation unit. (Note that every header file that this source file included will be preprocessed and will be considered as part of this translation unit)Everything within a translation unit is considered as internal, everything else is considered as external. In C++, you may reference an external symbol by using keywords like
extern
,__declspec (dllimport)
and so on.**C. What is “resolve”?**Resolve is a linking-time term. In linking-time, linker attempts to find the external definition for every symbol in object files that cannot find its definition internally. The scope of this searching process including:
This searching process is called resolve.
**D. Finally, why Unresolved External Symbol?**If the linker cannot find the external definition for a symbol that has no definition internally, it reports an Unresolved External Symbol error.
E. Possible causes of LNK2019: Unresolved External Symbol error. We already know that this error is due to the linker failed to find the definition of external symbols, the possible causes can be sorted as:
For example, if we have a function called foo defined in a.cpp:
In b.cpp we want to call function foo, so we add
to declare function foo(), and call it in another function body, say
bar()
:Now when you build this code you will get a LNK2019 error complaining that foo is an unresolved symbol. In this case, we know that foo() has its definition in a.cpp, but different from the one we are calling(different return value). This is the case that definition exists.
If we want to call some functions in a library, but the import library is not added into the additional dependency list (set from:
Project | Properties | Configuration Properties | Linker | Input | Additional Dependency
) of your project setting. Now the linker will report a LNK2019 since the definition does not exist in current searching scope.ugmeyewa22#
Template implementations not visible.
Unspecialized templates must have their definitions visible to all translation units that use them. That means you can't separate the definition of a template to an implementation file. If you must separate the implementation, the usual workaround is to have an
impl
file which you include at the end of the header that declares the template. A common situation is:To fix this, you must move the definition of
X::foo
to the header file or some place visible to the translation unit that uses it.Specialized templates can be implemented in an implementation file and the implementation doesn't have to be visible, but the specialization must be previously declared.
For further explanation and another possible solution (explicit instantiation) see this question and answer.
v9tzhpje23#
If all else fails, recompile.
I was recently able to get rid of an unresolved external error in Visual Studio 2012 just by recompiling the offending file. When I re-built, the error went away.
This usually happens when two (or more) libraries have a cyclic dependency. Library A attempts to use symbols in B.lib and library B attempts to use symbols from A.lib. Neither exist to start off with. When you attempt to compile A, the link step will fail because it can't find B.lib. A.lib will be generated, but no dll. You then compile B, which will succeed and generate B.lib. Re-compiling A will now work because B.lib is now found.
z9ju0rcb24#
Symbols were defined in a C program and used in C++ code.
The function (or variable)
void foo()
was defined in a C program and you attempt to use it in a C++ program:The C++ linker expects names to be mangled, so you have to declare the function as:
Equivalently, instead of being defined in a C program, the function (or variable)
void foo()
was defined in C++ but with C linkage:and you attempt to use it in a C++ program with C++ linkage.
If an entire library is included in a header file (and was compiled as C code); the include will need to be as follows;
siotufzp25#
what is an "undefined reference/unresolved external symbol"
I'll try to explain what is an "undefined reference/unresolved external symbol".
note: i use g++ and Linux and all examples is for it
For example we have some code
and
Make object files
After the assembler phase we have an object file, which contains any symbols to export. Look at the symbols
I've rejected some lines from output, because they do not matter
So, we see follow symbols to export.
src2.cpp exports nothing and we have seen no its symbols
Link our object files
and run it
Linker sees exported symbols and links it. Now we try to uncomment lines in src2.cpp like here
and rebuild an object file
OK (no errors), because we only build object file, linking is not done yet. Try to link
It has happened because our local_var_name is static, i.e. it is not visible for other modules. Now more deeply. Get the translation phase output
So, we've seen there is no label for local_var_name, that's why linker hasn't found it. But we are hackers :) and we can fix it. Open src1.s in your text editor and change
to
i.e. you should have like below
we have changed the visibility of local_var_name and set its value to 456789. Try to build an object file from it
ok, see readelf output (symbols)
now local_var_name has Bind GLOBAL (was LOCAL)
link
and run it
ok, we hack it :)
So, as a result - an "undefined reference/unresolved external symbol error" happens when the linker cannot find global symbols in the object files.
s3fp2yjn26#
The order in which interdependent linked libraries are specified is wrong.
The order in which libraries are linked DOES matter if the libraries depend on each other. In general, if library
A
depends on libraryB
, thenlibA
MUSTappear beforelibB
in the linker flags.For example:
Create the libraries:
Compile:
So to repeat again, the orderDOESmatter!
6tqwzwtp27#
Declared but did not define a variable or function.
A typical variable declaration is
As this is only a declaration, asingle definitionis needed. A corresponding definition would be:
For example, the following would generate an error:
Similar remarks apply to functions. Declaring a function without defining it leads to the error:
Be careful that the function you implement exactly matches the one you declared. For example, you may have mismatched cv-qualifiers:
Other examples of mismatches include
The error message from the compiler will often give you the full declaration of the variable or function that was declared but never defined. Compare it closely to the definition you provided. Make sure every detail matches.
woobm2wo28#
链接对应的库/对象文件或编译实现文件失败
通常,每个翻译单元将生成一个目标文件,其中包含在该翻译单元中定义的符号的定义。要使用这些符号,您必须链接到这些目标文件。
在GCC下,您可以指定要在命令行中链接在一起的所有目标文件,或者一起编译实现文件。
-l...
必须位于任何.o
/.c
/.cpp
文件的右侧。这里的
libraryName
只是库的简单名称,没有特定于平台的附加内容。例如,在Linux上,库文件通常称为libfoo.so
,但您只需编写-lfoo
。在Windows上,相同的文件可能被称为foo.lib
,但您将使用相同的参数。您可能需要使用-L‹directory›
添加可以找到这些文件的目录。确保在-l
或-L
之后不写入空格。对于XCode:添加用户头搜索路径->添加库搜索路径->将实际的库引用拖放到项目文件夹中。
在MSVS下,添加到工程中的文件会自动将其目标文件链接在一起,并生成一个
lib
文件(常用)。要在单独的项目中使用符号,需要在项目设置中包括lib
文件。这是在Input -> Additional Dependencies
中的项目属性的Linker部分中完成的。(应该在Linker -> General -> Additional Library Directories
中添加lib
文件的路径)使用随lib
文件提供的第三方库时,如果不这样做,通常会导致错误。还可能发生忘记将文件添加到编译中的情况,在这种情况下,不会生成目标文件。在GCC中,将文件添加到命令行。在MSVS中,将文件添加到项目中将使其自动编译(尽管文件可以手动从构建中单独排除)。
在Windows编程中,未链接所需库的标志是未解析符号的名称以
__imp_
开头。在文档中查找函数的名称,它应该说明您需要使用哪个库。例如,MSDN将信息放在每个函数底部名为“库”的部分中的一个框中。ia2d9nvy29#
类成员:
纯
virtual
析构函数需要实现。将析构函数声明为纯函数仍然需要您定义它(与常规函数不同):
这是因为在隐式销毁对象时会调用基类析构函数,因此需要定义。
virtual
方法必须实现或定义为纯方法。这类似于没有定义的非
virtual
方法,但增加了一个推理,即纯声明生成一个虚拟vtable,并且您可能在不使用函数的情况下获得链接器错误:为此,请将
X::foo()
声明为纯:非
virtual
类成员有些成员即使没有显式使用,也需要定义:
以下内容将产生错误:
在类定义本身中,实现可以内联:
或室外:
如果实现在类定义之外,但在头中,则必须将方法标记为
inline
,以防止多重定义。如果使用,则需要定义所有使用的成员方法。
一个常见的错误是忘记对名称进行限定:
其定义应为
static
数据成员必须在类外定义单个翻译单元:可以为类定义中整型或枚举型的
static``const
数据成员提供初始值设定项;然而,ODR使用该成员仍然需要如上所述的命名空间范围定义。C++11允许在类内对所有static const
数据成员进行初始化。