Linux中Makefile设计
1.编译流程
1.预编译
gcc -E hello.c -o hello.i
目的:
1.展开宏定义
2.引入头文件,将.h引入.c
2.汇编
gcc -S hello.i -o hello.s
目的:
将C语言转换为汇编代码
3.编译
gcc -c hello.s -o hello.o
4.链接
gcc -o hello hello.o
-S 汇编
-o 输出
-c 编译
linux对文件后缀没有判断
使用MakeFile命令默认在当前目录下寻找文件名为MakeFile的文件
2.设计makefile
显示规则
//要对生成的目标所添加的依赖
格式:
target:dep
cmd
//makefile先检测依赖关系是否存在,若存在则执行代码,否则跳过,查询其他指令是否能达成依赖条件
hello.i:hello.c
变量
OBJ = OBJ := OBJ +=
头对象
TARGET=要生成的文件名 调用: $(文件名)
尾对象:
.PHONY: rm -rf $(变量名) 调用方法: make clean
通配符
- % 任意一个
- ? 所有
- *所有
- $@ 代表目标文件
- $^ 代表依赖文件
- $< 代表第一个依赖文件
Makefile关键字参数(自定义变量)
TARGET = 最后要生成的文件名 INCLUDE= 头文件 DEFS = 宏定义的参数 CFLAGES =gg编译参数 CC=gcc LIBS = 库 -l -L SRC(wildcard *.c) 查找返回目录下所有.c文件 OBJ =$(patsubst %.c,%.o $(SRC))
patsubst 函数是将SRC列表中的.c文件转换为.o存进obj,对文件没有任何影响。
符号表
1.readelf -h filename查看头
2.readelf -s filename 查看头文件的符号表
3.objcopy —only-keep-debug filename filename.symbol.1.0(版本) 剥离出readelf(符号表),原文件不受影响
4.objcopy strip-debug filename filename.release 剥离符号表
*(拓展)
stripe filename.release 剥离符号表(深度清除符号表)
基本编译命令
多数UNIX平台都通过CC调用它们的C编译程序.除标准和CC以外,LINUX和FREEBSD还支持gcc,基本的编译命令有以下几种:
1. -c 编译产生对象文件(*.obj)而不链接成可执行文件,当编译几个独立的模块,而待以后由链接程序把它们链接在一起时,就可以使用这个选项,如:
$cc -c hello.c ===> hello.o
$cc hello.o
2. -o 允许用户指定输出文件名,如
$cc hello.c -o hello.o
or
$cc hello.c -o hello
3.-g 指明编译程序在编译的输出中应产生调试信息.这个调试信息使源代码和变量名引用在调试程序中或者当程序异常退出后在分析core文件时可被使用.
$cc -c -g hello.c
4. -D 允许从编译程序命令行定义宏符号
一共有两种情况:一种是用-DMACRO,相当于在程序中使用#define MACRO,另一种是用-DMACRO=A,相当于程序中的#define MACRO A.如对下面这代码:
#ifdefine DEBUG
printf("debug message\n");
#endif
编译时可加上-DDEBUG=1参数,执行程序则打印出编译信息
gcc -o -DDEBUG=1 -DCHANDLKE -DTANZHOU printf printf.c
5. -I 可指定查找include文件的其他位置.例如,如果有些include文件位于比较特殊的地方,比如/usr/local/include,就可以增加此选项如下:
$cc -c -I/usr/local/include -I/opt/include hello.c 此时目录搜索会按给出的次序进行.
6. -E 这个选项是相对标准的,它允许修改命令行以使编译程序把预先处理的C文件发到标准输出,而不实际编译代码.
在查看C预处理伪指令和C宏时,这是很有用的.可能的编译输出可重新定向到一个文件,然后用编辑程序来分析:
$cc -c -E hello.c >cpp.out 此命令使include文件和程序被预先处理并重定向到文cpp.out。
以后可以用编辑程序或者分页命令分析这个文件,并确定最终的C语言代码看起来如何.
7. -o 优化选项,这个选项不是标准的
-O和 -O1指定1级优化
-O2 指定2级优化
-O3 指定3级优化
-O0指定不优化
$cc -c O3 -O0 hello.c 当出现多个优化时,以最后一个为准!!
8.-Wall 以最高级别使用GNU编译程序,专门用于显示警告用!!
$gcc -Wall hello.c
9.-L指定连接库的搜索目录,-l(小写L)指定连接库的名字
$gcc main.o -L/usr/lib -lqt -lpthread -lrt -o hello
上面的命令把目标文件main.o与库qt相连接,连接时会到/usr/lib查找这个库文件.也就是说-L与-l一般要成对出现.
成品
TARGET=mult_proxy //最终目标文件的名字
SRC = $(wildcard *.c) //遍历当前目录下的全部.c文件,形成一个列表
OBJ = $(patsubst %.c,%.o,$(SRC)) //将变量src下面的全部.c结尾的文件,转换为.o存入OBJ
INCLUDE =
DEFS =
CFLAGS = -g
CC =gcc
LIBS =
RELEASE=release
SYMBOL=debug
$(TARGET):$(OBJ)
$(CC) $(CFLAGS) $(DEFS) -o $@ $^ $(LIBS)
make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。
1. gcc -g -o mult_proxy $(OBJ)
2.obj中是.o文件,则去寻找.c件
3.返回至1
$(RELEASE):$(TARGET)
objcopy --strip-debug $(TARGET) $(TARGET).release
strip $(TARGET).release
$(SYMBOL):$(TARGET)
objcopy --only-keep-debug $(TARGET) $(TARGET).symbol
.PHONY:
.PHONY意思表示clean是一个“伪目标”,不成文的规矩是——“clean从来都是放在文件的最后”。
clean:
rm -rf *.o $(TARGET) $(TARGET).release $(TARGET).symbol
程序去符号表步骤
确认程序是否存在符号表
readelf -s test-1
生成符号表
objcopy --only-keep-debug filename filename.symbol
生成发布程序
objcopy --strip-debug filename filename.relase
使用符号表进行debug
gdb -q --symbol=filename.symbol --exec=filename-release
symbol-file .filename.symbol
patsubst 函数
1、wildcard : 扩展通配符
2、notdir : 去除路径
3、patsubst :替换通配符
例子: 建立一个测试目录,在测试目录下建立一个名为sub的子目录 $ mkdir test $ cd test $ mkdir sub
在test下,建立a.c和b.c2个文件,在sub目录下,建立sa.c和sb.c2 个文件
建立一个简单的Makefile src=$(wildcard .c ./sub/.c) dir=$(notdir $(src)) obj=$(patsubst %.c,%.o,$(dir) )
all: @echo $(src) @echo $(dir) @echo $(obj) @echo “end”
执行结果分析: 第一行输出: a.c b.c ./sub/sa.c ./sub/sb.c
wildcard把 指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开。
第二行输出: a.c b.c sa.c sb.c notdir把展开的文件去除掉路径信息
第三行输出: a.o b.o sa.o sb.o
在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o, 任何输出。 或者可以使用 obj=$(dir:%.c=%.o) 效果也是一样的。
这里用到makefile里的替换引用规则,即用您指定的变量替换另一个变量。 它的标准格式是 $(var:a=b) 或 ${var:a=b} 它的含义是把变量var中的每一个值结尾用b替换掉a
今天在研究makefile时在网上看到一篇文章,介绍了使用函数wildcard得到指定目录下所有的C语言源程序文件名的方法,这下好了,不用手工一个一个指定需要编译的.c文件了,方法如下:
SRC = $(wildcard *.c)
等于指定编译当前目录下所有.c文件,如果还有子目录,比如子目录为inc,则再增加一个wildcard函数,象这样:
SRC = $(wildcard .c) $(wildcard inc/.c)
也可以指定汇编源程序: ASRC = $(wildcard *.S)
这样一来,makefile模板可修改的基本就是AVR名称和时钟频率了,其它的一般不用动了。
PS:针对patsubst我们来好好聊一聊
这是个模式替换函数
格式:$(patsubst , , ) 名称:模式字符串替换函数——patsubst。 功能:查找 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式 ,如果匹配的话,则以 替换。这里, 可以包括通配符“%”,表示任意长度的字串。如果 中也包含“%”,那么, 中的这个“%”将是 中的那个“%”所代表的字串。(可以用“\”来转义,以“%”来表示真实含义的“%”字符) 返回:函数返回被替换过后的字符串。
示例:
$(patsubst %.c,%.o,x.c.c bar.c)
把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o”
make中有个变量替换引用
对于一个已经定义的变量,可以使用“替换引用”将其值中的后缀字符(串)使用指定的字符(字符串)替换。格式为“$(VAR:A=B)”(或者“${VAR:A=B}”),意思是,替换变量“VAR”中所有“A”字符结尾的字为“B”结尾的字。“结尾”的含义是空格之前(变量值多个字之间使用空格分开)。而对于变量其它部分的“A”字符不进行替换。例如:
foo := a.o b.o c.o
bar := $(foo:.o=.c)
在这个定义中,变量“bar”的值就为“a.c b.c c.c”。使用变量的替换引用将变量“foo”以空格分开的值中的所有的字的尾字符“o”替换为“c”,其他部分不变。如果在变量“foo”中如果存在“o.o”时,那么变量“bar”的值为“a.c b.c c.c o.c”而不是“a.c b.c c.c c.c”。
它是patsubst的一个简化,那么到底是简化成了什么样子呢
CROSS=
CC=$(CROSS)gcc
CFLAGS= -Wall
LDFLAGS=
PKG = src
SRCS = $(wildcard $(PKG)/inc/.c) $(wildcard $(PKG)/.c)
BOJS = $(patsubst %.c,%.o,$(SRCS))
#BOJS = $(SRCS: .c = .o)
#%.o:%.c
# $(CC) -c $< $(CFLAGS) -o $@
.PHONY:main
main:$(BOJS)
-$(CC) -o $@ $(CFLAGS) $^ $(LDFLAGS)
-mv main ./myfile
起初使用的是变量替换引用的方式,但是却始终不生成中间的.o文件,但是使用patsubst后,一切正常了,如果你知道为什么,请留言告诉我吧