http://blog.csdn.net/dc_726/article/details/48978849
C实战:项目构建Make,Automake,CMake
在本系列文章《C实战:强大的程序调试工具GDB》中我们简要学习了流行的调试工具GDB的使用方法。本文继续“C实战”的主题,对同样非常流行的构建工具Make的用法和原理一探究竟,并顺便看一下一些高级衍生产品。
1.Make基础
首先我们编写一个简单的C项目,以此项目在实战中学习Make的相关知识。更全面的介绍请参考官方手册。
<code class="language-bash hljs has-numbering">cdai@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ tree . ├── hello.c ├── hello.h ├── main.c └── Makefile <span class="hljs-number">0</span> directories, <span class="hljs-number">4</span> files</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>
整个程序的逻辑非常简单:main.c中包含一个main方法,调用了hello.c中的sayHello()函数,打印了一句话到控制台上。
<code class="language-c hljs has-numbering"><span class="hljs-comment">// cat main.c hello.h hello.c</span> <span class="hljs-comment">// ----- main.c -----</span> <span class="hljs-preprocessor">#include "hello.h"</span> <span class="hljs-keyword">int</span> main(<span class="hljs-keyword">void</span>) { sayHello(<span class="hljs-string">"Make"</span>); <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>; } <span class="hljs-comment">// ----- hello.h -----</span> <span class="hljs-preprocessor">#ifndef _HELLO_H_</span> <span class="hljs-preprocessor">#define _HELLO_H_</span> <span class="hljs-keyword">void</span> sayHello(<span class="hljs-keyword">char</span> *name); <span class="hljs-preprocessor">#endif</span> <span class="hljs-comment">// ----- hello.c -----</span> <span class="hljs-preprocessor">#include "hello.h"</span> <span class="hljs-preprocessor">#include <stdio.h></span> <span class="hljs-keyword">void</span> sayHello(<span class="hljs-keyword">char</span> *name) { <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Hello, %s!\n"</span>, name); }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul>
1.1 基本语法
一个简单的Makefile包含很多规则(Rule),每一条规则的语法结构由目标(Target)、先决条件(Prerequisite)、动作(Recipe)三部分组成:
- 目标:通常有两种命名方法,一是与要生成的可执行文件或目标文件同名,二是说明动作的目的,例如最常见的clean清理规则。对于第二种规则命名,为了避免与同名文件冲突,可以将目标名加入到
.PHONY
伪目标列表中。默认情况下,make执行Makefile中的第一个规则,此规则被称为最终目标 - 先决条件:先决条件是用来创建目标的输入文件,一个目标可以依赖多个先决条件
- 动作:动作由Make命令负责执行,可以包含多个命令,每个命令可以另起一行。一定要注意的是:命令必须以
TAB
开头!
<code class="language-Makefile hljs http has-numbering"><span class="hljs-attribute">target</span>: <span class="hljs-string">prerequisite</span> <span class="hljs-attribute">recipe</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li></ul>
下面就看一下示例项目的Makefile是什么样子的。在Makefile中有3个规则,其中目标main依赖于main.o和hello.o,利用gcc执行链接,这与我们的代码结构是相对应的。而main.o和hello.o则分别依赖于各自的源代码.c文件和hello.h头文件,并利用gcc -c执行编译。
<code class="language-Makefile hljs avrasm has-numbering"><span class="hljs-label">main:</span> main<span class="hljs-preprocessor">.o</span> hello<span class="hljs-preprocessor">.o</span> gcc -o main main<span class="hljs-preprocessor">.o</span> hello<span class="hljs-preprocessor">.o</span> <span class="hljs-label">main.o:</span> main<span class="hljs-preprocessor">.c</span> hello<span class="hljs-preprocessor">.h</span> gcc -c main<span class="hljs-preprocessor">.c</span> -o main<span class="hljs-preprocessor">.o</span> <span class="hljs-label">hello.o:</span> hello<span class="hljs-preprocessor">.c</span> hello<span class="hljs-preprocessor">.h</span> gcc -c hello<span class="hljs-preprocessor">.c</span> -o hello<span class="hljs-preprocessor">.o</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>
1.2 实现原理
Make看似非常智能,其实它的原理就像其语法规则一样简单。
- 确定目标:如果没有指明,则执行最终目标,即第一个规则的目标
- 处理变量和规则:替换变量,推导隐式规则(下一节会学习)
- 生成依赖关系链:为所有目标生成依赖关系链
- 递归构建:从依赖链的底部向上,根据先决条件会有三种情况:
4.1 先决条件不存在,则执行规则中的命令
4.2 先决条件存在,且至少一个比目标“更新”,则执行规则中的命令重新生成
4.3 先决条件存在,且都比目标“更旧”, 则什么都不做
了解了Make的原理,就看一下我们的示例项目Make的执行过程。可以看到,Make以第一个目标main作为构建目标,从关系链底部的main.o和hello.o开始构建,最终生成了可执行文件main。接下来就执行main,可以看到控制台输出了”Hello, Make!”,证明我们构建成功了!
<code class="language-bash hljs has-numbering">cdai@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ make gcc -c main.c -o main.o gcc -c hello.c -o hello.o gcc -o main main.o hello.o cdai@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ ./main Hello, Make!</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>
再次执行make会看到“‘main’ is up to date.”的提示,说明Make检测到了没有发生任何修改。如果我们做一点改动,例如修改以下sayHello()函数中的输出,再执行Make就能看到hello.o和main被重新构建,而main.o规则的命令没有被执行。
<code class="language-bash hljs has-numbering">cdai@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ make make: <span class="hljs-string">'main'</span> is up to date. cdai@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ make gcc -c hello.c -o hello.o gcc -o main main.o hello.o cdai@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ ./main Hello111, Make!</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
2.Make进阶
2.1 变量
在Makefile中,我们可以用变量来替换重复出现在先决条件或动作中的字符串。例如,对于前面我们的示例Makefile,最明显的问题就是gcc和main目标依赖的main.o和hello.o出现了多次,我们可以用变量将它们提取出来。同样地,我们也经常将链接和编译选项做成变量。
<code class="language-Makefile hljs avrasm has-numbering"><span class="hljs-keyword">LD</span> = gcc CC = gcc CFLAGS = -Wall OBJECTS = main<span class="hljs-preprocessor">.o</span> hello<span class="hljs-preprocessor">.o</span> <span class="hljs-label">all:</span> main <span class="hljs-label">main:</span> $(OBJECTS) $(<span class="hljs-keyword">LD</span>) -o main $(OBJECTS) <span class="hljs-label">main.o:</span> main<span class="hljs-preprocessor">.c</span> hello<span class="hljs-preprocessor">.h</span> $(CC) $(CFLAGS) -c $< -o $@ <span class="hljs-label">hello.o:</span> hello<span class="hljs-preprocessor">.c</span> hello<span class="hljs-preprocessor">.h</span> $(CC) $(CFLAGS) -c hello<span class="hljs-preprocessor">.c</span> -o hello<span class="hljs-preprocessor">.o</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>
执行一下make可以看到效果,我们提取出来的变量在执行之前都被替换到了正确的位置。
<code class="language-bash hljs has-numbering">cdaih@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ make gcc -Wall -c main.c -o main.o gcc -Wall -c hello.c -o hello.o gcc -o main main.o hello.o</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
2.2 隐式规则
使用Make编译.c源文件时,规则的命令和先决条件都可以简化,对于命令,我们不用明确指出,Make能够自动将.c编译成.o;对于先决条件,Make还会自动寻找.o对应的.c源文件,我们只需给出头文件即可。
<code class="language-Makefile hljs avrasm has-numbering"><span class="hljs-keyword">LD</span> = gcc OBJECTS = main<span class="hljs-preprocessor">.o</span> hello<span class="hljs-preprocessor">.o</span> <span class="hljs-label">all:</span> main <span class="hljs-label">main:</span> $(OBJECTS) $(<span class="hljs-keyword">LD</span>) -o main $(OBJECTS) <span class="hljs-label">main.o:</span> hello<span class="hljs-preprocessor">.h</span> <span class="hljs-label">hello.o:</span> hello<span class="hljs-preprocessor">.h</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>
我们将main.o和hell.o的规则都做了简化,执行一下可以看到Make自动执行了cc -c
,并根据目标找到了对应的源文件main.c和hello.c。
<code class="language-bash hljs has-numbering">cdaih@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ make cc -c -o main.o main.c cc -c -o hello.o hello.c gcc -o main main.o hello.o</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
2.3 模式规则
隐式规则虽然很方便,但有时我们还想自己控制规则,这时我们可以使用模式规则。老Make支持.c.o
这种规则定义,而新Make一般推荐使用模式规则,因为它支持模式匹配,更灵活、更强大!例如,我们定义目标名匹配%.o和先决条件匹配%.c的话,就执行编译命令。这样main.o和hello.o被简化的同时,我们还对其进行了精确的控制。
<code class="language-Makefile hljs avrasm has-numbering"><span class="hljs-keyword">LD</span> = gcc CC = gcc CFLAGS = -Wall OBJECTS = main<span class="hljs-preprocessor">.o</span> hello<span class="hljs-preprocessor">.o</span> %<span class="hljs-preprocessor">.o</span>: %<span class="hljs-preprocessor">.c</span> $(CC) $(CFLAGS) -c $< -o $@ <span class="hljs-label">all:</span> main <span class="hljs-label">main:</span> $(OBJECTS) $(<span class="hljs-keyword">LD</span>) -o main $(OBJECTS) <span class="hljs-label">main.o:</span> main<span class="hljs-preprocessor">.c</span> hello<span class="hljs-preprocessor">.h</span> <span class="hljs-label">hello.o:</span> hello<span class="hljs-preprocessor">.c</span> hello<span class="hljs-preprocessor">.h</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li></ul>
执行一下看看效果。
<code class="language-bash hljs has-numbering">cdaih@vm /syspace/<span class="hljs-number">2</span>-ccpp/<span class="hljs-number">24</span>-pragmatic/build-tool/make $ make gcc -Wall -c main.c -o main.o gcc -Wall -c hello.c -o hello.o gcc -o main main.o hello.o</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
3.Makefile生成工具
Make的流行也带动起一批自动生成Makefile的工具,目的就是进一步减轻项目构建中的工作量,让我们程序员全身心投入到开发之中。在这些工具中,不得不提Automake和CMake。
3.1 Automake
Automake其实是一系列工具集Autotools中的一员,要想发挥Automake的威力,需要配合使用Autotools中的其他工具,例如autoscan、aclocal、autoconf和autoheader。在下面的Automake构建流程中,能看到这些工具的身影。
- autoscan:生成configure.scan
- configure.in:将configure.scan重命名为
configure.in
后,修改内容。重点是AM_INIT_AUTOMAKE和AC_CONFIG_FILES两项,如果没配置的话,下一步的aclocal是无法产生aclocal.m4的 - aclocal:生成
aclocal.m4
- autoconf:生成
configure
- autoheader:生成config.h.in,使程序可移植
- Makefile.am:手动编写Makefile.am。bin_PROGRAMS指定最终生成可执行文件的名称,helloworld_SOURCES指定所有源文件
- NEWS AUTHORS README ChangeLog:手动创建
- automake:执行
automake -a
生成Makefile.in - configure:执行
./configure
生成Makefile
<code class="hljs coffeescript has-numbering"><span class="hljs-comment"># Step 1:</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># autoscan</span> <span class="hljs-comment"># Step 2:</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># mv configure.scan configure.in</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># cat configure.in</span> <span class="hljs-comment"># -*- Autoconf -*-</span> <span class="hljs-comment"># Process this file with autoconf to produce a configure script.</span> AC_PREREQ([<span class="hljs-number">2.63</span>]) AC_INIT(main, <span class="hljs-number">1.0</span>) AM_INIT_AUTOMAKE(main, <span class="hljs-number">1.0</span>) AC_CONFIG_SRCDIR([main.c]) AC_CONFIG_HEADERS([config.h]) <span class="hljs-comment"># Checks for programs.</span> AC_PROG_CC <span class="hljs-comment"># Checks for libraries.</span> <span class="hljs-comment"># Checks for header files.</span> <span class="hljs-comment"># Checks for typedefs, structures, and compiler characteristics.</span> <span class="hljs-comment"># Checks for library functions.</span> AC_CONFIG_FILES([Makefile]) AC_OUTPUT <span class="hljs-comment"># Step 3:</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># aclocal</span> <span class="hljs-comment"># Step 4:</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># autoconf</span> <span class="hljs-comment"># Step 5:</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># autoheader</span> <span class="hljs-comment"># Step 6:</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># cat Makefile.am </span> bin_PROGRAMS=main main_SOURCES=main.c hello.c <span class="hljs-comment"># Step 7:</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># touch NEWS README AUTHORS ChangeLog</span> <span class="hljs-comment"># Step 8:</span> [root<span class="hljs-property">@vm</span> automaketest]<span class="hljs-comment"># automake -a</span> configure.<span class="hljs-attribute">in</span>:<span class="hljs-number">6</span>: installing <span class="hljs-string">'./install-sh'</span> configure.<span class="hljs-attribute">in</span>:<span class="hljs-number">6</span>: installing <span class="hljs-string">'./missing'</span> Makefile.<span class="hljs-attribute">am</span>: installing <span class="hljs-string">'./INSTALL'</span> Makefile.<span class="hljs-attribute">am</span>: installing <span class="hljs-string">'./COPYING'</span> using GNU General Public License v3 file Makefile.<span class="hljs-attribute">am</span>: Consider adding the COPYING file to the version control system Makefile.<span class="hljs-attribute">am</span>: <span class="hljs-keyword">for</span> your code, to avoid questions about which license your project uses. Makefile.<span class="hljs-attribute">am</span>: installing <span class="hljs-string">'./depcomp'</span> <span class="hljs-comment"># Step 9:</span> [root<span class="hljs-property">@BC</span>-VM-edce4ac67d304079868c0bb265337bd4 automaketest]<span class="hljs-comment"># ./configure </span> checking <span class="hljs-keyword">for</span> a BSD-compatible install... /usr/bin/install -c checking whether build environment <span class="hljs-keyword">is</span> sane... <span class="hljs-literal">yes</span> checking <span class="hljs-keyword">for</span> a thread-safe mkdir -p... /bin/mkdir -p checking <span class="hljs-keyword">for</span> gawk... gawk checking whether make sets $(MAKE)... <span class="hljs-literal">yes</span> checking <span class="hljs-keyword">for</span> gcc... gcc checking <span class="hljs-keyword">for</span> C compiler <span class="hljs-reserved">default</span> output file name... a.out checking whether the C compiler works... <span class="hljs-literal">yes</span> checking whether we are cross compiling... <span class="hljs-literal">no</span> checking <span class="hljs-keyword">for</span> suffix <span class="hljs-keyword">of</span> executables... checking <span class="hljs-keyword">for</span> suffix <span class="hljs-keyword">of</span> object files... o checking whether we are using the GNU C compiler... <span class="hljs-literal">yes</span> checking whether gcc accepts -g... <span class="hljs-literal">yes</span> checking <span class="hljs-keyword">for</span> gcc option to accept ISO C89... none needed checking <span class="hljs-keyword">for</span> style <span class="hljs-keyword">of</span> include used <span class="hljs-keyword">by</span> make... GNU checking dependency style <span class="hljs-keyword">of</span> gcc... gcc3 <span class="hljs-attribute">configure</span>: creating ./config.status config.<span class="hljs-attribute">status</span>: creating Makefile config.<span class="hljs-attribute">status</span>: creating config.h config.<span class="hljs-attribute">status</span>: executing depfiles commands</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li></ul>
这样Makefile就生成好了,看一下当前目录发现已经这么多文件了!如果想清理一下怎么办呢?其实Automake早为我们想好了,它生成的Makefile功能很多:
+ make:编译源代码,生成目标文件
+ make clean:清理之前make产生的临时文件
+ make install:将编译好的可执行文件安装到系统目录,一般为/usr/local/bin
+ make dist:生成软件发布包,将可执行文件及相关文件打包成”PACKAGE-VERSION.tar.gz”的tarball。其中PACKAGE和VERSION可以在configure.in中通过AM_INIT_AUTOMAKE(PACKAGE, VERSION)定义。对于我们的例子,执行后会生成main-1.0.tar.gz
+ make distcheck:查看发布包是否正确,解压开执行configure和make来确认
+ make distclean:不仅将make产生的文件,同时将configure生成的文件也都删除,包括Makefile
<code class="language-bash hljs has-numbering">[root@vm automaketest]<span class="hljs-comment"># make dist</span> { test ! <span class="hljs-operator">-d</span> <span class="hljs-string">"main-1.0"</span> || { find <span class="hljs-string">"main-1.0"</span> -type d ! -perm -<span class="hljs-number">200</span> -exec chmod u+w {} <span class="hljs-string">';'</span> && rm -fr <span class="hljs-string">"main-1.0"</span>; }; } test <span class="hljs-operator">-d</span> <span class="hljs-string">"main-1.0"</span> || mkdir <span class="hljs-string">"main-1.0"</span> test -n <span class="hljs-string">""</span> \ || find <span class="hljs-string">"main-1.0"</span> -type d ! -perm -<span class="hljs-number">755</span> \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -<span class="hljs-number">444</span> -links <span class="hljs-number">1</span> -exec chmod a+r {} \; -o \ ! -type d ! -perm -<span class="hljs-number">400</span> -exec chmod a+r {} \; -o \ ! -type d ! -perm -<span class="hljs-number">444</span> -exec /bin/sh /root/Temp/automaketest/install-sh -c -m a+r {} {} \; \ || chmod -R a+r <span class="hljs-string">"main-1.0"</span> tardir=main-<span class="hljs-number">1.0</span> && /bin/sh /root/Temp/automaketest/missing --run tar chof - <span class="hljs-string">"<span class="hljs-variable">$tardir</span>"</span> | GZIP=--best gzip -c >main-<span class="hljs-number">1.0</span>.tar.gz { test ! <span class="hljs-operator">-d</span> <span class="hljs-string">"main-1.0"</span> || { find <span class="hljs-string">"main-1.0"</span> -type d ! -perm -<span class="hljs-number">200</span> -exec chmod u+w {} <span class="hljs-string">';'</span> && rm -fr <span class="hljs-string">"main-1.0"</span>; }; } [root@vm automaketest]<span class="hljs-comment"># tree -L 1</span> . ├── aclocal.m4 ├── AUTHORS ├── autom4te.cache ├── autoscan.log ├── ChangeLog ├── config.h ├── config.h.in ├── config.log ├── config.status ├── configure ├── configure.in ├── COPYING -> /usr/share/automake-<span class="hljs-number">1.11</span>/COPYING ├── depcomp -> /usr/share/automake-<span class="hljs-number">1.11</span>/depcomp ├── hello.c ├── hello.h ├── INSTALL -> /usr/share/automake-<span class="hljs-number">1.11</span>/INSTALL ├── install-sh -> /usr/share/automake-<span class="hljs-number">1.11</span>/install-sh ├── main.c ├── main-<span class="hljs-number">1.0</span>.tar.gz ├── Makefile ├── Makefile.am ├── Makefile.in ├── missing -> /usr/share/automake-<span class="hljs-number">1.11</span>/missing ├── NEWS ├── README └── stamp-h1 <span class="hljs-number">1</span> directory, <span class="hljs-number">24</span> files [root@vm automaketest]<span class="hljs-comment"># make distclean</span> test -z <span class="hljs-string">"main"</span> || rm <span class="hljs-operator">-f</span> main rm <span class="hljs-operator">-f</span> *.o rm <span class="hljs-operator">-f</span> *.tab.c test -z <span class="hljs-string">""</span> || rm <span class="hljs-operator">-f</span> test . = <span class="hljs-string">"."</span> || test -z <span class="hljs-string">""</span> || rm <span class="hljs-operator">-f</span> rm <span class="hljs-operator">-f</span> config.h stamp-h1 rm <span class="hljs-operator">-f</span> TAGS ID GTAGS GRTAGS GSYMS GPATH tags rm <span class="hljs-operator">-f</span> config.status config.cache config.log configure.lineno config.status.lineno rm -rf ./.deps rm <span class="hljs-operator">-f</span> Makefile</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li></ul>
测试一下,看看Automake生成的Makefile是否能正常工作。
<code class="language-bash hljs has-numbering">[root@vm automaketest]<span class="hljs-comment"># make</span> make all-am make[<span class="hljs-number">1</span>]: Entering directory <span class="hljs-string">'/root/Temp/automaketest'</span> gcc -DHAVE_CONFIG_H -I. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c mv <span class="hljs-operator">-f</span> .deps/main.Tpo .deps/main.Po gcc -DHAVE_CONFIG_H -I. -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o hello.c mv <span class="hljs-operator">-f</span> .deps/hello.Tpo .deps/hello.Po gcc -g -O2 -o main main.o hello.o make[<span class="hljs-number">1</span>]: Leaving directory <span class="hljs-string">'/root/Temp/automaketest'</span> [root@vm automaketest]<span class="hljs-comment"># ./main </span> Hello, Make!</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>
3.2 CMake
前面我们已经见识了Automake的强大和复杂。现在我们重新用CMake生成Makefile,Automake中的9步被压缩到了只需要2步!
- 编写CMakeLists.txt
- 执行
cmake .
3.2.1 CMakeLists.txt
对于我们示例中这种简单的项目,CMakeLists.txt简单得不能再简单了。指定好项目名称和最终生成的可执行文件名称后,就完成了!
<code class="language-CMake hljs vala has-numbering"><span class="hljs-preprocessor"># CMake 最低版本号要求</span> cmake_minimum_required (VERSION <span class="hljs-number">2.8</span>) <span class="hljs-preprocessor"># 项目信息</span> project (main) <span class="hljs-preprocessor"># 查找当前目录下的所有源文件</span> <span class="hljs-preprocessor"># 并将名称保存到 DIR_SRCS 变量</span> aux_source_directory(. DIR_SRCS) <span class="hljs-preprocessor"># 指定生成目标</span> add_executable(main ${DIR_SRCS})</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>
3.2.2 cmake
现在执行cmake .
就能得到一个CMake为我们自动生成的Makefile。这个Makefile比我们手写的要复杂得多,这里就不深入分析了。除了Makefile外,CMake还产生了一些缓存文件和临时文件,目前还不清楚具体是做什么的。
<code class="language-bash hljs has-numbering">[root@vm cmaketest]<span class="hljs-comment"># cmake .</span> -- The C compiler identification is GNU <span class="hljs-number">4.4</span>.<span class="hljs-number">7</span> -- The CXX compiler identification is GNU <span class="hljs-number">4.4</span>.<span class="hljs-number">7</span> -- Check <span class="hljs-keyword">for</span> working C compiler: /usr/bin/cc -- Check <span class="hljs-keyword">for</span> working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - <span class="hljs-keyword">done</span> -- Check <span class="hljs-keyword">for</span> working CXX compiler: /usr/bin/c++ -- Check <span class="hljs-keyword">for</span> working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - <span class="hljs-keyword">done</span> -- Configuring <span class="hljs-keyword">done</span> -- Generating <span class="hljs-keyword">done</span> -- Build files have been written to: /root/Temp/cmaketest [root@vm cmaketest]<span class="hljs-comment"># tree -L 1</span> . ├── CMakeCache.txt ├── CMakeFiles ├── cmake_install.cmake ├── CMakeLists.txt ├── hello.c ├── hello.h ├── main.c └── Makefile <span class="hljs-number">1</span> directory, <span class="hljs-number">7</span> files [root@vm cmaketest]<span class="hljs-comment"># make</span> Scanning dependencies of target main [ <span class="hljs-number">50</span>%] Building C object CMakeFiles/main.dir/main.c.o [<span class="hljs-number">100</span>%] Building C object CMakeFiles/main.dir/hello.c.o Linking C executable main [<span class="hljs-number">100</span>%] Built target main</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li></ul>