嵌入式Linux学习笔记(三)Linux C编译/Makefile基础

7 篇文章 0 订阅

一、代码编译

  • 没有使用VIM编辑器,使用VSCode编辑代码,简易容易上手,且支持Linux。

1、 编译代码

(1)安装编译需要的软件包

  • 安装 gcc、g++、make 等工具,build-essential提供了编译程序所需的所有软件包。
sudo apt-get install build-essential
  • 查看GCC版本号,“Target: x86_64-linux-gnu”一行,这说明这个 GCC 编译器是针对 X86 架构的,因此只能编译在 X86 架构 CPU 上运行的程序。如果想要编译在 ARM 上运行的程序就需要针对 ARM 的 GCC 编译器,也就是交叉编译器! ARM 开发,因此后期肯定要安装针对 ARM 架构的 GCC 交叉编译器。目标架构不同,需要的GCC编译器就不同。
gcc -v

在这里插入图片描述

(2)编译代码命令

  • GCC 编译器和其它编译器一样,不仅能够检测出错误类型,而且标记除了错误
    发生在哪个文件,哪一行。
gcc [选项] [文件名字]

-c:只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o:<输出文件名>用来指定编译结束以后的输出文件名,如果使用这个选项的话 GCC 默认编译出来的可执行文件名字为 a.out。 -g:添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编
译的时候生成调试所需的符号信息。
-O:对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进行优化,这样产生的可执行文件执行效率就高。
-O2:比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。
  • VScode编辑代码
    在这里插入图片描述
  • 终端编译代码指令gcc,./a.out运行代码
//默认编译后输出a.out
gcc main.c

在这里插入图片描述

//指定输出文件名称,输出main
gcc main.c –o main

在这里插入图片描述

(3)编译流程

  • GCC 编译器的编译流程是:预处理、编译、汇编和链接。
  • 预处理就是展开所有的头文件、替换程序中的宏、解析条件编译并添加到文件中。
  • 编译是将经过预编译处理的代码编译成汇编代码,也就是我们常说的程序编译。
  • 汇编就是将汇编语言文件编译成二进制目标文件。
  • 链接就是将汇编出来的多个二进制目标文件链接在一起,形成最终的可执行文件,链接的时候还会涉及到静态库和动态库等问题。

二、Makefile基础

1、简介

  • 像脚本文件一样,一键编译多个文件。在工程目录下创建名为“Makefile”的文件,
    文件名一定要叫做“Makefile”!!!
作用:

1、如果工程没有编译过,那么工程中的所有.c 文件都要被编译并且链接成可执行程序。
2、如果工程中只有个别 C 文件被修改了,那么只编译这些被修改的 C 文件即可。
3、如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的 C 文件,并且
链接成可执行文件。
  • 编辑Makefile,所有行首需要空出来的地方一定要使用“TAB”键!不要使用空格键!
    在这里插入图片描述
gcc -o main main.o input.o calcu.o //将编译出来的所有.o 文件链接成可执行文件 main

//分别是将 main.c、input.c 和 calcu.c 编译成对应的.o 文件,使用了“- c”选项,只编译不链接
gcc -c main.c			
gcc -c input.c
gcc -c calcu.c
  • Makefile 编写好以后我们就可以使用 make 命令来编译我们的工程了,直接在命令行中输入“make”即可,make 命令会在当前目录下查找是否存在“Makefile”这个文件,如果存在的话就会按照 Makefile 里面定义的编译方式进行编译。
    在这里插入图片描述
  • Makefile 中命令缩进没有使用 TAB 键,会导致一下错误。
    在这里插入图片描述

2、Makefile 语法

(1)Makefile 规则格式

目标…... : 依赖文件集合……
	命令 1
	命令 2
	……
  • 举例,这条规则的目标是 main,main.o、input.o 和 calcu.o 是生成 main 的依赖文件,如果要更新目标 main,就必须先更新它的所有依赖文件,如果依赖文件中的任何一个有更新,那么目标也必须更新,“更新”就是执行一遍规则中的命令列表。规则的命令是用来创建或者更新目标的。规则除第一条,没有先后顺序。
//这是一条规则
main : main.o input.o calcu.o					//目标:依赖文件集合
	 gcc -o main main.o input.o calcu.o			//命令1

(2)Make 的执行过程

1、make 命令会在当前目录下查找以 Makefile(makefile 其实也可以)命名的文件。
2、当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。
3、当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标。

(3)Makefile 变量

  • Makefile 中的变量都是字符串!类似 C 语言中的宏。
  • 举例,main.o input.o 和 calcue.o输入了两遍
main: main.o input.o calcu.o
	 gcc -o main main.o input.o calcu.o

可替换为:

