Linux下makefile 编译项目

2023-05-16

文章目录

  • 1、规划makefile编写
  • 2、makefile文件
    • 2.1、根目录下common.mk
    • 2.2、config.mk
    • 2.3、根目录makefile
  • 2.4、其他目录下

1、规划makefile编写

a、根目录下放三个文件:

1、makefile:是咱们编译项目的入口脚本,编译项目从这里开始,起总体控制作用。
2、config.mk:配置脚本,被makefile包含,单独分处理,为了应付一些可变的东西。
3、common.mk:最核心的编译脚本,定义makefile编译规则,并且各个子目录中都用到这个来编译.c文件的编译

b、每个子目录下

都有一个叫做makefile的文件,每个makefile文件,都会包含根目录下的common.mk。

现在不支持目录中嵌套子目录

2、makefile文件

2.1、根目录下common.mk


#.PHONY:all clean 

ifeq ($(DEBUG),true)
#-g是生成调试信息。GNU调试器可以利用该信息
CC = g++ -std=c++11 -g 
VERSION = debug
else
CC = g++ -std=c++11
VERSION = release
endif

#CC = gcc

# $(wildcard *.c)表示扫描当前目录下所有.c文件
#SRCS = nginx.c ngx_conf.c
SRCS = $(wildcard *.cxx)

#OBJS = nginx.o ngx_conf.o  这么一个一个增加.o太麻烦,下行换一种写法:把字符串中的.c替换为.o
OBJS = $(SRCS:.cxx=.o)

#把字符串中的.c替换为.d
#DEPS = nginx.d ngx_conf.d
DEPS = $(SRCS:.cxx=.d)

#可以指定BIN文件的位置,addprefix是增加前缀函数
#BIN = /mnt/hgfs/linux/nginx
BIN := $(addprefix $(BUILD_ROOT)/,$(BIN))

#定义存放ojb文件的目录,目录统一到一个位置才方便后续链接,不然整到各个子目录去,不好链接
#注意下边这个字符串,末尾不要有空格等否则会语法错误 
LINK_OBJ_DIR = $(BUILD_ROOT)/app/link_obj
DEP_DIR = $(BUILD_ROOT)/app/dep

#-p是递归创建目录,没有就创建,有就不需要创建了
$(shell mkdir -p $(LINK_OBJ_DIR))
$(shell mkdir -p $(DEP_DIR))

#我们要把目标文件生成到上述目标文件目录去,利用函数addprefix增加个前缀
#处理后形如 /mnt/hgfs/linux/nginx/app/link_obj/ngx_signal2.o /mnt/hgfs/linux/nginx/app/link_obj/ngx_signal.o
# := 在解析阶段直接赋值常量字符串【立即展开】,而 = 在运行阶段,实际使用变量时再进行求值【延迟展开】
# /mnt/hgfs/linux/nginx/app/link_obj/nginx.o   /mnt/hgfs/linux/nginx/app/link_obj/ngx_conf.o 
OBJS := $(addprefix $(LINK_OBJ_DIR)/,$(OBJS))
DEPS := $(addprefix $(DEP_DIR)/,$(DEPS))

