首页 > 系统相关 >【ARM-Linux篇】Makefile入门

【ARM-Linux篇】Makefile入门

时间:2024-06-02 23:59:10浏览次数:30  
标签:src TARGET Makefile echo Linux VAR ARM 赋值

一、编译工具及构建工具介绍

make的出现是为了解决手动编译和链接大型工程的问题,它可以避免重复的工作,提高效率,保证正确性。make工具就根据makefile中的命令进行编译和链接的。但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改,因此更高级的一些构建系统或者工具工具像cmake、qmake、ninja和auto make就出现了,它们可以根据一些配置文件来自动化编译和链接软件项目。

•cmake是一个跨平台的构建系统,它可以根据CMakeLists.txt中的指令来生成不同平台和工具的工程文件,例如Makefile、Visual Studio解决方案、Ninja文件等。cmake可以支持多种语言和多种架构,它还提供了一些高级功能,如测试、打包、安装等。
•qmake是一个用于Qt项目的构建系统,它可以根据.pro或.pri中的指令来生成Makefile或其他形式的工程文件。
•ninja是一个小巧而快速的构建工具,它可以根据ninja.build中的规则来执行编译和链接命令。ninja主要关注于性能和效率,它可以利用多核处理器和并行处理来加速构建过程。ninja通常不需要用户直接编写配置文件,而是由其他构建系统(如cmake)来生成
•auto make是一个用于生成Makefile.in文件的工具,Makefile.in是一种用于auto conf的配置文件格式,auto conf是一个用于生成configure脚本的工具。configure脚本是一个用于检测系统环境并生成最终的Makefile文件的脚本Makefile.am是一种用于auto make的配置文件格式,它包含了一些指令和变量,用于定义程序或库的源文件、目标文件、依赖关系和编译选项等。 

•make是一个经典而通用的构建工具,它可以根据Makefile中的规则来执行编译和链接命令。make可以支持多种平台和工具,它还提供了一些高级功能,如条件判断、函数调用、模式匹配。

二、Makefile简介

1. 编译的四个阶段

2.Makefile的规则 

a.基本规则

target ... : prerequisites ...
<tab缩进>command
<tab缩进>...
<tab缩进>...

target 也就是一个目标文件,可以是 Object File,也可以是执行文件。还可以是一个标签( Label)。prerequisites 就是,要生成那个 target 所需要的文件或是目标。command 也就是 make 需要执行的任意shell命令。

b. 伪目标

如果一个目标和一个实际文件同名,那么make会认为该目标已经是最新的,不需要重新生成,也不会执行其命令。通过将目标声明为伪目标,可以避免这种情况,强制执行其命令。

c. 变量赋值和预定义变量 

Makefile中的变量赋值运算符有四种,分别是=、:=、?=+=, $符号表示取变量的值,当变量名多于一个字符时,使用"( )"

= 表示延迟展开赋值,即变量的值是在使用时才确定,可能会受到后面的赋值影响。例如,VAR_A = A,VAR_B = $(VAR_A) B,VAR_A = AA,那么最后VAR_B的值是AA B,而不是A B。
:= 表示直接赋值,即变量的值是在定义时就确定,不会受到后面的赋值影响。例如,VAR_A := A,VAR_B := $(VAR_A) B,VAR_A := AA,那么最后VAR_B的值是A B,而不是AA B。
?=表示条件赋值,即只有当变量没有被赋值时,才使用等号后面的值作为变量的值。例如,VAR ?=new_value,如果VAR在之前没有被赋值,那么VAR的值就为new_value,否则保持原来的值不变。

+= 表示追加赋值,即将等号后面的值追加到变量原来的值之后,形成一个新的值。例如,VAR +=new_value,如果VAR在之前没有被赋值,那么VAR的值就为new_value,如果VAR在之前被赋值为old_value,那么VAR的值就为old_value new_value

$符的其他用法:

$^ 表示所有的依赖文件
$@ 表示生成的目标文件
$< 代表第一个依赖文件

d.注释和换行符 

采用#进行一行注释
采用\作为续行符

e. 变量的替换引用 

语法格式:

$(var:a=b)或${var:a=b}

表示把变量var的值中的a后缀替换成b后缀。例如:

src := a.c b.c c.c
obj := $(src:c=o) 

把变量src的值中的.c后缀替换成.o后缀,赋值给变量obj,结果是:

obj := a.o b.o c.o 

•示例代码 

# 这是一个Makefile的注释
TARGET = hello #TARGET延迟赋值hello
CC := gcc #CC立即赋值gcc
CC += -g #CC追加赋值-g, gcc -g表示添加调试信息,可用于gdb的调试

SRC = hello.c
OBJ = $(SRC:.c=.o) #变量的替换引用,把hello.c的.c替换成.o

debug :
    @echo "hello world"
    echo $(SRC)
    echo $(OBJ)

$(TARGET): $(SRC)
    $(CC) -o $@ $<

compile: $(TARGET)

clean:
    @rm hello hello.o -r

.PHONY: clean compile

f.常见函数

1) wildcard通配符函数

