当前位置: 首页 > news >正文

【Linux】自动化编译工具——make/makefile(超细图例详解!!)

目录

一、前言

 二、make / Makefile背景介绍

 🥝Makefile是干什么的?

 🍇make又是什么?

三、demo实现【见见猪跑🐖】 

 四、依赖关系与依赖方法

1、概念理清 

2、感性理解【父与子👨】

3、深层理解【程序的翻译环境 + 栈的原理】 

 五、多学一招:项目清理

 1、演示与原理讲解

 2、.PHONY伪目标的作用

 3、.PHONY伪目标的原理 

 六、make的工作原理分析

 1、再谈make与Makefile

 2、探究make的判断机制🔍

 七、Makefile小知识📚

 八、总结与提炼

 九、共勉


一、前言

        在之前的博客中,讲解了 Linux的基本指令:指令详解  ,但是呢,在我们常见的项目编译中肯定会包含很多代码文件,只会运用 指令 是不够滴,所以本次博客我们来介绍一下如何使用 make/Makefile 实现项目的自动化构建

  • 大部分老铁都应该知道如何在Linux上编译C语言代码,而且清楚了可执行文件a.out的由来,是从
    • test.c经过预编译test.i
    • test.i经过编译test.s
    • test.s经过汇编test.o
    • test.o经过链接a.out
  • 如果有老铁还不清楚的可看看这篇 编译+链接 的过程,是不是觉得很冗余复杂,我们平常做做练习还好,但若是到了那些大型工程中,可是具有上千、上万条代码,若是一次编译完成之后又修改了源代码,接着又想进行编译,此时便需要重新敲入指令,那会使得工作量变得很大。可是在VS中,我们可以无限地修改自己的代码,然后随时编译运行,不需要考虑这些复杂的原理
  • Linux中有没有这样的一站式操作呢,那就是【make/Makefile】👈

 二、make / Makefile背景介绍

首先我们来介绍一下什么是make/Makefile,以及它们之间的关系 

 🥝Makefile是干什么的?

  • Makefile 是一个文件。它是一个工程文件的编译规则,它记录了原始码如何编译的详细信息、描述了整个工程的编译链接等规则。
  • Makefile 带来的好处就是——“自动化编译"。一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率🚀

🎯先来看一下Makefile的【语法】: 

target(目标文件):文件1 文件2(依赖文件列表)		//依赖关系<Tab>gcc -o 欲建立的执行文件 目标文件1 目标文件2		///依赖方法command......
  • target就是我们想要建立的信息,一般称作目标文件。而后面的依赖文件列表就是具有相关性的 object files,也就是目标文件所依赖的文件(可以是一个或多个,也可以没有)

 🎯然后看一下Makefile的【规则】:

  •  目标文件与依赖文件列表文件之间要使用冒号隔开目标文件:依赖文件列表
  •  target可以是一个目标文件、执行文件,甚至可以是一个标签【后面会提到的伪目标】
  •  依赖方法前面必须加Tab空格键
  •  依赖方法以gcc为例,也可以是其他的shell指令【command】

💪会不会写Makefile ,从一个侧面说明了一个人是否具备完成大型工程的能力💪 

 🍇make又是什么?

  • make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi 的 make,Visual C++的nmake,Linux下GNU的make。可见,Makefile都成为了一种在工程方面的编译方法

【总结一下】:make 一条命令makefile 是一个文件,两个搭配使用,完成项目自动化构建👈 

三、demo实现【见见猪跑🐖】 

了解可什么是make/Makefile之后,我们就来用一用它们 

  • 刚才说到make命令是用来解释 Makefile 中指令的,所以我们需要创建一个。我喜欢用大写的Makefile,当然你写成 makefile 也是可以的
  •  这里直接vim Makefile即可,进入编辑界面,如果有不懂vim的,可以看看我的文章----------
  • Vim 的超详细使用

  • 此时我们可以再创建一个test.c,作为源文件,然后开始往里面写内容
  • 现在我要通过gcc去编译这个test.c的文件,然后生成一个我自己命名的【mytest】这个可执行文件,此时我们只需要在Makefile写上这两行即可
mytest:test.cgcc -o mytest test.c

  • 然后回到命令行,我们来执行一下这个make指令,它就是自动在当前源文件的所在路径下搜寻Makefile,并解释里面命令。之后若是我们需要去编译任何文件,只需要在Makefile里面做一个添加即可,怎么样,是不是很方便

