当前位置:首页 > > 糖果Autosar
[导读]一初识Makefilemake是一种用于项目编译的应用程序,本质是一种脚本。而Makefile则是对make脚本的规则描述。仅仅是写脚本编译项目的话shell脚本也是可以做的,用make的原因在于,make可以解析源文件之间的依赖,根据依赖关系自动维护编译工作。执行宿主操作系统中...


一 初识Makefile

make是一种用于项目编译的应用程序,本质是一种脚本。而Makefile则是对make脚本的规则描述。
仅仅是写脚本编译项目的话shell脚本也是可以做的,用make的原因在于,make可以解析源文件之间的依赖,根据依赖关系自动维护编译工作。执行宿主操作系统中的各种命令。
Makefile是一个描述文件,定义一系列的规则来指定源文件之间的调用先后顺序。有自己特定的语法规则,可以定义函数及函数调用。可以集成各种系统命令。Makefile用于指导make程序如何完成工作。


Makefile示例:


sayhello:
echo "hello world!"
  • 1


  • 2



其中sayhello称为目标,下方的 echo “hello world!” 是实现目标的命令。其中echo前面是TAB制表符,而不能是空格。
对于文件名,可以叫Makefile或makefile,也可以自定义名称。对于是否自定义Makefile文件名的区别在于使用方式不同。


采用默认名称makefile或Makefile:有两种方法,我们的Makefile文件名为Makefile


make -f 文件名 目标名
  • 1




make -f Makefile sayhello
  • 1



或者


make 目标名
  • 1




make -f make.txt sayhello
  • 1



如果不指定目标名字,则默认执行最前面的目标。



makefile三要素:目标;依赖;命令


makefile执行原理:从上到下建立依赖关系;从下到上执行


makefile建立

通过实现一个加减乘除方法作为例子,文件结构如图所示



src中文件如图所示:



然后编写src中Makefile文件


最简单的makefile

  1. app:add.c jian.c cheng.c chu.c main.c


  2. gcc add.c jian.c cheng.c chu.c main.c -I../include -o app



makefile进阶

  1. app:add.o jian.o cheng.o chu.o main.o


  2. gcc add.o jian.o cheng.o chu.o main.o -o app


  3. add.o:add.c


  4. gcc -c add.c -I../include


  5. jian.o:jian.c


  6. gcc -c jian.c -I../include


  7. cheng.o:cheng.c


  8. gcc -c cheng.c -I../include


  9. chu.o:chu.c


  10. gcc -c chu.c -I../include


  11. main.o:main.c


  12. gcc -c main.c -I../include



makefile优化

(1)常用的变量名(约定俗成的):

CC:表示c编译器版本


CFLAGS:表示编译时参数


CPPFLAGS:表示预处理参数


CXX:表示C 编译器版本


CXXFLAGS:表示c 编译时参数


LDFLAGS:表示库参数库选项


INCLUDE:表示头文件目录


TARGET:表示目标名


RM:删除选项


(2)一些特殊字符

$(变量):对变量取值


@:只显示命令结果,忽略命令本身


-:如果当前命令出错,忽略错误,继续执行


%:通配符,通配符是以遍历的方式实现的


(3)特殊变量

用于当前目标:


$@:代表目标


$<:代表依赖中的第一个


$^:代表所有依赖


(4)makefile内置函数

wildcard:按照指定格式获取当前目录下的所有文件名


例:SOURCEFILE=$(wildcard *.c):获取.c后缀的所有文件并返回赋值给SOURCEFILE


patsubst:根据指定的格式进行替换(字符串替换)


例:DEFFILE=(SOURCEFILE))


代码

  1. .PHONY:clean #伪目标


  2. CC=gcc


  3. INCLUDE=-I../include


  4. CFLAGS=-c -g -Wall $(INCLUDE) #-g增加调试信息 -Wall严格编译


  5. CPPFLAGS=-E -D #-E头文件展开 -D编译时定义宏


  6. CXX=g


  7. LDFLAGS=-L../lib -lpthread #这只是个例子,并没用到该库。-l库名


  8. TARGET=app


  9. RM=rm -rf



  10. SRCFILE=$(wildcard *.c)


  11. DEFFILE=$(patsubst %.c,%.o,$(SRCFILE))



  12. $(TARGET):$(DEFFILE)


  13. $(CC) $^ -o $(TARGET)


  14. %.o:%.c


  15. $(CC) $(CFLAGS) $<



  16. clean:


  17. -$(RM) $(TARGET) $(DEFFILE)


  18. install:


  19. sudo cp $(TARGET) /usr/bin


  20. uninstall:


  21. sudo $(RM) /usr/bin/$(TARGET)




二、Makefile基本结构与依赖

Makefile由一个个规则组成,一个规则的结构大致如下:


targets : prerequisites
commands


targets可以有多个目标,目标之间空格隔开,prerequisites可以包含多个依赖项,依赖项之间空格隔开。


其中 target 为我们要构建的目标,prerequisite为构建目标的依赖项。command为构建目标所需的命令。


举例子来说明,有两个c语言程序文件,func.c和main.c:


func.c文件


//func.c
#include
void func()
{
printf("hello world!\n");
}
  • main.c文件


//main.c
extern void func();
int main()
{
func();
return 0;
}
Makefile文件:


all main : main.o func.o
gcc main.o func.o -o main







main.o : main.c
gcc -o main.o -c main.c



func.o : func.c
gcc -o func.o -c func.c



目标依赖规则:


  • 当目标不存在时,执行对应命令。


  • 当依赖在时间上比目标更新时,执行对应命令。


  • 当依赖关系连续存在时,要依次向上回溯每个目标。


