C中的多个源文件 - makefile究竟如何工作?

Aeo*_*ife 26 c makefile file

我是C的初学者,我需要学习makefile的工作方式,而且我对C文件组合的工作方式有点困惑.假设我们有一个main.c,一个foo.c和一个bar.c. 如何编写代码以便main.c识别其他文件中的函数?另外,在foo.c和bar.c中,是在main函数中编写的所有代码还是我们需要编写其他函数来完成我们需要它们做的事情?我已经阅读了有关如何编写makefile的教程,并且它在大多数情况下都有意义,但我对它的基本后勤仍然有点困惑.

Gav*_*n H 27

通常情况下,您将为头文件中的其他文件定义函数,然后可以将其包含在main.c中.例如,请考虑以下代码段:

main.c中:

#include "foo.h"

int main(int argc, char *argv[]) {
    do_foo();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

foo.h中:

void do_foo();
Run Code Online (Sandbox Code Playgroud)

foo.c的:

#include <stdio.h>
#include "foo.h"

void do_foo() {
    printf("foo was done\n");
}
Run Code Online (Sandbox Code Playgroud)

会发生什么是将main.c转换为目标文件(main.o),并将foo.c转换为目标文件(foo.o).然后链接器将这两个文件链接在一起,这就是do_foo()main.c中的函数与foo.o中的函数"关联"的位置.

示例GCC命令:gcc -o myprogram main.c foo.c

示例makefile

myprogam: main.o foo.o
    gcc -o myprogram main.o foo.o

main.o: main.c foo.h
    gcc -c main.c

foo.o: foo.c foo.h
    gcc -c foo.c
Run Code Online (Sandbox Code Playgroud)

  • 使用真实选项卡缩进Makefile,如http://stackoverflow.com/a/9580615/1461060中所述 (4认同)

Kos*_*Kos 16

关于C/C++编译

如果有一组文件,通常会做两件事:

  • 将每个源文件(.c)编译为目标文件(.o)
  • 将所有目标文件链接到可执行文件.

源文件是独立的 - 您需要头文件才能提供有关给定模块中的函数的"信息"(声明),以便让任何其他模块使用它们.头文件不是自己编译的 - 它们是#include源文件的一部分.

请看下面的命令如何以及如何处理它们make.


关于makefile

Makefile是一组用于构建它们的目标和规则.一个目标是"东西可以在一个给定的文件建立和结果".(还存在"虚假"目标,这些目标不会导致文件,只是执行命令 - 调用常见的目标clean来删除编译结果).

每个目标有两个部分:

  • 依赖关系列表,"敏感性列表"(此目标所需的其他文件和目标)(之后:,以逗号分隔),
  • 用于构建此目标的shell命令列表(在上面,缩进)

考虑这个例子:

main: main.o module1.o module2.o
    g++ main.o module1.o module2.o -o main
Run Code Online (Sandbox Code Playgroud)

这意味着:"要构建文件main,我需要首先确保目标main.o,module1.o并且module2.o是最新的;然后我需要调用以下命令......".

这也可以改写为:

main: main.o module1.o module2.o
    gcc $^ -o $@
Run Code Online (Sandbox Code Playgroud)

变量($以变​​量开头的所有内容)将扩展为依赖项列表和目标名称,如您所愿.

您可以定义自己的变量并按如下方式展开它们:

OBJS = main.o module1.o module2.o

main: $(OBJS)
    # code goes here
Run Code Online (Sandbox Code Playgroud)

您按如下方式编译单个翻译单元:

main.o: main.c
    gcc -c $< -o $@
    # note the -c option, which means: "compile, but don't link"
    # $< will expand to the first source file
Run Code Online (Sandbox Code Playgroud)

当main.c或其任何标头发生更改时,您可以添加标头依赖关系以重建main.o:

main.o: main.c module1.h module2.h
    gcc -c $< -o $@
Run Code Online (Sandbox Code Playgroud)

为了不反复编写相同的命令,您可以定义一般规则并提供依赖项(如果需要):

%.o: %.c
    gcc -c $< -o $@

main.o: main.c module1.h module2.h
module1.o: module1.c module1.h module2.h
Run Code Online (Sandbox Code Playgroud)

自动生成依赖项也有一些魔力(参见链接).使用Make的一个缺点是它不能单独完成(就像一些构建系统那样 - 就像SCons,我更喜欢C/C++).


Cli*_*ord 6

实质上,makefile 由以下形式的规则组成:

<this file> : <needs these files>
    <and is created by this command>
Run Code Online (Sandbox Code Playgroud)

通常,您至少有一个高级目标,如果其任何依赖项不存在,则 make 查找将该文件作为目标的规则。它会递归地执行此操作,直到解决了顶级目标的所有依赖项,然后再执行顶级命令(如果有的话 - 依赖项和命令都是规则中的可选字段)

make 文件可以具有基于模式的“默认规则”,并且有用于各种文件匹配场景的内置宏以及用户定义宏和嵌套 makefile 的包含。

我已将上述规则形式简化为最常见的情况。事实上,该命令根本不需要创建目标,它只是一个在依赖项中的所有文件都存在后执行的命令。此外,目标也不必是文件。通常,顶级目标是称为“all”或类似名称的“虚拟”目标。

当然,还有许多微妙之处和细微差别需要制作,所有这些都在手册中详细说明(特别是 GNU make,还有其他 make 实用程序)。