看到了 make / Makefile 的基本实现过程,我们再来说一下 它的原理吧!!!

 四、依赖关系与依赖方法

通过小小的demo,想必你已经感受到了【自动化构建工具】的强大,我们来仔细看看Makefile中的指令为何要如此书写✍ 

1、概念理清 

  • 对于 mytest:test.c,冒号左侧是目标文件,右侧是它的依赖文件,所以就可以说它们之间存在一种【依赖关系】,只有test.c存在才可以有mytest
  • 那要如何通过test.c去生成mytest呢❓ 此时就需要使用到下面的这句gcc指令gcc -o mytest test.c 👉它叫做【依赖方法

 2、感性理解【父与子👨】

 就这么说还是不太好理解,我们举个父与子的生活小案例来帮助理解

今天呢,是这个月的12号的了,家里面在月初给你的2000块钱差不多也花完了,于是这两天只能吃土,此时你打开微信后看到和老爸的聊天框,于是就想着和老爸要点钱【毕竟儿子向父亲要钱天经地义😀

  •  这里的老爸和儿子指的就是[依赖关系]
  •  儿子向老爸要钱指的就是[依赖方法]


下面辨析几种依赖关系与依赖方法 

错误的依赖方法 

  • 此时你打电话和你老爸说:“我是你儿子,你帮我写作业。”
  • 以上这句话就是依赖关系正确,但是依赖方法不正确。老爸帮儿子写作业无法执行

所以只有依赖关系不行,还得有正确的依赖方法 

错误的依赖关系 

  • 此时你拿起室友的手机和他爸爸打电话说:“我是你儿子,你给我点零花钱。”
  • 以上这句话就是依赖方法正确,但是依赖关系不正确。因为别人的老爸没义务给你钱

依赖方法对了,但是依赖关系不对也不行 

 ✔️ 正确的依赖关系与依赖方法

  • 经历了种种挫折后,你重新拿起手机说:“老爸,我是你儿子,可以给我点零花钱吗?”
  • 上面这种说法就是完全正确的依赖关系与依赖方法

完成一件事,必须得有正确的依赖关系 + 正确的依赖方法 

3、深层理解【程序的翻译环境 + 栈的原理】 

 看完了【依赖关系】与【依赖方法】的感性理解,相信你对它们有了一定程度的认识,接下去深入地来了解一下它们之间的关系

  1 mytest:test.o2     gcc test.o -o mytest
  • 开头提到过源程序是如何经过一步步的编译来形成可执行文件的吗,因为可执行文件mytest是依赖于汇编后的目标文件test.o的,但是现在我们没有这个文件,因此就要去倒推一下如何获取这个test.o
  •   对于test.o来说,它依赖于test.s这个经过编译之后文件,可是【test.s】不存在,所以跳转到下一条依赖关系
  3 test.o:test.s4     gcc -c test.s -o test.o
  • 对于test.s来说,它依赖于test.i这个经过预编译之后的文件,可是【test.i】不存在,所以跳转到下一条依赖关系 
  5 test.s:test.i6     gcc -S test.i -o test.s
  •  对于test.i来说,它依赖于test.c这个源文件,查找后发现源文件存在,于是开始执行gcc命令
  7 test.i:test.c8     gcc -E test.c -o test.i

 以下就是我们需要在Makefile中修改的【依赖关系】与【依赖方法】

  • 最后来到命令行中执行一下【make】命令,便完成了所有的编译,对于之前一步步地写这个编译的过程,真的是来得方便很多

  • 因为只有当执行完了最后一条命令后生成了【test.i】的文件之后才可以一一往上继续执行,这种反着来的执行逻辑就相当于是我们在数据结构中学过的,有一个先进后出的逻辑

 那这个Makefile这么牛,我们将 gcc编译 的顺序修改一下,会发生什么呢?

  • 可是呢,当我再去make的时候,却发现这个执行的顺序还是按照没打乱之前的位置,这说明了一点:make会自动推导Makefile中的依赖关系形成栈式结构

【总结一下】:[依赖关系] 中,若是目标文件所依赖的文件不存在,就将这个依赖方法入栈,转到下一组[依赖关系],依次循环往复,直到当前目标文件所依赖的文件存在时,就进行出栈,开始执行依赖方法最后获取的便是那个我们最初想要的目标文件,即使Makefile中的编译顺序发生了变化,make也会去做一个自动推导的工作

 五、多学一招:项目清理

 1、演示与原理讲解

平时我们在进行各种操作之后目录中都会出现很多文件,此时当我们不想要这些文件的时候,就得去一一删除,显得尤为麻烦,如果编译可以使用Makefile来自动化构建,那清理项目中的文件可不可以呢,我们来看看 

  • 此时我们在Makefile中增加一个【清理】功能

  • 来看一下是否可以达到清理的目的

  • 当我想使用清理功能的时候,并没有像自动化编译那样直接make,而是在make后面加上了一个clean,这是为什么呢?
  • 新加上的.PHONY是什么?它对clean而言意味着什么?

 我们带着这些问题一起进入【伪目标】------ .PHONY 的学习📖

 2、.PHONY伪目标的作用

  • .PHONY是一个伪目标,Makefile中将 .PHONY 放在一个目标前就是指明这个目标是伪文件目标。其作用就是防止在Makefile中定义的执行命令的目标和工作目录下的实际文件出现名字冲突

  • 也就是下面这句,此时的clean.PHONY修饰了,那么它就可以反复执行它的依赖方法

.PHONY:clean
  • 可以看到对于目标文件clean来说,它的依赖文件列表为空,上面我们也有提到过它可以为空
 11 clean:12     rm -f mytest test.i test.s test.o
  • 所以只要你一直使用【make clean】,它便会反复地执行rm -f mytest test.i test.s test.o
  • .PHONY 配置项的目标clean并不是其他文件生成的实际文件,使make命令会自动绕过隐含规则搜索过程,也就是说执行命令make clean自动忽略名为"clean"文件的存在,因此声明.PHONY配置项会改善性能,并且不需要担心实际同名文件存在与否😮
  • 【通俗一点说】:.PHONY修饰的目标clean并不是某个依赖项生成的实际文件,因此make命令不再去搜寻当前文件夹下是否有clean文件,这样少去做一些事,自然会改善性能,并且不用担心当前文件夹下是否有同名的文件

 我们到命令行中来验证一下⌨️

  • 可以看到,我进行了三次make clean,不过其实在第一次执行的时候,就已经达成了我们清理的目的,可是后面还可以继续执行,这其实就是.PHONY修饰起的作用
  • 其实对于【clean】来说,不加修饰其实也是可以辺反复执行的,这点我们在本模块开头的时候有说到过。我现在将这个修饰去掉,来试试看

  • 可以看到,即使是去掉了.PHONY做修饰之后一样是可以反复执行

 那就有同学问:这是为什么呢?为何clean不加.PHONY修饰也可以多次执行

  • 原因就在于它的依赖对象为空,当我们需要生成这个【clean】目标文件的时候就不需一些文件必须要存在,因此就可以一直[clean]

 3、.PHONY伪目标的原理 

  • 可是呢,对于他的指令就不行了,例如我们上面说到过的gcc去编译一个文件的过程

  • 我们试着在【mytest】前面加上一个.PHONY的修饰试试

  • 然后再去试试能不能进行反复使用【这里给读者详细解释一下.PHONY修饰的原理】

我们来详细分析一下,首先可以清楚的是加上.PHONY修饰之后便可以多次make,但是可以看到在编译的过程中进行make的时候所执行的指令不太相同,只有gcc test.o -o mytest这一句,却少了如何产生【test.o】的过程,这是为何呢

  • 因为在经过一次make之后,gcc对【test.c】进行了预编译、编译、汇编,最后生成了【test.o】,那它就已经在那里了,在此中间我们没有再对源文件进行再度修改,在编译的时候,其实会去查看目标对象和依赖对象的生成时间,若是依赖对象的生成时间要早于目标对象,说明它还没有被重新修改过,所以无需再度去重新编译生成(这一块在后面make的工作原理中细讲)
  •  因此我们再去make的话gcc是不会重新编译的,可以当我去修改了一下【test.c】这个源文件之后,再度去make一下的话gcc又会对这个源文件进行一个重新的全过程编译。 

❗编译这一块比较复杂,需要重点理解❗ 

  • 不过其实可以看出,每次去修改一下就重新编译全部的文件,也是挺繁琐的。所以我们在开发的时候一般不给编译生成的目标文件带.PHONY的修饰,就防止其被多次重复编译

