有时候我们会写很多小程序,程序之间有些风马牛不相及,但是这些程序又老是抱团出现。比如对于开发板上面的各种功能,都会有小程序来检测是不是可以使用helloworld,gpio,led,beep…等等。以往我们都是把每一个程序当成一个程序来写,这样假设有10个程序,我们需要写10个Makefile,然后再分开管理。因为我们都恨懒,所以我们想让这个事情变的简单自动化起来。
解决设想:
我们写一个build脚本文件,里面做三个事情:
1:configure一下所有文件,从而生成需要的Makefile。
2:make,生成所需要的所有可执行文件。
3:把这些分散在各处的可执行文放到集中营里,比如scripts文件夹下面。
解决步骤:
1:首先情景假定,我们在一个叫做app的文件夹下面,需要干的事情有:(按照字母顺序出场)beep,camera,framebuffer,gpio,hello,net,uart,video,其中net中又下分tcp udp两类,然后tcp和udp中又下分server-tcp server-udp client-tcp client-udp。好,目前的目录结构应该是比较复杂了。
我们在app目录下面建立各个子文件夹,然后我们先假设程序都很简单,一个C文件就可以了,于是,我们在每个最终端的文件夹下面建立好C文件。
程序写完了之后大概是这样子的:
app
|–beep
|–camera
|–framebuffer
|–gpio
|–hello
|–net
| |–tcp
| | |–server
| | |–client
| |–udp
| | |–server
| | |–client
|–uart
|–video
OK,目前看来,现在情况和我们单独处理这些小程序还没什么关系,但是我们现在还没有给它们写过Makefile,当然,我们也不打算手工完成,我们打算让它自动生成Makefile。
2:完成Makefile.am的编写,在app目录下建立Makefile.am文件,里面的内容是
SUBDIRS=beep camera framebuffer gpio hello net uart video
SUBDIRS表示子目录,=号赋值,多个目录间用空格分隔。
每个子目录中也要写有Makefile.am文件,里面的内容略有不同
bin_PROGRAMS=xxx
xxx_SOURCES=xxxxxxx.c
这里xxx表示你要在这个目录里生成的可执行文件叫什么名字,xxxxxxx.c表示生成xxx需要的源文件是哪个,算是一种依赖关系的建立。
在这里提出的有两点,第一点:对于多层目录,我才用的是每层目录下的Makefile.am指示出下一层包含的子目录,没有进行多层目录包含的处理;第二点是对于源文件依赖关系复杂的情况,我还没有进行处理过,这里处理的是简单的形式,主要为了对结构有认识。
3:运行autoscan。生成configure.scan文件
mv configure.scan configure.ac
vi configure.ac
我们对自动扫描产生的文件进行重命名,然后对其进行修改
AC_INIT([],[],[])这个宏填一下
加入宏AM_INIT_AUTOMAKE(xxx,xxx)
4:运行aclocal
运行autoheader
生成 README NEWS AUTHORS ChangeLog文件
5:运行automake -a
运行autoconf
6:OK,现在我们进行到了一个milestone的地方了,下面我们需要运行的是configure来进行配置,生成Makefile,但是我们先在这里停一下,有个小问题需要解决。
问题就是,我们要进行交叉编译,所以要告诉configure换一下编译器,不改的话就是默认的gcc。
经过google+baidu,我们需要这样干:
CC=arm-xxxx-linux-gcc ./configure –config-cache –host=arm-linux
据说,编译器要写在前面传递,后面的host要加,cache-file的话,别人加了,所以我就加了……
7:运行完毕之后,没有报错,而且Makefile中的CC也都是我们的交叉编译工具,然后运行make。就生成所有的应用程序了。
8:事情到这里基本上就可以结束了,因为autoconf,automake的功能就完成了,我们的程序编译已经可以自动化了。剩下的事情为了把这件事情变的更加完美一些。
我们建立一个名叫build的脚本文件
#!/bin/bash
CC=….
make
….
对吧,脚本文件大家都知道的。
而且我们在运行第一次之后可以吧不需要重复运行的比如configure之类的话用#屏蔽掉。
下面做的事情是写个丑陋的脚本来拷贝一些文件,丑陋是因为我不会高级的用法,将就着把功能实现了。
file=./beep/beep
file+=:./camera/camera
……..
在这里,很笨的手工指定了可执行文件的位置,因为我不会自动提取……
+=是追加变量值,:号为了好分割字符串,最后file的效果和PATH一样,你在shell里echo $PATH看看就知道什么样子的了。
path=`echo $file |
awk -v RS=”" ‘{ gsub(“\n”, “:”); print }’ |
awk -v ORS=”\n” ‘{ gsub(“:”, “\n”); print }’`
这段我也没法具体解释清除,照着书上的例子抄过来的,主要的作用就是把那些用:号连接的字符串变成一行一行的输出来,也就是把:替换成\n,貌似sed就可以阿,还没试验……
for i in $path
do
echo -n ‘cp’ $i
if [ -f $i ]
then
cp $i ./scripts
echo ” to ./scripts” OK
else
echo ” to ./scripts” FAILED
fi
done
就是把每个提取出来的文件放到某个目录下去,然后再打印个信息出来看看。
9:没有第9项了,这个事情到现在已经被基本上有点丑陋和漂亮的解决了。