【问题标题】:Header Files in Multiple Directories: Best Practices多个目录中的头文件:最佳实践
【发布时间】:2009-02-28 15:37:14
【问题描述】:

我是 C 新手

我用动态语言(javascript、python、haskell 等)编写了大量代码,但我现在正在为研究生学习 C,但我不知道自己在做什么。

问题

最初,我使用 makefile 在一个目录中构建我的所有源代码,效果非常好。但是,我的项目正在增长,我想将源代码拆分为多个目录(单元测试、实用程序、核心等)。例如,我的目录树可能如下所示:

.
|-- src
|   |-- foo.c
|   |-- foo.h
|   `-- main.c
`-- test
    `-- test_foo.c

test/test_foo.c 同时使用src/foo.csrc/foo.h。使用makefile,构建它的最佳/标准方法是什么?最好有一种规则用于构建项目,另一种规则用于构建测试。

注意

我知道还有其他方法可以做到这一点,包括 autoconf 和其他自动解决方案。但是,我想了解正在发生的事情并能够从头开始编写 makefile,尽管它可能不切实际。

任何指导或提示将不胜感激。谢谢!

[编辑]

所以目前给出的三种解决方案如下:

  • 将全局使用的头文件放在并行的include目录中
  • 使用#include 语句中的路径,如#include "../src/foo.h"
  • 使用-I 开关通知编译器包含位置

到目前为止,我喜欢-I switch 解决方案,因为它不涉及在目录结构更改时更改源代码。

【问题讨论】:

  • +1 用于 -I 开关,这是最灵活的方式。顺便说一下,将公共头文件放在专用的包含目录中没有问题(任何方式都是好的做法)并使用 -I 提供该目录的路径(灵活性)。

标签: c makefile header-files


【解决方案1】:

对于 test_foo.c,您只需要告诉编译器在哪里可以找到头文件。例如。

gcc -I../src -c test_foo.c

然后编译器也会在这个目录中查找头文件。然后在 test_foo.c 中编写:

#include "foo.h"

编辑: 要链接到 foo.c,实际上是针对 foo.o,您需要在目标文件列表中提及它。我假设你已经有了目标文件,然后再做:

gcc test_foo.o ../src/foo.o -o test

【讨论】:

  • 这不会包括 foo.c 对吧?我应该确保将其作为构建 test_foo.c 的依赖项包含在内?
  • 你想直接包含 foo.c 吗?这也有效,即#include“foo.c”。如果你想链接它,你必须在对象列表中列出它。
  • 我可以在使用编译器时看到它是如何工作的 - 但是智能感知如何知道头文件在哪里?
  • 部分回答我自己的问题:如果使用 cmake 和 vscode,那么c_cpp_properties.json 可以包含以下键值对:"configurationProvider": "ms-vscode.cmake-tools" 即 cmake-tools 扩展可以读取 cmake(它定义了哪些目录通过target_include_directories 使用-I 选项提供给编译器),因此可以告诉智能感知在哪些目录中搜索头文件
【解决方案2】:

我也很少使用 GNU 自动工具。相反,我将在根目录中放置一个手工制作的 makefile。

要获取源目录中的所有标题,请使用以下内容:

get_headers = $(wildcard $(1)/*.h)
headers := $(call get_headers,src)

然后,您可以使用以下方法使测试目录中的目标文件依赖于这些头文件:

test/%.o : test/%.c $(headers)
    gcc -std=c99 -pedantic -Wall -Wextra -Werror $(flags) -Isrc -g -c -o $@ $<

如您所见,我不喜欢内置指令。还要注意-I 开关。

获取目录的目标文件列表稍微复杂一些:

get_objects = $(patsubst %.c,%.o,$(wildcard $(1)/*.c))
test_objects = $(call get_objects,test)

以下规则将为您的测试创建对象:

test : $(test_objects)

test 规则不应该只生成目标文件,还应该生成可执行文件。如何编写规则取决于您的测试结构:例如,您可以为每个 .c 文件创建一个可执行文件,或者只创建一个测试所有文件的可执行文件。

【讨论】:

  • 从源文件中获取目标文件,你也可以简单的做:SRC_OBJECTS := $(SRC_FILES:.c=.o)
【解决方案3】:

这样做的一种常见方法是将单个 C 文件使用的头文件命名为与该 C 文件相同且位于同一目录中,以及许多 C 文件使用的头文件(尤其是整个 C 文件使用的头文件) project) 位于与 C 源目录平行的目录 include 中。

【讨论】:

  • 我会使用-I 告诉 gcc 这些文件,就像 quinmars 的回答一样吗?
  • 您有两个选择。要么使用从源文件到包含文件的相对路径,要么在#include 行中根本不包含任何路径而使用'-I'。你的选择。我都看到了。
【解决方案4】:

您的测试文件应该直接使用相对路径包含头文件,如下所示:

#include "../src/foo.h"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-22
    • 2010-10-04
    • 2012-05-07
    • 2013-03-03
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 2012-05-03
    相关资源
    最近更新 更多