上面那个Makefile中,all和main都是目标。all是没有规则的终极目标,他可以用作生成多个目标。把main和all写在一起的话,make就会检查main的依赖,如果main是最新的就不会执行编译。


上述Makefile文件,执行make all或 make 命令的时候,先检查,main是否存在,如果不存在则检查main的依赖项,main.o和func.o这两个目标,依次向上检查,生成目标。
如果目标存在,但依赖项比目标时间要新,则也要向上检查,生成目标。


三 伪目标的引入

Makefile中的目标指什么?


  • Makefile中目标一般对应着一个文件


  • make比较目标文件和依赖之间的新旧关系,如果依赖新则执行命令


  • make以文件处理作为第一优先级


为什么需要引入伪目标?


一个场景是,Makefile文件中有一个名为clean的目标。对应的命令是清除相应目标文件。如果当前工作目录下没有名为clean的文件,这样是没问题的。但是如果当前目录下存在名为clean的文件,那么make每次检查这个目标的时候就会发现这个文件已经存在了,clean是最新的,导致clean目标对应的清除命令不会执行。



四 Makefile中变量的定义及使用



  1. CC := gcc


  2. TAGRET := hello.out



  3. $(TARGET): func.o main.o


  4. $(CC) -o $(TARGET) func.O



上述Makefile中第一二行依次定义了变量CC、TARGET,第四五行引用了这两个变量,引用变量采用"变量名或者{变量名}"的形式。



Makefile中的变量只能是字符串类型。


Makefile中变量有四种赋值方式:


1,简单赋值( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效


2,递归赋值( = )赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响


3,条件赋值( ?= )如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。


4,追加赋值( = )原变量用空格隔开的方式追加一个新值



用例子来了解一下各个赋值的差别:



简单赋值



  1. x := foo


  2. y := $(x)b


  3. x := new



  4. .PHONY : test


  5. test:


  6. @echo "y => $(y)"


  7. @echo "x => $(x)"


输出值:


x => new


y => foob



递归赋值


  1. x = foo


  2. y = $(x)b


  3. x = new



  4. .PHONY : test


  5. test:


  6. @echo "y => $(y)"


  7. @echo "x => $(x)"


输出值:


y = > newb


x => new



条件赋值


  1. x := foo


  2. y := $(x)b


  3. x ?= new



  4. .PHONY : test


  5. test:


  6. @echo "y => $(y)"


  7. @echo "x => $(x)"


输出值:


y => foob


x = foo



追加赋值


  1. x := foo


  2. y := $(x)b


  3. x = $(y)



  4. .PHONY : test


  5. test:


  6. @echo "y => $(y)"


  7. @echo "x => $(x)"


输出结果:


y => foob


x => foo foob



递归赋值就是一个连锁反应,只要之前与该变量直接产生过关联的变量都会有影响。


条件赋值,第一次为变量赋值的时候推荐条件赋值。



五 Makefile中的变量值的替换



1.使用指定字符串替换变量中的后缀字符(串)


格式:{var:a=b}


注意:替换表达式中不能有空格】


例:


  1. src := acc bcc ccc


  2. obj := $(src:cc=o)


  3. test:


  4. @echo "obj => $(obj)"


make test输出结果:


ao bo co



2.变量的模式替换


使用%保留变量值中的指定字符串,替换替他字符


格式:{var:a%b=x%y}


注意:替换表达式中不能有空格


例:


  1. src := a123b.c a234b.c ajkhb.c


  2. obj := $(src:a%b.c=x%y)


  3. test:


  4. @echo "obj => $(obj)"



分析:原串 a123b.c按照a%b.c进行模式匹配的时候a与b.c中间的123就会被%匹配到,后边就会被保留下来,a和b.c就会被x和y取代。其他的类似。


make test执行结果:


x123y x234y xjkhy



3.规则中的模式替换


targets:target-pattern:prereq-pattern


command1


command2


意义:通过target-pattern从targets中匹配子目标,再通过prereq-pattern从子目标生成依赖,进而构成完整规则。


例:


  1. objs := func.o main.o


  2. $(objs): %.o : %.c


  3. gcc -o $@ -c $^


分析:


上述第二行,通过%.o匹配objs中的func.o,通过func.c生成依赖,再匹配main.o生成main.c依赖。


上述第二行会被make程序解析成


  1. func.o: func.c


  2. gcc -o $@ -c $^


  3. main.o: main.c


  4. gcc -o $@ -c $^




4.变量的嵌套引用


一个变量名中可以包含对其他变量的引用


嵌套引用的本质是使用一个变量表示另外一个变量


例:


  1. x := y


  2. y := z


  3. a := $($(x))


分析: 这个很好理解,上述第三行可以解析为


a := $(y) ==> a := z
5.命令行变量


在shell中运行make的时候,在命令行中定义变量


命令行变量可以默认覆盖Makefile中定义的变量。


例:


  1. hm := hello makefile


  2. test:


  3. @echo "hm => $(hm)"



shell中执行 make hm = cmd


执行结果: hm => cmd



6.override关键字


override关键字用于保护Makefile中的变量不被覆盖。


  1. override var := dest


  2. test:


  3. @echo "var => $(var)"


shell中执行 make hm = cmd


执行结果: var =>dest


这个类似于C 中的const关键字



7.define关键字


define关键字用于在Makefile中定义多行变量


变量定义从变量名开始到endef结束


define定义的变量等价于使用 = 定义的变量(递归赋值)


例:


  1. define ade


  2. Jack!


  3. Tom!


  4. endef


可以加上override 修饰



  1. over define cmd


  2. @echo "Run cmd ls..."


  3. @ls


  4. endif



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