包括来自静态库的头文件

Eth*_*gue 14 c gcc header-files static-libraries .a

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

富/ foo.c的:

#include <stdio.h>
void foo(void) {
    printf("something");
}
Run Code Online (Sandbox Code Playgroud)

富/ foo.h中:

#ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif
Run Code Online (Sandbox Code Playgroud)

我的程序代码如下:

test.c的:

#include "foo.h"
int main() {
    foo();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我有一个名为"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
Run Code Online (Sandbox Code Playgroud)

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

test.c:1:17: fatal error: foo.h: No such file or directory
  #include "foo.h"
                  ^
Compilation terminated
Run Code Online (Sandbox Code Playgroud)

但是,当我省略#include行时,它确实有效,但我更喜欢在静态库中使用头文件.我做错了什么,我该如何解决?

Jon*_*ler 28

标头不存储在库中.标题与库分开存储.库包含目标文件; 标头不是目标文件.默认情况下,在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"
    
    Run Code Online (Sandbox Code Playgroud)

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

    gcc -Ifoo -o test test.c -L. -lfoo
    
    Run Code Online (Sandbox Code Playgroud)

    我故意排除了-static; 只有在静态库和共享库之间做出选择时才有必要,但是你只有libfoo.a,所以链接器无论如何都会使用它.

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

    gcc -c -Ifoo test.c
    gcc -o test test.o -L. -lfoo
    
    Run Code Online (Sandbox Code Playgroud)
  2. 你的头部防守有问题.你最初有(但已经更新了问题所以这个错字不再存在):

    #ifndef foo_h__
    #define foo_h_
    
    Run Code Online (Sandbox Code Playgroud)

    你需要:

    #ifndef foo_h__
    #define foo_h__
    
    Run Code Online (Sandbox Code Playgroud)

    两个行中的宏名称必须相同.请注意,在这种情况下,拼写错误几乎是无害的 - 但在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.
    
    Run Code Online (Sandbox Code Playgroud)

你可能合理地想知道:

  • 如果我-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",则编译将按所述方式工作.如果你写了(in foo/foo.c)#include "foo/foo.h",那么创建命令行foo.o就需要了,-I.所以可以找到标题.