我正在学习如何在Linux发行版上创建makefile
。
我正在使用以下代码(我知道它可以用小写形式编写,但长形式是有意的)来正确理解makefile
的行为
test: test.o
cc -o test test.o
test.o: test.c
cc -c test.c
clean:
rm test.o
现在,当我在shell中使用make
和make clean
时,它们按预期工作。
但是,我想知道target
在makefile
中的重要性。因此,首先将test.o: test.c
行更改为test2.o: test.c
并在shell中键入make
;我最初的猜测是我的home
目录中有一个名为test2.o
的文件,但事实并非如此,我仍然看到test.o
再次被创建。
所以,上述行为引出了我的问题,target
中makefile
组件的重要性是什么?
答案 0 :(得分:1)
'target'是Make检查以确定是否需要执行与目标关联的命令的文件。
即。如果您将test.o: test.c
更改为test2.o: test.c
,则会看到test2.o
不存在,因此执行命令cc -c test.c
- 它仍然只创建test.o
。因此,如果重新运行make,您将看到编译器再次执行 ,因为test.o
仍然不存在。
在原始版本test.o: test.c
中,只有test.o
不存在,或test.c
的修改时间比{{1}更新时,才会执行编译器}。
答案 1 :(得分:1)
目标在命令部分中可用作变量$@
,可用于定义构建的内容。
在你的makefile中你有:
test2.o: test.c
cc -c test.c
因为您没有告诉编译器输出作为cc
命令的一部分,它从test.o
创建了test.c
,这是默认行为。如果您运行cc -c file.c
,默认情况下会生成file.o
。
您需要将目标文件指定为用于生成目标的命令的一部分,因此:
test2.o: test.c
cc -c test.c -o $@
会使编译器适当地生成test2.o
文件。
从根本上讲,makefile只不过是一组目标,目标的依赖关系以及用于制作这些目标的命令集。您必须确保作为构建过程的一部分,来自一组命令的最终产品是目标,以便具有正常运行的makefile。
编译器对在makefile中运行它的事实一无所知。
默认的make系统预先创建了一堆自动规则。这些包括从.o
文件制作.c
文件的规则 - 它知道它需要使用以下规则和命令编译文件:
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
其中COMPILE.c
:
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
和OUTPUT_OPTION
是:
OUTPUT_OPTION = -o $@
CC
默认为cc
,CFLAGS
默认为空,CPPFLAGS
默认为空,TARGET_ARCH
默认为空。您可以使用make -p
结果命令是:
cc -c -o $@ $<
其中$@
是目标的名称,$<
是依赖项列表中的第一项。此模式匹配名为<something>.o
的所有目标文件,其中存在名为<something>.c
的现有文件。如果有test.o
作为目标的请求,那么它将编译一个名为test.c
的文件,因为该文件存在并符合这些规则。
答案 2 :(得分:0)
cc -c test.c
的默认输出文件是test.o
。如果您想要创建test2.o
,则需要明确说明:
test2.o:test.c cc -o test2.o -c test.c
cc
对makefile
或其正在运行的目标一无所知。
目标的重要性在于它们用于查找所有依赖项。因此,makefile中的第一条规则表明test
依赖于test.o
:在创建test
之前,首先需要创建test.o
,如果test.o
}已更改,您需要重建test
。
目标下方的命令可以执行创建目标所需的任何操作。但是你必须明确地编写代码(尽管有一些宏可以自动将目标和依赖项替换到命令行中 - 当目标包含通配符模式时,这些宏非常有用)。
答案 3 :(得分:0)
<强> TL;博士强>
您的test2.o
规则永远不会执行。 test.o
由make的隐式规则创建。
让我们把它分开。
test.o: test.c
cc -c test.c
这是规则。
规则的一般语法是:
targets : prerequisites
recipee
因此,test.o
是目标,test.c
是先决条件。
如果:
执行 recipee (应该,但不必,创建目标)。
那么,让我们来看看你的Makefile:
test: test.o
cc -o test test.o
test.o: test.c
cc -c test.c
当您说make test
时,您想要创建目标test
。此目标以test.o
为先决条件。
对于test.o
,存在另一条规则,其中test.c
为先决条件。因此 规则首先检查并执行(编译源代码到目标代码),然后检查test
先决条件,并在需要时运行recipee(将目标代码链接到可执行格式)
因此,首先将
test.o: test.c
行更改为test2.o: test.c
并在shell中键入make;我最初的猜测是我的主目录中有一个名为test2.o
的文件,但事实并非如此,我仍然看到test.o
再次被创建。
没有目标具有test2.o
先决条件,并且您没有要求具体构建(make test2.o
),因此永远不会执行test2.o
的配方。
但test
仍有test.o
作为先决条件。由于Makefile中没有明确的该名称目标规则,make
会将其替换为implicit rule,以便从现有.o
文件创建.c
文件。