【总结一下】:

📚 .PHONY修饰的是伪目标,对于伪目标来说,它可以被反复执行

📚 .PHONY修饰的一定能被反复执行但是能被反复执行的不一定被.PHONY修饰

 六、make的工作原理分析

 1、再谈make与Makefile

  • 通过【ldd】去查看make指令的动态依赖关系,我们可以发现 make指令 也是依赖于标准的C库,而我们在Makefile中写得也都是一些指令,因此使用make指令才可以对Makefile中的内容做一个识别

 因此我们可以得出一个结论

👉make是专门给【Makefile】写的一个命令,在执行make的时候,就会自动在你当前目录下去搜索Makefile这个文件,搜索之后打开,然后对它里面的内容做分析 


make 是如何进行分析 Makefile 的呢,有什么规则吗❓

  • make扫描Makefile文件时会默认执行第一组依赖关系和依赖方法 
  • 还记得我们
    • 在获取mytest这个目标对象的时候都是直接使用的【make】吗;
    • 而在获取clean这个目标对象时却用的是【make clean】
  • 那你是否会感到疑惑为何不使用【make mytest】就可以获取到吗,就是因为默认执行的就是第一组的依赖关系和依赖方法
  • 我们可以试着把【clean】和【mytest】调个位置

  • 可以看到,在调换了位置之后我们直接【make】的话获取的就是clean对象了,想要去使用gcc编译源文件生成可执行文件就需要用到【make mytest】。
  • 不过也并不是第一组依赖关系和依赖方法就一定要直接【make】,我们使用【make clean】也是可以用的

 2、探究make的判断机制🔍

 好,我们来深入探讨一下刚才遗留下的问题:make究竟是如何知道我们的可执行文件是否需要重新编译呢❓

  • 再来回顾一下,当我们执行完一次【make】获取mytest这个目标文件后,第二次再去执行【make】指令就不会其效果了,这是为何呢?

  • 我们可以将源文件和可执行文件当做是一条时间轴。对于可执行文件来收,它生成的时间一定是晚于源文件的【因为中间要经过一系列编译 + 链接的过程】

  • 我们可以通过【stat】这个指令来查看源文件和可执行文件的所有属性,不过要观察的还是其中一个叫做ACM时间
    • Access: 最后一次访问该文件的时间
    • Change:最后一次改变该文件属性或状态的时间
    • Modify:最近一次修改文件内容的时间【比较的是这个时间】
  • 可以很清晰地看出10:30:14是要早于11:20:57的。所以【make】指令才会不起作用。所以它就是通过这个 Modify 时间来进行对比才能判断出是否需要重新编译

 七、Makefile小知识📚

 本模块来拓展一下有关make/Mailefile里的一些小知识

1. Makefile文件保存了编译器和链接器的参数选项,并且描述了所有源文件之间的关系。make程序会读取makefile文件中的数据,然后根据规则调用编译器,汇编器,链接器产生最后的输出

2. Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释

  • 【显式规则】:如何生成一个或多个目标文件;
  • 【隐晦规则】:make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写✍makefile,比如源文件与目标文件之间的时间关系判断之类;
  • 【变量定义】:在makefile中可以定义变量,当makefile被执行时,其中的变量都会被扩展到相应的引用位置上,通常使用 $(var) 表示引用变量;
  • 【文件指示】:包含在一个makefile中引用另一个makefile,类似C语言中的include

3. 默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”“makefile”“Makefile”的文件

4. 我们可以在Makefile中添加一些特殊符号,就可以起到一些特殊的功能 

  • 即这个$@$^,前者表示:左侧被编译的所有内容,即【目标文件】,后者表示:之后所有内容,即【依赖文件】

  • 此时,当我们再去make的时候,就可以发现这个特殊符号自动替换成了:两侧的【目标文件】和【依赖文件】


 接下去我再来介绍一种 Makefile 中的特殊文件

  • 写了这么多【make】,你是否感觉每次都会出现回显很麻烦呢?能不能像我们在敲普通指令的时候一样,直接给出结果呢?

  • 这里我们就可以在执行的命令行前加上这个@

  • 此时当我们在【make】和【make clean】的时候就不会产生任何回显了,可以达到一样的效果

 八、总结与提炼

 最后我们来总结一下本文所学习的内容📖

