Makefile实战(3)(看完这3篇就足够了)
lipiwang 2024-11-27 17:15 10 浏览 0 评论
这篇主要讲解实际工程项目的实战部分,看这篇之前可以看看之前2篇文章。
项目结构如下图:
huge 项?是上层有两个?录,?个是 build ?录,?另?个则是source ?录。前者?于存放共公的 make.rule,以及编译整个项?的的 Makefile。此外在 build ?录中还会在编译时?动?成 libs 和 exes 两个??录。libs ?录?于存放编译出来的库?件,? exes ?于存放编译出来的可执??件。source ?录则?于存放项?的源程序,其下将按各个软件模块分成不同的??录。在现在的 huge 项?中,包括 foo 库和 huge 主程序,所以在 source?录下分别创建了 foo 和huge ??录。对于每?个软件模块??录,?分为?于存放源程序的 src??录和?于存放头?件的 inc??录。当进?编译时,我们希望 Makefile 在 src ?录下?创建?个 deps ?录,?于存放依赖?件,这?点与 compliated 项?中的 deps ?录是?样的;另?个?录objs,也同 complicated 项??样,?于存放编译过程中?成的?标?件。另外,在每?个 src ?录中都会有?个 Makefile,这? Makefile的作?是只?于构建所在?录中的源程序,可以想像的是,在 build ?录下?的 Makefile 将调?每?个软件模块 src ?录下的 Makefile,从?实现整个项?的构建。为了实现各软件模块 src ?录中 Makefile之间最?程度的复?,我们可以让它们共?的部分放在?个独?的?件中 —— 这就是 build ?录下的make.rule 的作?。
创建?录
并不关?项?的源程序,源程序可以在需要时再放?。请先根据图 3.1 创建好那些需要?动创建的?录,采?图3.2 所示的命令能完成这些?动?录的创建?作。
先创建位于 source/foo/src 下?的 Makefile,这个 Makefile 我们可以基于complicated 项?最终版本的 Makefile 进??定的更改?得到,如图 3.3 所示。
图 3.3 中的 Makefile 与 complicated 项?的最终版本相?,包含如下的更改:
(1)增加了 AR 和 ARFLAGS 两个变量,?途是?以?成静态库。
(2)给 DIR_EXES 变量赋了正确的值,?于表示 exes ?录的实际位置。现在,还是采?相对路径。
(3)在 DIRS 变量中增加了 DIR_LIBS 变量中的内容,以便在?成库?件之前创建 build/libs ?录
(4)新增了 RMS 变量,?于表示需要删除的?录和(或)?件。由于这个 Makefile 只是针对构建libfoo.a 库的,所以当我们运? make clean 时,我们不能将位于 build ?录下的 exes和 libs ?录全部删除,这与前?的 complicated 项?是完全不同的。
(5)删除了将 compliated赋值给 EXE 变量,同时增加了 ifneq 条件语句?于判断 EXE 变是否被定义。因为后?在设置 all ?标的依赖关系时,需要判断EXE 变量是否有值,如果没有值,我们并不需要让 all ?标依赖$(EXE)。如果 EXE 没有值,我们也不需要为其调? addprefix 函数增加前缀,否则这会打破我们后?判断 EXE 变量是否有值,从?决定是否让 all ?录依赖于它这??法。
(6)如果 EXE 有值那么我们应当将其值加?到 RMS 变量中,以便在我们调? make clean时清除它。
(7)新增了 LIB 变量,?于存放库名,在这?库的名称就是 libfoo.a。同样采?处理 EXE 变量的?法增加了条件语句。
(8)对 all ?标增加条件语句以决定是否将$(EXE)或是$(LIB)作为它的先决条件。
(9)增加了?条?于构建库的规则,?法就是采? crs 参数调? ar 命令以?成库。
(10)在 clean ?标命令中,采?删除 RMS 变量中的内容,?不是 DIRS 变量中的内容。这?点前?我们说过了,因为我们不希望在 foo模块中 make clean时将 build?录下的 libs 和 exes?录也删除。
现在需要试?试这个 Makefile 是否能?作,在试之前,我们需要先在 src ?录中增加?个源程序。这可以采? touch 命令来创建?个空的 foo.c ?件,操作结果如图 3.4 所示。
从运?的结果来看,的确是在 build/libs ?录的下??成了?个 libfoo.a 库?件。运? make clean以后,也并没有将 build/libs 这个?录给删除,?只是删除了 libfoo.a ?件,这正是我们所设计的。接下来,我们需要考虑的是,将这个?件运?到 source/huge/src ?录下?去。最为直接的想法是,将 foo模块的 Makefile 拷?到 huge/src ?录下?去,然后做?些?的改动。在这样做之前,请等?下!Makefile 的设计与我们采?编程语?进?设计是?样的,我们需要考虑尽可能的复?,以提?可维护性。要做好这?点,这需要我们站在更?的层次去思考如何设计 Makefile。
提?复?性
在?开始,我们提到在 build 的?录下?将会放?个 make.rule ?件,这个?件的?的就是为了让所有位于各软件模块的 src ?录下?的 Makefile 能使?它以提?复?性。也就是说,我们需要考虑将 foo 模块的 Makefile 中的?部分内容放?到 make.rule 中。显然,只能将那些我们认为是公共的部分放?其中。那反过来,foo 模块的 Makefile 中,哪些是不能公?的呢?我想有以下?点:
(1)变量 EXE 和 LIB 的定义对于每?个软件模块是不同的。?如在我们的 huge 项?中,我们需要在source/foo/src ?录中的 Makefile ?将 LIB 变量的值设置为 libfoo.a,且 EXE 变量应当为空。但是,在 source/huge/src ?录中的 Makefile ??,我们却要反过来,只定义EXE 变量的值为hug。
(2)DIR_EXES 变量和 DIR_LIBS 变量由于运?了相对路径,所以也是每个模块特有的。但是可以采?绝对路径的?式解决这个问题。?如,我们可以定义?个 ROOT 环境变量,其值设置为 huge 项?的根?录,这样的话 DIR_EXES 和 DIR_LIBS 就可以通过以 ROOT 为相对路径,从?使得其值对于所有的模块都相同。
考虑到复?性,现在 foo 模块的 Makefile 由两部分组成了,build ?录中的 make.rule 和source/foo/src ?录中的 Makefile,其内容如图 3.5 所示。
有了这?改动以后,你会发现 foo 模块的 Makfile 中 的内容很是简单,其中原来的?部分内容都被放到了 make.rule ?件中。如果要运? make,那么必须先在 Shell 上 export 所需的 ROOT 变量,图 3.6示例了操作步骤。
注意:在 export 所需的 ROOT 变量时,除了先要进? huge项?的根?录外,pwd 命令前后的字符是“`”?不是“’”,这个字符是键盘上“!”键左边的那?个。从运?结果来看,我们为了提?复?性的努?有?点进展!
接下来需要考虑 sourc/huge/src ?录中的 Makefile 了,我们希望在这个?录中放的程序能?成?个可执??件,在测试 Makefile 时,需要在?录中放置?个 main.c ?件,其中的内容如图 3.7所示,?Makefile 的内容如图 3.8 所示。
需要进? source/huge/src ?录进? make,以检验其下的 Makefile 是否能正常?作,结果如图 3.9 所示。你?定会对这?运?的结果感到满意!
加?源程序?件
现在我们的 Makefile 系统已经有了初步的成果了,下?要做的是将源程序加?到?录中。所需的程序内容可以从 complicated 项?中得来,如图 2.10 所示。现在让我们试?试进? source/foo/src?录中进?编译,运?结果如图 3.10 所示。
在构建 foo.dep 依赖?件时,make 就发现了错误,但是还是继续进?编译,直到编译foo.c 时才因为错误?终?。这种?为并不是我们所期望的,理想的情况是,make ?旦发现错误就应当?即退出,这有利于我们在第?时间知道第?个出错点,从?不容易隐藏错误。那这是为什么呢?前?我们说了我们在构建依赖?件的规则中运?了 set -e 命令,以告诉 Shell ?发现错误就退出,可是为什么没有退出呢?想?想我们是如何包含依赖?件的?我们在 include 指令的前?放了?个‘-’,告诉 make 在include 出现错误时,不要报错。正是这?原因导致了即使 make 发现了错误,仍进?后续的构建操作。改动很简单,将 make.rule 中 include 语句前的‘-’去掉,去掉之后的 make 结果如图 3.11 所示。
这?次虽然 make 会报告找不到 foo.dep,但继续进? foo.dep 的?成操作,这是我们所希望的?为。接着,在?成 foo.dep 时,由于找不到 foo.h 头?件所以出错了,这?次 make 直接就告诉了我们这?错误。
下?要做的是解决 foo.h 头?件找不到的问题。根据图 3.1 所示的 huge 项?的?录结构,你会发现,现在的 foo.c 源?件和 foo.h 头?件是分别被存放在不同的?录中的,当进?依赖?件构建时,我们需要采??种形式告诉编译器到指定的?录中查找头?件。看来,我们得对 Makefile 进??定的改造了,改造的基本原理是,利? gcc 的-I(‘i’的?写)选项。更改后的 Makefile 如图 3.12 所示
从改动来看就是增加了?个?于存放各模块所需?到的全部头?件的?录的变量 ——INC_DIRS,这?变量可以存放多个?录,这完全是根据软件模块的需要的。此外,在 make.rule 中增加了?个条件语句块,即当 INC_DIRS 中的值不为空时,先采? strip 函数去除多余的空格,然后再? addprefix 函数为所有的?录的前?加上“-I”前缀。最后的改动就是,让?标?件?成规则和依赖?件?成规则中增加对INC_DIRS 变量的引?,以告诉 gcc 到哪去找头?件。增加这些改动之后,让我们再看看编译 libfoo.a的结果是怎样的,如图 3.13 所示。
这次 libfoo.a 能被成功构建出来了,那 huge 可执?程序呢?进? source/huge/src ?录,运?make 的结果如图 3.14 所示。出错了!
可以看出 main.o ?标?件被正确的?成了,但在连接时找不到_foo 的引?,即找不到 foo ()函数。由于foo ()函数的实现是放在 libfoo.a 库中的,?我们?没有告诉编译器,在连接时应当到 libfoo.a中找所需的函数。其实,现在要做的与前?头?件?录的指定?作是相类似,只是这?次要?到 gcc的-l(?写的L)和-L 选项,更改后的 Makefile 如图 3.15 所示。
这次的改动包含:
(1)在 make.rule ?件中增加了 LINK_LIBS 变量(的引?),这?变量?来存放所有需要在连接时?到的库。
(2)在 make.rule 中将 DIR_LIBS 变量加?到连接器的搜索?录中去,这通过使? gcc 的-L 选项做到。由于我们采?将所有的库?件都放?$(DIR_LIBS)?录中,现在看来这种?式能简化 Makefile 的设计,因为我们不需要指定多个?录。
(3)在各模块的 src ?录中的 Makefile 中,增加了 LINK_LIBS 变量(的定义),且在source/huge/src/Makefile 中对 LINK_LIBS赋值为 foo。在 Linux 中,?个库名的格式为libxxxx.a(或.so),其中的 xxxx 就是我们采? gcc 的-l 选项时所需给的名。在这个 Makefile中,LINK_LIBS 变量的 foo 值就是表示 libfoo.a 库。
图 3.16 是更改后的编译结果,现在 huge 可执?程序能正确的?成了。在结果的最后,你也可以看到运?huge 可执?程序的输出结果。
?此,我们已经完成了各模块 src ?录下?的 Makefile ?件的创建?作。此时,假设我们想往huge 项?中增加?个 libbar.a 库,或说 bar 模块。让我们看?看对于新增模块的 Makfile 需要做些什么?作,以此,也可以检验我们的编译系统设计得如何。假设我们在图 3.1 的?录结构的基础上增加如图 3.17 所示的?录结构,?于存放 bar 模块的源程序。bar 模块的源程序及 Makefile 则如图3.18 所示。
为了构建 libbar.a,我们需要进? source/bar/src ?录运? make 命令,结果如图 3.19 所示。不可思议吧!当需要增加?个软件模块时,我们在 Makefile ??需要做的?作?常的少。只需将已存在的?个 Makefile 拷?过来,然后?改?下就好了,这是?个好的程序编译环境应当具备的?个特征,这?点 huge 项?做到了!
在进? source/huge/src ?录之后进?编译之前,我们需要对main.c和其 Makefile进??点改动,以使其使?新增加的 bar库。更改后的 main.c和 Makefile如图3.20 所示。
图 3.21 示例了 huge 可执?程序的编译和运?结果。回过头来看?看图 3.20 中 Makefile 的改动,你会发现为了给 huge 可执?程序增加?个库,改动?常的?。这??次证明了 huge 项?的编译环境具有很好的可维护性。
简化操作
为了编译 huge 项?,我们需要进?不同的?录进?make(优化这类操作),这并不是?件容易事。下?,我们得考虑如何简化 huge 项?的编译,还记得图 3.1中我们所规划的 build ?录下?的 Makefile 吗?我们现在就是要完成这个 Makefile 的内容,从?简化 huge 项?的编译?作。
不打算?步?步的介绍这个 Makefile 是如何设计出来的的,?是直接列出在图 3.22。以我们现在的?平,我想你可以明?这个 Makefile 在?什么。其中有?点需要指出的是,在这个 Makefile 中,使?了 Shell 中的 for 语句,?于遍历变量 DIRS 中的每?个?录,并进??录运?make 命令。在 1.5.2节中我们提到了 MAKE 特殊变量,在这个 Makefile 中我们就?到了它。之所以?它,?不直接使?make 是为了更好的移植性。还有?点需要注意的是,由于库必须?可执?程序先构建出来,所以在 DIRS 变量中,我们必需将库?录放在可执?程序的?录之前,因为 Makefile 是根据?录的先后顺序来进?构建?作的。
个 Makefile 的结果如何?图 3.23 给出了答案。结果证明,这个 Makefile 的确是简化了我们的?作,我们只要以在 build ?录下运? make 命令就可以构建整个项?。此外,也可以在各个软件模块的 src ?录下单独构建各个模块。你可能会问,我们这?所有的库都是静态库,每?个库的重新构建都需要重新?成 huge 可执??件,因此,单独构建某?个模块似乎没有意义。是的,但是如果我们的库采?的是动态库。那么重新构建某个单独的模块就很有意义了,尤其是?型的项?。因为,在很多情况下,动态库是可以单独构建的,对其的重新构建并不需要对主程序进?重构。
?结
huge 项?中的 Makefile 是?个真正实?的实现,其完全可以被运?到?型项?中去。到此,你已经学会了如何?步?步的构建?个真正实?的软件编译环境了!
本篇是Makefile实战第三篇,欢迎关注、点赞,收藏。
相关推荐
- 《每日电讯报》研发数字工具,教你更有效率地报道新闻
-
为鼓励新闻编辑部持续创新,《每日电讯报》正在尝试有战略地研发数字工具。网站的数字媒体主任马尔科姆o科尔斯(MalcolmColes)表示,《每日电讯报》正试图去“创建一些可持续资产”,以便于让记者们...
- html5学得好不好,看掌握多少标签
-
html5你了解了多少?如果你还是入门阶段的话,或者还是一知半解的话,那么我们专门为你们收集的html5常用的标签大全对你就很有帮助了,你需要了解了html5有哪些标签你才能够更好的。驾驭html5...
- 前端分享-少年了解过iframe么(我想了解少年)
-
iframe就像是HTML的「内嵌画布」,允许在页面中加载独立网页,如同在画布上叠加另一幅动态画卷。核心特性包括:独立上下文:每个iframe都拥有独立的DOM/CSS/JS环境(类似浏...
- 做SEO要知道什么是AJAX(人能看到但搜索引擎看不到的内容)
-
一个明显的,人能看到但搜索引擎不能看到的内容是AJAX。那么什么是AJAX呢?其实,了解过的基本上也都清楚,AJAX不是新的编程语言,而是一种使用现有标准的新方法。AJAX最大的优点是在不重新加...
- 介绍最前沿的人工智能创新,‘无反向传播’神经网络训练方法?
-
图像由GoogleImageFX生成前言:本文整理自NoProp原始论文与实践代码,并结合多个公开实现细节进行了全流程复现。对神经网络训练机制的探索仍在不断演进,如果你也在研究反向传播之...
- 说说我们对HTML6的期许(对html的看法)
-
HTML5概述HTML5是HTML语言最受欢迎的版本之一,它支持音频和视频、离线存储、移动端、和标签属性等等。还提供了article,section,header这样的标签来帮助开发者更好...
- 浏览器中在线预览pdf文件,pdf.mjs插件实现web预览pdf
-
背景:本来只是淘宝上卖卖袜子,想着扩展一下业务,准备做同名“来家居”海外袜子馆外贸项目,碰到pdf在线预览的需求,就找了pdf.js插件进行实践后把此方法记录下来,可以通过多种方法来实现,每种方法都有...
- SVG 在前端的7种使用方法,你还知道哪几种?
-
本文简介点赞+关注+收藏=学会了技术一直在演变,在网页中使用SVG的方法也层出不穷。每个时期都有对应的最优解。所以我打算把我知道的7种SVG的使用方法列举出来,有备无患~如果你还...
- HTML5常用标签大全(html5em标签)
-
HTML前端开发最终取决于掌握标签的多少HTML大概有七八百个标签楼主这里给大家总结了下HTML常用标签标签描述<!--...-->定义注释。<!DOCTYPE>定义文档类型...
- "伪君子Snoop Dogg!"... WHAT?| MetroDaily 24/7
-
TUE.01-新作品-虽说年纪大了会有点糊涂,但是最近SnoopDogg的这波操作实在是让粉丝们有点迷,甚至有人表示没想到他是这样的"伪君子"......而这一切都源于他近日在IG上Po出的一...
- 莎夏·班克斯盼望表哥Snoop Dogg为其作出场曲
-
NXT女子冠军莎夏·班克斯(SashaBanks)近日接受了迈阿密先驱报采访,访谈纪要如下:关于她出众的形象:“我一向喜欢与众不同。为了能让人眼前一亮,我的装束总是非常前卫、非常抢眼,这样才能让观众...
- 喜欢Snoop!全球第一间「史努比博物馆」海外分馆在东京!
-
1950年起,由美國漫畫家CharlesM.Schulz創作的作品《Snoopy》史努比,其鮮明的可愛角色與幽默的劇情內容,至今仍成為許多大朋友與小朋友心中的最愛。為了紀念作者所設立的全球首...
- Vetements 推出 Snoop Dogg 肖像「天价」T-Shirt
-
Vetements的CEOGuramGvasalia早前才透露品牌经营策略的秘密–Vetements如何成为人人热议的话题品牌。但似乎他仍有更多需要解释的东西–这个法国奢侈品牌最新...
- 狗爷Snoop Dogg的《I Wanna Thank Me》巡回演唱会旧金山站
-
西海岸匪帮说唱歌手SnoopDogg在《IWannaThankMe》巡回演唱会旧金山站表演(图片来自ICphoto)西海岸匪帮说唱歌手SnoopDogg(图片来自ICphoto)西海...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)