工作过程中,平时不怎么关注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编写的更多相关文章

  1. 单目录下多文件 makefile编写

    makefile很久就接触过了,但是一直没怎么深入的去学习和总结:在项目中我也只是看看makefile或者修改部分语句,全部自己动手写的话还真没有:知识在于沉淀,这句说的非常好,所以现在把自己理解的东 ...

  2. 多目录下多文件 makefile编写

    前面已经分享了单目录项下多文件的makefile的编写,现在来看看多目录下多文件makefile的编写: 在做项目时,一般文件都会分几个目录来存放:基本的是  include/  bin/ src/ ...

  3. linux 下C语言编程库文件处理与Makefile编写

    做开发快3年了,在linux下编译安装软件算是家常便饭了.就拿gcc来说,都有不下10次了,可基本每次都会碰到些奇奇怪怪的问题.看来还是像vs.codeblocks这样的ide把人弄蠢了.便下定决心一 ...

  4. 如何将多个C文件链接在一起----Makefile编写及make指令

    需使用GCC编译器,关于MinGW的安装指南:https://people.eng.unimelb.edu.au/ammoffat/teaching/20005/Install-MinGW.pdf 单 ...

  5. Makefile 文件的编写

    目录 目录 Makefile 编写规则 Makefile 编写规则 生成的目标文件:依赖文件 生成目标文件所需执行的动作(注:命令行前需加Tab推进) 例: VPATH=inc src main:ma ...

  6. Yocto开发笔记之《Makefile编写》(QQ交流群:519230208)

    开了一个交流群,欢迎爱好者和开发者一起交流,转载请注明出处. QQ群:519230208,为避免广告骚扰,申请时请注明 “开发者” 字样 =============================== ...

  7. Make和Makefile编写(详见GCC手册)

    Makefile和Make Rules 多模块软件.依赖树和Make 默认规则 Make使用程序对简单变量的支持 内建变量 虚目标 特殊目标 一般性语法错误及其纠正措施 命令行的使用和调试 Makef ...

  8. 转载linux c语言程序的Makefile编写

    对于程序设计员来说,makefile是我们绕不过去的一个坎.可能对于习惯Visual C++的用户来说,是否会编写makefile无所谓.毕竟工具本身已经帮我们做好了全部的编译流程.但是在Linux上 ...

  9. makefile编写--引用

    1. Makefile 简介 Makefile 是和 make 命令一起配合使用的. 很多大型项目的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项目中各种库和代码之 ...

随机推荐

  1. DC-5 靶机渗透测试

    DC-5 靶机渗透测试 冲冲冲,好好学习 .核心:footer 文件包含漏洞,wfuzz .收获总结写在文末. 谨记任务:找地方上传shell---> root. 操作机:kali 172.66 ...

  2. JS实现自定义工具类,隔行换色、复选框全选、隔行高亮等

    很多功能都可以放在js的工具类中,在使用的时候直接调用 本次实现的功能包括: /** 0.当点击表的整行的任意位置时,第一列的复选框或者单选框均选中  1.隔行换色 2.复选框的全选效果 3.实现表格 ...

  3. VIM的命令历史

    例如有一段文本,将所有CTRL替换为ctrl,将所有A替换为a,也就是执行了:%s/CTRL/ctrl/g和:%s/A/a/g两条命令,然后进行了很多其他编辑,最后关闭VIM. 后来又有一段文本,也需 ...

  4. 【动画消消乐|CSS】086.炫酷水波浪Loading过渡动画

    前言 Hello!小伙伴! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出-   自我介绍 ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计 ...

  5. Java 横向技术 Spring框架【笔记】

    Java横向技术 spring框架[笔记] Spring 的两大特性是什么? AOP(Aspect Oriented Programming,面向切面编程)与 IOC(Inverse of Contr ...

  6. 08-SpringCloud Consul

    Consul简介 官网 Consul下载地址 What is Consul? Consul is a service mesh solution providing a full featured c ...

  7. Xilinx约束学习笔记(一)—— 约束方法学

    <Xilinx约束学习笔记>为自己阅读 Xilinx 官方 UG903 文档后的学习笔记,大多数为翻译得来,方便大家学习. 1 约束方法学 1.1 组织约束文件 Xilinx 建议将时序约 ...

  8. 依赖注入@Autowired@Primary@Quelifier使用

    @Autowired 注入声明的SpringBean对象,根据一定的规则首先按照注入的类型去查找,如果没有找到安装注入的名称去匹配你要注入的属性名称,如果都没有找到启动项目时抛出异常,@Autowir ...

  9. C#协作试取消线程

    https://segmentfault.com/q/1010000017109927using System; using System.Collections.Generic; using Sys ...

  10. uwp 基础知识

    (TitleId,DiaplayName,args,LogoUri,size); Obj.VisualElements.ShowNameOnSquare150x150Logo = true; if ( ...