【问题标题】:Undefined reference to 'pthread_create' — linker command option order (libraries before/after object files?) [duplicate]对'pthread_create'的未定义引用-链接器命令选项顺序(目标文件之前/之后的库?)[重复]
【发布时间】:2012-03-04 10:08:48
【问题描述】:

当我尝试编译它时,我收到一个特定的错误。但是,这是不可能的,因为我使用了正确的标志。在server.c 中有库pthread.h。 那么,我该如何解决我的链接问题呢? 我正在使用 Linux(Ubuntu)。

make
gcc -c -Wall -Wunused -ansi -pedantic -ggdb  -o Server1.o Server.c
gcc -c -Wall -Wunused -ansi -pedantic -ggdb  Util.c
gcc -o Server1.exe -Wall -Wunused -ansi -pedantic -ggdb -lpthread -lm Server1.o Util.o
Server1.o: In function `main':
/home/ruggero/ruggero_fine/Server.c:1002: undefined reference to `pthread_create'
collect2: ld returned 1 exit status
make: *** [Server1.exe] Errore 1

【问题讨论】:

  • 你试过-pthread(没有'l')吗?见stackoverflow.com/questions/1662909/…
  • headerpthread.h;不过,那不是图书馆。该库将具有诸如 libpthread.so 之类的名称(在链接时;在运行时具有诸如 libpthread.so.1 之类的名称)。

标签: c ubuntu linker pthreads


【解决方案1】:

在目标文件之后列出库

仅链接目标文件和库时,在目标文件之后列出库:

gcc -o Server1.exe -Wall -Wunused -ansi -pedantic -ggdb  Server1.o Util.o -lpthread -lm

当链接命令包含源文件时,在库之前列出源文件和目标文件(如果有)。因此,-l 选项位于命令行的末尾。指定库所在位置的相关-L 选项应位于指定库的-l 选项之前。

次要问题是:

为什么会起作用?

当 C 编译器调用链接器时,它告诉链接器拉入一些名称类似于 crt0.o 的系统目标文件,并告诉它查找符号 main(或者可能是 _main(),具体取决于本地命名约定)。它还按照您在命令行中指定的顺序提供目标文件和库。当它遇到一个目标文件时,链接器会记录它提供的定义,以及它所做的不满意的引用。当它遇到一个库时,它会扫描该库以查看它是否可以满足任何不满足的引用。如果该库可以提供任何尚未满足的引用,那么它会在“可执行文件”中包含该库的(相关部分)。对于共享库,链接器确保库将在运行时加载。对于静态库,链接器包括库中至少满足一个引用的目标文件,重新扫描直到没有其他引用可以满足。如果库不满足引用,则将其忽略。该过程完成后,如果任何引用仍未满足,您会收到错误消息。

因此,在您的场景中,您在 Server1.oUtil.o 之前有 -lpthread。由于-lpthread 没有提供main 函数并且这是唯一相关的不满足符号,因此它被忽略了。数学库-lm 也可能已被忽略,或者它可能是一个空存根,用于保存为数学库与主 C 库分开的其他系统设计的代码。然后链接器读取您的目标文件,并找到对pthread_create() 的引用。之后扫描 C 库 -lc (libc.so) 时,发现符号满足除 pthread_create 之外的所有内容。

当库在目标文件之后列出时,链接器在扫描-lpthread 时就知道它需要pthread_create,并确保在运行时加载共享库。

GNU ld--as-needed 选项

上面的讨论本质上是平台中立的。如果您遵循“目标文件后的库”规则,您的链接器行在所有平台上都能正常工作的最大机会。

如果您在使用 GNU binutils 包,尤其是 GNU ld 命令的系统上,您可能会发现不同的行为。

来自Sourceware 的手册(如果您尝试http://www.gnu.org/software/binutils/manuals,您会被重定向到这里)包含以下信息:

--as-needed
--no-as-needed
此选项会影响--as-needed 选项后命令行中提到的动态库的 ELF DT_NEEDED 标记。通常,链接器将为命令行中提到的每个动态库添加一个 DT_NEEDED 标记,无论该库是否实际需要。 --as-needed 导致 DT_NEEDED 标记仅针对链接中的该点满足来自常规对象文件的非弱未定义符号引用的库发出,或者,如果在其他库的 DT_NEEDED 列表中找不到该库,来自另一个动态库的非弱未定义符号引用。在相关库之后出现在命令行上的目标文件或库不会影响是否根据需要查看该库。这类似于从档案中提取目标文件的规则。 --no-as-needed 恢复默认行为。

似乎不同系统的不同版本对as-needed 选项使用不同的值。虽然--no-as-needed 行为很方便,因为它允许您在命令行上以或多或少的任意顺序对库和目标文件进行排序,但这也意味着命令行上列出的所有库都在运行时加载,即使有库中没有实际使用的符号(因此--no-as-needed 等效于假设的--whether-needed-or-not 标志)。使用 --as-needed 选项是经典且可移植的行为。

有传言说,一些 Linux 发行版在过去 5 年左右(第三个千年的第二个十年上半叶,为了争论)的某个时候,将其系统上的默认行为从 --no-as-needed 更改为 --as-needed )。您可以在一些关于 SO 的问题中找到支持这一谣言的证据。

【讨论】:

  • 对,它有效。你能解释一下为什么吗?
  • 我一直以为gcc是从右到左解析的,所以库需要列在最后,保证先加载。
  • @Neo:我从未听说过链接器会这样做。这与“没有链接器可以做到这一点”不太一样,但是在我一直在 Unix 系统上工作的所有时间里,我工作过的所有 Unix 系统都有从左到右通过参数列表。当然,这只是 25 年多一点的经验,只有十几个 Unix 变体(宙斯,有人吗?),但我从未听说过像你描述的逆向系统。而且,具体来说,我目前使用的 GCC 系统(MacOS X、Linux、HP-UX、AIX、Solaris、Cygwin)都不能从右到左工作。
  • 啊!也许这是我误解/误解的事情。并且错误.. 如果我的评论听起来像是我想说你错了或其他什么,那不是我的意图。 :) 还有 25 年!呜呜呜!
  • 精彩的答案。我只是好奇,这种行为是否记录在案?至少对于 gcc?
【解决方案2】:

编译时使用-pthread。试试吧,你会解决你的问题

【讨论】:

    猜你喜欢
    • 2013-06-20
    • 2021-06-18
    • 1970-01-01
    • 2016-12-10
    • 2018-01-22
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多