包括静态库中的头文件

伊桑·麦克塔格

我正在测试C静态库和程序。该库代码位于我的项目的子目录“ foo”中,包含以下文件:

foo / foo.c:

#include <stdio.h>
void foo(void) {
    printf("something");
}

foo / foo.h:

#ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif

我的程序代码如下:

test.c:

#include "foo.h"
int main() {
    foo();
    return 0;
}

我有一个名为“ build”的构建脚本,其中包含以下内容:

建立:

#!/bin/bash
gcc -c -Wall -Werror foo/foo.c
ar rcs libfoo.a foo.o
gcc -static -o test test.c libfoo.a # I have also tried -L. -lfoo

但是当我运行build时,它给了我以下错误:

test.c:1:17: fatal error: foo.h: No such file or directory
  #include "foo.h"
                  ^
Compilation terminated

但是,当我省略#include行时,它确实可以工作,但是如果可以在我的静态库中使用头文件,我会更喜欢。我在做什么错,该如何解决?

乔纳森·莱夫勒

标头未存储在库中。标头与库分开存储。库包含目标文件;标头不是目标文件。默认情况下,Unix系统上的标准标头存储在/usr/include例如,您通常会找到/usr/include/stdio.hand/usr/include/string.h/usr/include/stdlib.h默认情况下,库存储在中/usr/lib(但您也可以在中找到/lib)。通常,编译器也被配置为也可以在其他地方查找。在下方是一个常见的替代位置/usr/local,因此/usr/local/include对于标头和/usr/local/lib库而言。还要注意,单个库可能有许多定义服务的标头。默认库是一个示例。它有着与那些中发现的功能<stdio.h><string.h><stdlib.h>和许多其他头了。

查看您的代码:

  1. 如果头文件位于中./foo/foo.h,则需要编写:

    #include "foo/foo.h"
    

    或者,如果您继续使用#include "foo.h",则需要使用以下参数指定在编译器命令行中查找标头的位置:

    gcc -Ifoo -o test test.c -L. -lfoo
    

    我故意排除了-static; 只有在静态库和共享库之间进行选择时才有必要,但是只有libfoo.a,所以链接器仍然会使用它。

    请注意,问题是编译错误,而不是链接错误。如果将程序构建分为两个步骤,这将更加清楚:(1)创建test.o和(2)链接程序:

    gcc -c -Ifoo test.c
    gcc -o test test.o -L. -lfoo
    
  2. 您的页眉防护出现故障。您原来有(但是已经更新了问题,所以不再出现此错字):

    #ifndef foo_h__
    #define foo_h_
    

    你需要:

    #ifndef foo_h__
    #define foo_h__
    

    这两行中的宏名称必须相同。请注意,在这种情况下,拼写错误几乎是无害的-但在Mac OS X上,clang(伪装为gcc)确实对此给出了警告(尽管我在进行任何编译之前就已经发现了它)。在某些其他情况下,您将无法获得标头保护程序旨在提供的保护。

    ./foo/foo.h:1:9: warning: 'foo_h__' is used as a header guard here, followed by #define of a
          different macro [-Wheader-guard]
    #ifndef foo_h__
            ^~~~~~~
    ./foo/foo.h:2:9: note: 'foo_h_' is defined here; did you mean 'foo_h__'?
    #define foo_h_
            ^~~~~~
            foo_h__
    1 warning generated.
    

您可能会合理地怀疑:

  • 如果-Ifoo在编译时需要test.c,为什么在编译时没有必要foo/foo.c

好问题!

  1. 不会伤害到 foo/foo.c
  2. GCC在找到翻译单元源代码的目录中查找标头(因此,在编译时foo/foo.c,它在foo目录中查找#include "foo.h"反正包含的标头
  3. 源文件也foo/foo.c应该包含在内foo.h这样做非常重要,因为这就是编译器提供必要的交叉检查以确保一致性的方式。如果您已编写#include "foo.h",则编译将按说明进行。如果你写了(在foo/foo.c#include "foo/foo.h",则用于创建命令行foo.o会需要-I.这样的标题可能被发现。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章