#找到目录中的所有.o文件(编译出来的)
LINK_OBJ = $(wildcard $(LINK_OBJ_DIR)/*.o)
#因为构建依赖关系时app目录下这个.o文件还没构建出来,所以LINK_OBJ是缺少这个.o的,我们 要把这个.o文件加进来
LINK_OBJ += $(OBJS)

#-------------------------------------------------------------------------------------------------------
#make找第一个目标开始执行[每个目标[就是我们要生成的东西],其实都是定义一种依赖关系],目标的格式为:
#目标:目标依赖【可以省略】
#	要执行的命令【可以省略】
#如下这行会是开始执行的入口,执行就找到依赖项$(BIN)去执行了,同时,这里也依赖了$(DEPS),这样就会生成很多.d文件了
all:$(DEPS) $(OBJS) $(BIN)

#这里是诸多.d文件被包含进来,每个.d文件里都记录着一个.o文件所依赖哪些.c和.h文件。内容诸如 nginx.o: nginx.c ngx_func.h
#我们做这个的最终目的说白了是,即便.h被修改了,也要让make重新编译我们的工程,否则,你修改了.h,make不会重新编译,那不行的
#有必要先判断这些文件是否存在,不然make可能会报一些.d文件找不到
ifneq ("$(wildcard $(DEPS))","")   #如果不为空,$(wildcard)是函数【获取匹配模式文件名】,这里 用于比较是否为""
include $(DEPS)  
endif

#----------------------------------------------------------------1begin------------------
#$(BIN):$(OBJS)
$(BIN):$(LINK_OBJ)
	@echo "------------------------build $(VERSION) mode--------------------------------!!!"

#一些变量:$@:目标,     $^:所有目标依赖
# gcc -o 是生成可执行文件
	$(CC) -o $@ $^ -lpthread

#----------------------------------------------------------------1end-------------------


#----------------------------------------------------------------2begin-----------------
#%.o:%.c
$(LINK_OBJ_DIR)/%.o:%.cxx
# gcc -c是生成.o目标文件   -I可以指定头文件的路径
#如下不排除有其他字符串,所以从其中专门把.c过滤出来 
#$(CC) -o $@ -c $^
	$(CC) -I$(INCLUDE_PATH) -o $@ -c $(filter %.cxx,$^)
#----------------------------------------------------------------2end-------------------



#----------------------------------------------------------------3begin-----------------
#我们现在希望当修改一个.h时,也能够让make自动重新编译我们的项目,所以,我们需要指明让.o依赖于.h文件
#那一个.o依赖于哪些.h文件,我们可以用“gcc -MM c程序文件名” 来获得这些依赖信息并重定向保存到.d文件中
#.d文件中的内容可能形如:nginx.o: nginx.c ngx_func.h
#%.d:%.c
$(DEP_DIR)/%.d:%.cxx
#gcc -MM $^ > $@
#.d文件中的内容形如:nginx.o: nginx.c ngx_func.h ../signal/ngx_signal.h,但现在的问题是我们的.o文件已经放到了专门的目录
# 所以我们要正确指明.o文件路径这样,对应的.h,.c修改后,make时才能发现,这里需要用到sed文本处理工具和一些正则表达式语法,不必深究
#gcc -MM $^ | sed 's,\(.*\)\.o[ :]*,$(LINK_OBJ_DIR)/\1.o:,g' > $@
#echo 中 -n表示后续追加不换行
	echo -n $(LINK_OBJ_DIR)/ > $@
#	gcc -MM $^ | sed 's/^/$(LINK_OBJ_DIR)&/g' > $@
#  >>表示追加
#	gcc -I$(INCLUDE_PATH) -MM $^ >> $@
	$(CC) -I$(INCLUDE_PATH) -MM $^ >> $@

#上行处理后,.d文件中内容应该就如:/mnt/hgfs/linux/nginx/app/link_obj/nginx.o: nginx.c ngx_func.h ../signal/ngx_signal.h

#----------------------------------------------------------------4begin-----------------



#----------------------------------------------------------------nbegin-----------------
#clean:			
#rm 的-f参数是不提示强制删除
#可能gcc会产生.gch这个优化编译速度文件
#	rm -f $(BIN) $(OBJS) $(DEPS) *.gch
#----------------------------------------------------------------nend------------------

2.2、config.mk

#定义项目编译的根目录,通过export把某个变量声明为全局的[其他文件中可以用],这里获取当前这个文件所在的路径作为根目录;
#BUILD_ROOT = /mnt/hgfs/linux/nginx
export BUILD_ROOT = $(shell pwd)

#定义头文件的路径变量
export INCLUDE_PATH = $(BUILD_ROOT)/_include

#定义我们要编译的目录
BUILD_DIR = $(BUILD_ROOT)/signal/ \
			$(BUILD_ROOT)/proc/   \
			$(BUILD_ROOT)/net/    \
			$(BUILD_ROOT)/misc/   \
			$(BUILD_ROOT)/logic/   \
			$(BUILD_ROOT)/app/ 

#编译时是否生成调试信息。GNU调试器可以利用该信息
#很多调试工具,包括Valgrind工具集都会因为这个为true能够输出更多的调试信息;
export DEBUG = true


2.3、根目录makefile


include config.mk
all:
#-C是指定目录
#make -C signal   

#可执行文件应该放最后
#make -C app      

#用shell命令for搞,shell里边的变量用两个$
	@for dir in $(BUILD_DIR); \
	do \
		make -C $$dir; \
	done


clean:
#-rf:删除文件夹,强制删除
	rm -rf app/link_obj app/dep nginx
	rm -rf signal/*.gch app/*.gch


2.4、其他目录下

#只生成 .d,.o即可 
BIN = nginx   #这个可以保证生成nginx可执行文件
include $(BUILD_ROOT)/common.mk
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下makefile 编译项目 的相关文章

  • PelcoD_协议指令分析

    通过协议收发控制第三方云台转动 一般的云台指令协议格式例如 xff1a span class token comment 发送带正负号的垂直角度 span span class token keyword float span vert a
  • 【学习笔记】Esp32 Arduino 串口中断函数 缓冲区修改

    Esp32 Arduino 串口中断函数 缓冲区修改 一 前景描述1 遇到的问题2 开发环境 二 解决问题1 示例代码2 代码缺陷2 解决办法 三 最后的话 一 前景描述 最近需要用Esp32上传数据 xff0c 有一块数据采集板 xff0
  • C++程序编译过程

    C 43 43 程序编译的四个步骤 xff1a 编译预处理 xff0c 编译优化 xff0c 汇编 xff0c 链接 编译预处理 xff1a 处理以 开头的指令 xff0c 将源码 cpp 文件处理成 i 文件 编译优化 xff1a 将 i
  • 查询方式/中断方式/DMA方式的区别及适用范围

    区别 xff1a 查询方式 xff1a CPU与设备串行工作 数据传送与主程序串行工作 xff1b 中断方式 xff1a CPU与设备并行工作 数据传送与主程序串行工作 xff1b DMA方式 xff1a CPU与设备并行工作 数据传送与主
  • vscode、idea、vim 开发工具快捷键

    vscode vscode快捷键文字版 配置启用 禁用 VSCodeVim 插件的快捷键 xff1a Vim Toggle Vim Mode 项 配置启用 vimrc 文件 idea 配置启用 禁用 Idea Vim 插件的快捷键 xff1
  • TDK一体化 IMU 评估板SmartBug2.0 像七星瓢虫一样可爱

    继 2019 年最初的 SmartBug 取得成功后 xff0c 2023 年 1 月初 xff0c TDK 公司宣布宣布推出 InvenSense SmartBug 2 0 评估板 SmartBug2 0 外观与 SmartBug 相似
  • C++ 指针(二)char与指针

    一 char字符串数组和char指针 上一小节对指针的操作进行简单的介绍 xff0c 本小节主要介绍的是char类型和指针之间的一些联系 xff08 虽然使用std string很方便 xff0c 但是我觉得了解这个还是有必要的 xff09
  • stm32f103单线半双工uart通信程序

    文章目录 前言 一 使用步骤 1 打开STMcubemx 2 添加代码 总结 前言 在使用数字舵机时 所用到的通信方式为uart通信 但舵机只有三根接线 出去vcc和gnd 只有一条通信线 也就是说要实现双向通信 只能使用单线半双工模式 本
  • BlueROV加舵机控制以及走过的弯路

    BlueROV加舵机控制以及走过的弯路 因实验需求 xff0c 需要在BlueROV上加上一个一自由度的机械臂 xff0c 由一个水下舵机控制 xff0c 水下舵机需要通过PWM控制 xff0c PWM输出由手柄控制 思路也很简单 xff1
  • ORB_SLAM2 CMakeLIsts文件注释

    最近在学习ORB SLAM 发现基本找不到CMakeLists的代码注释 就决定自己注释一份 如果发现有问题的地方 欢迎和我交流 span class token function cmake minimum required span s
  • UART、RS232 、RS485 区别

    UART RS232 RS485 区别 UART RS232 RS485这些物理层的串口通信 xff0c 它们都是在同一时间发送一位 RS232 RS485只是串口通讯的变种 xff0c 理解了UART串口通讯 xff0c 那么RS232和
  • 在STM32中使用printf()的方法(可直接复制粘贴)

    1 使用printf的方法 1 1 重定向 在使用printf之前添加重定向代码 xff1a span class token macro property span class token directive hash span span
  • 【字符串】字符串长度与字节长度

    字符串长度 xff1a 字符串在遇到 0 之前一共有几个字符 字节长度 字符串里出现的所有元素 例如 xff1a char str 61 123abc 0123 字符串长度 xff1a 6 字节长度 xff1a 11 PS xff1a 如果
  • C语言-字符串拼接(不用strcat函数)

    include lt stdio h gt int main char str1 100 char str2 100 int i 61 0 j 61 0 printf 34 请输入字符串1 xff1a n 34 gets str1 prin
  • Qt(十四)——实现机器人完整导航功能

    Qt xff08 十四 xff09 实现机器人完整导航功能 目录 1 ui 设计2 核心代码 1 ui 设计 2 核心代码
  • vector容器存放自定义数据类型及指针

    include lt iostream gt using namespace std include lt vector gt class person public person string a int b name a age b s
  • unreal 启动报错:运行引擎需要D3D11兼容GPU(功能级别11.0,着色器模型5.0)处理

    问题 AMD核显电脑 xff0c 突然有一天开机后显示器显示效果发白 xff0c 刚开始没在意 xff0c 后来某天想使用Unreal时发现启动不了了 xff0c 弹窗报错 xff1a 运行引擎需要D3D11兼容GPU xff08 功能级别
  • Win10 RealSense L515 ORBSLAM2 配置全攻略

    目录 背景简介Step 1 准备 SDKStep 2 连接设备Step 3 测试例程Step 4 配置环境Step 5 相机标定Step 6 编写入口Step 7 实地运行附录A xff1a 获取内参代码附录B xff1a yaml 参数文
  • rviz仿真底盘移动与云台击打

    rviz仿真底盘移动与云台击打 底盘与云台通过坐标轴来模拟 xff0c 目标方块与子弹可视化通过marker仿真 其中底盘与云台固连 xff0c 底盘xy方向移动云台会同步移动 xff0c 云台可进行pitch和yaw轴旋转 xff0c 通
  • 机器视觉中坐标系转换

    机器视觉 立体视觉等等方向常常涉及到四个坐标系 xff1a 世界坐标系 相机坐标系 图像坐标系 像素坐标系 整体预览如下 1 世界坐标系和相机坐标系 世界坐标系 xff0c 也称为测量坐标系 xff0c 它是一个三维直角坐标系 Xw Yw

随机推荐

  • 机械臂DH参数总结

    DH参数 DH参数 xff08 Denavit Hartenberg parameters xff09 是一个用四个参数表达两对关节连杆之间位置角度关系的机械臂数学模型和坐标系确定系统 DH选的四个参数都的含义如下 xff1a link l
  • 机器人正解和逆解

    正解FK 给定机器人各关节的角度 xff0c 计算出机器人末端的空间位置 逆解IK 已知机器人末端的位置和姿态 xff0c 计算机器人各关节的角度值 挖个坑待完善
  • LeetCode—232 用栈实现队列 Cpp&Python

    LeetCode 225 用队列实现栈 Cpp amp Python 一 方法与思路二 C 43 43 代码三 Python代码 一 方法与思路 使用栈实现队列的下列操作 xff1a push x 将一个元素放入队列的尾部 pop 从队列首
  • E: Unable to locate package解决办法

    问题 xff1a E Unable to locate package 解决 xff1a sudo apt span class token operator span get updade
  • Yolo框架简介

    YOLO xff08 You Only Look Once xff09 是一种基于深度神经网络的对象识别和定位算法 xff0c 其最大的特点是运行速度很快 xff0c 可以用于实时系统 现在YOLO已经发展到v4版本 论文地址 xff1a
  • Ubuntu下编辑权限只读文件的方法

    首先要注意的是只读文件一般都是系统文件 xff0c 或者软件配置文件 xff0c 修改时要尤其谨慎 本文提供两种方法 xff1a 方法一 首先安装一个插件 span class token function sudo span apt sp
  • Ros下Aruco模块的使用

    生成ARUCO ROS MARKER 链接 http chev me arucogen 首先启动ros roscore 打开相机节点 xff0c 在此提供usb相机与Realsense D435i的启动方法 xff1a roslaunch
  • 脚气、灰指甲治疗实验方案

    脚气 xff08 已临床实验 xff09 脚气 xff0c 又叫足廯 香港脚 糜烂性脚气 症状 xff1a 80 都是这种类型 常见于多汗人群 角质层被汗水浸软 xff0c 发白了以后 xff0c 走动不断摩擦表皮脱落 xff0c 露出鲜红
  • VS2015显示“正在从以下位置加载符号“的解决办法

    解决方法 xff1a VS 工具 选项 调试 符号 看到 MicroSoft符号服务器 xff0c 去掉方框中的 xff0c 确定即可 xff0c 之后就不会再调试时加载
  • 【面包】STM32学习笔记(二) --- USART 串口通信学习总结

    tip xff1a 如有错误 xff0c 希望指出 xff0c 非常感谢 xff01 目录 简介一 USART是什么 xff1f 二 问答通信方式1 USART和UART区别2 单工 半双工 全双工区别 三 代码实验1 说明2 代码初始化配
  • [论文阅读笔记] Reciprocal n-body Collision Avoidance(ORCA/RVO2)

    论文阅读 Reciprocal n body Collision Avoidance ORCA RVO2 文章目录 论文阅读 Reciprocal n body Collision Avoidance ORCA RVO2 论文地址Intro
  • 在VSCode中搭建C++编译环境

    在VSCode中搭建C 43 43 编译环境 VSCode当中搭建C 43 43 环境下载VSCode下载MinGW配置文件撰写测试小程序 VSCode当中搭建C 43 43 环境 vscode作为一款轻量级编程软件深受编程人员喜爱 xff
  • 【C++学习笔记】头文件详解

    个人整理学习用 xff0c 非教材 xff0c 有错误欢迎指正 头文件 究竟什么是头文件 xff1f 首先说明一个概念 xff0c 所谓的文件后缀并不是必须的 xff0c 在Linux下这种特点尤为明显 对于编译器来说 xff0c 无论是
  • 编程实现字符串连接函数strcat()

    按如下函数原型编程实现字符串连接函数strcat 的功能 void MyStrcat char dstStr char srcStr 输入提示信息 xff1a Input a string Input another string 输入字符
  • UDP通讯

    目录 利用DatagramSocket发送和接收UDP数据报 DatagramPacket构造方法说明 利用DatagramPacket和Datagramsocket简单实现服务器和客户端的通信 UDP协议通讯的用户状态跟踪 利用Datag
  • ubuntu 下C/C++文件编写

    1 Ubuntu下c cpp文件 1 1 cmake方式编译 cmake通常建立CmakeLists txt xff0c 通过cmake命令生成makefile文件编译工程 文件内容 xff1a span class token numbe
  • C语言基础入门:链表详解篇

    链表概述 链表是一种常见的重要的数据结构 它是动态地进行存储分配的一种结构 它可以根据需要开辟内存单元 链表有一个 头指针 变量 xff0c 以head表示 xff0c 它存放一个地址 该地址指向一个元素 链表中每一个元素称为 结点 xff
  • Linux c udp广播

    文章目录 1 对比2 代码2 1 服务端2 2 客户端 1 对比 服务端 xff1a 需要利用这个函数开发套接字的发广播权限 xff0c 并且需要客户端地址绑定为广播地址 span class token function setsocke
  • React—— HelloWorld

    React 学习笔记 Hello WorldJSX JavaScript XML 语法规则JavaScript 语法函数组件 类组件 amp 属性 props组合组件 生命周期函数 xff08 不全 xff09 amp 状态 state事件
  • Linux下makefile 编译项目

    文章目录 1 规划makefile编写2 makefile文件2 1 根目录下common mk2 2 config mk2 3 根目录makefile 2 4 其他目录下 1 规划makefile编写 a 根目录下放三个文件 xff1a