Makefile中的wildcard 是一个函数,用于扩展通配符,返回与通配符匹配的文件列表。通配符是一种特殊的字符,可以表示多个文件名或目录名,常见的通配符有 * 和 ?,分别表示任意长度的任意字符和单个任意字符。格式如下:

$(wildcard argments)

比如*.c 表示所有以 .c 结尾的文件名,a?.txt 表示所有以 a 开头,中间有一个任意字符,以 .txt 结尾的文件名。例如: 

SRC = $(wildcard src/*.c)

表示查找并返回src目录下所有的.c文件, *表示通配符, 匹配一个或者多个任意字符。

2)shell命令函数

$(shell <cmd> <args>)

•cmd: 执行命令名称
•args:参数列表
•返回值: 返回命令执行结果 

例如:

SRC = $(shell find . -name *.c)

表示查找当前目录及子目录下的所有.c文件结尾的代码源文件 

3) patsubst替换函数

$(patsubst pattern,replacement,text) 

•pattern: 是一个包含通配符 % 的模式,表示匹配任意长度的任意字符
•replacement: 是一个替换字符串,也可以包含 %,表示用 pattern 中匹配的字符替换。
•text:是一个要处理的文本,可以包含多个以空格分隔的单词。

•返回值:patsubst 函数会在 text 中找到所有符合 pattern 的单词,并用 replacement 替换它们,然后返回替换后的文本。 

例如,如果有一个变量 src,它的值是:

src = a.c b.c c.c 

想把它的值中的所有 .c 后缀替换成 .o 后缀,可以这样写: 

obj = $(patsubst %.c,%.o,$(src)) 

这样,obj 的值就是:

obj = a.o b.o c.o 

4) subst替换函数 

$(subst from,to,text)

•from: 是要被替换的字符或单词
•to: 是替换后的字符或单词
•text:是要处理的字符串。
•返回值:subst 函数会在 text 中找到所有的 from,并用 to 替换它们,然后返回替换后的字符串。

例如:

$(subst ee,EE,feet on the street) 

返回: 

fEEt on the strEEt  

5)dir函数 

$(dir NAMES...)

dir 函数是一个用于从文件名序列中提取目录部分的函数 

6)suffix函数 

$(suffix <names...>)

•功能:从文件名序列中取出各个文件名的后缀。
•返回值:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
例如: 

$(suffix src/foo.c src-1.0/bar.c hacks)

返回值:

.c .c 

7)basename函数 

$(basename <names...>)

•功能:从文件名序列中取出各个文件名的前缀部分。
•返回值:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。
例如: 

$(basename src/foo.c src-1.0/bar.c hacks)

返回值:

src/foo src-1.0/bar hacks 

8) addsuffix函数 

$(addsuffix <suffix>,<names...>)

•功能:把后缀加到中的每个单词后面。
•返回:返回加过后缀的文件名序列。
例如: 

$(addsuffix .c,foo bar)

返回值:

foo.c bar.c 

9)addprefix函数 

$(addprefix <suffix>,<names...>)

•功能:把前缀加到中的每个单词后面。
•返回值:返回加过前缀的文件名序列。
例如: 

$(addprefix src/,foo bar)

返回值:

src/foo src/bar 

10)foreach函数 

$(foreach <var>,<list>,<text>)

•功能:把list中使用空格分割的单词依次取出并赋值给变量var, 然后执行text表达式

例如: 

files := foo bar baz
files-with-c := $(foreach file,$(files),$(file).c)

11)条件判断语言 

a) ifeq/ifneq语句:

ifeq语句 : 判断参数 是否相等,相等为 true, 否则是 false。

ifeq (arg1, arg2)
        #arg1 arg2 相等执行这里的语句
else
        #arg1 arg2 不相等执行这里的语句
endif

ifneq语句:判断参数 是否不等,不等为 true, 否则为 false。

ifneq (arg1, arg2)
        #arg1 arg2 不相等执行这里的语句
else
        #arg1 arg2 相等执行这里的语句
endif

b) ifdef/ifndef语句

ifdef 语句: 判断参数 是否有值,有值为 true, 否则是 false。

ifdef var
        #如果定义了var,执行这里的内容
else
        #如果没定义var,执行这里的内容
endif

ifndef : 判断参数 是否没有值,没有值为 true, 否则为 false。

ifndef var
        #如果没定义var,执行这里的内容
else
        #如果定义var,执行这里的内容
endif 

三、Makefile综合示例

Makefile

#这是一个Makefile
#TARGET = hello
CC := gcc
#CC += -g
INCLUDE = /usr/include/ \
			/usr/local/include

SRC := $(shell find . -name *.c)
TARGET := $(patsubst ./src/%,./obj/%,$(subst .c,,$(SRC)))
TARGET_DIR = $(dir $(TARGET))
I_FLAGS := $(foreach var,$(INCLUDE), -I$(var)) #-I/usr/local/include

ifndef CC
	CC += -g
else
	CC := gcc
endif

debug:
	@echo "hello wolrd"
	echo $(CC)
	echo $(SRC)
#	echo $(OBJ)
	echo $(TARGET)
	echo $(TARGET_DIR)
	echo $(suffix src/foo.c src-1.0/bar.c hacks)
	echo $(basename src/foo.c src-1.0/bar.c hacks)
	echo $(addsuffix .c,foo bar)
	echo $(addprefix src/,foo bar)
	echo $(I_FLAGS)

$(TARGET): $(SRC)
	mkdir -p $(TARGET_DIR)
	$(CC) -o $@ $< $(I_FLAGS)

compile: $(TARGET)

clean:
	@rm  $(TARGET_DIR) -rf

.PHONY: clean compile

hello.c(放在src文件夹)

#include <stdio.h>

int main()
{
    printf("hello world\n");

    return 0;
}

make结果 

标签:src,TARGET,Makefile,echo,Linux,VAR,ARM,赋值
From: https://blog.csdn.net/m0_66492811/article/details/139304024

相关文章

  • 《Linux内核完全注释》学习笔记:2.5 Linux内核对内存的使用方法
    在Linux0.11内核中,为了有效地使用机器中的物理内存,内存被划分成几个功能区域,如图2-9所示。图2-9物理内存使用的功能区域分布图Linux内核程序占据在物理内存的开始部分,接下来是用于供硬盘或软盘等块设备使用的高速缓冲区部分。当一个进程需要读取块设备中的数据时,系统会......
  • 【Linux系统编程】冯诺依曼体系、操作系统、进程的认识
    目录一、认识冯诺依曼体系二、认识操作系统三、认识进程一、认识冯诺依曼体系我们日常使用的计算机,笔记本和我们不常见的计算机如服务器,它们都遵循冯诺依曼体系。下图是冯诺依曼体系结构的图解:我们可以看到冯诺依曼体系结构由以下硬件组成:输入设备、输出设备、存储器......
  • Shell 脚本演示 Linux 中的 Wait 命令
    Wait命令是进程管理命令之一。Linux中有不同的进程命令,主要使用5个命令,它们是ps、wait、sleep、kill、exit。ps是进程状态的缩写。它显示有关活动进程的信息。wait命令将暂停调用线程的执行,直到其子进程之一终止。它将返回该命令的退出状态。sleep命令用于将下一个命令的执行......
  • springboot本地运行正常,打包jar包上传Linux服务器后报错,无法正常运行解决方法
    问题描述:springboot本地运行正常,打包jar包上传Linux服务器后报错,无法正常运行说明:以下两种打包方式均在IDEA软件内完成,上传服务器使用宝塔面板管理1.第一次打包方式; 设置完打包路径后,进入build菜单进行打包:  选择build或rebuild进行打包,打包后上传jar包到服务器,运......
  • linux服务器硬件及RAID配置实战
    RAID磁盘阵列介绍是RedundantArrayofIndenpendentDisks的缩写,中文简称为独立冗余磁盘阵列把多个独立的物理硬盘按不同的方式组合起来形成一个硬盘组(逻辑硬盘),从而提供比单个硬盘更高的存储性能和提供数据备份技术。组成磁盘阵列的不同方式称为RAID级别(RAIDLevels)常用......
  • 【Linux 网络】网络基础(三)(其他重要协议或技术:DNS、ICMP、NAT)
    一、DNS(DomainNameSystem)DNS 是一整套从域名映射到 IP 的系统。1、DNS 背景TCP/IP 中使用 IP 地址和端口号来确定网络上的一台主机的一个程序,但是 IP 地址不方便记忆。于是人们发明了一种叫主机名的东西,是一个字符串,并且使用 hosts 文件来描述主机名......
  • U-boot、linux内核、根文件系统移植以及程序
    终于这几天把这个移植的流程过了一遍,所以特此回来总结。U-boot移植首先是U-boot移植。Linux系统要启动就必须需要一个bootloader程序,也就说芯片上电以后先运行一段bootloader程序。这段bootloader程序会先初始化DDR等外设,然后将Linux内核从flash(NAND,NORFLASH,SD,MMC等)拷......
  • Linux下GMAC网络设备:硬件接口、GMAC/PHY、驱动、测试程序
    1嵌入式网络硬件接口如下是常见的嵌入式网络硬件接口框图:SOC集成MAC。MAC通过MII系列接口和PHY之间传输数据,通过MDIO接口初始化配置PHY芯片。PHY芯片和RJ45之间通过4组差分模拟信号传输数据,并驱动RJ45的LED信号灯。RJ45通过网线和外部连接。1.1嵌入式网络几种常见架构......
  • Linux-shell的108个案例
    通用函数库#catdiy_func.shredecho(){ #颜色开头部分 echo-ne"\e[5;31m" #取出要加上颜色的内容 echo-n"$@" #颜色的结束部分 echo-e"\e[0m" #echo-e"\e[5;31m$@\e[0m"}greenecho(){ echo-ne"\e[1;32m" ec......
  • Linux-samba-Ubuntu
    sudoaptinstallsamba-ymkdir-pSharechmod0777Sharesudocp/etc/samba/smb.conf/etc/samba/smb.conf.baksudovim/etc/samba/smb.conf[Ubuntu_22.04] comment=Samba path=/home/grayson/Share public=yes writable=yes available=yes browsea......