工作过程中,平时不怎么关注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: BeijingCC = gcc
MAKE = make
CFLAGS = -g -W -O2
LFLAGS = #directory
TOP_DIR := $(PWD)OBJ_DIR := $(TOP_DIR)/targetBIN_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_DIRall : $(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. linux环境cpp/c文件的makefile编写(caffe举例)

    编译单个cpp文件 方法一.g++ 文件名.cpp,生成一个名为 "文件名.out" 的可执行文件 方法二.g++ -c 文件名.cpp -o 新文件名.o:生成一个被命名成 &q ...

  2. Linux平台Makefile文件的编写基础篇和GCC参数详解

    问:gcc中的-I.是什么意思....看到了有的是gcc -I. -I/usr/xxxxx..那个-I.是什么意思呢 最佳答案 答:-Ixxx 的意思是除了默认的头文件搜索路径(比如/usr/incl ...

  3. CUDA、MPI和SU混编,MakeFile文件的编写

    本人研究地震勘探的全波形反演,最近在用CUDA+MPI加速反演过程. 写代码过程中最关键的是Makefile文件的编写,也是最难的.下面给出基于SU(Seismic Unix)的CUDA+MPI开发过 ...

  4. Makefile文件的编写

    文章目录 前言 第一个最简单的 Makefile 文件举例 第二个Makefile示例 第三个Makefile示例 第四个Makefile示例 第五个Makefile示例 总结 前言 Makefile ...

  5. Linux下makefile文件的编写

    在学习如何编写makefile文件之前,我们首先需要了解什么是makefile文件: makefile描述了整个工程的编译和链接等规则.它指明了哪些文件需要先编译,哪写文件需要后编译,哪些文件需要重新 ...

  6. Makefile文件的编写(实例详解)

    1.什么是Makefile? 一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,Makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译 ...

  7. [动态库]动态库生成和使用以及Makefile编写

    转自:https://www.cnblogs.com/ljtknowns/p/5647793.html 文件目录结构如下 1 dynamiclibapp.c 2 Makefile 3 comm/inc ...

  8. linux 生成和使用动态链接库和静态链接库的Makefile编写

    引用 Jesse Rei 的 linux 生成和使用动态链接库和静态链接库的Makefile编写 生成和使用动态链接库和静态链接库的Makefile编写 1. 概述 介绍linux下生成和使用动态链接 ...

  9. Linux C编程Makefile编写初步-转

    Linux C编程Makefile编写初步 假设我们有下面这样的一个程序,源代码如下:  /* main.c */  #include "mytool1.h"  #include  ...

最新文章

  1. 《翻译》Intel 64 与 IA-32 架构软件开发者手册卷1翻译
  2. 200kb以上图片储存
  3. lustre1.6.5+drbd主备切换
  4. bzoj2049 Cave 洞穴勘测 LCT模版
  5. CCIE-LAB-SDN-第六篇-SDWAN-Branch2-vEdge-51-vEdge-52
  6. ping不通Linux系统解决方法
  7. 【JEECG技术文档】表单配置-树形表单
  8. latex常用的公式
  9. 设计模式之——观察者模式
  10. Django之Django debug toolbar调试工具
  11. SpringBoot 根据条件注入需要的 Bean
  12. unity天空盒渐变_unity如何制作绚丽的太空天空盒?
  13. 数据治理之元数据管理实践
  14. 基于PCQQ协议的Python QQ机器人库
  15. 国产操作系统统信UOS简单体验评测
  16. 新春将至,“牛”气冲天
  17. 从SS7到VOIP sip
  18. java jsp聊天系统_java web实现简单聊天室
  19. java jackson包_jackson.jar
  20. LaTex如何输入数集符合(整数集、实数集、复数集)

热门文章

  1. 决策树(Decision Tree)简介
  2. 给我一份软件需求规格说明书模板
  3. POI中HSSF和XSSF操作Excel
  4. psp掌机的系统源码
  5. Photoshop CS4验证序列号无效之破解
  6. 2022-01-14:离建筑物最近的距离。 你是个房地产开发商,想要选择一片空地 建一栋大楼。你想把这栋大楼够造在一个距离周边设施都比较方便的地方,通过调研,你希望从它出发能在 最短的距离和 内抵达周
  7. 已经30了,可以从零开始学编程吗?
  8. 如何快速找到微博热卖博主跟爆款商品?这个功能就可以!
  9. 考研成绩公布了,分享一下自己曾经走过的那些坑
  10. 7-8 九连环问题(c++解决)