包括来自静态库的头文件

时间:2014-12-26 18:43:23

标签: c gcc static-libraries header-files .a

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

富/ foo.c的:

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

富/ foo.h中:

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

我的编程代码如下:

test.c的:

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

我有一个名为&#39; build&#39;的构建脚本,其中包含以下内容:

构建

#!/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行时,它确实有效,但我更喜欢在静态库中使用头文件。我做错了什么,我该如何解决?

1 个答案:

答案 0 :(得分:26)

标头不存储在库中。标题与库分开存储。库包含目标文件;标头不是目标文件。默认情况下,Unix系统上的标准头文件存储在/usr/include中 - 例如,您通常会找到/usr/include/stdio.h/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.
    
  3. 你可能会合理地怀疑:

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

    好问题!

    1. 这不会伤害foo/foo.c
    2. 的汇编
    3. GCC在找到翻译单元源代码的目录中查找标题(因此,在编译foo/foo.c时,它会在foo目录中查找包含为#include "foo.h"的标题
    4. 源文件foo/foo.c也应包含foo.h;这是非常重要的,因为编译器提供了确保一致性所必需的交叉检查。如果您已编写#include "foo.h",则编译将按所述方式工作。如果你写了(foo/foo.c#include "foo/foo.h",那么创建foo.o的命令行就需要-I.,因此可以找到标题。