Visual Studio NuGet package needs to be updated for new toolset version
I just had this problem trying to link libpng with Visual Studio 2013. The problem is that the package file only had libraries for Visual Studio 2010 and 2012.
The correct solution is to hope the developer releases an updated package and then upgrade, but it worked for me by hacking in an extra setting for VS2013, pointing at the VS2012 library files.
I edited the package (in the packages folder inside the solution's directory) by finding packagename\build\native\packagename.targets and inside that file, copying all the v110 sections. I changed the v110 to v120 inthe condition fields onlybeing very careful to leave the filename paths all as v110. This simply allowed Visual Studio 2013 to link to the libraries for 2012, and in this case, it worked.
# 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
// 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
}
Linker errors can happen when a header file and its associated shared library (.lib file) go out of sync. Let me explain.
How do linkers work? The linker matches a function declaration (declared in the header) with its definition (in the shared library) by comparing their signatures. You can get a linker error if the linker doesn't find a function definition that matches perfectly.
Is it possible to still get a linker error even though the declaration and the definition seem to match? Yes! They might look the same in source code, but it really depends on what the compiler sees. Essentially you could end up with a situation like this:
// header1.h
typedef int Number;
void foo(Number);
// header2.h
typedef float Number;
void foo(Number); // this only looks the same lexically
Note how even though both the function declarations look identical in source code, but they are really different according to the compiler.
You might ask how one ends up in a situation like that?Include pathsof course! If when compiling the shared library, the include path leads to header1.h and you end up using header2.h in your own program, you'll be left scratching your header wondering what happened (pun intended).
An example of how this can happen in the real world is explained below.
Further elaboration with an example
I have two projects: graphics.lib and main.exe. Both projects depend on common_math.h. Suppose the library exports the following function:
// graphics.lib
# include "common_math.h"
void draw(vec3 p) { ... } // vec3 comes from common_math.h
And then you go ahead and include the library in your own project.
// main.exe
# include "other/common_math.h"
# include "graphics.h"
int main() {
draw(...);
}
Boom! You get a linker error and you have no idea why it's failing. The reason is that the common library uses different versions of the same include common_math.h (I have made it obvious here in the example by including a different path, but it might not always be so obvious. Maybe the include path is different in the compiler settings).
Note in this example, the linker would tell you it couldn't find draw(), when in reality you know it obviously is being exported by the library. You could spend hours scratching your head wondering what went wrong. The thing is, the linker sees a different signature because the parameter types are slightly different. In the example, vec3 is a different type in both projects as far as the compiler is concerned. This could happen because they come from two slightly different include files (maybe the include files come from two different versions of the library).
Debugging the linker
DUMPBIN is your friend, if you are using Visual Studio. I'm sure other compilers have other similar tools.
The process goes like this:
Note the weird mangled name given in the linker error. (eg. draw@graphics@XYZ).
Dump the exported symbols from the library into a text file.
Search for the exported symbol of interest, and notice that the mangled name is different.
Pay attention to why the mangled names ended up different. You would be able to see that the parameter types are different, even though they look the same in the source code.
Reason why they are different. In the example given above, they are different because of different include files.
[1] By project I mean a set of source files that are linked together to produce either a library or an executable.
EDIT 1: Rewrote first section to be easier to understand. Please comment below to let me know if something else needs to be fixed. Thanks!
$ 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
The same result if you compile and link in one step, like:
$ 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
A minimal example involving a shared system library, the compression library libz
eg2.c
# include <zlib.h>
# include <stdio.h>
int main()
{
printf("%s\n",zlibVersion());
return 0;
}
Compile your program:
$ gcc -c -o eg2.o eg2.c
Try to link your program with libz and fail:
$ 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
Same if you compile and link in one go:
$ 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
And a variation on example 2 involving pkg-config:
$ gcc -o eg2 $(pkg-config --libs zlib) eg2.o
eg2.o: In function `main':
eg2.c:(.text+0x5): undefined reference to `zlibVersion'
What are you doing wrong?
In the sequence of object files and libraries you want to link to make your program, you are placing the libraries before the object files that refer to them. You need to place the libraries after the object files that refer to them.
Link example 1 correctly:
$ gcc -o eg1 eg1.o -L. -lmy_lib
Success:
$ ./eg1
Hello World
Link example 2 correctly:
$ gcc -o eg2 eg2.o -lz
Success:
$ ./eg2
1.2.8
Link the example 2 pkg-config variation correctly:
By default, a linkage command generated by GCC, on your distro, consumes the files in the linkage from left to right in commandline sequence. When it finds that a file refers to something and does not contain a definition for it, to will search for a definition in files further to the right. If it eventually finds a definition, the reference is resolved. If any references remain unresolved at the end, the linkage fails: the linker does not search backwards.
First,example 1, with static library my_lib.a
A static library is an indexed archive of object files. When the linker finds -lmy_lib in the linkage sequence and figures out that this refers to the static library ./libmy_lib.a, it wants to know whether your program needs any of the object files in libmy_lib.a.
There is only object file in libmy_lib.a, namely my_lib.o, and there's only one thing defined in my_lib.o, namely the function hw.
The linker will decide that your program needs my_lib.o if and only if it already knows that your program refers to hw, in one or more of the object files it has already added to the program, and that none of the object files it has already added contains a definition for hw.
If that is true, then the linker will extract a copy of my_lib.o from the library and add it to your program. Then, your program contains a definition for hw, so its references to hw are resolved.
When you try to link the program like:
$ gcc -o eg1 -L. -lmy_lib eg1.o
the linker has not addedeg1.oto the program when it sees -lmy_lib. Because at that point, it has not seen eg1.o. Your program does not yet make any references to hw: it does not yet make any references at all, because all the references it makes are in eg1.o.
So the linker does not add my_lib.o to the program and has no further use for libmy_lib.a.
Next, it finds eg1.o, and adds it to be program. An object file in the linkage sequence is always added to the program. Now, the program makes a reference to hw, and does not contain a definition of hw; but there is nothing left in the linkage sequence that could provide the missing definition. The reference to hw ends up unresolved, and the linkage fails.
Second,example 2, with shared library libz
A shared library isn't an archive of object files or anything like it. It's much more like a program that doesn't have a main function and instead exposes multiple other symbols that it defines, so that other programs can use them at runtime.
Many Linux distros today configure their GCC toolchain so that its language drivers (gcc,g++,gfortran etc) instruct the system linker (ld) to link shared libraries on an as-needed basis. You have got one of those distros.
This means that when the linker finds -lz in the linkage sequence, and figures out that this refers to the shared library (say) /usr/lib/x86_64-linux-gnu/libz.so, it wants to know whether any references that it has added to your program that aren't yet defined have definitions that are exported by libz
If that is true, then the linker will not copy any chunks out of libz and add them to your program; instead, it will just doctor the code of your program so that:-
At runtime, the system program loader will load a copy of libz into the same process as your program whenever it loads a copy of your program, to run it.
At runtime, whenever your program refers to something that is defined in libz, that reference uses the definition exported by the copy of libz in the same process.
Your program wants to refer to just one thing that has a definition exported by libz, namely the function zlibVersion, which is referred to just once, in eg2.c. If the linker adds that reference to your program, and then finds the definition exported by libz, the reference is resolved
But when you try to link the program like:
gcc -o eg2 -lz eg2.o
the order of events is wrong in just the same way as with example 1. At the point when the linker finds -lz, there are no references to anything in the program: they are all in eg2.o, which has not yet been seen. So the linker decides it has no use for libz. When it reaches eg2.o, adds it to the program, and then has undefined reference to zlibVersion, the linkage sequence is finished; that reference is unresolved, and the linkage fails.
Lastly, the pkg-config variation of example 2 has a now obvious explanation. After shell-expansion:
gcc -o eg2 $(pkg-config --libs zlib) eg2.o
becomes:
gcc -o eg2 -lz eg2.o
which is just example 2 again.
I can reproduce the problem in example 1, but not in example 2
The linkage:
gcc -o eg2 -lz eg2.o
works just fine for you!
(Or: That linkage worked fine for you on, say, Fedora 23, but fails on Ubuntu 16.04)
That's because the distro on which the linkage works is one of the ones that does not configure its GCC toolchain to link shared libraries as-needed.
Back in the day, it was normal for unix-like systems to link static and shared libraries by different rules. Static libraries in a linkage sequence were linked on the as-needed basis explained in example 1, but shared libraries were linked unconditionally.
This behaviour is economical at linktime because the linker doesn't have to ponder whether a shared library is needed by the program: if it's a shared library, link it. And most libraries in most linkages are shared libraries. But there are disadvantages too:-
It is uneconomical at runtime, because it can cause shared libraries to be loaded along with a program even if doesn't need them.
The different linkage rules for static and shared libraries can be confusing to inexpert programmers, who may not know whether -lfoo in their linkage is going to resolve to /some/where/libfoo.a or to /some/where/libfoo.so, and might not understand the difference between shared and static libraries anyway.
This trade-off has led to the schismatic situation today. Some distros have changed their GCC linkage rules for shared libraries so that the as-needed principle applies for all libraries. Some distros have stuck with the old way.
Why do I still get this problem even if I compile-and-link at the same time?
If I just do:
$ gcc -o eg1 -I. -L. -lmy_lib eg1.c
surely gcc has to compile eg1.c first, and then link the resulting object file with libmy_lib.a. So how can it not know that object file is needed when it's doing the linking?
Because compiling and linking with a single command does not change the order of the linkage sequence.
When you run the command above, gcc figures out that you want compilation + linkage. So behind the scenes, it generates a compilation command, and runs it, then generates a linkage command, and runs it, as if you had run the two commands:
So the linkage fails just as it does if you do run those two commands. The only difference you notice in the failure is that gcc has generated a temporary object file in the compile + link case, because you're not telling it to use eg1.o. We see:
Putting interdependent libraries in the wrong order is just one way in which you can get files that need definitions of things coming later in the linkage than the files that provide the definitions. Putting libraries before the object files that refer to them is another way of making the same mistake.
I recently had this problem, and it turned out it was a bug in Visual Studio Express 2013. I had to remove a source file from the project and re-add it to overcome the bug.
Steps to try if you believe it could be a bug in compiler/IDE:
Clean the project (some IDEs have an option to do this, you can also manually do it by deleting the object files)
Try start a new project, copying all source code from the original one.
Suppose you have a big project written in c++ which has a thousand of .cpp files and a thousand of .h files.And let's says the project also depends on ten static libraries. Let's says we are on Windows and we build our project in Visual Studio 20xx. When you press Ctrl + F7 Visual Studio to start compiling the whole solution ( suppose we have just one project in the solution )
What's the meaning of compilation ?
Visual Studio search into file**.vcxproj**and start compiling each file which has the extension .cpp. Order of compilation is undefined.So you must not assume that the file main.cpp is compiled first
If .cpp files depends on additional .h files in order to find symbols that may or may not be defined in the file .cpp
If exists one .cpp file in which the compiler could not find one symbol, acompiler time errorraises the message Symbol x could not be found
For each file with extension .cpp is generated an object file .o and also Visual Studio writes the output in a file named ProjectName.Cpp.Clean.txt which contains all object files that must be processed by the linker.
The Second step of compilation is done by Linker.Linker should merge all the object file and build finally the output ( which may be an executable or a library)
Steps In Linking a project
Parse all the object files and find the definition which was only declared in headers ( eg: The code of one method of a class as is mentioned in previous answers, or event the initialization of a static variable which is member inside a class)
If one symbol could not be found in object files he also is searched in Additional Libraries.For adding a new library to a projectConfiguration properties->VC++ Directories->Library Directoriesand here you specified additional folder for searching libraries andConfiguration properties->Linker->Inputfor specifying the name of the library. -If the Linker could not find the symbol which you write in one .cpp he raises alinker time errorwhich may sound like error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)
Observation
Once the Linker find one symbol he doesn't search in other libraries for it
The order of linking librariesdoes matter.
If Linker finds an external symbol in one static library he includes the symbol in the output of the project.However, if the library is shared( dynamic ) he doesn't include the code ( symbols ) in output, but Run-Time crashes may occur
How To Solve this kind of error
Compiler Time Error :
Make sure you write your c++ project syntactical correct.
Linker Time Error
Define all your symbol which you declare in your header files
Use #pragma once for allowing compiler not to include one header if it was already included in the current .cpp which are compiled
Make sure that your external library doesn't contain symbols that may enter into conflict with other symbols you defined in your header files
When you use the template to make sure you include the definition of each template function in the header file for allowing the compiler to generate appropriate code for any instantiations.
29条答案
按热度按时间r6l8ljro1#
Visual Studio NuGet package needs to be updated for new toolset version
I just had this problem trying to link libpng with Visual Studio 2013. The problem is that the package file only had libraries for Visual Studio 2010 and 2012.
The correct solution is to hope the developer releases an updated package and then upgrade, but it worked for me by hacking in an extra setting for VS2013, pointing at the VS2012 library files.
I edited the package (in the
packages
folder inside the solution's directory) by findingpackagename\build\native\packagename.targets
and inside that file, copying all thev110
sections. I changed thev110
tov120
inthe condition fields onlybeing very careful to leave the filename paths all asv110
. This simply allowed Visual Studio 2013 to link to the libraries for 2012, and in this case, it worked.cetgtptt2#
针对共享库进行链接时,请确保使用的符号没有隐藏。
GCC的默认行为是所有符号都是可见的。但是,当使用选项
-fvisibility=hidden
构建转换单元时,只有标有__attribute__ ((visibility ("default")))
的函数/符号在生成的共享对象中是外部的。您可以通过调用以下命令来检查您正在寻找的符号是否为外部符号:
隐藏/本地符号由
nm
显示,符号类型为小写,例如t
而不是代码段的`t:您还可以使用带有选项
-C
的nm
来取消名称的混乱(如果使用的是C++)。与Windows-dll类似,可以使用定义标记公共函数,例如
DLL_PUBLIC
定义为:大致对应于Windows的/MSVC版本:
更多information about visibility可以在GCC维基上找到。
当用
-fvisibility=hidden
编译翻译单元时,所得到的符号仍然具有外部链接(由nm
以大写符号类型表示),并且如果目标文件成为静态库的一部分,则可以用于外部链接而没有问题。仅当目标文件链接到共享库时,该链接才变为本地链接。要查找对象文件中隐藏的符号,请执行以下操作:
vpfxa7rd3#
尽管这是一个相当古老的问题,有多个公认的答案,但我想分享一下如何解决一个晦涩“未定义的引用”错误。
不同版本的库
我使用别名来引用
std::filesystem::path
:文件系统从C17开始就在标准库中,但我的程序需要**也用C14编译**,所以我决定使用变量别名:假设我有三个文件:main.cpp、file.h、file.cpp:
注意main.cpp和file.h中使用的不同的库。因为main.cpp#includd‘d“file.h”在<filessystem>之后,所以那里使用的文件系统版本是C++17版本。我过去常常使用以下命令编译该程序:
$
g++ -g -std=c++17 -c main.cpp
->将main.cpp编译为main.o$
g++ -g -std=c++17 -c file.cpp
->将file.cpp和file.h编译为file.o$
g++ -g -std=c++17 -o executable main.o file.o -lstdc++fs
->链接main.o和file.o这样,需要
path_t
的file.o中包含并在main.o中使用的任何函数都会出现“未定义的引用”错误,因为main.o引用了std::filesystem::path
,但file.o引用了std::experimental::filesystem::path
**。解决方案
要解决这个问题,我只需要将file.h中的<实验性::文件系统>更改为<文件系统>。
gywdnpxw4#
const
变量声明/定义中缺少extern(仅限C++)对于来自C语言的人来说,在C++中,全局e1d1d1变量具有内部(或静态)链接,这可能会令人惊讶。在C中情况并非如此,因为所有全局变量都隐式为
extern
(即,当缺少关键字static
时)。示例:
正确的做法是使用头文件并将其包含在file2.cpp和file1.cpp中
或者,可以使用显式
extern
在file1.cpp中声明const
变量pbpqsu0x5#
清理重建
一个“干净”的构建可以去除以前的构建、失败的构建、不完整的构建以及其他与构建系统相关的构建问题留下的“枯木”。
通常,IDE或构建将包括某种形式的“干净”函数,但这可能未正确配置(例如,在手动Makefile中)或可能失败(例如,中间或结果二进制文件是只读的)。
一旦“清理”完成,确认“清理”已成功,并且所有生成的中间文件(例如,自动生成的Makefile)都已被成功删除。
这个过程可以看作是最后的手段,但通常是一个很好的第一步;特别是如果最近添加了与错误相关的代码(无论是在本地还是从源代码存储库中)。
yc0p9oo06#
UNICODE
定义不一致Windows Unicode构建时,
TCHAR
等被定义为wchar_t
等。如果不使用UNICODE
构建,TCHAR
定义为char
等。这些UNICODE
和_UNICODE
定义会影响所有"T
" string types;LPTSTR
、LPCTSTR
及其ELK。在定义了
UNICODE
的情况下生成一个库并尝试将其链接到未定义UNICODE
的项目中会导致链接器错误,因为TCHAR
的定义与wchar_t
的定义不匹配。错误通常包括具有
char
或wchar_t
派生类型的函数a值,也可能包括std::basic_string<>
等。当浏览代码中受影响的函数时,通常会引用TCHAR
或std::basic_string<TCHAR>
等。这是一个迹象,表明代码最初是用于Unicode和多字节字符(或“窄”)构建的。要纠正此问题,请使用
UNICODE
(和_UNICODE
)的一致定义构建所有必需的库和项目。1.这可以用任何一种方式来完成;
1.或在项目设置中;
项目属性>常规>项目默认设置>字符集
1.或在命令行上;
替代方案也适用,如果不打算使用Unicode,请确保未设置定义,和/或在项目中使用并一致应用多字符设置。
不要忘记在“发布”和“调试”版本之间也要保持一致。
w80xi6nr7#
When your include paths are different
Linker errors can happen when a header file and its associated shared library (.lib file) go out of sync. Let me explain.
How do linkers work? The linker matches a function declaration (declared in the header) with its definition (in the shared library) by comparing their signatures. You can get a linker error if the linker doesn't find a function definition that matches perfectly.
Is it possible to still get a linker error even though the declaration and the definition seem to match? Yes! They might look the same in source code, but it really depends on what the compiler sees. Essentially you could end up with a situation like this:
Note how even though both the function declarations look identical in source code, but they are really different according to the compiler.
You might ask how one ends up in a situation like that?Include pathsof course! If when compiling the shared library, the include path leads to
header1.h
and you end up usingheader2.h
in your own program, you'll be left scratching your header wondering what happened (pun intended).An example of how this can happen in the real world is explained below.
Further elaboration with an example
I have two projects:
graphics.lib
andmain.exe
. Both projects depend oncommon_math.h
. Suppose the library exports the following function:And then you go ahead and include the library in your own project.
Boom! You get a linker error and you have no idea why it's failing. The reason is that the common library uses different versions of the same include
common_math.h
(I have made it obvious here in the example by including a different path, but it might not always be so obvious. Maybe the include path is different in the compiler settings).Note in this example, the linker would tell you it couldn't find
draw()
, when in reality you know it obviously is being exported by the library. You could spend hours scratching your head wondering what went wrong. The thing is, the linker sees a different signature because the parameter types are slightly different. In the example,vec3
is a different type in both projects as far as the compiler is concerned. This could happen because they come from two slightly different include files (maybe the include files come from two different versions of the library).Debugging the linker
DUMPBIN is your friend, if you are using Visual Studio. I'm sure other compilers have other similar tools.
The process goes like this:
[1] By project I mean a set of source files that are linked together to produce either a library or an executable.
EDIT 1: Rewrote first section to be easier to understand. Please comment below to let me know if something else needs to be fixed. Thanks!
w8f9ii698#
加好友模板...
给出带有友元运算符(或函数)的模板类型的代码片段;
正在将
operator<<
声明为非模板函数。对于与Foo
一起使用的每个类型T
,都需要有一个非模板化的operator<<
。例如,如果声明了类型Foo<int>
,则必须有如下运算符实现;由于未实现它,链接器无法找到它并导致错误。
要纠正这一点,您可以在
Foo
类型之前声明一个模板运算符,然后作为朋友声明相应的示例化。语法有点笨拙,但看起来如下所示;上述代码将操作符的友好关系限制为
Foo
的相应示例化,即operator<< <int>
示例化仅限于访问Foo<int>
示例化的私有成员。替代方案包括;
operator<<
的实现可以在类定义内内联完成;首先在类或类模板X内的友元声明中声明的名称将成为X最内部封闭命名空间的成员,但不能进行查找(考虑X的参数相关查找除外),除非在命名空间作用域提供匹配的声明...
有关模板朋友的更多信息,请访问cp首选项和C++常见问题解答。
Code listing showing the techniques above。
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)
v2g6jxz69#
不支持链接器脚本的GNU LD Package 器
有些.so文件实际上是GNU ld linker scripts,例如libtbb.so文件是包含以下内容的ASCII文本文件:
一些更复杂的构建可能不支持这一点。例如,如果在编译器选项中包括-v,则可以看到mainwin gcc wrapper mwdip在要链接的库的详细输出列表中丢弃链接器脚本命令文件。一种简单的解决方法是将链接器脚本输入命令文件替换为该文件的副本(或符号链接),例如
或者,您可以用.so的完整路径替换-l参数,例如,用
/home/foo/tbb-4.3/linux/lib/intel64/gcc4.4/libtbb.so.2
代替-ltbb
ccrfmcuu10#
Your linkage consumes libraries before the object files that refer to them
libfoo
depends onlibbar
, then your linkage correctly putslibfoo
beforelibbar
.undefined reference to
something errors.#include
d and are in fact defined in the libraries that you are linking.Examples are in C. They could equally well be C++
A minimal example involving a static library you built yourself
my_lib.c
my_lib.h
eg1.c
You build your static library:
You compile your program:
You try to link it with
libmy_lib.a
and fail:The same result if you compile and link in one step, like:
A minimal example involving a shared system library, the compression library
libz
eg2.c
Compile your program:
Try to link your program with
libz
and fail:Same if you compile and link in one go:
And a variation on example 2 involving
pkg-config
:What are you doing wrong?
In the sequence of object files and libraries you want to link to make your program, you are placing the libraries before the object files that refer to them. You need to place the libraries after the object files that refer to them.
Link example 1 correctly:
Success:
Link example 2 correctly:
Success:
Link the example 2
pkg-config
variation correctly:The explanation
By default, a linkage command generated by GCC, on your distro, consumes the files in the linkage from left to right in commandline sequence. When it finds that a file refers to something and does not contain a definition for it, to will search for a definition in files further to the right. If it eventually finds a definition, the reference is resolved. If any references remain unresolved at the end, the linkage fails: the linker does not search backwards.
First,example 1, with static library
my_lib.a
A static library is an indexed archive of object files. When the linker finds
-lmy_lib
in the linkage sequence and figures out that this refers to the static library./libmy_lib.a
, it wants to know whether your program needs any of the object files inlibmy_lib.a
.There is only object file in
libmy_lib.a
, namelymy_lib.o
, and there's only one thing defined inmy_lib.o
, namely the functionhw
.The linker will decide that your program needs
my_lib.o
if and only if it already knows that your program refers tohw
, in one or more of the object files it has already added to the program, and that none of the object files it has already added contains a definition forhw
.If that is true, then the linker will extract a copy of
my_lib.o
from the library and add it to your program. Then, your program contains a definition forhw
, so its references tohw
are resolved.When you try to link the program like:
the linker has not added
eg1.o
to the program when it sees-lmy_lib
. Because at that point, it has not seeneg1.o
. Your program does not yet make any references tohw
: it does not yet make any references at all, because all the references it makes are ineg1.o
.So the linker does not add
my_lib.o
to the program and has no further use forlibmy_lib.a
.Next, it finds
eg1.o
, and adds it to be program. An object file in the linkage sequence is always added to the program. Now, the program makes a reference tohw
, and does not contain a definition ofhw
; but there is nothing left in the linkage sequence that could provide the missing definition. The reference tohw
ends up unresolved, and the linkage fails.Second,example 2, with shared library
libz
A shared library isn't an archive of object files or anything like it. It's much more like a program that doesn't have a
main
function and instead exposes multiple other symbols that it defines, so that other programs can use them at runtime.Many Linux distros today configure their GCC toolchain so that its language drivers (
gcc
,g++
,gfortran
etc) instruct the system linker (ld
) to link shared libraries on an as-needed basis. You have got one of those distros.This means that when the linker finds
-lz
in the linkage sequence, and figures out that this refers to the shared library (say)/usr/lib/x86_64-linux-gnu/libz.so
, it wants to know whether any references that it has added to your program that aren't yet defined have definitions that are exported bylibz
If that is true, then the linker will not copy any chunks out of
libz
and add them to your program; instead, it will just doctor the code of your program so that:-libz
into the same process as your program whenever it loads a copy of your program, to run it.libz
, that reference uses the definition exported by the copy oflibz
in the same process.Your program wants to refer to just one thing that has a definition exported by
libz
, namely the functionzlibVersion
, which is referred to just once, ineg2.c
. If the linker adds that reference to your program, and then finds the definition exported bylibz
, the reference is resolvedBut when you try to link the program like:
the order of events is wrong in just the same way as with example 1. At the point when the linker finds
-lz
, there are no references to anything in the program: they are all ineg2.o
, which has not yet been seen. So the linker decides it has no use forlibz
. When it reacheseg2.o
, adds it to the program, and then has undefined reference tozlibVersion
, the linkage sequence is finished; that reference is unresolved, and the linkage fails.Lastly, the
pkg-config
variation of example 2 has a now obvious explanation. After shell-expansion:becomes:
which is just example 2 again.
I can reproduce the problem in example 1, but not in example 2
The linkage:
works just fine for you!
(Or: That linkage worked fine for you on, say, Fedora 23, but fails on Ubuntu 16.04)
That's because the distro on which the linkage works is one of the ones that does not configure its GCC toolchain to link shared libraries as-needed.
Back in the day, it was normal for unix-like systems to link static and shared libraries by different rules. Static libraries in a linkage sequence were linked on the as-needed basis explained in example 1, but shared libraries were linked unconditionally.
This behaviour is economical at linktime because the linker doesn't have to ponder whether a shared library is needed by the program: if it's a shared library, link it. And most libraries in most linkages are shared libraries. But there are disadvantages too:-
-lfoo
in their linkage is going to resolve to/some/where/libfoo.a
or to/some/where/libfoo.so
, and might not understand the difference between shared and static libraries anyway.This trade-off has led to the schismatic situation today. Some distros have changed their GCC linkage rules for shared libraries so that the as-needed principle applies for all libraries. Some distros have stuck with the old way.
Why do I still get this problem even if I compile-and-link at the same time?
If I just do:
surely gcc has to compile
eg1.c
first, and then link the resulting object file withlibmy_lib.a
. So how can it not know that object file is needed when it's doing the linking?Because compiling and linking with a single command does not change the order of the linkage sequence.
When you run the command above,
gcc
figures out that you want compilation + linkage. So behind the scenes, it generates a compilation command, and runs it, then generates a linkage command, and runs it, as if you had run the two commands:So the linkage fails just as it does if you do run those two commands. The only difference you notice in the failure is that gcc has generated a temporary object file in the compile + link case, because you're not telling it to use
eg1.o
. We see:instead of:
See also
The order in which interdependent linked libraries are specified is wrong
Putting interdependent libraries in the wrong order is just one way in which you can get files that need definitions of things coming later in the linkage than the files that provide the definitions. Putting libraries before the object files that refer to them is another way of making the same mistake.
b4lqfgs411#
因为当涉及到链接器错误时,人们似乎被定向到这个问题上,所以我将在这里补充这一点。
GCC 5.2.0的链接器错误的一个可能原因是现在默认选择了一个新的libstdc++库ABI。
如果您收到有关对涉及std::__cxx11命名空间或标记[abi:cxx11]中的类型的符号的未定义引用的链接器错误,则可能表示您正试图将使用不同的_GLIBCXX_USE_CXX11_ABI宏值编译的目标文件链接在一起。当链接到使用较旧版本的GCC编译的第三方库时,通常会发生这种情况。如果第三方库不能用新的ABI重新构建,那么您将需要用旧的ABI重新编译代码。
因此,如果您在切换到5.1.0之后的GCC时突然遇到链接器错误,这将是一件需要检查的事情。
jdgnovmf12#
链接的.lib文件与.dll关联
我也有同样的问题。假设我有项目MyProject和TestProject。我已经有效地将MyProject的库文件链接到TestProject。然而,这个库文件是在构建MyProject的DLL时生成的。此外,我没有包含MyProject中所有方法的源代码,而只是访问了DLL的入口点。
为了解决这个问题,我将MyProject构建为Lib,并将TestProject链接到这个.lib文件(我将生成的.lib文件复制粘贴到TestProject文件夹中)。然后,我可以将MyProject重新构建为DLL。它正在编译,因为TestProject所链接的库确实包含MyProject中类中所有方法的代码。
vmjh9lq913#
A bug in the compiler/IDE
I recently had this problem, and it turned out it was a bug in Visual Studio Express 2013. I had to remove a source file from the project and re-add it to overcome the bug.
Steps to try if you believe it could be a bug in compiler/IDE:
2w3kk1z514#
Use the linker to help diagnose the error
Most modern linkers include a verbose option that prints out to varying degrees;
For gcc and clang; you would typically add
-v -Wl,--verbose
or-v -Wl,-v
to the command line. More details can be found here;For MSVC,
/VERBOSE
(in particular/VERBOSE:LIB
) is added to the link command line./VERBOSE
linker option.yyyllmsg15#
Suppose you have a big project written in c++ which has a thousand of .cpp files and a thousand of .h files.And let's says the project also depends on ten static libraries. Let's says we are on Windows and we build our project in Visual Studio 20xx. When you press Ctrl + F7 Visual Studio to start compiling the whole solution ( suppose we have just one project in the solution )
What's the meaning of compilation ?
The Second step of compilation is done by Linker.Linker should merge all the object file and build finally the output ( which may be an executable or a library)
Steps In Linking a project
error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)
Observation
How To Solve this kind of error
Compiler Time Error :
Linker Time Error
#pragma once
for allowing compiler not to include one header if it was already included in the current .cpp which are compiled