为什么编译器抛出 "undefined reference to ..." 尽管在参数中提供了所有需要的库
Why does the compiler throw "undefined reference to ..." despite providing all needed libraries in the arguments
我正在开发一个程序,它将监视所选程序的使用情况并将其记录到 .csv 文件中。这样,当我在 full-screen 玩游戏时,我可以确定哪些程序使用了最多的特定资源。我像这样包含了 psapi header:
...
#include <psapi.h>
...
并且我使用 MinGW 的 G++ 进行编译,使用以下选项和我正在使用的函数的必要库(库来自函数的文档):g++ -lkernel32 -lpsapi test.cpp -o test.exe
但它仍然抛出错误:
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:\Users\james\AppData\Local\Temp\cclpYDm2.o:test.cpp:(.text+0x3e7): undefined reference to `GetProcessMemoryInfo@12'
collect2.exe: error: ld returned 1 exit status
我觉得要么我的图书馆出了问题,要么我做错了什么。我试过用 "extern "C"" 包围 header,但我仍然得到完全相同的消息。我还验证了该库存在;如果没有,编译器会抛出一个不同的错误。 #pragma comment
也不起作用,使用 -static
标志也没有效果。我还尝试定义 PSAPI_VERSION 宏并将其设置为 1,将其放在 psapi 的 include 语句之前。
TL;DR:尽管有正确的库,编译器仍抛出未定义的引用错误。我怀疑是:
- 库安装不正确
- 我在链接时做错了
请试试这个。您提供给 g++ 的参数顺序实际上很重要。始终将库放在参数的末尾。
g++ -o test.exe test.cpp -lkernel32 -lpsapi
g++ 工具链首先会经过test.cpp
并将其编译成一个二进制目标文件,这是一个临时文件,名字很有趣,但我们暂时称它为test.o
。此时test.o
中还有部分函数引用无法解析
然后,g++ 工具链看到 -lkernel32
,然后是 -lpsapi
。它依次进入这两个库并为您找到 test.o
中缺少的功能。
如果是静态链接,它会从库中复制需要的函数编译后的二进制代码拼接成test.o
。如果你是动态链接,它会设置一些"entry"到动态库。
这就是顺序很重要的原因。编译器工具链将仅复制(设置入口)那些需要的函数,因为库通常非常大并且包含许多其他函数你真的不需要。当当前不需要库中的任何内容时,就像您最初编写的命令一样,g++ 不需要从 运行 之前的 -lkernel32 -lpsapi
到 test.cpp
,它只会跳过这些库。
简而言之,如果lib_a
依赖于lib_b
,你应该在参数中把lib_a
放在lib_b
之前。在 lib_x
依赖于 lib_y
又依赖于 lib_x
的极少数情况下,您必须编写类似 g++ file.cpp lib_x lib_y lib_x
.
的内容
请注意,此规则仅适用于图书馆。 所有源文件中的函数将保存在二进制目标文件中。因此,即使 file_x
依赖于 file_y
,写 g++ file_y.cpp file_x.cpp
也是可以的,因为所有函数都保留在 file_y.o
和 file_x.o
中,当将它们链接在一起时,链接器可以找到它们。
相关问题:GCC C++ Linker errors: Undefined reference to 'vtable for XXX', Undefined reference to 'ClassName::ClassName()'
我正在开发一个程序,它将监视所选程序的使用情况并将其记录到 .csv 文件中。这样,当我在 full-screen 玩游戏时,我可以确定哪些程序使用了最多的特定资源。我像这样包含了 psapi header:
...
#include <psapi.h>
...
并且我使用 MinGW 的 G++ 进行编译,使用以下选项和我正在使用的函数的必要库(库来自函数的文档):g++ -lkernel32 -lpsapi test.cpp -o test.exe
但它仍然抛出错误:
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:\Users\james\AppData\Local\Temp\cclpYDm2.o:test.cpp:(.text+0x3e7): undefined reference to `GetProcessMemoryInfo@12'
collect2.exe: error: ld returned 1 exit status
我觉得要么我的图书馆出了问题,要么我做错了什么。我试过用 "extern "C"" 包围 header,但我仍然得到完全相同的消息。我还验证了该库存在;如果没有,编译器会抛出一个不同的错误。 #pragma comment
也不起作用,使用 -static
标志也没有效果。我还尝试定义 PSAPI_VERSION 宏并将其设置为 1,将其放在 psapi 的 include 语句之前。
TL;DR:尽管有正确的库,编译器仍抛出未定义的引用错误。我怀疑是:
- 库安装不正确
- 我在链接时做错了
请试试这个。您提供给 g++ 的参数顺序实际上很重要。始终将库放在参数的末尾。
g++ -o test.exe test.cpp -lkernel32 -lpsapi
g++ 工具链首先会经过test.cpp
并将其编译成一个二进制目标文件,这是一个临时文件,名字很有趣,但我们暂时称它为test.o
。此时test.o
中还有部分函数引用无法解析
然后,g++ 工具链看到 -lkernel32
,然后是 -lpsapi
。它依次进入这两个库并为您找到 test.o
中缺少的功能。
如果是静态链接,它会从库中复制需要的函数编译后的二进制代码拼接成test.o
。如果你是动态链接,它会设置一些"entry"到动态库。
这就是顺序很重要的原因。编译器工具链将仅复制(设置入口)那些需要的函数,因为库通常非常大并且包含许多其他函数你真的不需要。当当前不需要库中的任何内容时,就像您最初编写的命令一样,g++ 不需要从 运行 之前的 -lkernel32 -lpsapi
到 test.cpp
,它只会跳过这些库。
简而言之,如果lib_a
依赖于lib_b
,你应该在参数中把lib_a
放在lib_b
之前。在 lib_x
依赖于 lib_y
又依赖于 lib_x
的极少数情况下,您必须编写类似 g++ file.cpp lib_x lib_y lib_x
.
请注意,此规则仅适用于图书馆。 所有源文件中的函数将保存在二进制目标文件中。因此,即使 file_x
依赖于 file_y
,写 g++ file_y.cpp file_x.cpp
也是可以的,因为所有函数都保留在 file_y.o
和 file_x.o
中,当将它们链接在一起时,链接器可以找到它们。
相关问题:GCC C++ Linker errors: Undefined reference to 'vtable for XXX', Undefined reference to 'ClassName::ClassName()'