本文我们学习了Linux下的项目自动化构建工具make/Makefile 

  • 首先清楚了【Makefile】它是一个文件,我们可以在里面写入一些编译的规则。而【make】则是一个命令,它可以用来解析Makefile中的内容
  • 接着,在通过初次写一个小案例去接触make/Makefile的时候我们了解到了【依赖关系】和【依赖方法】,不仅感性地去理解了它们,而且深入地清楚了它们的底层实现逻辑是基于数据结构中的栈
  • 然后,不仅仅局限于一个目标文件,我们又学了一招,知道了如何去清理项目中的文件,知道了.PHONY修饰的文件叫做【伪目标文件】
  • 最后,我们通过再度触及make/Makefile,真正搞清楚了它们之间的关系,也了解到make在判断一个文件是否需要重新编译的时候是基于比较源文件与目标文件的【Modify时间】

 九、共勉

       以下就是我对【Linux】makefile自动化编译 的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对  Linux--进程 的理解,请持续关注我哦!!!!!    

 

相关文章:

【Linux】自动化编译工具——make/makefile(超细图例详解!!)

目录 一、前言 二、make / Makefile背景介绍 &#x1f95d;Makefile是干什么的&#xff1f; &#x1f347;make又是什么&#xff1f; 三、demo实现【见见猪跑&#x1f416;】 四、依赖关系与依赖方法 1、概念理清 2、感性理解【父与子&#x1f468;】 3、深层理解【程序…...

goroutine调度策略

Golang的调度器采用M:N调度模型&#xff0c;其中M代表用户级别的线程(也就是goroutine)&#xff0c;而N代表的事内核级别的线程。Go调度器的主要任务就是N个OS线程上调度M个goroutine。这种模型允许在少量的OS线程上运行大量的goroutine。 Go调度器使用了三种队列来管理gorout…...

TypeScript中`unknown`的使用场景:安全处理未知类型

TypeScript中unknown的使用场景&#xff1a;安全处理未知类型 引言 在TypeScript中&#xff0c;unknown类型是除了any类型之外的另一种选择&#xff0c;它用于表示一个值可能是任何类型。与any不同&#xff0c;unknown提供了一种更安全的方式来处理未知的数据&#xff0c;因为…...

react18【系列实用教程】JSX (2024最新版)

为什么要用 JSX&#xff1f; JSX 给 HTML 赋予了 JS 的编程能力 JSX 的本质 JSX 是 JavaScript 的语法扩展&#xff0c;浏览器本身不能识别&#xff0c;需要通过解析工具&#xff08;如babel&#xff09;解析之后才能在浏览器中运行。 bable 官网可以查看解析过程 JSX 的语法 …...

Docker 创建网络

问题&#xff1a; 1.需要将多个容器添加到同一个网络. 2.docker-compose.yaml 如果不指定&#xff0c;默认会重新创建一个网卡. 创建网卡 docker network create -d bridge mynet ##-d 指定模式&#xff08;默认桥接&#xff09;查看自定义网络信息 docker inspect mynet…...

ASME美国机械工程师学会文献如何查询下载经验分享

一、ASME美国机械工程师学会数据库简介&#xff1a; ASME是世界上最大的技术出版机构之一&#xff0c;制定众多的工业和制造业行业标准。现在ASME拥有工业和制造行业的600项标准和规范&#xff0c;这些标准在全球90多个国家被采用。 ASME数据库包含25种专业期刊&#xff0c;其…...

Spring MVC分页示例

Spring MVC分页示例 分页用于在不同部分显示大量记录。在这种情况下&#xff0c;我们将在一页中显示10、20或50条记录。对于其余记录&#xff0c;我们提供链接。 我们可以在Spring MVC中简单地创建分页示例。在此分页示例中&#xff0c;我们使用MySQL数据库来获取记录。 创建…...

C++基础——继承(上)

一、继承的概念 继承 (inheritance) 机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许实现者保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称之为派生类&#xff1b; 继承呈现了面向对象程序设计的层次结构…...

编译安装Python3

1、源码安装 1、安装依赖软件包 yum -y install gcc gcc-c zlib-devel bzip2-devel openssl-devel sqlite-devel readline-devel libffi-devel # python3.7版本安装 2、下载 curl -o python3.6.5.tgz https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz // 或者 w…...

MySQL数据库核心面试题

