make工具和Makefile基础语法(含有交叉编译、pthread_create()的处理)

目录

  • 含有交叉编译、pthread_create()处理
  • 初次使用
    • 1、编写Makefile文件
    • 2、make
    • 3、make clean
  • Makefile基本语法
    • 1、Makefile规则格式
    • 2、变量
    • 3、变量赋值符(=、:=、?=、+=)
    • 4、模式规则(通配符)
    • 5、自动化变量
    • 6、伪目标
    • 7、条件判断
    • 8、函数使用
      • 1、函数 subst
      • 2、函数 patsubst
      • 3、函数 dir
      • 4、函数 notdir
      • 5、函数 foreach
      • 6、函数 wildcard

含有交叉编译、pthread_create()处理

摘自:使用makefile编译含有pthread_create()函数时报错:对‘pthread_create’未定义的引用

交叉编译的话直接将Makefile里面的gcc替换成arm-linux-gnueabihf-gcc即可。

在linux应用程序中使用了多线程编程,但是makefile编译却报如下错误:

/tmp/cc5i6uH7.o:在函数‘main’中:
tcpSever.c:(.text+0x62):对‘modRegInit’未定义的引用
tcpSever.c:(.text+0x76):对‘ryS’未定义的引用
tcpSever.c:(.text+0xc0):对‘ryS’未定义的引用
tcpSever.c:(.text+0x10a):对‘ryS’未定义的引用
tcpSever.c:(.text+0x14e):对‘ryS’未定义的引用
collect2: error: ld returned 1 exit status

网上查找解决方案,发现修改makefile即可。如下

test: rySys.o  tcpSever.ogcc -o test rySys.o tcpSever.o -lpthread 
rySys.o: rySys.c rySys.hgcc -c rySys.c -lpthread 
tcpSever.o: tcpSever.c rySys.c rySys.hgcc -c tcpSever.c -lpthread 
clean:rm *.orm test

初次使用

当文件有几十、上百甚至上万个的时候用终端输入 gcc 命令的方法显然是不现实的,为此提出了一个解决大工程编译的工具:make,描述哪些文件需要编译、哪些需要 重新编译 的文件就叫做 Makefile。使用的时候只需要一个 make 命令即可完成整个工程的自动编译,极大的提高了软件开发的效率。

使用make工具可以自动完成编译工作,这些工作包括:

  • 如果修改了某几个源文件,则只重新编译这几个源文件;
  • 如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。

在这里插入图片描述

1、编写Makefile文件

在工程目录下创建Makefile文件:
在这里插入图片描述

Makefile 里面是由一系列的规则组成的,这些规则格式如下:

目标…... : 依赖文件集合……命令1命令2……

Makefile 和 .c 文件是处于同一个目录的,在Makefile文件中输入如下代码:

main: main.o fun1.o fun2.ogcc -o main main.o fun1.o fun2.o
main.o: main.cgcc -c main.c
fun1.o: fun1.cgcc -c fun1.c
fun2.o: fun2.cgcc -c fun2.cclean:rm *.orm main

上述代码中所有行首需要空出来的地方一定要使用 “TAB” 键!不要使用空格键!这是 Makefile 的语法要求

2、make

Makefile 编写好以后我们就可以使用make命令来编译我们的工程了,直接在命令行中输入make即可,make 命令会在当前目录下查找是否存在 “Makefile” 这个文件,如果存在的话就会按照 Makefile 里面定义的编译方式进行编译:

make

在这里插入图片描述
此时我们修改一下 fun1.c 的文件源码,再make:
在这里插入图片描述
可以看出因为我们修改了fun1.c这个文件,所以fun1.c和最后的可执行文件main重新编译了,其它没有修改过的文件就没有编译,而且我们只需要输入make命令即可,非常方便。

3、make clean

make clean

在这里插入图片描述

Makefile基本语法

1、Makefile规则格式

目标...: 依赖文件集合...命令1命令2......

