11 学习跟我一起写makefile

网站链接:跟我一起写Makefile

Mkafile的规则

目标: 依赖
	命令

目标:一个目标文件,也可以是一个执行文件,或者一个label。
依赖:生成这个目标的所有的文件
command:该target要执行的命令

Makefile寻找路径:

  1. 如果这个工程没有编译过,那么我们的所有c文件都要编译并被链接。
  2. 如果这个工程的某几个c文件被修改,那么我们只编译被修改的c文件,并链接目标程序。
  3. 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的c文件,并链接目标程序。

makefile中的使用变量

edit : main.o kbd.o command.o display.o \
        insert.o search.o files.o utils.o
    cc -o edit main.o kbd.o command.o display.o \
        insert.o search.o files.o utils.o

为了简便makefile中的编写,可以利用变量的思路,将

objects = main.o kbd.o command.o display.o \
     insert.o search.o files.o utils.o

通过使用$(objects)就能使用上述变量

makefile的自动推导

例如:

#include<stdio.h>
int main() {
  printf("hello world\n");
  return 0;
}                      

编写Makefile文件:

target = hello
objects = hello.o
$(target):$(objects)
$(objects):

只要make看到一个 .o 文件,它就会自动的把 .c 文件加在依赖关系中

Makefile的文件名

执行make命令时,会在当前目录下寻找:“GNUmakefile”、“makefile”、“Makefile”的文件,推荐使用后两种,也可以通过-f 或者 -file指定文件名

引用其他的Makefile

可以通过include包含其他的Makefile文件,语法如下:

include <filename>

下面两个语句等价

include foo.make *.mk $(bar)
include foo.make a.mk b.mk c.mk e.mk f.mk

Makefile通配符

make中支持三个通配符:*, ?, ~
波浪号( ~ )字符在文件名中也有比较特殊的用途。如果是 ~/test ,这就表示当前用户的 $HOME 目录下的test目录。
*.c代表所有后缀为c的文件,如果文件名中存在通配符需要进行转义,*

例如:

clean:
    cat main.c
    rm -f *.o

但是下列例子:

objects = *.o

并不表示所有的.o文件,如果需要将变量展开需要进行如下写法:

objects := $(wildcard *.o)

文件搜寻

在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。
目录之间需要由冒号进行分隔:

VPATH = src:../headers

伪目标

我们只有通过显式地指明这个“目标”才能让其生效。

.PHONY : clean
clean :
    rm *.o temp
all : prog1 prog2 prog3
.PHONY : all

prog1 : prog1.o utils.o
    cc -o prog1 prog1.o utils.o

prog2 : prog2.o
    cc -o prog2 prog2.o

prog3 : prog3.o sort.o utils.o
    cc -o prog3 prog3.o sort.o utils.o

上述代码可以通过make自动执行后面的代码

自动生成依赖性¶

大多数的C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。

cc -M main.c

书写命令

make会一按顺序一条一条的执行命令,每条命令的开头必须以 Tab 键开头

显示命令

在进行shell命令前需要添加@,比如echo:

echo 666
输出:
echo 666
666

命令执行

如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。

exec:
    cd /home/hchen
    pwd
exec:
    cd /home/hchen; pwd

命令出错

有些时候,命令的出错并不表示就是错误的。例如mkdir创建已经存在的文件,需要通过在Makefile的命令行前面加一个减号

clean:
    -rm -f *.o

嵌套执行make

在一些大的工程中,我们会把我们不同模块或是不同功能的源文件放在不同的目录中,我们可以在每个目录中都书写一个该目录的Makefile,这有利于让我们的Makefile变得更加地简洁,而不至于把所有的东西全部写在一个Makefile中,这样会很难维护我们的Makefile,这个技术对于我们模块编译和分段编译有着非常大的好处。

subsystem:
    cd subdir && $(MAKE)
等价于:
subsystem:
    $(MAKE) -C subdir

定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较利于维护。这两个例子的意思都是先进入“subdir”目录,然后执行make命令。

: 表示依赖, ^:表示依赖, 表示依赖,@表示目标

使用变量

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上 $ 符号.

追加变量值

objects = main.o foo.o bar.o utils.o
objects += another.o

于是,我们的 $(objects) 值变成:“main.o foo.o bar.o utils.o another.o”(another.o被追加进去了)

使用条件判断 ifeq ifneq

libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
    $(CC) -o foo $(objects) $(libs_for_gcc)
else
    $(CC) -o foo $(objects) $(normal_libs)
endif

该方法能够判断CC是否为gcc,关键词 ifeq、elseendif,任何一个条件语句的结束都应该以endif结束

关键词 ifdef ifndef

示例:

bar =
foo = $(bar)
ifdef foo
    frobozz = yes
else
    frobozz = no
endif

使用函数

语法如下所示:

$(<function> <arguments>)

subst

$(subst <from>,<to>,<text>)

名称:字符串替换函数

功能:把字串 中的 字符串替换成 。

返回:函数返回被替换过后的字符串。

comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))

$(bar) 的值是 a,b,c 。

