【问题标题】:Static Library Include Issue in CC 中的静态库包含问题
【发布时间】:2012-12-02 01:54:02
【问题描述】:

我按照以下教程创建了一个静态库。

http://tldp.org/HOWTO/Program-Library-HOWTO/static-libraries.html

http://www.adp-gmbh.ch/cpp/gcc/create_lib.html

http://www.cs.dartmouth.edu/~campbell/cs50/buildlib.html

我使用ar 工具在C 中生成了一个静态库。该库来自不同的目录。我正在正确生成库,并且我正在使用它来编译我的程序,如下所示:

gcc -lpthreads main.c -o server -L thread-pool -lthreadpool

当前目录下的库名为thread-pool,其中包含libthreadpool.a

根据教程,我需要在main.c 中包含我的.h 文件,如下所示:#include "threadpool.h"。 GCC 抛出一个错误,提示找不到 threadpool.h。这很明显,因为它位于不同的目录中。

当我包含为:#include threadpool/threadpool.h" 时,它会编译但实际上不起作用。它仍然无法识别这些功能。我不确定为什么会这样。我认为在编译静态库时,实际上您不需要实际发送.h 文件或任何源。

这里有什么问题?我该如何克服这个问题?

编辑:

我知道 .h 文件与静态库不同。我不知道为什么我上面所说的似乎让我在两者之间感到困惑。

无论如何,当使用静态库时,是否意味着我们还需要.h 文件并将其包含到源代码中,而不仅仅是使用静态库编译程序?

【问题讨论】:

  • 这里似乎有些混乱。 .h 文件的#include 以及与静态库的链接是分开的。 #include 的工作方式与往常一样,独立于任何库文件。
  • @ThomasPadron-McCarthy 我知道区别。请参阅上面的编辑。
  • 好的。但如前所述,.h 文件的#include 和与库文件的链接是分开的,我不明白为什么你认为链接会以某种神奇的方式让你跳过#include?我会尝试在答案中写一个更长的解释。
  • 我猜是因为我用它编译了它。好吧,无论如何,我正确地进行了包含,但由于某种原因它仍然无法正常工作。
  • 不,你没有用它编译。但我试图在下面的回答中更清楚地解释。

标签: c gcc static-libraries


【解决方案1】:

库和标头是两个不同(尽管相关)的东西。您还可以通过编译器选项解决您的问题,为编译器提供一个额外的目录来查找头文件:

gcc -lpthreads -I threadpool main.c -o server -L thread-pool -lthreadpool

由于您的threadpool 库可能依赖于libpthread,您可能需要更改编译器命令行,使libpthreads 出现在libthreadpool 之后以避免链接问题:

gcc -I threadpool main.c -o server -L thread-pool -lthreadpool -lpthreads

实际上,首选选项是使用-pthread 选项,以确保正确链接pthread 库,并确保完成线程支持所需的任何其他编译器配置(-pthread 选项的顺序不t 似乎很重要):

gcc -pthread -I threadpool main.c -o server -L thread-pool -lthreadpool

在任何目标文件之后而不是在它们之前列出库(例如-lxyz)也是一个好主意。在某些系统上,它可以双向工作;在所有已知系统上,在目标文件之后列出库总是有效的。

【讨论】:

  • 所以当一个人想要使用一个静态库时,也必须有.h文件,并且包括那个?无论如何,这样做是行不通的。即使包含#include threadpool/threadpool.h,我在尝试使用那里的功能时也会出错。
  • 一般来说,是的 - 要构建程序,头文件必须在编译时可用并包含在内,库必须在链接时可用并链接。要回答有关您继续遇到的错误的问题,我们需要有关这些错误的信息。
【解决方案2】:

正如 Michael Burr 所说,.h 文件的 #include 和与库文件的链接是两个不同(但相关)的东西。

当您构建一个由多个部分(例如多个 .c 源文件或库)组成的 C 程序时,该过程分两步完成。首先,单独的源 .c 文件被编译,也就是说,从 C 源代码翻译成可执行机器指令的模块。然后将程序所需的所有模块和库链接在一起,构建可执行文件。

静态动态链接的区别只是链接完成。从概念上讲,它们是一样的,但静态链接(带有静态库)是提前完成的,形成一个可以稍后运行的可执行文件,而动态链接是在执行前立即完成的。

链接的类型(静态或动态)根本不影响编译步骤。

在编译单个源文件期间,编译器需要为调用库函数生成代码。例如,如果一个库包含一个以 double 作为参数的函数 f,而源文件包含代码 f(7),编译器需要知道有一个名为 f 的函数,并且它需要一个 double 作为参数,因此编译器可以在实际调用函数 f 之前生成将整数 7 转换为双精度的代码。

这是通过将函数 declarations 放入 .h 文件中来完成的,然后将其包含在您的 .c 源文件中。例如,该声明可能如下所示:

void f(double);

这使得编译器能够生成正确的代码,并在出现错误时给出正确的警告和错误消息。

另一方面,该库包含已编译的函数定义,它是执行某些操作的函数的实际代码。

请注意,编译步骤与库文件关系不大,与静态链接或动态链接的区别无关。为了能够#include .h 文件,编译器需要知道在哪里可以找到 .h 文件。这可能与实际的库文件完全不同。库文件甚至不必存在于同一台计算机上,甚至根本不存在。执行#include 时,库中的实际函数可能尚未编写。

混淆的一个来源可能是 gcc 命令,

gcc -lpthreads main.c -o server -L thread-pool -lthreadpool

看起来它同时执行编译和链接。确实如此,但这只是为了方便起见,在幕后它仍然分两个单独的步骤完成。

【讨论】:

  • #include(和所有#prefixed 语句)不是编译过程本身的一部分,它们在预处理器编译之前被解析。此外,从技术上讲,头文件中函数的每个参数的类型也不是必需的...旧语法是: foo(a,b)int a,b;{function of a and b}... 只有富(一,乙);在标头中,稍后添加了类型检查,但编译器仍会编译旧样式。
  • 好吧,是否应该调用编译过程的预处理器部分是有争议的。但它当然可以被视为一个单独的步骤,甚至最初是一个单独的可执行程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
  • 2018-01-17
  • 1970-01-01
  • 2011-04-14
相关资源
最近更新 更多