#Makefile 变量的使用					//注释			
objects = main.o input.o calcu.o
main: $(objects)
	gcc -o main $(objects) 
- ① 赋值符“=”
  • 在 Makefile 要输出一串字符的话使用“echo”,就和 C 语言中的“printf”一样。
  • 赋值符“=”,变量的真实值取决于它所引用的变量的最后一次有效值。
name = zzk
curname = $(name) 
name = david

print: 
	@echo curname: $(curname)

结果:curname:david

- ② 赋值符“:=”
  • 赋值符“:=”,变量的真实值取决于它所引用的变量的第一次定义值。
- ③ 赋值符“?=”
  • 如果前面curname没有被赋值,就使用?=这个变量值。
curname ?= david
- ④变量追加“+=”
  • main.o input.o calcu.o
objects = main.o inpiut.o
objects += calcu.o

(4)Makefile 模式规则

  • “%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾的文件,类似与通配符,a.%.c 就表示以 a.开头,以.c 结束的所有文件。
  • 当“%”出现在目标中的时候,目标中“%”所代表的值决定了依赖中的“%”值,使用方
    法如下:
%.o : %.c
	命令
main: main.o input.o calcu.o 
	gcc -o main main.o input.o calcu.o 
main.o: main.c
	gcc -c main.c 
input.o: input.c 
	gcc -c input.c 
calcu.o: calcu.c 
	gcc -c calcu.c 
 
clean:
	rm *.o
	rm main

使用模式规则改为:

objects = main.o input.o calcu.o 
main: $(objects)
	gcc -o main $(objects)

%.o : %.c 
	  #命令

clean: 
	rm *.o
	rm main

(5)Makefile自动化变量 ?

  • 常用的三种:
$@:规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模式中定义的目标集合。
$<:依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%)定义的,那么“$<”就是符合模式的一系列的文件集合。
$^:所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件,“$^”会去除重复的依赖文件,值保留一份。
  • $@
  • $<
  • $^
objects = main.o input.o calcu.o 
main: $(objects) 
	gcc -o main $(objects)
 
%.o : %.c 						#使用了模式规则
	gcc -c $< 					#使用了自动化变量
	
clean:
	rm *.o
	rm main

(5)Makefile 伪目标

  • 使用伪目标的主要是为了避免 Makefile 中定义的只执行命令的目标和工作目录下的实际文
    件出现名字冲突,也可以编写一个规则用来执行一些命令。
.PHONY : clean
  • 声明 clean 为伪目标以后不管当前目录下是否存在名为“clean”的文件,输入“make clean”的话规则后面的 rm 命令都会执行。
objects = main.o input.o calcu.o 
main: $(objects) 
	gcc -o main $(objects)
 
.PHONY : clean					#伪目标

%.o : %.c 						#使用了模式规则
	gcc -c $< 					#使用了自动化变量
	
clean:
	rm *.o
	rm main

(6)Makefile 条件判断

  • 关键字:ifeq、ifneq、ifdef 和 ifndef

  • 语法一:

<条件关键字> 
	<条件为真时执行的语句>
endif
  • 语法二:
<条件关键字> 
	<条件为真时执行的语句>
else
	<条件为假时执行的语句>
endif
- ① ifeq、ifneq 判断是否相等
ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >,<参数 2>’
ifeq “<参数 1>,<参数 2>”
ifeq “<参数 1>,<参数 2>’
ifeq ‘<参数 1>,<参数 2>
- ② ifdef、ifndef 判断是否非空
  • 如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。“变量名”同样可以是一个函数的返回值。
ifdef <变量名>

(7)Makefile 函数使用(不支持自定义函数)

$(函数名 参数集合)
或者
${函数名 参数集合}
- ① 函数 subst
  • 把字符串“my name is zzk”中的“zzk”替换为“ZZK”
$(subst zzk,ZZK,my name is zzk)
- ②函数 patsubst
  • 将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”,替换完成以后的字
    符串为“a.o b.o c.o”。
$(patsubst %.c,%.o,a.c b.c c.c)
- ③函数 dir
  • 提取文件“/src/a.c”的目录部分,也就是“/src”
$(dir </src/a.c>)
- ④函数 notdir
  • 提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。
$(notdir </src/a.c>)
- ⑤函数 foreach
  • 此函数的意思就是把参数中的单词逐一取出来放到参数中,然后再执行 所包含的表达式。每次 都会返回一个字符串,循环的过程中, 中所包含的每个字符串会以空格隔开,最后当整个循环结束时, 所返回的每个字符串所组成的整个字符串将会是函数 foreach 函数的返回值。
- ⑥函数 wildcard
  • 获取当前目录下所有的.c 文件,类似“%”。
$(wildcard *.c)

  • 参照【正点原子】文档学习。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值