Makefile的一些基础收集

注意事项:
一定要用table键缩进!!!否则无法运行
-Wall:选项可以打印出编译时所有的错误或者警告信息。这个选项很容易被遗忘,编译的时候,没有错误或者警告提示,以为自己的程序很完美,其实,里面有可能隐藏着许多陷阱。变量没有初始化,类型不匹配,或者类型转换错误等警告提示需要重点注意,错误就隐藏在这些代码里面。没有使用的变量也需要注意,去掉无用的代码,让整个程序显得干净一点。下次写Makefile的时候,一定加-Wall编译选项。
-O0: 表示编译时没有优化。
-O1: 表示编译时使用默认优化。
-O2: 表示编译时使用二级优化。
-O3: 表示编译时使用最高级优化。
-Os:相当于-O2.5优化,但又不所见代码尺寸

prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容

反斜杠 \ Makefile中的换行符 # Makefile的注释符
在Makefile中的命令,必须要以[Tab]键开始

src= ( w i l d c a r d . / s r c / . c ) / / . / c / / s r c = / s r c / a . c . / s r c / b . c . / s r c / c . c o b j = (patsubst %.c, %.o, ( s r c ) ) s r c . c . o o b j = (patsubst ./src/%.c, ./obj/%.o, ( s r c ) ) o b j = . / o b j / a . o . / o b j / b . o . . e x p o r t L D L I B R A R Y P A T H = ; I (头文件路径) -I ( W O R K D I R ) / i n c / (obj): 预处理(往有 - c 的后面加)
a.out:$(obj) 连接阶段
-c:包含预处理、编译、汇编
CFLAGS = -Wall -O -g
-Wall 是打开警告开关,-O代表默认优化,可选:-O0不优化,-O1低级优化,-O2中级优化,-O3高级优化,-Os代码空间优化。
-g是生成调试信息,生成的可执行文件具有和源代码关联的可调试的信息

rm -f :强制执行,不管文件存不存在,执行就是
.PHONY:声明clean为伪目标

1.
vim t.c
int main() {return 0;}
a.out : t.c
(table缩进)gcc t.c -o a.out —>条件
a.out:目标 t.c依赖文件
make

写这个Makefile

//目标文件 + 材料:a.out是目标文件,后面是生存目标文件的材料
a.out: itcast_asnl_der.c itcastderlog.c keymng_msg.c main.c
//操作,怎样生存目标文件
gcc itcast_asnl_der.c itcastderlog.c keymng_msg.c main.c -o a.out 操作

-c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件

//编译把编译和连接分开

gcc -c itcast_asnl_der.c -o itcast_asnl_der.o
gcc -c itcastderlog.c -o itcastderlog.o
gcc -c keymng_msg.c -o keymng_msg.o
gcc -c main.c -o main.o
//连接
gcc itcast_asnl_der.o itcastderlog.o keymng_msg.o main.o -o a.out
如果只修改一个文件,那就只重新编译一个文件
把编译和连接分开 ,对应的Makefile
a.out: itcast_asnl_der.o itcastderlog.o keymng_msg.o main.o
gcc itcast_asnl_der.o itcastderlog.o keymng_msg.o main.o -o a.out //连接
//编译
itcast_asnl_der.o : itcast_asnl_der.c
gcc -c itcast_asnl_der.c -o itcast_asnl_der.o
itcastderlog.o : itcastderlog.c
gcc -c itcastderlog.c -o itcastderlog.o
keymng_msg.o : keymng_msg.c
gcc -c keymng_msg.c -o keymng_msg.o
main.o : main.c
gcc -c main.c -o main.o
make -n
最开始a.out后面的.o文件是找不到的,那么就会往下找,直到找到能够生存后面的.o文件为止,再去执行
规则中的依赖如果不存在,在Makefile文件中寻找新的规则 专业解释

makefile
1.一个规则
目标:依赖条件[依赖条件]
(一个table缩进)命令
规则中的依赖如果不存在,在Makefile文件中寻找新的规则将其生成
规则中的依赖生成时间要早于目标的时间,否则说明目标需要更新