数据库中的引擎 常用的引擎有InnoDB、MyIsam、Memory三种。 MyIsam&#xff1a;组织形式分为三种&#xff1a; frm文件存储表结构、MyData文件存储表中的数据、MyIndex文件存储表的索引数据。是分开存储的。 Memory&#xff1a;基于内存的&#xff0c;访问速度快&#xff0…...

Golang | Leetcode Golang题解之第85题最大矩形

题目&#xff1a; 题解&#xff1a; func maximalRectangle(matrix [][]byte) (ans int) {if len(matrix) 0 {return}m, n : len(matrix), len(matrix[0])left : make([][]int, m)for i, row : range matrix {left[i] make([]int, n)for j, v : range row {if v 0 {continu…...

Linux基础知识面试题

1. 请描述Linux操作系统的安装过程&#xff0c;并说明其中的关键步骤。 Linux操作系统的安装过程通常涉及以下几个关键步骤&#xff1a; 准备安装介质&#xff1a;需要从官网或者其他可靠来源下载Linux发行版的ISO镜像文件&#xff0c;并制作一个启动U盘或者烧录到DVD中。现在…...

中国高分辨率国家土壤信息网格基本属性数据集(2010-2018)

中国高分辨率国家土壤信息网格基本属性数据集&#xff08;2010-2018&#xff09; 数据介绍 土壤是人类生存和发展的基础&#xff0c;多个联合国可持续发展目标&#xff08;SDGs&#xff09;与土壤资源利用和管理直接相关。然而&#xff0c;全球和我国现有土壤信息大多源于历史土…...

数据仓库项目---Day01

文章目录 框架的安装包数据仓库概念项目需求及架构设计项目需求分析项目框架技术选型系统数据流程设计框架版本选型集群资源规划设计 数据生成模块数据埋点主流埋点方式埋点数据上报时机 服务器和JDK准备搭建三台Linux虚拟机(VMWare)编写集群分发脚本xsyncSSH无密登录配置JDK准…...

若依生成树表和下拉框选择树表结构(在其他页面使用该下拉框输入)

1.数据库表设计 生成树结构的主要列是id列和parent_id列&#xff0c;后者指向他的父级 2.来到前端代码生成器页面 导入你刚刚写出该格式的数据库表 3.点击编辑&#xff0c;来到字段 祖籍列表是为了好找到直接父类&#xff0c;不属于代码生成器方法&#xff0c;需要后台编…...

考研数学|李林《880》做不动,怎么办!?看这一篇!

在考研数学的备考过程中&#xff0c;遇到难题是很常见的情况&#xff0c;尤其是当你尝试解决李林880习题集中的问题时。他以其难度和深度著称&#xff0c;旨在帮助考生深入理解数学分析的复杂概念。 如果你在解题过程中感到困难&#xff0c;这并不是你个人的问题&#xff0c;而…...

paddle ocr 版面分析

教程 https://github.com/PaddlePaddle/PaddleOCR/blob/a4b7d3ba4a8333a23bab1fc1472aa18deec211d1/ppstructure/layout/README_ch.md 额外的模型&#xff0c;但是yolov2的模型缺少yml配置文件&#xff0c;找不到 https://github.com/PaddlePaddle/PaddleOCR/blob/main/ppstruc…...

25. K 个一组翻转链表 - 力扣(LeetCode)

基础知识要求&#xff1a; Java&#xff1a;方法、while循环、for循环、if else语句 Python&#xff1a; 方法、while循环、for循环、if else语句 题目&#xff1a; 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个…...

使用 GPT-4-turbo+Streamlit+wiki+calculator构建Math Agents应用【Step by Step】

&#x1f496; Brief&#xff1a;大家好&#xff0c;我是Zeeland。Tags: 大模型创业、LangChain Top Contributor、算法工程师、Promptulate founder、Python开发者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 个人说明书&#xff1a;Zeeland&…...

[240514] OpenAI 发布 GPT-4o,人机交互的历史性时刻 | 苹果芯片进军服务器剑指AI​ | 谷歌大会以AI为主

目录 OpenAI 发布 GPT-4o&#xff0c;人机交互的历史时刻苹果芯片进军服务器&#xff0c;剑指生成式 AI2024年谷歌开发者大会将围绕 AI 展开 OpenAI 发布 GPT-4o&#xff0c;人机交互的历史时刻 OpenAI 发布了 GPT-4o&#xff0c;大家一直都想要现在终于等到的语音助手 : 勿需…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...