自从上周我就开始折腾Linux下的Makefile和autotools工具. 看着好几百页的技术文档, 头皮真有点麻了. 花了一点心思看完了Makefile技术文档之后, 并在网上找到一个通用的Makefile模板, 并自己有针对性进行了修改, 并成功运用到我的一个项目中去. 感觉有点成就, 说明我之前的阅读没有白费,看英文水平还是可以的:).但是我又觉得有点失落, 现在不是有了autotools了吗, 维护一个大型的项目, 很少有人去亲自编写Makefile的. 特别是针对一些跨平台和交叉编译的时候, 维护这样的Makefile不仅让人感觉到无助, 而且不人性化. 但是有了Autotools之后, 一些就变化简单. 况且我还没有尝试过自己编写Makefile在多个目录下,产生多个可执行目标, 生成静态或共享为数库, 这些东西由于我所接触到的项目没有涉及到,再加上自己亲自动手, 感觉有点茫然不知所措.还是静下心下学学autotools相关工具吧(谁说linux下,只要学会几种工具,就够用了, 不用像windows下学习VC系统软件一样? 你看,我不是又学了Makefile又要去学autotools相关工具吗?而且更难学,语法跟原来又有很大不一样,而Windows下的VC系统软件都是一些傻瓜式的操作, 只要一点就懂, 感觉有点被骗了.呵呵,,,,)今天我又下载了automake和autoconf. 先下载了automake里面讲得有点浅显而且没有我要找的东西: 在不同目录下生成不同的可执行目标, 维护不同目录下的不同模块(将其制作成Lib或可执行文件), 特别是不同模块之间有相互关系的那种,如何进行编写Makefile并使其具有可移植性和通用性. 于是乎我就关掉了automake打开了autoconf, OK完全符合我的要求, 不过里面将的都是一些很详细的介绍, 应用实例很少, 看了之后很难产生一些深刻的印象, 甚至一些还没有看懂:(. 还是找找相关的实例吧, 于是我就在网上找到如下的实例: ########################################################################## 一般如何写用code1.c, code2.c生成 prog1的configure.in和Makefile.am。 首先建立一个项目文件夹tt。在tt下建立dir1目录。 [kj501@s2023 dir1]$ mkdir -p tt/dir1 && cd tt/dir1 [kj501@s2023 dir1]$ 然后在dir1目录中分别建立code1.c, code1.h, code2.c, code2.h. 下面是code1.h: #include <stdlib.h>; void foo_a(); 下面是code1.c: #include "code1.h" void foo_a() { printf("This is code1./n"); } 下面是code2.h: #include <stdlib.h>; void foo_b(); 下面是code2.c,这里让code.c作为prog1的入口点: #include "code1.h" #include "code2.h" void foo_b() { printf("This is code2./n"); } int main() { foo_a(); foo_b(); } 建立好这几个文件之后,下面就可以正式建立configure.in和Makefile.am了。 首先在tt目录下建立configure.in文件: #指定项目的一个源文件 AC_INIT(dir1/code2.c) #指定项目名称和版本号 AM_INIT_AUTOMAKE(prog1, 0.0.1) #检查编译器 AC_PROG_CC #输出Makefile文件 AC_OUTPUT(Makefile dir1/Makefile) 同时建立tt目录下的Makefile.am文件,这个文件很简单,就一句话: SUBDIRS=dir1 然后建立dir1目录下的Makefile.am文件,这才是真正起作用的Makefile.am文件: bin_PROGRAMS=prog1 prog1_SOURCES=code1.c code2.c 完成之后,为了方便操作,再写一个autogen.sh文件,保存在tt目录下。 #!/bin/sh aclocal automake --add-missing autoconf 存盘之后,用chmod +x改成可执行文件。然后执行autogen.sh。./autogen.sh在此基础上,如果要同时实现code1.c, code2.c生成 prog1, 而 code3.c生成prog2。由于code1.c,code2.c,code3.c都在同一个目录,只要改写dir1目录下的Makefile.am就可以了。 为了便于说明问题,首先要在dir1目录下增加一个code3.h 和code3.c文件。下面是code3.h: #include <stdlib.h>; void foo_c(); 下面是code3.c: #include "code3.h" void foo_c() { printf("This is code3./n"); } int main() { foo_c(); } 然后修改dir1目录下的Makefile.am文件: bin_PROGRAMS=prog1 prog2 prog1_SOURCES=code1.c code2.c prog2_SOURCES=code3.c 再重新执行一次autogen.sh。make之后,在dir1目录下就会同时存在prog1和prog2两个程序。你先体会一下吧。然后自己做做用code4.c和 code5.c生成 prog3。 引用的源程序都是放在同一个目录下的,如果要放在不同的目录,可以把要引用的源文件编译成静态库文件。为便于说明问题,准备了如下文件: 在tt目录下新建dir2目录,保存code4.h和code4.c文件。 下面是code4.h: #include <stdlib.h>; void foo_d(); 下面是code4.c: #include "code1.h" #include "code4.h" void foo_d() { printf("This is code4./n"); } int main() { foo_a(); foo_d(); } dir1目录下的code1.h和code1.c和上面的一样,我就不写了。修改tt目录下的configure.in文件。 #指定项目的一个源文件 AC_INIT(dir2/code4.c) #指定项目名称和版本号 AM_INIT_AUTOMAKE(myproject, 0.0.1) #检查编译器 AC_PROG_CC #检查ranlib AC_PROG_RANLIB #输出Makefile文件 AC_OUTPUT(Makefile dir1/Makefile dir2/Makefile) 同时修改tt目录下的Makefile.am文件。 SUBDIRS = dir1 dir2 在dir1目录下修改Makefile.am文件。这时是将code1.c编译成一个不安装(noinst)的静态库文件。 noinst_LIBRARIES=libcode1.a libcode1_a_SOURCES=code1.c 在dir2目录下添加一个Makefile.am文件。 INCLUDES= -I../dir1 bin_PROGRAMS=prog4 prog4_SOURCES=code4.c prog4_LDADD=../dir1/libcode1.a 然后执行autogen.sh就可以了 ##################################################################### 看了上面的autoconf 和automake 实例, 感觉有关项目中各源文件的之间的关系的复杂仍然还没有得到解决. 比如说在dir1中有很多源文件, 假如有200个. 即使这此源文件关系很简单, 那么要将这些源文件全部添加到该目录下的Makefile.am感觉有点人工, 还不如自己有直接在这个目录写一个模式依赖规则(%.o: %c和%.d: %.c)的Makefile来得轻松. 也许Makefile.am语法中含有这样的功能? 目录我还没有找到.希望我能尽快找到. 闲话少说, 如果这200个源文件关系错综复杂, 生成多个可执行文件. 我想如果要我去从中找相应的关系, 我觉得会faint死的. 这时如果有人说, 是不是将这200个源文件分成几个模块, 好可以, 我们将模块中源文件数限制在50以内吧. 我们可以将一些不生成可执行的目录做成静态库, 但有的目录会调用生成可执行文件的目录中的函数功能, 比如目录A中某源代码调用了目录B中一些接口函数, 但是目录B是生成的可执行输出的. 这此总不会将目录B即做一份可执行输出又做一份静态库吧.感觉这种方法不是很好. 如果不是这样话, 那么就要在目录A中的Makefile.am中的维护一份目录A中的源代码关系表, 和所调用目录B中函数功能所在源代码关系表, 感觉好复杂. 感觉还不好直接人式写Makefile来得方便. 以上是我今天学习autotool一些小小心得, 学了一点, 不全, 希望随着以后学习, 逐步对自己一些错误或不完全的认识做一些改进. 后面还会有.希望网上一些同仁们跟我一起共同学习学习GNU Build System的神奇, 感觉一下它是不是传说中的那样,呵呵....