多文件多子目录makefile

news2024/11/15 10:09:38

这里写目录标题

  • 1 makefile原理
  • 2 MakeFile步骤
  • 3 多文件多子目录Makefile实例
  • 4 总结
  • 附录一:常用Bash指令
  • 附录二:常用批处理变量
  • 附录三:常用makefile指令

1 makefile原理

编译过程是将高级语言(如C、C++等)源代码转换为可执行程序的过程。这个过程通常包括预处理、编译、汇编和链接四个主要阶段。下面将详细解释每个阶段的任务和过程:

  1. 预处理(Preprocessing)
    预处理是编译过程的第一步,它主要处理源代码中的预处理指令,如宏定义(#define)、条件编译(#if、#elif、#else、#endif)和文件包含(#include)等。预处理器的输出是一个纯文本文件,通常具有.i或.ii扩展名,这个文件已经去除了注释、宏定义被展开、条件编译指令被处理,并且包含了所有被#include指令指定的文件内容。

  2. 编译(Compilation)
    编译阶段将预处理后的源代码转换成汇编语言代码。这个过程可以分为几个子步骤:

    扫描(Scanning):将源代码分解成一系列的单词(tokens),如标识符、保留字、常数、运算符和界符。
    语法分析(Parsing):根据语言的语法规则,将tokens组织成语法树(syntax tree)的形式,以表示源代码的语法结构。
    语义分析(Semantic Analysis):检查语法树的语义正确性,包括类型检查、控制流检查等,并为语法树节点标注类型信息。
    源代码优化(Source Code Optimization):对语法树进行优化,以提高代码的执行效率。
    代码生成(Code Generation):将优化后的语法树转换成汇编代码。
    目标代码优化(Target Code Optimization):对生成的汇编代码进行进一步的优化,以适应不同CPU架构的特性。

  3. 汇编(Assembly)
    汇编阶段将编译生成的汇编代码转换成机器语言指令,即二进制代码。汇编器的输出是一个目标文件(object file),通常具有.o或.obj扩展名。这个文件包含了程序的二进制代码,但还不能直接执行,因为它可能还包含了未解析的外部引用(如对其他程序或库函数的调用)。

  4. 链接(Linking)
    链接阶段将多个目标文件以及所需的库文件合并成一个可执行文件(executable file)。这个过程包括:
    合并各个.obj文件的section:将不同目标文件中的代码段、数据段等合并到同一个可执行文件中。
    合并符号表:将所有目标文件和库文件中的符号(如函数名、变量名)合并到一个统一的符号表中。
    符号解析:解决目标文件中未解析的外部引用,即将符号表中的符号与实际的代码或数据地址关联起来。
    符号地址重定位:调整程序中所有符号的地址,以确保它们在可执行文件中的位置是正确的。
    最终,链接器生成一个可执行文件,该文件包含了程序运行所需的所有代码和数据,并且可以在目标操作系统上直接执行。
    综上所述,编译过程是一个复杂而精细的过程,它涉及多个阶段和多个工具(如预处理器、编译器、汇编器和链接器)的协同工作。通过这个过程,高级语言的源代码被转换成机器可以直接执行的二进制代码。

2 MakeFile步骤

  • 1 运行cygwin环境
  • 2 运行make指令将搜索当前路径下makefile文件并执行第一个目标
  • 3 预处理:生成预处理后的代码(可选地保存为.i文件)
  • 4 编译+汇编(隐式):生成对象文件(.o或.obj)
  • 5 链接:生成可执行文件(如.exe、.elf),然后可以转换为其他格式(如.hex)以用于特定目的

3 多文件多子目录Makefile实例

文件结构
在这里插入图片描述
在这里插入图片描述

其中OpenCygwin.bat用于再windows上运行unix环境,makefile文编译文件其中将会指定编译器路径,这里使用的是Gcc;bin 存放中间文件 inc存放代码头文件;src存放.c文件;main.c将会调用两个子文件中的函数

  • OpenCygwin.bat
@echo off
:: 定义Cygwin bash的路径  
set CYGWIN_BASH=E:\GRC\Tools\cywin64\cygwin64\cygwin64\bin\bash  
  
:: 构造bash命令,切换到批处理文件所在的目录(转换为Cygwin路径)  
:: 注意:%~dp0给出批处理文件的目录(不包括文件名),但需要转换为/cygdrive/e/形式  
set CYGWIN_PATH='%~dp0'  
  
:: 启动bash,以登录shell和交互式模式运行,并执行cd命令和exec bash  
%CYGWIN_BASH% --login -i -c "cd %CYGWIN_PATH%; pwd; exec bash"  
  
:: 注意:pwd命令用于显示当前目录,以验证是否成功切换
  • makefile
# 定义编译器和编译选项  
CXX=gcc 
CXXFLAGS=-I./inc -Wall -g  
  
# 定义目录  
SRCDIR=src  
BINDIR=bin  
OBJDIR=$(BINDIR)/obj  
  
# 创建目标文件夹  
#$(shell mkdir -p $(OBJDIR) $(BINDIR) 2>/dev/null)  
  
# 查找所有 .c 文件并生成对应的 .o 文件目标  
SRCS=$(shell find $(SRCDIR) -name '*.c')  
OBJS=$(SRCS:$(SRCDIR)/%.c=$(OBJDIR)/%.o)  
CLEAN_OBJ =$(shell find $(SRCDIR) -name '*.o')
# 最终目标  
TARGET=myapp  
  
# 默认目标  
all: $(TARGET)  
  
# 链接目标  
$(TARGET): $(OBJS)
	@echo "build in $@ from $^... "
	$(CXX) $(CXXFLAGS) -o $@ $^  
  
# 编译规则(模式规则)  
$(OBJDIR)/%.o: $(SRCDIR)/%.c
	@echo "build in $@ ..."
	$(CXX) $(CXXFLAGS) -c $< -o $@   
  
# 清理  
clean:  
	rm -f $(CLEAN_OBJ) $(TARGET)  
  
.PHONY: all clean

运行结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4 总结

本文为博主个人学习总结记录,如有不正,欢迎指正

附录一:常用Bash指令

Bash(Bourne Again SHell)是Linux系统中最常用的命令行解释器,提供了丰富的命令和功能,帮助用户有效管理和操作Linux系统。以下是一些常用的Bash指令及其简要说明:

  1. 文件和目录操作
    ls:列出目录内容。常用选项包括-l(长格式显示)、-a(显示所有文件,包括隐藏文件)、-h(以易读方式显示文件大小)。
    cd:切换当前工作目录。例如,cd /path/to/dir切换到指定目录,cd …切换到上级目录。
    pwd:显示当前工作目录的路径。
    mkdir:创建新目录。使用-p选项可以递归创建多层目录。
    rm:删除文件或目录。使用-r选项递归删除目录,-f选项强制删除不提示确认。
    cp:复制文件或目录。使用-r选项递归复制目录。
    mv:移动或重命名文件或目录。
    touch:创建新文件或修改文件的时间戳。
  2. 文件查看和编辑
    cat:查看文件内容。对于较长的文件,可以配合-n选项显示行号。
    less:分页显示文件内容,比cat更适合查看大文件。
    head:显示文件的前几行。使用-n选项指定行数。
    tail:显示文件的后几行。使用-n选项指定行数,-f选项实时查看文件更新。
    grep:在文件中搜索指定的文本或模式。常用选项包括-i(不区分大小写)、-r(递归搜索)。
    vi/vim:文本编辑器,用于创建和编辑文件。
  3. 系统管理
    ps:显示当前运行的进程。
    top:实时显示系统资源的使用情况,包括CPU、内存等。
    kill:终止正在运行的进程。通过进程ID(PID)来指定要终止的进程。
    reboot:重启系统。
    shutdown:关闭系统。
    uname:显示系统信息,如内核名称、主机名等。
  4. 网络管理
    ping:测试与目标主机的网络连通性。
    ssh:远程登录到其他主机,进行远程管理或操作。
    scp:在本地和远程系统间复制文件。
    curl:发送HTTP请求并获取网页内容。
    wget:从网络上下载文件。
  5. 权限管理
    chmod:修改文件或目录的权限。通过指定权限模式(如755)来改变文件或目录的访问权限。
    chown:修改文件或目录的所有者。需要超级用户权限来更改其他用户的文件所有者。
    chgrp:修改文件或目录的所属组。
  6. 其他常用命令
    man:查看命令的手册页,获取命令的详细说明和用法。
    info:查看命令的信息页,提供另一种获取命令帮助的方式。
    history:显示最近执行过的命令历史记录。
    find:根据特定条件查找文件或目录。
    du:显示目录或文件的磁盘使用情况。
    df:显示文件系统的磁盘空间使用情况。

附录二:常用批处理变量

在批处理(Batch)脚本中,变量是一种重要的元素,用于存储和引用数据。常用的批处理变量主要分为两类:系统变量和用户自定义变量。以下是对这两类变量的详细介绍:

1.系统变量
系统变量是由系统根据其定义的条件自动赋值的变量,用户无需手动为它们赋值即可直接使用。系统变量包括多种类型,如硬件类、操作系统类、文件路径类、系统时间类等。以下是一些常用的系统变量:

%CD%:扩展到当前目录的字符串。
%DATE%:用与DATE命令相同的格式扩展到当前日期。
%TIME%:用与TIME命令相同的格式扩展到当前时间。
%RANDOM%:扩展到0和32767之间的任意十进制数字。
%ERRORLEVEL%:扩展到当前ERRORLEVEL数值,用于表示上一个命令的退出代码。
%CMDEXTVERSION%:扩展到当前命令处理器扩展名版本号。
%CMDCMDLINE%:扩展到调用命令处理器的原始命令行。
%0:批处理文件的完整路径名。
%1 至 %9:批处理文件的参数,%1代表第一个参数,%2代表第二个参数,依此类推。注意,批处理文件最多可以有9个参数。
%*:返回所有参数的值,而不需要一个个输入%1、%2等。

2.用户自定义变量
用户自定义变量是由用户根据需要自行定义的变量。它们只在定义它们的批处理程序中有效。用户自定义变量通常使用set命令来定义和赋值。以下是一些使用set命令定义和使用用户自定义变量的示例:

定义变量:set 变量名=变量值。例如,set myVar=Hello World。
引用变量:在需要引用变量的地方,使用%变量名%的格式。例如,echo %myVar%将输出Hello World。
取消变量:通过为变量赋值一个空字符串来取消变量,但请注意,这并不会从内存中删除变量,只是使其值变为空。要真正释放变量所占用的内存空间,需要考虑批处理脚本的执行环境和上下文。
可选参数:
set /p 变量名=提示信息:允许用户通过键盘输入来为变量赋值。
set /a 变量名=表达式:用于执行算术运算,并将结果赋值给变量。例如,set /a count=1+2将变量count的值设置为3。

附录三:常用makefile指令

  • 打印信息
#期望打印的数据
ifeq ($(DIR),)
DIR := $(shell cygpath -m "$(COMPONENT_DIR)\DEMO")
endif

#方式一 任意位置打印
$(info CDD_DIR is $(CDD_DIR))  # 使用 GNU Make 的 $(info) 函数来打印信息 

#方式二 再构建目标中打印
all:  
    @echo "CDD_DIR is $(CDD_DIR)"
  • 调用其他文件
include $(MAKE_DIR)/rules_iar.mak //将对应位置的文件内容拷贝到此处
  • 定义宏(也称为函数或模板)
define ADD_COMPONENT  
$(info Adding component: $1)  //$1 表示调用ADD_COMPONENT时传入的第一个参数 $2则是第二个参数
-include $2/$1_cfg.mak  
-include $2/$1_check.mak  
-include $2/$1_defs.mak  
include $2/$1_rules.mak  
endef
  • $(foreach …) 函数
$(foreach var,list,text)
var 是临时变量名,它在循环的每次迭代中都会被赋予 list 中的一个元素值。
list 是要遍历的元素列表,元素之间通常由空格分隔。
text 是每次迭代中要执行的Makefile语句或文本,其中可以引用 var 来获取当前迭代的元素值。
可以理解为用var去遍历list,并再text中对var操作

eg:
FILES = foo.c bar.c baz.c  
 
all:  
   @echo "Processing files:"  
   $(foreach file,$(FILES),$(info Processing $(file)))  
   @echo "Done processing files."
#在这个例子中,$(foreach ...) 遍历 FILES 列表中的每个文件名,并使用 $(info ...) 打印正在处理的文件名
  • $(Call …) 函数
$(call variable,param,param,...)
variable 是你之前已经定义的一个变量,它包含了要执行的Makefile代码(通常是一个宏或模板)。这个变量应该被定义为一个字符串,其中包含了你想要执行的命令或规则,以及占位符(如$(1)、$(2)等)来代表传递给call函数的参数。
param,param,... 是传递给variable中定义的宏的参数列表。在宏内部,你可以通过$(1)、$(2)等方式来引用这些参数,其中$(1)代表第一个参数,$(2)代表第二个参数,依此类推

eg:
#定义一个宏,用于编译C文件,并接受额外的编译选项  
define compile_c_with_opts  
$(CC) $(CFLAGS) $(1) -c -o $@ $<  
endef  
 
#调用宏来编译main.c,并传递额外的编译选项-O2  
main.o: main.c  
   $(call compile_c_with_opts,-O2)  
 
#假设CC和CFLAGS已经在其他地方被定义了  
CC=gcc  
CFLAGS=-Wall
  • $(eval …)函数
$(eval text)
text 是要动态执行的Makefile代码
可以理解为 任何text都会为eval函数转换为makefile代码

eg:
# 假设我们有一个组件列表  
COMPONENTS = comp1 comp2 comp3  
 
# 定义一个宏来生成构建规则  
define generate_rule  
$(1)_obj = $(1).o  
$(1)_obj: $(1).c  
   $(CC) $(CFLAGS) -c -o $$@ $$<  
endef  
 
#遍历组件列表,并为每个组件调用generate_rule宏  
$(foreach comp,$(COMPONENTS),$(eval $(call generate_rule,$(comp))))  
 
#假设CC和CFLAGS已经在其他地方被定义了  
CC=gcc  
CFLAGS=-Wall -g  
 
#现在我们可以构建所有组件的对象文件了  
all: $(foreach comp,$(COMPONENTS),$(comp)_obj)  
   @echo "All objects built successfully."

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2135154.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何利用数字化智慧法务管理平台,提升企业合规与治理水平?

在当今这个日新月异的时代&#xff0c;企业管理正面临着前所未有的挑战与机遇。随着数字化浪潮的汹涌澎湃&#xff0c;企业治理水平的提升已不再是简单的管理升级&#xff0c;而是需要借助科技的力量&#xff0c;实现智慧化、精细化的管理。而智慧法务管理平台&#xff0c;正是…

电子电路产业园废水处理与资源回收的创新实践

随着电子产品的普及和技术革新步伐的加快&#xff0c;电子电路制造业已成为推动现代科技发展的关键力量之一。然而&#xff0c;随之而来的环保问题不容忽视。电镀工艺作为电子电路生产中的一个核心环节&#xff0c;其产生的含镍废水处理成为了企业必须面对的重要课题。本文将探…

【组件】前端js HEIC/HEIF 转换为JPEG、PNG或GIF格式 苹果格式

【组件】前端js HEIC/HEIF 转换为JPEG、PNG或GIF格式 Heic2any: Client-side conversion of HEIC/HEIF image files to JPEG,PNG, or GIF in the browser.https://alexcorvi.github.io/heic2any/#demo GitHub - alexcorvi/heic2any: Converting HEIF/HEIF image formats to PN…

redis 中缓存 百万级别表的查询数据 出错:Query execution was interrupted

项目背景&#xff1a;项目需要 首检合格率 这个结果&#xff0c;但是sql执行非常慢&#xff0c;就想着使用redis来优化接口的速度。现在我需要将数据库查询结果存储到redis&#xff0c;但是就是这一小步&#xff0c;也非常困难。我是用定时任务来实现上面的目的。 Component S…

基于android studio开发的仿QQ聊天软件源代码+数据库+实验报告

安卓客户端基于java 编程语言 在android studio 环境中开发。 内部图片资源很大一部分是反编译手机QQapp 获得的。 服务器端技术路线 聊天系统服务器基于Java Socket网络编程和并发编程、多线程技术、jdbc实现。 通过哈希表&#xff08;hashmap&#xff09;存储来自每一个向客…

读书笔记:《程序员修炼之道——从小工到专家》

前言 此书有两个版本&#xff0c;我读的是第一版&#xff0c;大学时买了略略翻过&#xff0c;当时太懵懂无法理解书中提出的观点&#xff0c;看了也记不得&#xff0c;感觉比较适用于有过1~2个项目工作经验的同学&#xff0c;初学者不一定能看得懂&#xff0c;工作之后看&…

学习通、智慧职教刷课脚本

&#x1f410;个人主页 可惜已不在 &#x1f40b;可以分享给身边有需要的人&#x1f436; &#x1f409;有用的话就留下一个三连吧&#x1f63c; 目录 一.安装 脚本运行器 篡改猴 - Microsoft Edge Addons 二.安装脚本 三.扩展 一.安装 脚本运行器 安装浏览器 Microsoft E…

【多因子分组箱线图】:附Origin详细画图教程

目录 No.1 理解箱线图 1 什么是箱线图 2 箱线图的组成 No.2 画图流程 1 导入数据并绘图 2 设置绘图细节 3 设置坐标轴 4 效果图 No.1 理解箱线图 1 什么是箱线图 箱线图&#xff0c;又称箱形图、盒须图或盒式图&#xff0c;用于体现数据分散情况的统计图。在视觉上辅助…

初始爬虫5

响应码&#xff1a; 数据处理&#xff1a; re模块&#xff08;正则表达式&#xff09; re模块是Python中用于正则表达式操作的标准库。它提供了一些功能强大的方法来执行模式匹配和文本处理。以下是re模块的一些常见用法及其详细说明&#xff1a; 1. 基本用法 1.1 匹配模式 …

CDGA|如何实施非常精准的数据治理策略?

在信息化高速发展的今天&#xff0c;数据已成为企业最重要的生产要素之一&#xff0c;其价值日益凸显。然而&#xff0c;随着数据量的爆炸性增长&#xff0c;如何精准地管理和控制数据成为企业亟待解决的问题。本文将从设定目标、制定策略、组织结构建设、制度流程规范以及技术…

新发现!一键管理所有远程会话的神器——1Remote

大家好&#xff0c;今天给大家介绍一款非常实用的工具——1Remote&#xff0c;这是一款现代化的个人远程会话管理器与启动器&#xff0c;让您的远程工作变得更加轻松高效&#xff01; 项目介绍 &#x1f680; 核心功能概览 多协议支持&#xff1a;1Remote支持RDP、SSH、VNC、…

OBD服务0X0A--请求排放相关的永久DTC

服务0x0A的主要目的是允许外部测试设备获取所有具有“永久DTC状态”的故障诊断码&#xff08;DTC&#xff09;。这些DTCs是“已确认”的&#xff0c;并且被保留在服务器的非易失性存储器&#xff08;NVRAM&#xff09;中&#xff0c;直到针对每个DTC的相应监控器确定故障不再存…

如何使用ORJSONResponse增强FastAPI应用性能:转换任意类型为JSON

在FastAPI中&#xff0c;ORJSONResponse 是一种自定义响应类型&#xff0c;它使用 orjson 库来提高 JSON 数据的序列化性能。orjson 是一个快速且正确的 Python JSON 库&#xff0c;它支持 dataclass、datetime 和 numpy 等数据类型的序列化。使用 ORJSONResponse 可以提升 API…

打造民国风格炫酷个人网页:用HTML和CSS3传递民国风韵

附源码&#xff01;&#xff01;&#xff01; 感谢支持 小弟不断创作网站demo感兴趣的可以关注支持一下 对了 俺在结尾带上了自己用的 背景 大家可以尝试换一下效果更好哦~~~ 如何创建一个民国风格的炫酷网页 在这篇博客中&#xff0c;我们将展示如何制作一个结合民国风格和…

【Java文件操作】文件系统操作文件内容操作

文件系统操作 常见API 在Java中&#xff0c;File类是用于文件和目录路径名的抽象表示。以下是一些常见的方法&#xff1a; 构造方法&#xff1a; File(String pathname)&#xff1a;根据给定的路径创建一个File对象。File(String parent, String child)&#xff1a;根据父路径…

CANFD接口卡配套奇瑞上位机检测电池状态

随着汽车电子的高速发展&#xff0c;车内信息的急剧增多&#xff0c;传统的CAN总线的数据传输能力已经很难满足车辆ECU的数据传输需求了&#xff0c;此时CANFD就应运而生了。 CANFD和CAN最主要的区别就是CANFD的ID段和数据段能够以不同的速率传输数据&#xff0c;这就保证了即…

下一代 AI 医疗:知识图谱RAG + 多智能体,听医生的话没前途,让医生听你的话才是正道!

下一代 AI 医疗&#xff1a;知识图谱RAG 多智能体&#xff0c;听医生的话没前途&#xff0c;让医生听你的话才是正道&#xff01; 医疗算法趋势现代 AI 医疗算法问题医学影像算法的局限医疗知识图谱的问题基于最本质循证医学实现人类级因果推理摆脱LLM概率性输出 嘘&#xff0…

用python操作Excel表格(自动化办公)!

文章开始前打个小广告——分享一份Python学习大礼包&#xff08;激活码安装包、Python web开发&#xff0c;Python爬虫&#xff0c;Python数据分析&#xff0c;人工智能、自动化办公等学习教程&#xff09;点击领取&#xff0c;100%免费&#xff01; 一、openpyxl介绍安装 1.…

影刀RPA:考勤自动打卡小程序

上班族&#xff0c;最惊心动魄的一件事&#xff0c;是什么&#xff0c;当然是&#xff1a;打卡 即使你在智能手机上设置提醒&#xff0c;比如闹钟或者日历事件&#xff0c;提醒自己按时打卡&#xff0c;但依然会忘记 即使公司很开明&#xff0c;使用的考勤系统支持可以设置自…

五大注入攻击网络安全类型介绍

1. SQL注入&#xff08;SQL Injection&#xff09; SQL注入流程 1.1. 概述 SQL注入是最常见的注入攻击类型之一&#xff0c;攻击者通过在输入字段中插入恶意的SQL代码来改变原本的SQL逻辑或执行额外的SQL语句&#xff0c;来操控数据库执行未授权的操作&#xff08;如拖库、获取…