2.个函数:
1. ( w i l d c a r d ) w i l d c a r d s r c > s r c = (wildcard *.c) 调用之后
src = itcast_asnl_der.c itcastderlog.c keymng_msg.c main.c

   2.$(patsubst 参1,参2,参3) --->   

将第3个参数当中,出现第1个参数的部分替换成第2 个参数
obj = ( p a t s u b s t (src)) 将src中的.c文件替换为.o文件
obj = itcast_asnl_der.o itcastderlog.o keymng_msg.o main.o
如果是 obj = ( p a t s u b s t (src)),得到的结果是
obj = itcast_asnl_der itcastderlog keymng_msg main
也就是把后面的.c去掉

src = ( w i l d c a r d . / . c ) / / . c o b j = ( p a t s u b (src)) //将src所有的 .c 文件替换成 .o 文件
a.out: ( o b j ) / / (obj),表示obj里面所有的文件
gcc $(obj) -o a.outitcast_asnl_der.o : itcast_asnl_der.c

gcc -c itcast_asnl_der.c -o itcast_asnl_der.o
itcastderlog.o : itcastderlog.c
gcc -c itcastderlog.c -o itcastderlog.o
keymng_msg.o : keymng_msg.c
gcc -c keymng_msg.c -o keymng_msg.o
main.o : main.c
gcc -c main.c -o main.o

注意make之后,代码的顺序 ./ 表示当前目录
gcc -c itcast_asnl_der.c -o itcast_asnl_der.o
gcc -c itcastderlog.c -o itcastderlog.o
gcc -c keymng_msg.c -o keymng_msg.o
gcc -c main.c -o main.o
gcc ./itcast_asnl_der.o ./itcastderlog.o ./keymng_msg.o ./main.o -o a.out
./ 表示当前目录

3.个自动变量 都是在当前的一个大语句中,只能在规则的命令中使用
@ : ^: 表示所有的依赖条件
$<: 表示第一个依赖条件,

src = ( w i l d c a r d . / . c ) / / . c o b j = ( p a t s u b (src)) //将src所有的 .c 文件替换成 .o 文件
//注意:所谓的.o文件一开始是没有的,在执行下面的命令,
有对应的.o文件生成之后,才会去执行这句命令

a.out: ( o b j ) / / (obj),表示obj里面所有的文件
gcc $(obj) -o a.out

itcast_asnl_der.o : itcast_asnl_der.c
gcc -c o @
// ( i t c a s t a s n l d e r . o : @表示(目标) itcast_asnl_der.o)
itcastderlog.o : itcastderlog.c
gcc -c o @
keymng_msg.o : keymng_msg.c
gcc -c o @
main.o : main.c
gcc -c < o @

记住用table键缩进!!!
写成:
src = ( w i l d c a r d . / . c ) o b j = ( p a t s u b (src))
ALL:a.out
a.out: ( o b j ) / / g c c ^ -o @ g c c c < -o @ / / 西 西 c l e a n : / / c l e a n r m r f . / a . o u t (obj) //清楚所有make之后生成的文件
.PHONY : clean ALL //表示无论如何,clean ALL,都要重新执行(应对与在Makefile当前执行的目录下创建了与clean ALL创建的同名文件时出现的问题)

ALL:用来指定Makefile的终极目标,如果不指定,那么Makefile执行后挨个往下执行,会把第一个碰到的文件的当做终极目标

如果这样:那么,Makefile就会把itcast_asnl_der.o当成终极目标,当生成完itcast_asnl_der.o之后,Makefile就不会往下执行了,它就认为活已经干完了
itcast_asnl_der.o : itcast_asnl_der.c
gcc -c o @

src = ( w i l d c a r d . / . c ) o b j = ( p a t s u b (src))
a.out: ( o b j ) g c c (obj) -o a.out

itcast_asnl_der.o : itcast_asnl_der.c
gcc -c o @
itcastderlog.o : itcastderlog.c
gcc -c o @
keymng_msg.o : keymng_msg.c
gcc -c o @
main.o : main.c
gcc -c o @

指定动态库所在位置。