patsubst

$(patsubst <pattern>,<replacement>,<text>)

名称:模式字符串替换函数。

功能:查找 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式 ,如果匹配的话,则以 替换。这里, 可以包括通配符 % ,表示任意长度的字串。如果 中也包含 % ,那么, 中的这个 % 将是 中的那个 % 所代表的字串。(可以用 \ 来转义,以 % 来表示真实含义的 % 字符)

返回:函数返回被替换过后的字符串。
示例:

$(patsubst %.c,%.o,x.c.c bar.c)

把字串 x.c.c bar.c 符合模式 %.c 的单词替换成 %.o ,返回结果是 x.c.o bar.o

strip

$(strip <string>)

名称:去空格函数。

功能:去掉 字串中开头和结尾的空字符。

返回:返回被去掉空格的字符串值。

示例:

$(strip a b c )

findstring

$(findstring <find>,<in>)

名称:查找字符串函数
功能:在字串 中查找 字串。
返回:如果找到,那么返回 ,否则返回空字符串。
示例:

$(findstring a,a b c)
$(findstring a,b c)

第一个函数返回 a 字符串,第二个返回空字符串

filter

$(filter <pattern...>,<text>)

名称:过滤函数
功能:以 模式过滤 字符串中的单词,保留符合模式 的单词。可以有多个模式。
返回:返回符合模式 的字串。

sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
    cc $(filter %.c %.s,$(sources)) -o foo

filter-out 反过滤

sort

$(sort <list>)

名称:排序函数
功能:给字符串 中的单词排序(升序)。
返回:返回排序后的字符串。
示例: $(sort foo bar lose) 返回 bar foo lose 。
备注: sort 函数会去掉 中相同的单词。

word

$(word <n>,<text>)

名称:取单词函数
功能:取字符串 中第 个单词。(从一开始)
返回:返回字符串 中第 个单词。如果 比 中的单词数要大,那么返回空字符串。
示例: $(word 2, foo bar baz) 返回值是 bar 。

wordlist

$(wordlist <ss>,<e>,<text>)

名称:取单词串函数
功能:从字符串 中取从 开始到 的单词串。 和 是一个数字。
返回:返回字符串 中从 到 的单词字串。如果 比 中的单词数要大,那么返回空字符串。如果 大于 的单词数,那么返回从 开始,到 结束的单词串。
示例: $(wordlist 2, 3, foo bar baz) 返回值是 bar baz 。

words

$(words <text>)

名称:单词个数统计函数

dir

$(dir <names...>)

名称:取目录函数——dir。
功能:从文件名序列 中取出目录部分。目录部分是指最后一个反斜杠( / )之前的部分。如果没有反斜杠,那么返回 ./ 。
返回:返回文件名序列 的目录部分。
示例: $(dir src/foo.c hacks) 返回值是 src/ ./ 。

notdir 与dir相反

$(notdir <names...>)

suffix

取后缀函数

$(suffix <names...>)

名称:取後缀函数——suffix。
功能:从文件名序列 中取出各个文件名的后缀。
返回:返回文件名序列 的后缀序列,如果文件没有后缀,则返回空字串。
示例: $(suffix src/foo.c src-1.0/bar.c hacks) 返回值是 .c .c。

basename

$(basename <names...>)

名称:取前缀函数——basename。
功能:从文件名序列 中取出各个文件名的前缀部分。
返回:返回文件名序列 的前缀序列,如果文件没有前缀,则返回空字串。
示例: $(basename src/foo.c src-1.0/bar.c hacks) 返回值是 src/foo src-1.0/bar hacks 。

addsuffix

$(addsuffix <suffix>,<names...>)

名称:加后缀函数——addsuffix。
功能:把后缀 加到 中的每个单词后面。
返回:返回加过后缀的文件名序列。
示例: $(addsuffix .c,foo bar) 返回值是 foo.c bar.c 。

addprefix

$(addprefix <prefix>,<names...>)

名称:加前缀函数——addprefix。
功能:把前缀 加到 中的每个单词前面。
返回:返回加过前缀的文件名序列。
示例: $(addprefix src/,foo bar) 返回值是 src/foo src/bar。

join

$(join <list1>,<list2>)

名称:连接函数——join。
功能:把 中的单词对应地加到 的单词后面。如果 的单词个数要比 的多,那么, 中的多出来的单词将保持原样。如果 的单词个数要比 多,那么, 多出来的单词将被复制到 中。
返回:返回连接过后的字符串。
示例: $(join aaa bbb , 111 222 333) 返回值是 aaa111 bbb222 333 。

shell函数

shell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。它和反引号“`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量,如:

contents := $(shell cat foo)
files := $(shell echo *.c)

error

$(error <text ...>)

产生一个致命的错误, <text …> 是错误信息。注意,error函数不会在一被使用就会产生错误信息,所以如果你把其定义在某个变量中,并在后续的脚本中使用这个变量,那么也是可以的。例如:

ifdef ERROR_001
    $(error error is $(ERROR_001))
endif

warning

$(warning <text ...>)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值