⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄

📁 收集了一些关于makefile的资料
💻
📖 第 1 页 / 共 3 页
字号:
      找“makefile”或“Makefile”,因此使用这两个名字是最简单      的。<br>          <br>      一个 makefile 主要含有一系列的规则,如下:<br><br>      <target> : <dependency> <dependency> ...<br>      (tab)&lt;command&gt;<br>      (tab)&lt;command&gt;<br>      .<br>      .<br>      .<br>      <br>      例如,考虑以下的 makefile :<br><br>=== makefile 开始 ===<br>myprog : foo.o bar.o<br>&nbsp;&nbsp;gcc foo.o bar.o -o myprog<br><br>foo.o : foo.c foo.h bar.h<br>&nbsp;&nbsp;gcc -c foo.c -o foo.o<br><br>bar.o : bar.c bar.h<br>&nbsp;&nbsp;gcc -c bar.c -o bar.o<br>=== makefile 结束 ===<br><br>      这是一个非常基本的 makefile —— make 从最上面开始,把上      面第一个目的,‘myprog’,做为它的主要目标(一个它需要保      证其总是最新的最终目标)。给出的规则说明只要文件‘myprog’      比文件‘foo.o’或‘bar.o’中的任何一个旧,下一行的命令将      会被执行。<br>      <br>      但是,在检查文件 foo.o 和 bar.o 的时间戳之前,它会往下查      找那些把 foo.o 或 bar.o 做为目标文件的规则。它找到的关于      foo.o 的规则,该文件的依靠文件是 foo.c, foo.h 和 bar.h 。      它从下面再找不到生成这些依靠文件的规则,它就开始检查磁碟      上这些依靠文件的时间戳。如果这些文件中任何一个的时间戳比      foo.o 的新,命令 'gcc -o foo.o foo.c' 将会执行,从而更新      文件 foo.o 。 <br>      <br>      接下来对文件 bar.o 做类似的检查,依靠文件在这里是文件      bar.c 和 bar.h 。<br>      <br>      现在, make 回到‘myprog’的规则。如果刚才两个规则中的任      何一个被执行,myprog 就需要重建(因为其中一个 .o 档就会比      ‘myprog’新),因此连接命令将被执行。<br>      <br>      希望到此,你可以看出使用 make 工具来建立程序的好处——前      一章中所有繁琐的检查步骤都由 make 替你做了:检查时间戳。      你的源码文件里一个简单改变都会造成那个文件被重新编译(因      为 .o 文件依靠 .c 文件),进而可执行文件被重新连接(因为       .o 文件被改变了)。其实真正的得益是在当你改变一个 header       档的时候——你不再需要记住那个源码文件依靠它,因为所有的      资料都在 makefile 里。 make 会很轻松的替你重新编译所有那      些因依靠这个 header 文件而改变了的源码文件,如有需要,再      进行重新连接。<br>      <br>      当然,你要确定你在 makefile 中所写的规则是正确无误的,只      列出那些在源码文件中被 #include 的 header 档……<br><br>   2.2 编写 make 规则 (Rules)<br><br>            最明显的(也是最简单的)编写规则的方法是一个一个的查      看源码文件,把它们的目标文件做为目的,而C源码文件和被它      #include 的 header 档做为依靠文件。但是你也要把其它被这些      header 档 #include 的 header 档也列为依靠文件,还有那些被      包括的文件所包括的文件……然后你会发现要对越来越多的文件      进行管理,然后你的头发开始脱落,你的脾气开始变坏,你的脸      色变成菜色,你走在路上开始跟电线杆子碰撞,终于你捣毁你的      电脑显示器,停止编程。到低有没有些容易点儿的方法呢?<br>      <br>      当然有!向编译器要!在编译每一个源码文件的时候,它实在应      该知道应该包括什么样的 header 档。使用 gcc 的时候,用 -M      开关,它会为每一个你给它的C文件输出一个规则,把目标文件      做为目的,而这个C文件和所有应该被 #include 的 header 文      件将做为依靠文件。注意这个规则会加入所有 header 文件,包      括被角括号(`<', `>')和双引号(`"')所包围的文件。其实我们可以      相当肯定系统 header 档(比如 stdio.h, stdlib.h 等等)不会      被我们更改,如果你用 -MM 来代替 -M 传递给 gcc,那些用角括      号包围的 header 档将不会被包括。(这会节省一些编译时间)<br>      <br>      由 gcc 输出的规则不会含有命令部分;你可以自己写入你的命令      或者什么也不写,而让 make 使用它的隐含的规则(参考下面的      2.4 节)。<br><br>   2.3 Makefile 变量<br><br>            上面提到 makefiles 里主要包含一些规则。它们包含的其它的东      西是变量定义。<br>      <br>      makefile 里的变量就像一个环境变量(environment variable)。      事实上,环境变量在 make 过程中被解释成 make 的变量。这些      变量是大小写敏感的,一般使用大写字母。它们可以从几乎任何      地方被引用,也可以被用来做很多事情,比如:<br>      <ul>               i) 贮存一个文件名列表。在上面的例子里,生成可执行文件的            规则包含一些目标文件名做为依靠。在这个规则的命令行            里同样的那些文件被输送给 gcc 做为命令参数。如果在这            里使用一个变数来贮存所有的目标文件名,加入新的目标            文件会变的简单而且较不易出错。<br><br>        ii) 贮存可执行文件名。如果你的项目被用在一个非 gcc 的系            统里,或者如果你想使用一个不同的编译器,你必须将所            有使用编译器的地方改成用新的编译器名。但是如果使用一            个变量来代替编译器名,那么你只需要改变一个地方,其            它所有地方的命令名就都改变了。<br><br>       iii) 贮存编译器旗标。假设你想给你所有的编译命令传递一组            相同的选项(例如 -Wall -O -g);如果你把这组选项存            入一个变量,那么你可以把这个变量放在所有呼叫编译器            的地方。而当你要改变选项的时候,你只需在一个地方改            变这个变量的内容。<br>      </ul>      要设定一个变量,你只要在一行的开始写下这个变量的名字,后      面跟一个 = 号,后面跟你要设定的这个变量的值。以后你要引用      这个变量,写一个 $ 符号,后面是围在括号里的变量名。比如在      下面,我们把前面的 makefile 利用变量重写一遍:<br><br>      === makefile 开始 ===<br>OBJS = foo.o bar.o<br>CC = gcc<br>CFLAGS = -Wall -O -g<br><br>myprog : $(OBJS)<br>&nbsp;&nbsp;$(CC) $(OBJS) -o myprog<br><br>foo.o : foo.c foo.h bar.h<br>&nbsp;&nbsp;$(CC) $(CFLAGS) -c foo.c -o foo.o<br><br>bar.o : bar.c bar.h<br>&nbsp;&nbsp;$(CC) $(CFLAGS) -c bar.c -o bar.o<br>=== makefile 结束 ===<br><br>      还有一些设定好的内部变量,它们根据每一个规则内容定义。三个      比较有用的变量是 $@, $< 和 $^ (这些变量不需要括号括住)。      $@ 扩展成当前规则的目的文件名, $< 扩展成依靠列表中的第      一个依靠文件,而 $^ 扩展成整个依靠的列表(除掉了里面所有重      复的文件名)。利用这些变量,我们可以把上面的 makefile 写成:<br><br>=== makefile 开始 ===<br>OBJS = foo.o bar.o<br>CC = gcc<br>CFLAGS = -Wall -O -g<br><br>myprog : $(OBJS)<br>&nbsp;&nbsp;$(CC) $^ -o $@<br><br>foo.o : foo.c foo.h bar.h<br>&nbsp;&nbsp;$(CC) $(CFLAGS) -c $< -o $@<br><br>bar.o : bar.c bar.h<br>&nbsp;&nbsp;$(CC) $(CFLAGS) -c $< -o $@<br>=== makefile 结束 ===<br>      <br>      你可以用变量做许多其它的事情,特别是当你把它们和函数混合      使用的时候。如果需要更进一步的了解,请参考 GNU Make 手册。      ('man make', 'man makefile')<br><br>   2.4 隐含规则 (Implicit Rules)<br><br>            请注意,在上面的例子里,几个产生 .o 文件的命令都是一样的。      都是从 .c 文件和相关文件里产生 .o 文件,这是一个标准的步      骤。其实 make 已经知道怎么做——它有一些叫做隐含规则的内      置的规则,这些规则告诉它当你没有给出某些命令的时候,应该      怎么办。<br>      <br>      如果你把生成 foo.o 和 bar.o 的命令从它们的规则中删除, make      将会查找它的隐含规则,然后会找到一个适当的命令。它的命令会      使用一些变量,因此你可以按照你的想法来设定它:它使用变量      CC 做为编译器(象我们在前面的例子),并且传递变量 CFLAGS       (给 C 编译器,C++ 编译器用 CXXFLAGS ),CPPFLAGS ( C 预      处理器旗标), TARGET_ARCH (现在不用考虑这个),然后它加      入旗标 '-c' ,后面跟变量 $< (第一个依靠名),然后是旗      标 '-o' 跟变量 $@ (目的文件名)。一个C编译的具体命令将      会是:<br>                 <br>      $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@<br><br>      当然你可以按照你自己的需要来定义这些变量。这就是为什么用      gcc 的 -M 或 -MM 开关输出的码可以直接用在一个 makefile       里。<br><br>   2.5 假象目的 (Phony Targets)<br><br>            假设你的一个项目最后需要产生两个可执行文件。你的主要目标      是产生两个可执行文件,但这两个文件是相互独立的——如果一      个文件需要重建,并不影响另一个。你可以使用“假象目的”来      达到这种效果。一个假象目的跟一个正常的目的几乎是一样的,      只是这个目的文件是不存在的。因此, make 总是会假设它需要      被生成,当把它的依赖文件更新后,就会执行它的规则里的命令      行。<br>      <br>      如果在我们的 makefile 开始处输入:<br><br>      all : exec1 exec2<br><br>      其中 exec1 和 exec2 是我们做为目的的两个可执行文件。 make      把这个 'all' 做为它的主要目的,每次执行时都会尝试把 'all'       更新。但既然这行规则里没有哪个命令来作用在一个叫 'all' 的      实际文件(事实上 all 并不会在磁碟上实际产生),所以这个规      则并不真的改变 'all' 的状态。可既然这个文件并不存在,所以      make 会尝试更新 all 规则,因此就检查它的依靠 exec1, exec2      是否需要更新,如果需要,就把它们更新,从而达到我们的目的。     <br>      <br>      假象目的也可以用来描述一组非预设的动作。例如,你想把所有由      make 产生的文件删除,你可以在 makefile 里设立这样一个规则:<br><br>      veryclean :<br>      	&nbsp;&nbsp;rm *.o<br>      	&nbsp;&nbsp;rm myprog<br>      <br>      前提是没有其它的规则依靠这个 'veryclean' 目的,它将永远      不会被执行。但是,如果你明确的使用命令 'make veryclean' ,      make 会把这个目的做为它的主要目标,执行那些 rm 命令。<br>      <br>      如果你的磁碟上存在一个叫 veryclean 文件,会发生什么事?这      时因为在这个规则里没有任何依靠文件,所以这个目的文件一定是      最新的了(所有的依靠文件都已经是最新的了),所以既使用户明      确命令 make 重新产生它,也不会有任何事情发生。解决方法是标      明所有的假象目的(用 .PHONY),这就告诉 make 不用检查它们      是否存在于磁碟上,也不用查找任何隐含规则,直接假设指定的目      的需要被更新。在 makefile 里加入下面这行包含上面规则的规则:<br><br>      .PHONY : veryclean<br>      <br>      就可以了。注意,这是一个特殊的 make 规则,make 知道 .PHONY      是一个特殊目的,当然你可以在它的依靠里加入你想用的任何假象      目的,而 make 知道它们都是假象目的。<br><br>   2.6 函数 (Functions)<br><br>            makefile 里的函数跟它的变量很相似——使用的时候,你用一个      $ 符号跟开括号,函数名,空格后跟一列由逗号分隔的参数,最后      用关括号结束。例如,在 GNU Make 里有一个叫 'wildcard' 的函      数,它有一个参数,功能是展开成一列所有符合由其参数描述的文      件名,文件间以空格间隔。你可以像下面所示使用这个命令:<br><br>      SOURCES = $(wildcard *.c)<br>      <br>      这行会产生一个所有以 '.c' 结尾的文件的列表,然后存入变量      SOURCES 里。当然你不需要一定要把结果存入一个变量。<br><br>      另一个有用的函数是 patsubst ( patten substitude, 匹配替      换的缩写)函数。它需要3个参数——第一个是一个需要匹配的      式样,第二个表示用什么来替换它,第三个是一个需要被处理的      由空格分隔的字列。例如,处理那个经过上面定义后的变量,<br><br>      OBJS = $(patsubst %.c,%.o,$(SOURCES))<br>      <br>      这行将处理所有在 SOURCES 字列中的字(一列文件名),如果它的      结尾是 '.c' ,就用 '.o' 把 '.c' 取代。注意这里的 % 符号将匹      配一个或多个字符,而它每次所匹配的字串叫做一个‘柄’(stem) 。      在第二个参数里, % 被解读成用第一参数所匹配的那个柄。<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -