链接器找不到符号,但库已被读取且符号存在。

8

我一直在尝试编译我的项目,但是出现了“未定义引用”错误。例如:

installertest.cpp:(.text+0x9d1): undefined reference to `XmlRpcValue::makeArray()'
...
installertest.cpp:(.text+0xede): undefined reference to `dbcancel'
installertest.cpp:(.text+0xefd): undefined reference to `dbfcmd'
installertest.cpp:(.text+0xf0f): undefined reference to `dbsqlexec'
installertest.cpp:(.text+0xf2d): undefined reference to `SHA1_Init'
...

我的命令行是:

g++ -o installertest \
    -lsybdb \
    -lxmlrpc \
    -lxmlrpc_cpp \
    -lxmlrpc_xmlparse \
    -lxmlrpc_xmltok \
    -lxmlrpc_util \
    -lxmlrpc++ \
    -lxmlrpc_server_cgi \
    -lssl \
    -std=c++0x \
    ContractData.o installertest.o

objdump -T 显示符号在 .so 文件中。例如:

libsybdb.so:
...
0000000000011c30 g    DF .text  0000000000000083  Base        dbcancel
...

/usr/lib/libxmlrpc_cpp.so:
...
0000000000002e78 g    DF .text  0000000000000092  Base        _ZN11XmlRpcValue9makeArrayEv
...

strace 显示链接器正在打开和读取库文件:

...
[pid  5019] stat("/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/libsybdb.so", {st_mode=S_IFREG|0644, st_size=421608, ...}) = 0
[pid  5019] open("/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/libsybdb.so", O_RDONLY) = 7
[pid  5019] fcntl(7, F_GETFD)           = 0
[pid  5019] fcntl(7, F_SETFD, FD_CLOEXEC) = 0
[pid  5019] fstat(7, {st_mode=S_IFREG|0644, st_size=421608, ...}) = 0
[pid  5019] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b16c200c000
[pid  5019] lseek(7, 0, SEEK_SET)       = 0
[pid  5019] read(7, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\0\0\0\0\0\0"..., 4096) = 4096
...
[pid  5019] stat("/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/libxmlrpc.so", {st_mode=S_IFREG|0644, st_size=80936, ...}) = 0
[pid  5019] open("/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/libxmlrpc.so", O_RDONLY) = 8
[pid  5019] fcntl(8, F_GETFD)           = 0
[pid  5019] fcntl(8, F_SETFD, FD_CLOEXEC) = 0
[pid  5019] fstat(8, {st_mode=S_IFREG|0644, st_size=80936, ...}) = 0
[pid  5019] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b16c200d000
[pid  5019] lseek(8, 0, SEEK_SET)       = 0
[pid  5019] read(8, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300?\0\0\0\0\0\0"..., 4096) = 4096
...

所有文件都针对x86-64,C库的头文件为extern "C"。我已经尝试了我所能想到的一切方法,但它仍然无法链接。
我甚至尝试删除所有C++11代码并在没有命令行开关的情况下进行编译,但仍然没有作用。
我的系统是Ubuntu Precise (12.04) 64-bit,使用g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3。所有软件包都从软件包管理器中安装,开发软件包已经安装。 编辑(2017-05-30)被标记为https://dev59.com/Z3VD5IYBdhLWcg3wO5AD的重复问题。其他问题问为什么参数顺序很重要。当提出这个问题时,不知道参数顺序会成为一个问题。
此外,之前的问题没有任何有用的扩展内容,而这个问题显示了手头的问题。以前的问题可以被视为对这个问题答案的有益扩展,但不是重复。

嗨,Ben。你能教我如何使用strace来检查进程吗?我的主要困难在于如何获取PID,因为编译过程非常快地结束了。我只使用ps aux | grep来获取PID,但是进程已经死亡了。 - William
@XingWang,没问题。你只需要在命令行前加上"strace -f -e trace=all"。根据你的系统,可能还需要加上"sudo"。所以,以我的例子为例:"strace -f -e trace=all g++ -o installertest ContractData.o installertest.o"... - Ben Jaguar Marshall
1个回答

14

你必须在目标文件之后放置库的链接器标志。 因此,而不是

g++ -o installertest \
-lsybdb \
-lxmlrpc \
-lxmlrpc_cpp \
-lxmlrpc_xmlparse \
-lxmlrpc_xmltok \
-lxmlrpc_util \
-lxmlrpc++ \
-lxmlrpc_server_cgi \
-lssl \
-std=c++0x \
ContractData.o installertest.o

使用

g++ -o installertest \
ContractData.o installertest.o \
-lsybdb \
-lxmlrpc \
-lxmlrpc_cpp \
-lxmlrpc_xmlparse \
-lxmlrpc_xmltok \
-lxmlrpc_util \
-lxmlrpc++ \
-lxmlrpc_server_cgi \
-lssl \
-std=c++0x

2
刚刚试了一下,居然成功了。真的吗?简单到我都不敢相信。 - Ben Jaguar Marshall
6
对于其他遇到这个问题的人,这里是推理过程。似乎现在gcc向ld发送链接器标志--as-needed。这将导致丢弃任何指定的库,如果这些库没有需要用于链接的符号。在第一种情况下,所有库都被丢弃,因为没有未解决的符号,然后在链接阶段找不到这些符号。在第二种情况下,ld收集了未解决符号列表,然后在指定的库中找到它们,并在实际链接阶段保留它们。 - Ben Jaguar Marshall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接