!!命令列表中的每条命令必须以 TAB 键开始,不能使用空格!

  • 比如:
main: main.o fun1.o fun2.ogcc -o main main.o fun1.o fun2.o

这条规则的目标是main,main.o、fun1.o、fun2.o是生成main的依赖文件,如果要更新目标main,就必须先更新它的所有依赖文件,如果依赖文件中的任何一个有更新(更改时间),那么目标也必须更新,“更新”就是执行一遍规则中的命令列表。make命令会为Makefile中的每个以 TAB 开始的命令创建一个 Shell 进程去执行。

  • 示例:
main: main.o fun1.o fun2.ogcc -o main main.o fun1.o fun2.o
main.o: main.cgcc -c main.c
fun1.o: fun1.cgcc -c fun1.c
fun2.o: fun2.cgcc -c fun2.cclean:rm *.orm main

make命令在执行这个Makefile的时候其执行步骤如下:

首先更新第一条规则中的main,第一条规则的目标成为默认目标,只要默认目标更新了那么就认为Makefile的工作完成。在第一次编译的时候由于main还不存在,因此第一条规则会执行,第一条规则依赖于文件main.o、fun1.o和fun2.o这个三个.o文件,这三个.o文件目前还都没有,因此必须先更新这三个文件。make 会查找以这三个.o文件为目标的规则并执行。

以main.o为例,发现更新main.o的是第二条规则,因此会执行第二条规则,第二条规则里面的命令为“gcc –c main.c”,这行命令就是不链接编译main.c,生成main.o。

最后一个规则目标是clean,它没有依赖文件,因此会默认为依赖文件都是最新的,所以其对应的命令不会执行,当我们想要执行clean的话可以直接使用命令make clean,执行以后就会删除当前目录下所有的.o文件以及main,因此clean的功能就是完成工程的清理工作。

  • 总结make执行过程:

① make命令会在当前目录下查找以 Makefile(或makefile) 命名的文件。

② 当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。

③ 当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标。

!!注意: 除了 Makefile 的“终极目标”所在的规则以外,其它规则的顺序在 Makefile中是没有意义的,“终极目标”就是指在使用 make 命令的时候没有指定具体的目标时,make 默认的那个目标,它是 Makefile 文件中第一条规则的目标,如果 Makefile 中的第一个规则有多个目标,那么这些目标中的第一个目标就是 make 的“终极目标”

2、变量

跟 C 语言一样 Makefile 也是支持变量的,如前面的例子:

main: main.o fun1.o fun2.ogcc -o main main.o fun1.o fun2.o

上述 Makefile 语句中,main.o、fun1.o、fun2.o 这三个依赖文件,我们输入了两遍,我们这个 Makefile 比较小,如果 Makefile 复杂的时候这种重复输入的工作就会非常费时间,Makefile 加入了变量支持,类似 C 语言中的宏。使用变量将上面的代码修改:

# Makefile 变量的使用
objects = main.o fun1.o fun2.o
main: $(objects)gcc -o main $(objects)

Makefile 的注释用#。
我们定义了一个变量objects,并且给这个变量进行了赋值,其值为字符串main.o fun1.o fun2.o,Makefile 中变量的引用方法是 $(变量名),如本例中: $(objects)。

我们在定义变量objects 的时候使用“=”对其进行了赋值,Makefile
变量的赋值符还有其它两个“:=”和“?=”,我们来看一下这三种赋值符的区别:

3、变量赋值符(=、:=、?=、+=)

使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值,比如如下代码:

① 赋值符=:

name = lcx
curname = $(name)
name = licxprint:@echo curname: $(curname)

第一行定义了一个变量name,值为lcx,第二行定义了变量curname,值也为lcx,第三行变量name的值改为licx,第五、六行是输出变量curname的值。在 Makefile 要输出一串字符的话使用echo。(第六行中的echo前面加了个 @符号,因为 Make 在执行的过程中会自动输出命令执行过程,在命令前加上@就不会输出命令执行过程)执行结果:
在这里插入图片描述
可以看出,curname的值不是lcx,而是变量name最后一次赋值的结果。

