怎么用ps切片在dw里做网站,什么身一什么网站建设,中山快速做网站服务,怎样建设文章网站目录
一、前言 二、make / Makefile背景介绍 #x1f95d;Makefile是干什么的#xff1f; #x1f347;make又是什么#xff1f;
三、demo实现【见见猪跑#x1f416;】 四、依赖关系与依赖方法
1、概念理清
2、感性理解【父与子#x1f468;】
3、深层理解【程序…目录
一、前言 二、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.itest.i经过编译到test.stest.s经过汇编到test.otest.o经过链接到a.out如果有老铁还不清楚的可看看这篇 编译链接 的过程是不是觉得很冗余复杂我们平常做做练习还好但若是到了那些大型工程中可是具有上千、上万条代码若是一次编译完成之后又修改了源代码接着又想进行编译此时便需要重新敲入指令那会使得工作量变得很大。可是在VS中我们可以无限地修改自己的代码然后随时编译运行不需要考虑这些复杂的原理那Linux中有没有这样的一站式操作呢那就是【make/Makefile】 二、make / Makefile背景介绍 首先我们来介绍一下什么是make/Makefile以及它们之间的关系 Makefile是干什么的
Makefile 是一个文件。它是一个工程文件的编译规则它记录了原始码如何编译的详细信息、描述了整个工程的编译链接等规则。
Makefile 带来的好处就是——“自动化编译。一旦写好只需要一个make命令整个工程完全自动编译极大的提高了软件开发的效率
先来看一下Makefile的【语法】
target目标文件)文件1 文件2依赖文件列表 //依赖关系Tabgcc -o 欲建立的执行文件 目标文件1 目标文件2 ///依赖方法command......target就是我们想要建立的信息一般称作目标文件。而后面的依赖文件列表就是具有相关性的 object files也就是目标文件所依赖的文件可以是一个或多个也可以没有 然后看一下Makefile的【规则】 目标文件与依赖文件列表文件之间要使用冒号隔开目标文件依赖文件列表 target可以是一个目标文件、执行文件甚至可以是一个标签【后面会提到的伪目标】 依赖方法前面必须加Tab空格键 依赖方法以gcc为例也可以是其他的shell指令【command】 会不会写Makefile 从一个侧面说明了一个人是否具备完成大型工程的能力 make又是什么
make是一个命令工具是一个解释makefile中指令的命令工具一般来说大多数的IDE都有这个命令比如Delphi 的 makeVisual C的nmakeLinux下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--进程 的理解请持续关注我哦