多文件Makefile编写
工作过程中,平时不怎么关注Makefile的书写规则,对于遇到的编译错误一般能看懂Makefile的基本规则也能解决。但如果想要编写Makefile文件还是有相当的难度的,更不用说包含多个目录和文件的功程了。于是在调试了一下午的情况下,终于把一个包含多个目录的基本Makefile给实现了,特此记录下来。 其实编写这个Makefile的目的很简单:便于集中分类管理平时的小程序。 (文章不是用来描述Makefile规则)
1. Makefile多目录结构
在windows上可以使用tree命令查看目录的树状信息(下图是在Windows下通过tree /f目录查看的)

简单的说明:
该工程目前包含有四个源代码目录和一个编译目录target,编写该功能的目的是为了方便对平时编写的小程序的管理和测试。
| 目录名 | 说明 |
|---|---|
| main | 存放main函数的C文件,用来测试运行其他接口程序 |
| process | 进程和线程相关 |
| scheduler | 任务调度代码实现 |
| sleep | 延时函数实现:select, pselect等实现 |
| target | 存放编译过程中生成的.o文件,因此不包含makefile |
2. 多目录Makefile编写思路
- 首先编译各个子目录的文件,生成一系列目标文件(.o文件)
- 然后将各个子目录编译生成的目标文件链接为最终的可执行文件
3. 工程根目录下的总控Makefile
#Makefile
#author : sunzd
#date : 2020-02-23
#location: Beijing
CC = gcc
MAKE = make
CFLAGS = -g -W -O2
LFLAGS =
#directory
TOP_DIR := $(PWD)
OBJ_DIR := $(TOP_DIR)/target
BIN_DIR := $(TOP_DIR)
SRC_SCHEDULE_DIR := $(TOP_DIR)/scheduler
SRC_SLEEP_DIR := $(TOP_DIR)/sleep
SRC_PROCESS_DIR := $(TOP_DIR)/process
SRC_MAIN_DIR := $(TOP_DIR)/main
#这里指定要编译的子目录信息
SUB_DIR := $(SRC_SCHEDULE_DIR) $(SRC_SCHEDULE_DIR) $(SRC_SLEEP_DIR) $(SRC_MAIN_DIR)
TARGET := demo.out
#方法一:手动指定所有的目标文件
#OBJS ?= $(OBJ_DIR)/scheduler.o
#OBJS += $(OBJ_DIR)/scheduler_demo.o
#OBJS += $(OBJ_DIR)/mySleep.o
#OBJS += $(OBJ_DIR)/main.o
#方法二:自动获取指定目录下的目标文件
#OBJS = $(shell ls $(OBJ_DIR)/*.o) works
#OBJS := $(shell ls $(OBJ_DIR)/*.o) can't work
#OBJS ?= $(OBJ_DIR)/$(wildcard *.o) can't work
OBJS ?= $(shell ls $(OBJ_DIR)/*.o)
#将重要的变量export,供子目录中的Makefile使用
export CC CFLAGS TOP_DIR OBJ_DIR BIN_DIR SRC_PROCESS_DIR SRC_SCHEDULE_DIR SRC_SLEEP_DIR OBJS \
SRC_MAIN_DIR
all : $(SUB_DIR) $(TARGET)
#依次进入各个子目录进行编译
$(SUB_DIR):ECHO
$(MAKE) -C $@
ECHO:
@echo sub directorys: $(SUB_DIR)
@echo begin compile::::
#最终要生成的目标文件规则
$(TARGET):$(OBJS)
#@echo ======== OBJS: $(OBJS) =======
$(CC) $(LFLAGS) $(CFLAGS) $(OBJS) -o $@
.PHNOY: clean
clean:
rm -rf $(OBJ_DIR)/*.o $(TARGET)
说明:
| 变量定义方式 | 说明 |
|---|---|
| = | 延时变量 |
| ?= | 延时变量 |
| := | 立即变量 |
| 延时变量 | 在定义时不计算变量的值,在用到时再计算变量的值 |
| 立即变量 | 在定义时便计算出变量的值 |
这里由于不想通过手动指定所有的.o文件,而这些文件只有在子目录完全编译成功后会生成,因此在定义时不能采用立即变量,必须采用延时变量,等到最后编译生成可执行文件时在计算获取target目录下的所有.o文件。主要是为了方便后续扩展。
4. 子目录下的Makefile
工程中四个子目录的Makefile文件都一样(确实很方便),如果后续需要提前新的功能创建新的目录,如果没有特殊需求,可以直接将Makefile拿来使用。
#获取当前目录下所有的.c文件
src := $(shell ls *.c)
#获取要编译的目标文件(.o文件): 使用patsubst函数做后缀替换实现
objs := $(patsubst %.c,%.o,$(src))
#OBJS += $(OBJ_DIR)/$(objs)
#目标: 1)编译.o文件 2)将.o文件移动到指定目录
all : $(objs) MOVE
#1)编译.o文件
%.o:%.c
$(CC) -c $^ -o $@
#2)将.o文件移动到指定目录
MOVE:
mv *.o $(OBJ_DIR)
4. 疑问
在Makefile规则的最后,一般是链接各个目录的目标文件生成最终的可执行文件。可以想到的方式有三种:
- 手动在中控Makefile中指定所有的.o文件(可能还有链接库,头文件等)。这种方式就是不方便扩展,每次增删文件需要修改总控的Makefile
- 将所有的目标文件放到一个特定的目录,最后读取对应的目录文件完成最后的链接操作。缺点很明显:对于需要链接特殊库和搜索指定路径的程序没有办法实现,还需要手动指定。
- 在总控Makefile中预先定义变量,每一个子目录的变量将各自的目标文件、链接文件、搜索路径添加到特定的全局变量中,最终由总控Makefile在生成最后的可执行文件时引用相应的全局变量即可。
在尝试使用第三种方式时,子目录虽然成功修改了全局变量OBJS,但是在总控的Makefile中,依然为空,尚不清楚哪个原因。留着后续处理
多文件Makefile编写的更多相关文章
- 单目录下多文件 makefile编写
makefile很久就接触过了,但是一直没怎么深入的去学习和总结:在项目中我也只是看看makefile或者修改部分语句,全部自己动手写的话还真没有:知识在于沉淀,这句说的非常好,所以现在把自己理解的东 ...
- 多目录下多文件 makefile编写
前面已经分享了单目录项下多文件的makefile的编写,现在来看看多目录下多文件makefile的编写: 在做项目时,一般文件都会分几个目录来存放:基本的是 include/ bin/ src/ ...
- linux 下C语言编程库文件处理与Makefile编写
做开发快3年了,在linux下编译安装软件算是家常便饭了.就拿gcc来说,都有不下10次了,可基本每次都会碰到些奇奇怪怪的问题.看来还是像vs.codeblocks这样的ide把人弄蠢了.便下定决心一 ...
- 如何将多个C文件链接在一起----Makefile编写及make指令
需使用GCC编译器,关于MinGW的安装指南:https://people.eng.unimelb.edu.au/ammoffat/teaching/20005/Install-MinGW.pdf 单 ...
- Makefile 文件的编写
目录 目录 Makefile 编写规则 Makefile 编写规则 生成的目标文件:依赖文件 生成目标文件所需执行的动作(注:命令行前需加Tab推进) 例: VPATH=inc src main:ma ...
- Yocto开发笔记之《Makefile编写》(QQ交流群:519230208)
开了一个交流群,欢迎爱好者和开发者一起交流,转载请注明出处. QQ群:519230208,为避免广告骚扰,申请时请注明 “开发者” 字样 =============================== ...
- Make和Makefile编写(详见GCC手册)
Makefile和Make Rules 多模块软件.依赖树和Make 默认规则 Make使用程序对简单变量的支持 内建变量 虚目标 特殊目标 一般性语法错误及其纠正措施 命令行的使用和调试 Makef ...
- 转载linux c语言程序的Makefile编写
对于程序设计员来说,makefile是我们绕不过去的一个坎.可能对于习惯Visual C++的用户来说,是否会编写makefile无所谓.毕竟工具本身已经帮我们做好了全部的编译流程.但是在Linux上 ...
- makefile编写--引用
1. Makefile 简介 Makefile 是和 make 命令一起配合使用的. 很多大型项目的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项目中各种库和代码之 ...
随机推荐
- 在屏幕上搜索图片并返回图片所在位置的坐标的AutoHotkey脚本源代码(类似大漠插件)
;~ 在屏幕上搜索图片并返回图片所在位置的坐标的AutoHotkey脚本源代码(类似大漠插件) ; https://www.autohotkey.com/boards/viewtopic.php?t ...
- DC-8 靶机渗透测试
DC-8 渗透测试 冲冲冲 ,好好学习 . 核心:cms上传添加存在漏洞组件,利用该组件getshell 操作机:kali 172.66.66.129 靶机:DC-4 172.66.66.137 网络 ...
- awk文本
目录 1.awk概念 2. 基本格式 3. 工作原理 4. 常见的内建变量(可直接用) 5. 按行输出文本 实例1:输出全部内容 实例2:输出第1到第3行的内容 实例3:输出第1行和第3行的内容,输出 ...
- RESTful API 设计风格
HTTP常用动词 GET(SELECT):从服务器取出资源(一项或多项). POST(CREATE):在服务器新建一个资源. PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源). ...
- Android程序员提加薪被拒,刷2000题跳槽涨薪50%!
为什么想跳槽? 简单说一下当时的状况,我在这家公司做了两年多,这两年多完成了一个大项目,作为开发的核心主力,开发压力很大,特别是项目上线前的几个月是非常辛苦,几乎每晚都要加班到12点以后,周末最多只有 ...
- 大学同学做Java开发比我多5K,八年老Android只会crud该转Java吗?
最近在网上看到这样一个帖子: 做了八年Android开发,感觉这块做着也挺没意思,日常工作就是做一些架构优化,质量数据监控,改一改构建脚本,最主要的是业务负责人没有一个是做客户端的,都是后端的人. 最 ...
- NTP 集群简略部署指南
NTP 集群简略部署指南 by 无若 1. NTP 简介 网络时间协议(英语:Network Time Protocol,简称NTP)是在数据网络潜伏时间可变的计算机系统之间通过分组交换进行时钟同步的 ...
- jdbc如何注册数据库驱动Driver的?
1. 先看看原生jdbc执行sql的步骤 // 在程序启动的时候需要注册一次mysql驱动,必须引入 mysql-connnector-java 的包 Class.forName("com. ...
- MySQL-10-索引应用规范
建立索引的原则 SQL文件 sql文件下载链接: https://alnk-blog-pictures.oss-cn-shenzhen.aliyuncs.com/blog-pictures/world ...
- IDM-下载工具
下载所需要的工具 1.IDM下载地址 链接:https://pan.baidu.com/s/1bHXA0pUYBOAC5f_2Iqvl_g 提取码:lsha 2.IDM破解包下载地址 链接:https ...