② 赋值符:=:

name = lcx
curname := $(name)
name = licxprint:@echo curname: $(curname)

执行结果:
在这里插入图片描述
显然,此时curname值为lcx,因为赋值符:=只能使用前面定义的值。

③ 赋值符?=

curname ?= licx

上述代码的意思是,如果变量curname前面没有被赋值,那么此变量就是licx,如果前面已经赋过值了,那么就使用前面赋的值。

④ 变量追加符+=

Makefile 中的变量是字符串,有时候我们需要给前面已经定义好的变量添加一些字符串,此时就要使用变量追加符号+=,如:

objects = main.o fun1.o
objects += fun2.oprint:@echo objects: $(objects)

在这里插入图片描述
可以看出,objects最后的值为main.o fun1.o fun2.o。

4、模式规则(通配符)

如下示例代码:

objects = main.o fun1.o fun2.o
main: $(objects)gcc -o main $(objects)main.o: main.cgcc -c main.c
fun1.o: fun1.cgcc -c fun1.c
fun2.o: fun2.cgcc -c fun2.cclean:rm *.orm main

显然,如果工程中.c文件很多,这样做就很不方便,我们可以使用 Makefile 中的模式规则,使用一条规则来将所有的.c文件编译为对应的.o文件。

模式规则中,至少在规则的目标定义中要包含%,否则就是一般规则,目标中的%表示对文件名的匹配,%表示长度任意的非空字符串,比如%.c就是所有的以.c结尾的文件,类似于通配符

示例可以改成如下形式:

objects = main.o fun1.o fun2.o
main: $(objects)gcc -o main $(objects)%.o: %.c#命令clean:rm *.orm main

第六行的命令我们需要借助下面的自动化变量 ↓↓↓

5、自动化变量

上面讲的模式规则中,目标和依赖都是一系列的文件,每一次对模式规则进行解析的时候都会是不同的目标和依赖文件,而命令只有一行,那么如何通过一行命令来从不同的依赖文件中生成对应的目标?自动化变量就是完成这个功能的!

自动化变量就是这种变量会把模中所定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完,自动化变量只应该出现在规则的命令中,常用的自动化变量如下:
在这里插入图片描述
常用的三种: $@、 $< 和 $^

那么上述代码我们可以完善:

objects = main.o fun1.o fun2.o
main: $(objects)gcc -o main $(objects)%.o: %.cgcc -c $<clean:rm *.orm main

6、伪目标

伪目标的主要是为了避免 Makefile 中定义的执行命令的目标和工作目录下的实际文件出现名字冲突,有时候我们需要编写一个规则用来执行一些命令,但是这个规则不是用来创建文件的,比如文章示例有如下代码用来完成清理工程的功能:

clean:rm *.orm main

上述规则中并没有创建clean文件的命令,因此工作目录下永远都不会存在文件clean,当我们输入make clean以后,后面的rm *.o和rm main总是会执行。如果我们在工作目录下创建一个名为clean(重名)的文件,当执行make clean的时候,规则因为没有依赖文件,所以目标被认为是最新的 (刚创建了一个clean文件,是最新的),因此后面的rm命令也就不会执行,如图所示:

在这里插入图片描述

为了避免这个问题,我们可以将clean声明为伪目标,声明方式如下:

.PHONY:clean

那么我们可以将示例代码修改为:

.PHONY : cleanclean:rm *.orm main

在这里插入图片描述

7、条件判断

在 C 语言中我们通过条件判断语句来根据不同的情况来执行不同的分支,Makefile 也支持条件判断,语法有两种如下:

<条件关键字>
<条件为真时执行的语句>
endif

以及:

<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif

其中条件关键字有 4 个:ifeq、ifneq、ifdef 和 ifndef,这四个关键字其实分为两对、ifeq 与ifneq、ifdef 与 ifndef,先来看一下 ifeq 和 ifneq,ifeq 用来判断是否相等,ifneq 就是判断是否不相等,ifeq 用法如下:

ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >,<参数 2>’
ifeq “<参数 1>,<参数 2>”
ifeq “<参数 1>,<参数 2>’
ifeq ‘<参数 1>,<参数 2>

上述用法中都是用来比较“参数 1”和“参数 2”是否相同,如果相同则为真,“参数 1”和“参数 2”可以为函数返回值。ifneq 的用法类似,只不过 ifneq 是用来了比较“参数 1”和“参数 2”是否不相等,如果不相等的话就为真。

ifdef 和 ifndef 的用法如下:

ifdef <变量名>

如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。“变量名”同样可以是一个函数的返回值。ifndef 用法类似,但是含义用户 ifdef 相反。

8、函数使用

Makefile 支持函数,类似 C 语言一样,Makefile 中的函数是已经定义好的,我们直接使用,不支持我们自定义函数。make 所支持的函数不多,函数的用法如下:

$(函数名 参数集合)

或者:

${函数名 参数集合}

可以看出,调用函数和调用普通变量一样,使用符号 “$ ” 来标识。参数集合是函数的多个参数,参数之间以逗号“,”隔开,函数名和参数之间以“空格”分隔开,函数的调用以“$”开头。

接下来我们介绍几个常用的函数,来保证后面的学习。其它的函数大家可以参考《跟我一起写 Makefile》这份文档。

1、函数 subst

函数 subst 用来完成字符串替换,调用形式如下:

$(subst <from>,<to>,<text>)

此函数的功能是将字符串< text>中的内容替换为< to>,函数返回被替换以后的字符串,比如如下示例:

$(subst zzk,ZZK,my name is zzk

把字符串“my name is zzk”中的“zzk”替换为“ZZK”,替换完成以后的字符串为“my name is ZZK”。

2、函数 patsubst

函数 patsubst 用来完成模式字符串替换,使用方法如下:

$(patsubst <pattern>,<replacement>,<text>)

此函数查找字符串< text>中的单词是否符合模式< pattern>,如果匹配就用< replacement>来替换掉,< pattern>可以使用通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字符串。如果< replacement>中也包涵“%”,那么< replacement>中的“%”将是< pattern>中的那个“%”所代表的字符串,比如:

$(patsubst %.c,%.o,a.c b.c c.c)

将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”,替换完成以后的字符串为“a.o b.o c.o”。

3、函数 dir

函数 dir 用来获取目录,使用方法如下:

$(dir <names…>)

此函数用来从文件名序列< names>中提取出目录部分,返回值是文件名序列< names>的目录部分,比如:

$(dir </src/a.c>)

提取文件“/src/a.c”的目录部分,也就是“/src”。

4、函数 notdir

函数 notdir 看名字就是知道去除文件中的目录部分,也就是提取文件名,用法如下:

$(notdir <names…>)

此函数用与从文件名序列< names>中提取出文件名非目录部分,比如:

$(notdir </src/a.c>)

提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。

5、函数 foreach

foreach 函数用来完成循环,用法如下:

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

此函数的意思就是把参数中的单词逐一取出来放到参数 < var> 中, 然后再执行 < text > 所包含的表达式。每次 < text > 都会返回一个字符串,循环的过程中,< text > 中所包含的每个字符串会以空格隔开,最后当整个循环结束时,< text > 所返回的每个字符串所组成的整个字符串将会是函数 foreach 函数的返回值。

6、函数 wildcard

通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时,通配符不会自动展开,这个时候就要用到函数 wildcard,使用方法如下:

$(wildcard PATTERN…)

比如:

$(wildcard *.c)

上面的代码是用来获取当前目录下所有的.c 文件,类似“%”。

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

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

相关文章

树莓派超声波模块测距

参考&#xff1a;树莓派超声波模块测距及C语言demo 作者&#xff1a;一只青木呀 发布时间&#xff1a; 2020-07-22 16:54:16 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/107516949 前面这篇博文已经讲过了&#xff1a;树莓派外设开发基础&#xf…

spring cloud (一、服务注册demo_eureka)

首先我的博客记理论知识很少&#xff0c;大家对spring boot、spring cloud 、分布式 、微服务什么的一点概念都没有的还请先去百度看看理论&#xff0c;知道了是做什么用的&#xff0c;然后再写下demo ,这样学起来才没有那么迷糊&#xff01; 我一般写下的demo都是我踩了很多坑…

JavaFX 的 UI 控件集 ControlsFX

出处&#xff1a;http://www.oschina.net/p/controlsfx JavaFX 的 UI 控件集 ControlsFX ControlsFX 开源项目旨在为 JavaFX 开发提供更多的 UI 控件和其他工具。 该项目主要针对JavaFX 8.0&#xff08;捆绑在JDK 8中&#xff09;&#xff0c;考虑到JavaFX中已经包含了一些控件…

shell 脚本编写使用

目录一、什么是shell 脚本二、shell 脚本写法三、shell 脚本语法1、第一个 shell 脚本2、read命令3、数值计算4、test命令5、中括号判断符6、默认变量7、条件判断8、函数9、循环一、什么是shell 脚本 终端中输入一系列命令完成一些操作&#xff0c;但是我们一条一条输入命令&a…

javaweb开发之处理表单上传文件和文件下载

2019独角兽企业重金招聘Python工程师标准>>> 一、基于表单的上传文件 1. enctype属性 当表单需要上传文件时&#xff0c;需指定表单 enctype 的值为 multipart/form-data。 在 form 元素的语法中&#xff0c;enctype 属性指定将数据发送到服务器时浏览器使用的编码…

单片机预备知识(电平、进制转换、字节、数据类型)

参考&#xff1a;郭天祥十天带你精通51单片机 网址&#xff1a;https://www.bilibili.com/video/BV1DW411a7mz/?spm_id_from333.788.videocard.0 目录电平特性二进制进制转换1K字节等于多少字节基本数据类型电平特性 二进制 进制转换 也可参考这篇&#xff1a;进制问题和C语言…

[summary] 单调队列

2019独角兽企业重金招聘Python工程师标准>>> 很久没做单调队列了╮(╯_╰)╭ 已经不太会了.... 单调队列究其本质就是队列,加上队尾可以删除. 队列都是从队尾插入,队首输出.单调队列也一样. 以队尾到队首递增的单调队列为例,我们需要保证队列的单调性,所以当插入一…

段错误的调试方法(printf输出、GDB)

参考&#xff1a;段错误产生原因及简单的调试方法 参考&#xff1a;如何解决段错误 参考&#xff1a;C语言gdb调试之精髓&#xff08;常用命令、多进程、多线程、程序日志&#xff09; 网址&#xff1a;https://www.bilibili.com/video/BV1ei4y1V758?fromsearch&seid40373…

STM32使用IIC总线通讯协议在OLED屏幕上显示字符串、汉字、单总线获取DHT11模块温湿度并通过IIC显示到屏幕(软件IIC)

参考&#xff1a;基于stm32软件IIC的oled显示温湿度 作者&#xff1a;ZPZ DayUp 发布时间&#xff1a; 2021-07-25 20:52:43 网址&#xff1a;https://blog.csdn.net/m0_56197680/article/details/119077076?spm1001.2014.3001.5501 目录软件模拟IIC时序(起始、停止、应答、发…

w ndows7端口在哪里,win7电脑遇到端口被占用的情况该如何查看并将其关闭

Windows7操作系统的酷炫和强大已经深受用户们的喜欢了&#xff0c;这里根大家分享的是教你查看win7电脑端口是否被占用的技巧&#xff0c;端口是我们在进行远程或者打印机等都会遇到的&#xff0c;但是有很多用户会遇到端口被占用的情况&#xff0c;遇到这样的问题首先就要找出…

STM32F103五分钟入门系列(十三)独立看门狗IWDG

参考&#xff1a;STM32F103五分钟入门系列&#xff08;十三&#xff09;独立看门狗IWDG 作者&#xff1a;自信且爱笑‘ 发布时间&#xff1a;2021-07-31 19:50:28 网址&#xff1a;https://blog.csdn.net/Curnane0_0/article/details/119269391?utm_sourceapp&app_version…

android自动软键盘,Android自定义软键盘

MyKeyboardAndroid自定义键盘的使用实现步骤第一步&#xff1a;1、新建一个xml文件夹放在res目录下面&#xff0c;然后新建xml文件:money_keyboard.xml2、然后在XML文件中添加按钮布局&#xff0c;这个布局就是键盘的样子了android:horizontalGap"1dp"android:keyWid…

Bootstrap使用-1

目录 结构&#xff1a;1. 视图函数2. 模板3. 登陆4. 怎样发生的添加模板基础模板提供的block定制基础模板结构&#xff1a; $ tree -I "__pycache*|*.pyc|*.xlsx" -FCL 3 . |-- templates/ | -- h1.html -- test-boostracp.py 1. 视图函数 test-boostracp.py from …

段错误、内存溢出、内存泄漏(区别)、堆溢出、栈溢出

参考&#xff1a;内存泄漏、内存溢出、段错误、堆溢出、栈溢出 作者&#xff1a;焦木白 发布时间&#xff1a;2019-10-22 网址&#xff1a;https://blog.csdn.net/jiaomubai/article/details/102680705?spm1001.2014.3001.5501 目录段错误内存溢出内存泄漏栈溢出堆溢出段错误 …

C语言中指针的地址和内容

参考&#xff1a;C语言中指针的地址和内容 作者&#xff1a;wallying 发布时间&#xff1a;2018-10-18 09:47:54 网址&#xff1a;https://blog.csdn.net/qq_36631580/article/details/89375140?spm1001.2014.3001.5502 #include <stdio.h>//一般用"地址"表示…

android运行过程简书,android 启动过程(一)

1、由init.rc调用 app_main.cpp的main方法&#xff0c;启动zygote进程3、调用AndroidRuntime.cpp 的start方法传递ZygoteInit类路径5、AndroidRuntime.cpp的start方法主要启动java虚拟机跟注册虚拟机&#xff0c;调用ZygoteInit的main方法6、ZygoteInit的main方法主要 把zygote…

回调函数 —— 借助中间通用函数(形参里有函数指针,实现函数注册)调用不同的回调函数 (多态/分层)

回调函数传参&#xff1a;函数指针做函数参数&#xff08;回调函数&#xff09; 目录背景回调函数是实现函数分层且单向依赖的好办法&#xff0c;使用函数指针运行struct结构体回调函数代码更清晰简单理解回调函数Demo其他回调函数博文背景 这是我在实际工作中遇到的问题&…

ESP8266等模块

模块讲解学习视频可参照&#xff1a;https://space.bilibili.com/323745961?spm_id_from333.788.b_765f7570696e666f.1 作者&#xff1a;叁议电子 目录ESP8266 WIFI模块介绍电脑操作ESP8266单片机上网ESP8266 WIFI模块介绍 电脑操作ESP8266 单片机上网

html5在线音乐列表播放器,HTML5列表音乐播放器SMusic

插件描述&#xff1a;一款基于HTML5、Css3的列表式音乐播放器&#xff0c;包含列表&#xff0c;音量&#xff0c;进度&#xff0c;时间&#xff0c;歌词展示以及模式等功能&#xff0c;不依赖任何库SMusic使用方法这是一款基于HTML5以及CSS3的列表式音乐播放器&#xff0c;增加…

unzipping/Users/xq/.gradle/wrapper /dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3-all.zi

unzipping/Users/xq/.gradle/wrapper /dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3-all.zip to /Users/xq/.gradle/wrapper/dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9 可能是下载时网络原因造成文件缺失 解决方法&#xff1a; cd /Users/xq/.gradle/w…