没有合适的资源?快使用搜索试试~ 我知道了~
Makefile工程实战.pdf
需积分: 1 0 下载量 192 浏览量
2024-01-12
16:00:33
上传
评论
收藏 406KB PDF 举报
温馨提示
试读
36页
通过前面那篇Makefile基础知识对Makefile的语法还有框架做出了简要介绍后。通过实战一步一步写一个简单的计算器项目。实现通过makefile来管理编译代码,包括生成静态库和动态库,多目录管理文件等等一系列架构组织,完成一个通用的Makefile模板。包括: 1. 构建工程 2. 自动添加目标对头文件的依赖 3. 目录管理源文件 4. 目录管理目标文件 5. 目录管理依赖文件 6. 目录管理头文件 7. 静态库的生成和使用 8. 态库的生成和使用 9. 第三方库文件的使用 10. 重构Makefile
资源推荐
资源详情
资源评论
Makefile 工程实战
1. 构建工程
通过前面知识点对 Makefile 的语法还有框架做出了简要介绍后,通过实战一步一步写一
个简单的计算器项目。实现通过 makefile 来管理编译代码,包括生成静态库和动态库,多目
录管理文件等等一系列架构组织,完成一个通用的 Makefile 模板。
首先先来构建一个加减乘除的一个简单的计算器项目工程。新建一个目录叫 operation,
在此新建目录下创建 add.c add.h operation.c 为加法模块,运算功能。 定义一个计算器计算
的主文件 operation.c,在这个主文件中会调用加法模块。
代码如下:
add.c
#include<stdio.h>
void add_init()
{
printf("add operation init\n");
}
add.h
#ifndef _ADD_H
#define _ADD_H
void add init();
#endif
operation.c
#include<stdio.h>
#include "add.h"
#include "sub.h"
int main()
{
printf("operation beginning");
add_init();
sub_init();
return 0;
}
那么,makefile 该怎么写呢,可以这样写:
Makefile:
PHONY:al clean
TARGET = test
0BJ = add.o operation.o
all:$(TARGET)
$(TARGET):$(OBJ)
gcc -o s@ $^
%.o:%.c
gcc -o s@ -c S^
clean:
rm -rf $(OBJ) S(TARGET)
TARGET:计算器应用程序的可执行文件 test
OBJ:包含需要生成以创建可执行文件的所有目标文件的名称。
%.c: 表示任何以 .c 为后缀的源文件。
%.o: 表示任何以 .o 为后缀的目标文件。
$@和$^是我们之前讲过的自动变量,$@表示目标,$^表示所有目标依赖
clean:伪目标用于删除所有生成的目标文件和可执行文件。
%.o:%.c
gcc -o s@ -c S^
这个规则是为了生成从源文件到目标文件的编译规则。
先定义了一个伪目标 all,然后让 all 去依赖可执行程序 test。即使没有 all,我也能通过
make 直接生成 test. 为什么要多此一举呢?之前在讲依赖树的时候我们注意到,树顶一般只
有一个,但是如果我想直接 make 生成多个可执行程序时比如 test1,test2,如果没有一个 all
作为树顶。我就无法直接 make 生成两个程序,而是只能 make test1, make test2,这其实非
常破坏依赖树的结构的,所以我们约定伪目标 all 是第一个目标,它通常依赖于构建整个项
目所需的所有子目标,比如对于上面提到的 test1,test2,我就让它们依赖于 all,这样我直接
make 就能用时构建出这两个程序。
当执行 "test" 目标时,它首先检查目标文件是否存在。如果目标文件不存在,它使用
Makefile 中定义的规则编译相应的源文件。一旦所有目标文件生成,目标将它们链接起来创
建可执行文件 "test"。
当我们再添加减法模块时,将 operation.c 修改:
sub.c
#include<stdio.h>
void sub init()
{
printf("sub operation init\n");
}
sub.h
#ifndef _SUB_H
#define _SUB_H
void sub_init();
#endif
operation.c
#include<stdio.h>
#include "add.h"
#include "sub.h"
int main()
{
printf("operation beginning\n");
add_init();
sub_init();
return 0;
}
此时,makefile 只需要添加 sub.o 目标文件在变量 OBJ 上即可,添加好之后,我们直接 make,
可以看见 sub.o 已经生成了。运行一下 test,我们也可以看见 sub 减法运算模块也已经正常
使用了。
Makefile:
PHONY:all clean
TARGET = test
oBJ = add.o sub.o operation.o
all:$(TARGET)
$(TARGET):$(OBJ)
gcc -o $@ $^
%.o:%.c
gcc -o $@ -c $^
clean:
rm -rf $(OBJ) $(TARGET)
当继续添加其他模块的时候,是否直接再在 OBJ 变量上添加目标文件,那如果一个工程
里面有几百个甚至更多.c 和.h 文件时,这样写就非常麻烦,此时为了使 makefile 更富有通用
性,更加简便,因此我们可以使用前面课程中 makefile 函数中的讲解过的一个函数叫做获取
匹配模式文件名函数----wildcard,这个函数在这里可以发挥特别的作用。
因此我们可以通过这个函数升级前面写的 makefile ,定义一个变量:
SRCS = $(wildcard *c)
SRCS 就是当前目录下所有的.c 文件
OBJ=$(SRCS:.c=.o)
把所有的.c 替换成.o
则 OBJ 就变成了当前目录下的所有.o 文件,此时,OBJ 变量的含义其实跟上述内容所实现的
含义一样。这样优化后,不管添加多少个.c 文件,这个 makefile 都是适用的,不需要进行修
改。
Makefile 如下:
PHONY:all clean
TARGET = test
SRCS =$(wildcard *.c)
0BJ =$(SRCS:.c=.o)
all:$(TARGET)
$(TARGET):$(OBJ)
gcc -o $@ $^
%.o:%.c
gcc -o $@ -c $^
clean:
rm -rf $(OBJ) $(TARGET)
可见此时执行结果是一样的,在用函数设置变量时,我们也可以打印一下看看,这两个变量
是否跟我们预想的一样,只需要添加打印语句:
@echo "SRCS = $(SRCS)
@echo "OBJ = $(OBJ)
2.自动添加目标对头文件的依赖
以上规则中,每个.o 文件只依赖对应的.c 文件,并没有依赖对应的.h 文件,那会造成什么样
的现象呢?
我们举个例子说说:
修改 sub.h 头文件,宏定义一个变量 math 为 8,例如:
sub.h
#ifndef _SUB_H
#define _SUB_H
void sub_init();
#define math 8
#endif
在 sub.c 的函数中打印 math 的值,编辑 sub.c,包含 sub.h ,增加打印语句
sub.c
#include<stdio.h>
#include "sub.h"
void sub init()
{
printf("sub operation init\n");
printf("number=%d\n",math);
}
修改完后,make 执行一下,此时 math=8,这个时候改一下这个宏定义的值,将 math 改为 9,
然后再进行编译 make,出现如下
make: Nothing to be done for all'
说明执行 make 命令时,所有需要的文件已经是最新时就会出现这个消息,这意味着刚才修
改了 sub.h 文件并没有成功重新编译。
可以编译可执行程序 test 查看:这时发现了,明明已经修改了将 math 的值改为 9,此时 math
怎么依然值为 8。
这是因为在上面的规则中,每个.o 文件只依赖了对应的.c 文件,并没有依赖对应的.h
文件。 所以当.h 文件修改了之后,不会再去重新编译所有依赖该.h 文件的目标文件,需要
在 Makefile 中添加目标对应.h 文件的依赖关系!
因此我们就需要添加对头文件的依赖,此时 sub.o 就得将它设置为依赖于 sub.h 和 sub.c,
为以下格式:
sub.o:sub.c sub.h
这个规则可不用写生成命令,因为前面讲过多规则目标,当多个规则是同一个目标时,会将
目标依赖进行合并成此目标的依赖文件列表,并且只使用最后一个规则中定义的命令即可。
则此时其实内部是这样的:
sub.o:sub.c usb.h
gcc -o sub.o -c usb.c usb.h
修改后如下:
.PHONY:all clean
TARGET = test
SRCS =$(wildcard *.c)
0BJ =$(SRCS:.c=.o)
all:$(TARGET)
$(TARGET):$(OBJ)
gcc -o $@ $^
sub.o:sub.c sub.h
%.o:%.c
gcc -o $@ -c $^
clean:
rm -rf $(OBJ) $(TARGET)
加入 sub.h 的依赖关系后执行 make
gcc: fatal error: cannotspecify -o with s or -E with multiple files
compilation terminated.
可见执行的命令与预想一致,但是又出现这个错误是怎么回事 ?错误显示 makefile 的语法
错误,使用选项-c 时不能与多个文件一起使用,我们得将.c 文件过滤出来,这时我们可以使
用 filter 过滤函数,让其更加简便。
此时如果我们要保留下.c 文件,可以这样写
$(filter %.c,$^)
编译可执行程序如下:此时 math 已经为 9,可以修改再进行实验!
其实,在讲基础部分讲过,在 makefile 中,可以自动生成头文件依赖关系,使用 gcc -MM xx.c
命令会自动生成此.c 文件头文件依赖关系:
gcc -MM sub.c >sub.d
并将依赖关系重定位到.d 文件中,执行命令语句为 : gcc -MM XX.c>XX.d ,则.d 文件中就是
其依赖关系。
生成 sub.d 文件后,于是我们可以将 makefile 再次改写一下:
.PHONY:all clean
TARGET = test
SRCS =$(wildcard *.c)
0BJ =$(SRCS:.c=.o)
all:$(TARGET)
$(TARGET):$(OBJ)
gcc -o $@ $^
include sub.d
%.o:%.c
gcc -o $@ -c $(filter %.c,$^)
剩余35页未读,继续阅读
资源评论
IVY_WANG_QAQ
- 粉丝: 574
- 资源: 2
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- Flume进阶-自定义拦截器jar包
- Dubins曲线算法讲解和在运动规划中的使用.pdf
- 上市公司-股票性质数据-工具变量(民企、国企、央企)2003-2022年.dta
- 上市公司-股票性质数据-工具变量(民企、国企、央企)2003-2022年.xlsx
- Reeds+Shepp曲线算法讲解和实现.pdf
- 毕业设计基于SpringBoot+MyBatisPlus+MySQL+Vue的外卖配送信息系统源代码+数据库
- 词向量(Word Embeddings)是自然语言处理(NLP)领域的一种重要技术.txt
- Surfer,线性函数
- MyBatis 的动态 SQL 是其核心特性之一.txt
- 时代的sdddsddsddsd
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功