解决:     1. 将自定义的动态库 cp 放到 标准C库 ( libc ) 所在目录位置;(不推荐)
    2. 在可执行文件所在目录位置 执行命令: export LD_LIBRARY_PATH=库路径; (临时生效)
    3. 帮助动态连接器 指定加载 动态库目录位置。 export LD_LIBRARY_PATH=库路径; 写入 ~/.bash_profile 中
    4. ...
    5. ...   APUE
ldd a.out 成功显示动态库位置。    ./a.out 运行。

————–makefile 知识回顾:
ALL:a.out
itcast_asn1_der.o:itcast_asn1_der.c
gcc -c itcast_asn1_der.c -o itcast_asn1_der.o
a.out:itcast_asn1_der.c itcastderlog.c keymng_msg.c test.c
gcc itcast_asn1_der.c itcastderlog.c keymng_msg.c test.c -o a.out
gcc -c itcastderlog.c -o itcastderlog.o
gcc -c keymng_msg.c -o keymng_msg.o
gcc -c test.c -o test.o
gcc itcast_asn1_der.o itcastderlog.o keymng_msg.o test.o -o a.out
1一个规则:
目标:依赖条件[依赖条件]
(一个tab缩进)命令
规则中的依赖,如果不存在,在makefile文件中寻找新的规则将其生成。
规则中的依赖生成时间要早于 目标的时间, 则说明目标需要更新。
2个函数:
( w i l d c a r d ) > s r c = (wildcard *.c) src = itcast_asn1_der.c itcastderlog.c keymng_msg.c test.c
( p a t s u b s t 1 2 3 ) > o b j = (patsubst %.c, %, ( s r c ) ) o b j = i t c a s t a s n 1 d e r . o i t c a s t d e r l o g . o k e y m n g m s g . o t e s t . o 3 @: 在规则的命令中, 表示目标
: <: 在规则的命令中, 表示第一个依赖条件。 如果有模式规则出现,可将依赖列表中的依赖依次取出,套用模式规则。
ALL:用来指定 makefile 中的 终极目标。

模式规则:
%.o:%.c
命令
静态模式规则:
$(obj):%.o:%.c
命令

模式规则: %成对出现匹配, 用某一种模板去套

%.o:%.c     %.o:%.c------>表示.o文件依赖于对应的.c文件
       命令

静态模式规则:在前面指定一个对象,也就是$(obj)的值套用后面的规则,如果指定所有的,当有不同的替换
比如加了一个%.o:%.s 那Makefile就不知道要套用那个规则了

$(obj): %.o : %.c

%.o:%.c
%.o:%.s
命令
%.o:%.c
gcc -c o @

makefile自己维护的变量:小写一般是用户自定义的,大写则是系统维护的,有些有默认值,有些无默认值
CC = cc,就是gcc
CPPFLAGS = :预处理器需要的选项。头文件展开,宏替换 -I
CFLAGS:编译时使用的参数 -Wall -g -c
LDFLAGS:链接库使用的新选项 -L -l
所有的makefile都是有返回值的

在命令前面加上-,表示如果执行失败,那么就忽略这个命令,继续执行下一条命令,不要停止

  = 是最基本的赋值
  := 是覆盖之前的值
  ?= 是如果没有被赋值过就赋予等号后面的值
  += 是添加等号后面的值
  1、“=”
  make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
  x = foo
y = ( x ) b a r x = x y z     y x y z b a r f o o b a r     2 :=     := m a k e f i l e m a k e f i l e     x := f o o y := (x) bar
x := xyz
  在上例中,y的值将会是 foo bar ,而不是 xyz bar 了

-O2表示优化选项,2表示最优优化,即编译器会优化你的程序;-o表示后边接的是文件名称; @ M a k e f i l e @表示xxx.o文件(xxx是你的源代码文件的名称前缀); < <表示第一个找到的.c文件。简而言之,假设在一个文件夹下有若干.c文件,那么下面的规则:
%.o:%.c
gcc -O2 -o @ < #表示Tab键
表示把所有的.c文件编译成中间.o文件
//

Makefile:项目代码的管理工具
1. Makefile的命名
2. Makefile的规则:
规则中的3要素:目标、依赖、命令
目标:依赖条件
命令

Makefile工作原理:

猜你喜欢

转载自blog.csdn.net/weixin_42795100/article/details/82659402