如何编写一个Makefile来编译一个简单的C程序

18

编译以下程序

#include <stdio.h>
int main(void)
{
   printf ("Hello from your first program!\n");
   return 0;
}

a) - 通过使用Makefile文件类型

b) - 可执行文件将被命名为Hello

“请帮我完成一项练习。我知道如何在CodeBlocks中完成它,但我不知道什么是Makefile以及如何在Linux中编写它。我使用命令"gcc filename.c"编译它,然后使用"./a.out"运行,但我仍然不理解Makefile是什么。它是一种类似于shell脚本的东西,还是指令?这个任务的Makefile应该长什么样?谢谢提前 :)”


12
你试过在谷歌搜索Makefile教程吗?请注意,我已经为你提供了链接。 - RedX
你尝试过CMake教程吗? - yegorich
3
因为某些原因,低级别的程序员确实参与了StackOverflow,但他们认为那里不是提供好答案和教授不懂的人的正确场所,仅仅是愤世嫉俗地提供链接或建议去阅读手册。¯_(ツ)_/¯ - Rafael Eyng
@RafaelEyng C++ 不是低级语言。 - ranemirusG
4个回答

24

这是用于“Hello World”程序的简单 makefile 文件。

CC      = gcc
CFLAGS  = -g
RM      = rm -f


default: all

all: Hello

Hello: Hello.c
    $(CC) $(CFLAGS) -o Hello Hello.c

clean veryclean:
    $(RM) Hello

假设您在一个目录中有两个名为 makefile.m1makefile.m2 makefiles ,如果您想要构建这两个makefile,那么请使用以下命令:

make -f makefile.m1 && make -f makefile.m2
make -f makefile.m1
make -f makefile.m2

或使用只包含以下内容的单个 Makefile:

m1:
  make -f makefile.m1

m2:
  make -f makefile.m2

并使用make m1make m2

现在让我们消除您对Makefile名称不需要的疑虑。

您可以随意命名Makefile,比如我想把它命名为myfirstmakefile.mk。但是后续使用时,您需要告诉make要使用哪个Makefile。使用-f选项即可:

make -f myfirstmakefile.mk

而且扩展名.mk也不是强制的,您可以使用任何您想要的扩展名,但永远不要忘记使用-f选项。

因此,这可能有助于让您理解。


非常感谢。你是用哪个Unix shell命令开始的?你是先输入nano Hello.c(编写了Hello world程序并键入了nano Hello.makefile),还是从一开始就采取了其他步骤? - Zhivago
我使用nano将其写入名为mkmk的文件中,当我键入make mkmk时,它会显示1make: nothing to be done by default,但是为什么呢? - Zhivago
1
不需要,在Linux中,只需将上面的代码复制到名为 Makefile 的新文件中,并在与上述 Makefile 相同的目录中创建 Hello.c 程序。现在从终端进入该目录,只需输入 make 即可构建 Hello.c,输入 make clean 清除输出。 - Jayesh Bhoi
我注意到如果你给一个makefile命名为除了"Makefile"之外的其他名称,它就无法工作。那么如果你需要制作两个makefiles怎么办? - Zhivago
不必一定将make文件命名为Makefile,你可以随意命名。让我更详细地解释一下makefile规则,请查看我的更新答案。 - Jayesh Bhoi
显示剩余3条评论

12

Makefile 是一个为 make 工具提供指令的文件,告诉它如何从一些依赖文件中创建一个文件(称为目标),使用一组由 shell 运行的命令。一个典型的 makefile 如下所示:

target: dependency [...]
        command1
        command2

请尝试运行man make以获取详细信息。

现在,对于您的任务,实际上不需要Makefile,因为make具有内置规则,知道如何编译一个简单的程序。您只需要将C源代码放在一个名为可执行文件名称(Hello)并带有.c扩展名的文件中,即Hello.c

然后只需简单地运行

$ make Hello
cc     Hello.c   -o Hello

万能的“make”命令。如果你想使用gcc而不是cc,可以运行

$ rm Hello
$ make CC=gcc Hello
gcc     Hello.c   -o Hello

如果你告诉你的教练/老师/教授说,一个空的makefile就是你所需要的,因为你知道内置规则会做正确的事情,那么你将获得一些额外的学分,也许你的教练会学到一些新东西 :-) 如果有人要求参考资料,你可以引用make手册的相关部分,或者像专业人士一样从make命令的POSIX标准Default Rules节中引用。

非常感谢。只是为了确保我理解正确。首先,我使用nano创建了一个Hello.c和我的源代码,然后保存并退出,并在终端控制台(Linux / Unix)中键入(make Hello),我得到了(cc Hello.c -o Hello)在我的命令下面。所以我猜cc(用于编译c)和(-o是将可执行输出放入文件输出的东西,但它实际上是什么意思/意味着普通话(compiles Hello.c并按默认方式给出Makefile指令的空输出?)。但是,当我运行相同的命令(make Hello)时,它会显示(make:'Hello'已经是最新的。 - Zhivago
使用make编译您的Hello.c文件,并根据您的文件名创建二进制文件。如果再次输入make命令,则会查找Hello.c文件中的更改,如果未找到,则简单输出Hello已经是最新版本 - Jayesh Bhoi
@Zhivago 当你第二次运行make时,它会检查依赖项是否比目标文件更新。如果依赖项比目标文件更新,则运行相关命令。否则,无需执行任何操作,make将显示“Hello已经是最新的”。 make足够智能,知道如果Hello.c没有更改,则无需编译它。这就是make的全部意义:尽可能地完成更新目标所需的最小工作量。如果你使用touch Hello.c或者rm Hello命令则需要重新编译。 - Jens
@Zhivago 编译器的 -o file 选项可以命名结果文件(默认为 a.out)。是的,cc 是传统的 Unix C 编译器名称,在 Linux 上与 gcc 相同。 - Jens
@Jens 你好,你能告诉我当你写 $ make CC=gcc Hello 的时候,你设置了一个参数还是一个变量吗? - Zhivago
@Zhivago $是提示符的符号。因此,该行使用两个参数运行make命令,CC=gcc设置一个make变量和Hello作为要构建的目标。 - Jens

9

在开始学习makefile之前,你需要知道什么是makefile以及为什么我们需要它。

什么是Makefile?

Makefile是按照一定的语法编写的脚本,可以通过编译和链接从源文件构建目标输出(通常是一个或多个可执行文件)。简单来说,makefile会以简单快捷的方式编译您的源代码。

为什么我们需要Makefile?

=> 大型项目可能包含多个相互依赖或以分层方式排列的源文件,例如,为了编译文件A,您必须首先编译B;为了编译B,您必须首先编译C;等等。

=> make是解决这些问题的方案。通过输入单个命令make,它可以按照良好的方式编译整个项目,并根据您的make规则(稍后我们将讨论)生成您的目标。

=> 一个重要的特点是,在对项目进行少量更改后重新编译时,它将仅重新编译已更改的那些文件以及依赖于它的任何其他文件。这节省了很多时间。

=> 对于大型项目,在每次对源进行少量更改时手动重新编译整个项目是繁琐、容易出错且耗时的。

这里有一个不错的链接:如何编写第一个makefile


5
一个Makefile是一份计算机配方,其中包含执行某些任务的指令以及这些任务之间的依赖关系。
在简单形式下,它看起来像这样:
a.out: filename.c
        gcc filename.c

阅读:“要从 filename.c 构建 a.out,请运行命令 gcc filename.c。如果 a.outfilename.c 新,则不执行任何操作”。

注意:在 gcc 行中的第一个字符必须是制表符(Makefile 对空格很敏感)


...程序将使用简单的“make”进行编译(构建),而不是“gcc filename.c”。 - Adam
这看起来像是最简单的Makefile了。还能更简单吗? - Adam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接