本文共 7258 字,大约阅读时间需要 24 分钟。
makefile 无法工作
如果要在更新某些文件时运行或更新任务,则可以使用make
实用程序。 make
实用程序需要一个文件Makefile
(或makefile
),该makefile
定义了要执行的任务集。 您可能已使用make
从源代码编译程序。 大多数开源项目使用make
来编译最终的可执行二进制文件,然后可以使用make install
。
在本文中,我们将使用基本和高级示例探索make
和Makefile
。 在开始之前,请确保已在系统中安装了make
。
让我们从在终端上打印经典的“ Hello World”开始。 创建一个空目录myproject
其中包含具有以下内容的文件Makefile
:
say_hello: echo "Hello World"
现在,通过在目录myproject
键入make
运行文件。 输出将是:
$ make echo "Hello World" Hello World
在上面的示例中,在任何编程语言中, say_hello
行为都类似于函数名。 这称为目标 。 先决条件或依赖项遵循目标。 为了简单起见,在此示例中我们没有定义任何先决条件。 命令echo "Hello World"
称为配方 。 配方使用先决条件作为目标 。 目标,先决条件和配方共同构成了规则 。
总而言之,以下是典型规则的语法:
target: prerequisites < TAB > recipe
例如,目标可能是取决于先决条件的二进制文件(源文件)。 另一方面,前提条件也可以是依赖于其他依赖项的目标:
final_target: sub_target final_target.c Recipe_to_create_final_target sub_target: sub_target.c Recipe_to_create_sub_target
目标不必是文件; 就像我们的示例一样,它可能只是配方的名称。 我们称这些为“虚假目标”。
回到上面的示例,执行make
时,将显示整个命令echo "Hello World"
,然后显示实际命令输出。 我们通常不想要那个。 要禁止回显实际命令,我们需要使用@
开头echo
:
say_hello: @ echo "Hello World"
现在尝试再次运行make
。 输出应仅显示以下内容:
$ make Hello World
让我们添加更多伪造目标: generate
并clean
Makefile
:
say_hello: @ echo "Hello World" generate: @ echo "Creating empty text files..." touch file- { 1 .. 10 } .txt clean: @ echo "Cleaning up..." rm * .txt
如果我们尝试在更改后运行make
,则仅执行目标say_hello
。 这是因为makefile中只有第一个目标是默认目标。 通常被称为默认目标 ,这就是为什么您会在大多数项目中将all
视为第一个目标的原因。 召集其他目标是all
的责任。 我们可以使用称为.DEFAULT_GOAL
的特殊伪造目标来覆盖此行为。
让我们在makefile的开头包含它:
.DEFAULT_GOAL := generate
这将默认运行目标generate
:
$ make Creating empty text files... touch file- { 1 .. 10 } .txt
顾名思义,虚假目标.DEFAULT_GOAL
一次只能运行一个目标。 这就是为什么大多数makefile将all
文件都包含为目标,并可以根据需要调用任意多个目标的原因。
让我们将all
虚假目标包括在内,并删除.DEFAULT_GOAL
:
all: say_hello generate say_hello: @ echo "Hello World" generate: @ echo "Creating empty text files..." touch file- { 1 .. 10 } .txt clean: @ echo "Cleaning up..." rm * .txt
在运行make
之前,让我们包括另一个特殊的伪音目标.PHONY
,在其中定义不是文件的所有目标。 make
将运行其配方,而不管该名称的文件是否存在或其最后修改时间是什么。 这是完整的makefile:
.PHONY: all say_hello generate clean all: say_hello generate say_hello: @ echo "Hello World" generate: @ echo "Creating empty text files..." touch file- { 1 .. 10 } .txt clean: @ echo "Cleaning up..." rm * .txt
make
应该调用say_hello
并generate
:
$ make Hello World Creating empty text files... touch file- { 1 .. 10 } .txt
这是一个很好的做法不叫clean
的all
或把它作为第一目标。 clean
应首先手动调用clean
来作为make
的第一个参数:
$ make clean Cleaning up... rm * .txt
现在您已经了解了基本Makefile的工作方式以及如何编写简单的Makefile,让我们看一些更高级的示例。
在makefile中定义变量的最简单方法是使用=
运算符。 例如,将命令gcc
分配给变量CC
:
CC = gcc
这也称为递归扩展变量 ,它在规则中使用,如下所示:
hello: hello.c ${CC} hello.c -o hello
您可能已经猜到了,配方在传递到终端时会如下扩展:
gcc hello.c -o hello
${CC}
和$(CC)
都是调用gcc
有效引用。 但是,如果尝试将变量重新分配给自己,则会导致无限循环。 让我们验证一下:
CC = gcc CC = ${CC} all: @ echo ${CC}
运行make
将导致:
$ make Makefile: 8 : *** Recursive variable 'CC' references itself ( eventually ) . Stop.
为了避免这种情况,我们可以使用:=
运算符(也称为简单扩展变量 )。 运行下面的makefile文件应该没有问题:
CC := gcc CC := ${CC} all: @ echo ${CC}
以下makefile可以使用变量,模式和函数来编译所有C程序。 让我们逐行探索它:
# Usage: # make # compile all binary # make clean # remove ALL binaries and objects .PHONY = all clean CC = gcc # compiler to use LINKERFLAG = -lm SRCS := $(wildcard *.c) BINS := $(SRCS:%.c=%) all: ${BINS} %: %.o @echo "Checking.." ${CC} ${LINKERFLAG} $< -o $@ %.o: %.c @echo "Creating object.." ${CC} -c $< clean: @echo "Cleaning up..." rm -rvf *.o ${BINS}
以#
开头的行是注释。
行.PHONY = all clean
定义all
虚假目标且clean
。
变量LINKERFLAG
定义在配方中与gcc
一起使用的标志。
SRCS := $(wildcard *.c)
: $(wildcard pattern)
是filenames的功能之一 。 在这种情况下,所有扩展名为.c
文件都将存储在变量SRCS
。
BINS := $(SRCS:%.c=%)
:这称为替代引用 。 在这种情况下,如果SRCS
具有价值'foo.c bar.c'
, BINS
将有'foo bar'
。
all: ${BINS}
:假目标将${BINS}
all
呼叫值作为单个目标。
规则:
% : % .o @ echo "Checking.." ${CC} ${LINKERFLAG} $ & lt; -o $ @
让我们看一个例子来理解这个规则。 假设foo
是${BINS}
中的值之一。 然后, %
将匹配foo
( %
可以匹配任何目标名称)。 以下是展开形式的规则:
foo: foo.o @ echo "Checking.." gcc -lm foo.o -o foo
如图所示, %
被foo
代替。 $<
被foo.o
替换。 $<
被图案化以匹配先决条件,而$@
匹配目标。 ${BINS}
每个值都将调用此规则
规则:
% .o: % .c @ echo "Creating object.." ${CC} -c $ & lt;
上一条规则中的每个前提条件都被视为该规则的目标。 以下是展开形式的规则:
foo.o: foo.c @ echo "Creating object.." gcc -c foo.c
最后,我们删除target clean
中的所有二进制文件和目标文件。
下面是上述makefile的重写,假设它位于具有单个文件foo.c:
的目录中foo.c:
# Usage: # make # compile all binary # make clean # remove ALL binaries and objects .PHONY = all clean CC = gcc # compiler to use LINKERFLAG = -lm SRCS := foo.c BINS := foo all: foo foo: foo.o @echo "Checking.." gcc -lm foo.o -o foo foo.o: foo.c @echo "Creating object.." gcc -c foo.c clean: @echo "Cleaning up..." rm -rvf foo.o foo
有关makefile的更多信息,请参考 ,其中提供了完整的参考资料和示例。
您还可以阅读我们的以了解如何自动为您的编码项目生成makefile。
翻译自:
makefile 无法工作
转载地址:http://pqdzd.baihongyu.com/