嵌入式菜鸟发菜

  嵌入式开发也做了半年多了,感觉仍然处在摸索阶段,有太多知识要吸收和理解。相比自己的老本行WEB,有些力不人心,渐感悟嵌入式门槛之高,于是就想把塞在脑门里的一些啰里八嗦发泄些出来。

  做嵌入式离不开硬件

  大学期间的模电数电差不多是混过去的, 因此硬件能力比较差,前段时间为了D触发器还查了好多资料。 每到这种时候,都不自觉地会想去读研,继续深造、系统学习。 好在,读研还得考研,俺对政治课是深恶痛疾,所以这种念头很快就打消了。
  干这行的,写底层驱动非要与硬件打交道,所以经常有许多芯片文档要看,开始时看那些文档还真不容易,没办法把握住重点。不过随着开发工作中经验的不断增加,也渐渐习惯了看文档,多数重点还是能把握住的。

  理论知识需要在实践中巩固

  大学期间学习的许多计算机理论, 因为时间太长又没有实际运用,多半已经忘掉了,尤其是一些比较复杂的理论。 但嵌入式开发需要许多理论做指导,像操作系统原理、计算机体系结构等等, 由于没有太多时间复习看书,在这个过程中一般是边做边查资料的。 这个月下来,渐渐发现以前不是很明白的部分都清楚了, 唯一头痛的是怎么抽时间把这些理论知识系统地看一遍。

  重视方法而不是技术本身

  嵌入式的应用领域很广,几乎无处不在。 平常到随身携带的手机,伟大到卫星飞船,产品的形态更是千姿百态。由于它的专用性,在不同的应用领域,产品软硬件架构之间的差别会比较大。这就意味着技术人员在不同应用领域之间切换(改行)的成本比较高,一个搞手机出身的,某天突然转去做卫星,没有半年一年是不能入行的。因此在平时的学习过程中要不断总结和改进,重视学习的方法,才有可能在不同领域切换时尽快入行。也许有人要说,我不想改行,但是,谁能保证,哪天不会冒出一个更先进的通讯方式能取代手机?
  一个人的学习能力永远是赶不上技术发展的速度,随着市场需求的不断变化,产品所采用的技术也有可能随时改变,面对着五花八门的技术,现实中的你还可能再执著于原来的技术吗?在这个时候,如果学习方法不科学,势必会浪费大量的时间在熟悉新技术上了。总慢人家半拍,心里上不会好受吧。
  对于像我这样的菜鸟,我给自己建议,刚开始学的东西不要太多了,先做好做精目前在做的项目。通过一两个项目的开发后,能够对产品开发整个过程以及产品架构有一个较深的认识,最好能精通一些必要的知识和技能。
  现在我做的ARM7+uClinux的项目,我希望在项目大体结束时能够达到的一些目标有:熟悉ARM体系结构、熟悉ARM指令系统、熟悉板上各类硬件在Linux下驱动的开发、熟悉嵌入式GUI的内部原理、巩固操作系统理论等。也许再通过一两个类似的项目,以上目标就能达到纯熟,到时就可以花一些时间往横向扩展,玩玩CPLD、FPGA什么的,到那时就基本上很容易入门了;或向纵向深入研究,剖析Linux内核源码,自己动手写操作系统和GUI库。

  要学习的东西还很多

  嵌入式开发的门槛高,这可不是空穴来风。在产品开发过程中,不是单纯的硬件设计、布板、制板和软件编码、测试,虽然要掌握这些东西已经不容易了,但还有许多容易被忽略的东西,却是新手与老手的区别,比如对各种规范和标准的理解。
  嵌入式项目过程与通常所说的软件项目过程的一个最重要的区别在于,嵌入式项目涵盖的流程更多、更复杂,软件项目也是嵌入式产品开发过程的一部分。软件产品不是实物产品,而嵌入式产品包括了软件、硬件和结构件,因此在项目过程中增加了硬件、结构件的设计与生产的流程。

  多方扩充学习,提高综合能力

  不否认某个领域上的专家的价值,但个人更希望通过多方面的学习和扩充,拓宽视野和思维,提高工作效率。知识面广了,对同一个问题就可能想出多种解决方法,对同一产品的方案更有可能想出一套创新的方案,想到别人想不到的。
  此外,日常生活工作中,重视时间管理、善于工具使用,能节省不少时间,做到别人做不到的。

  经验与前景

  经验对于项目过程来说非常重要。在设计阶段,设计人员可以根据经验判断设计的可行性;开发与调试阶段,开发人员可以根据经验快速地解决问题;在管理方面,经验的重要性就更不用说了。经验可以为企业节省成本、降低风险,使企业有能力在竞争激烈的市场上快速推出产品抢占市场、打败对手。
  人总是会衰老的,在衰老过程中学习能力会不断下渐;如果不是靠经验吃饭,那么在衰老的过程中就很快被年轻的精英赶超,渐渐被淘汰。
  个人认为,不论在哪个行业,靠经验吃饭的职业才有前途,嵌入式开发也有这个特点,所以对个人发展来讲,前景看好。加上这个领域本身就有前途,因此从事这个领域开发工作的前途无量。

  发泄完毕,睡觉!

— EOF —

以模块方式加载驱动

为了调试驱动方便,准备让驱动以模块的方式加载,这样就不用重复地烧写整个系统了。

但是在给uclinux选上以模块方式加载支持后:

  │ │   [*] Enable loadable module support                   │ │

  │ │   [ ]   Set version information on all module symbols  │ │

  │ │   [*]   Kernel module loader                           │ │

编译过程就出错了:

make CFLAGS="-D__KERNEL__ -I/home/work1/uClinux-dist-server/linux-2.4.x/include  -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fno-common -pipe -fno-builtin -D__linux__ -DNO_MM -mapcs-32  -mtune=arm7tdmi -mshort-load-bytes -msoft-float -gdwarf-2" -C  drivers

make[2]: Entering directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers'

make -C block

make[3]: Entering directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers/block'

make all_targets

make[4]: Entering directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers/block'

make[4]: *** 没有规则可以创建"ll_rw_blk.o"需要的目标"DAC960.c"。 停止。

make[4]: Leaving directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers/block'

make[3]: *** [first_rule] 错误 2

make[3]: Leaving directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers/block'

make[2]: *** [_subdir_block] 错误 2

make[2]: Leaving directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers'

make[1]: *** [_dir_drivers] 错误 2

make[1]: Leaving directory `/home/work1/uClinux-dist-server/linux-2.4.x'

make: *** [linux] 错误 1

打开linux-2.4.x/drivers/block/Makefile,发现Makefile里两处指定的都是大写的DAC960.c,而linux-2.4.x/drivers/block/下的这两个文件名都是小写的。后来看了看linux-2.6.18的内核,发现他们是把dac960.c和dac960.h改成了DAC960.c和DAC960.h。

修改后编译又见异常:

make[4]: Entering directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers/char'

arm-elf-gcc -D__KERNEL__ -I/home/work1/uClinux-dist-server/linux-2.4.x/include  -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fno-common -pipe -fno-builtin -D__linux__ -DNO_MM -mapcs-32  -mtune=arm7tdmi -mshort-load-bytes -msoft-float -gdwarf-2  -nostdinc -iwithprefix include -DKBUILD_BASENAME=serial_core_44b0x  -c -o serial_core_44b0x.o serial_core_44b0x.c

serial_core_44b0x.c:2244: parse error before `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2244: warning: type defaults to `int' in declaration of `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2244: warning: data definition has no type or storage class

serial_core_44b0x.c:2245: parse error before `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2245: warning: type defaults to `int' in declaration of `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2245: warning: data definition has no type or storage class

serial_core_44b0x.c:2246: parse error before `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2246: warning: type defaults to `int' in declaration of `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2246: warning: data definition has no type or storage class

serial_core_44b0x.c:2247: parse error before `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2247: warning: type defaults to `int' in declaration of `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2247: warning: data definition has no type or storage class

serial_core_44b0x.c:2248: parse error before `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2248: warning: type defaults to `int' in declaration of `this_object_must_be_defined_as_export_objs_in_the_Makefile'

serial_core_44b0x.c:2248: warning: data definition has no type or storage class

make[4]: *** [serial_core_44b0x.o] 错误 1

make[4]: Leaving directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers/char'

make[3]: *** [first_rule] 错误 2

make[3]: Leaving directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers/char'

make[2]: *** [_subdir_char] 错误 2

make[2]: Leaving directory `/home/work1/uClinux-dist-server/linux-2.4.x/drivers'

make[1]: *** [_dir_drivers] 错误 2

make[1]: Leaving directory `/home/work1/uClinux-dist-server/linux-2.4.x'

make: *** [linux] 错误 1

按照提示”this_object_must_be_defined_as_export_objs_in_the_Makefile”检查了一下linux-2.4.x/drivers/char/Makefile,发现是export-objs列表里少了serial_core_44b0x.o,加上后即可编译通过。 

模块的加载和卸除需要用到insmod和rmmod,所以还需要将busybox里的这两个工具选上。之后就可以用“insmod 模块名”和“rmmod 模块名”来加载和卸除模块了。

— EOF —

也谈谈JFFS2

上周大致看了些关于Flash上日志型文件系统的资料,了解到传统的基于闪存转换层(FLT)的文件系统存在的主要问题:
1. 效率低。因为每次都要把要修改的数据所在擦写块放入内存,产生了许多不必要的读操作;写入时,要将原来的擦写块擦除,然后再将内存中修改的数据写入该擦写块。这样就造成了数据带宽的严重浪费。
2. 降低了Flash的寿命。因为有大量无用的擦写动作,使得许多不需要擦除的块被擦除重写,这导致了整个Flash使用寿命的降低。
3. 没有提供磨损平衡,也会降低Flash的寿命。因为只要一个擦写块坏了,整块Flash也就不能用了,而那些频繁修改的块将会比其它块更快地成为坏块。
4. 不安全。如果在擦写过程中突然掉电,那么整个擦写块的数据将可能丢失。

日志型文件系统(LogFS)就是为解决以上问题而产生的,它将对文件的修改描述成日志,从而减少对Flash的擦写。只有当擦写请求超过一个擦写块的边界时,文件系统才会对Flash进行擦写。这种更新方式也叫out-of-place。
JFFS2就是Flash上应用最广的一个日志结构的文件系统。它提供的垃圾回收机制,使得我们不需要马上对擦写越界的块进行擦写,而只需要将其设置一个标志,标明为脏块。当可用的块数不足时,垃圾回收机制才开始回收这些节点。同时,由于JFFS2基于日志结构,在意外掉电后仍然可以保持数据的完整性,而不会丢失数据。

然而,JFFS2仍然有其缺点,这也是人们提出JFFS3的原因。
因为挂载时需要扫描整块Flash,来确定节点的合法性以及建立必要的数据结构,这使得JFFS2挂载时间比较长。
又由于JFFS2是将节点信息保存在内在中的,使得它所占用的内存量和节点数目成正比。
另外,由于JFFS2是通过随机方式来实现磨损平衡的,它不能保证磨损平衡的确定性。

JFFS3就是为解决JFFS2的这些缺陷而设计的,目前仍处于设计阶段。
但是,我们可以通过修改JFFS2来克服一些问题。比如通过打上EBS(erase block summary,磨损块小结)来提高JFFS2文件系统的挂载速度,并改进磨损平衡。
在官方CVS上fs/jffs3目录下的代码并不是真正的JFFS3,它就是在JFFS2基础上打上Fernc Havasi写的EBS补丁实现的。

上周五为了找这个EBS补丁花了好长时间,在补丁的官方网站上也没有找到可用的链接:
http://www.inf.u-szeged.hu/jffs2/mount.php
只是提示在新版本的JFFS2中已经包含该补丁:“Erase Block Summary is the part of JFFS2 from 2005-09-07”。
郁闷的是redhat那边那个JFFS2的CVS似乎连不上 :(
只好继续寻找……可惜找到之后发现它并不适合我的uClinux版本(linux-2.4.20),它是为某个版本的linux-2.6.x写的,而新版本的2.6内核中已经带有EBS补丁。
没有办法,只好舍弃……
把EBS补丁的下载地址贴出来,也许有人需要:
http://www.inf.u-szeged.hu/jffs2/jffs2-summary-20050823.patch
链接失效的话,可以点这边下载:
jffs2-summary-20050823.patch

如果想要深入研究JFFS2文件系统,可以看看linuxforum上shrek2写的《JFFS2文件系统源代码情景分析》(点击下载)

延伸阅读:

— EOF —

SQLite移植手记

前几天成功地把Berkeley DB移植到uClinux上,虽然可以正常工作了,但是文件还是太大了些。今天来试一个稍微小一点的,它叫SQLite。 SQLite实现了大部分SQL92标准的SQL语句,同时支持ACID。还有其它许多特性这里不做深究,因为这在嵌入式领域来说应该是够用了。

Hily Jiang
Email&Gtalk: hilyjiang at Gmail
Blog: http://hily.me/blog/

下载:
下载页面:http://www.sqlite.org/download.html
我使用的还是当前最新版本:sqlite-3.3.7.tar.gz
(写完的时候已经更新出3.3.8版本了,真快啊……)

安装:
时间不多,简单介绍安装过程:
解压sqlite到uclinux-dist/user/sqlite/

============ 对uClinux的修改 ============
1. 下载sqlite,解压到uclinux-dist/user/下
2. 编辑uclinux-dist/user/下的Makefile,增加:

dir_$(CONFIG_USER_SQLITE_SQLITE)            += sqlite

3. uclinux-dist/config/Configure.help中增加:

CONFIG_USER_SQLITE_SQLITE
  SQLite Database.

4. uclinux-dist/config/config.in最后增加:

mainmenu_option next_comment
comment 'Database'
bool 'sqlite'			CONFIG_USER_SQLITE_SQLITE
endmenu

============ 对SQLite的修改 ============
1. uclinux-dist/user/sqlite/main.mk中:
TCCX修改为:

TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src $(CFLAGS)

LIBOBJ修改为(一些模块不需要,比如tcl):

LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \
         callback.o complete.o date.o delete.o \
         expr.o func.o hash.o insert.o loadext.o \
         main.o opcodes.o os.o os_unix.o \
         pager.o parse.o pragma.o prepare.o printf.o random.o \
         select.o table.o tokenize.o trigger.o \
         update.o util.o vacuum.o \
         vdbe.o vdbeapi.o vdbeaux.o vdbefifo.o vdbemem.o \
         where.o utf.o legacy.o vtab.o

sqlite3$(EXE)规则部分修改为:

shell.o: $(TOP)/src/shell.c sqlite3.h
	$(TCCX) $(READLINE_FLAGS) -c $(TOP)/src/shell.c

sqlite3$(EXE): shell.o libsqlite3.a
	$(TCC) $(LDFLAGS) -o $@ shell.o \
	libsqlite3.a $(LIBREADLINE) $(THREADLIB) $(LDLIBS)

去掉install,增加:

distclean: clean
	rm -f config.h

2. 拷贝Makefile.linux-gcc为Makefile,修改如下:

TCC = $(CROSS)gcc
AR = $(CROSS)ar cr
RANLIB = $(CROSS)ranlib
#TCL_FLAGS = -I/home/drh/tcltk/8.4linux
#LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl

 

编译:
在make menuconfig的user application部分可以看到刚添加的Database –>菜单,进入并选择SQLite,保存退出后按原先的步骤重新编译内核即可。如果只需要sqlite的库,那么make user_only就可以了。
编译完成后会在user/sqlite目录下生成库libsqlite3.a。

测试一下:
编写一个测试程序sqlitetest.c,代码如下(来自官方quick start):

#include <stdio.h>
#include <sqlite3.h>

static int callback(void *NotUsed, int argc, char **argv, char **azColName){
  int i;
  for(i=0; i
然后为它写一个Makefile,大致如下:
UCLINUX_PATH = /home/uClinux-dist
SQLITE_PATH = $(UCLINUX_PATH)/user/sqlite

CROSS = arm-elf-
CPU_CFLAGS = -O3 -Wall -mapcs-32 -mtune=arm7tdmi -fno-builtin -msoft-float -Os  \
	-D__uClinux__ -D__ARM_CPU__  \
	-I$(UCLINUX_PATH)/lib/uClibc/include -I$(UCLINUX_PATH)/linux-2.4.x/include \
	-I$(SQLITE_PATH) \
	-D_DEBUG_
CPU_LDFLAGS = -nostartfiles -Wl, -elf2flt -L$(UCLINUX_PATH)/lib/uClibc/lib
CPU_ARFLAGS = r
CPU_LDLIBS = $(UCLINUX_PATH)/lib/uClibc/lib/crt0.o $(UCLINUX_PATH)/lib/uClibc/lib/crti.o \
	$(UCLINUX_PATH)/lib/uClibc/lib/crtn.o -lc
MY_LDFLAGS = -L$(SQLITE_PATH)
MY_LDLIBS = -lsqlite3

CFLAGS = $(CPU_CFLAGS)
LDFLAGS = $(CPU_LDFLAGS) $(MY_LDFLAGS)
LDLIBS = $(CPU_LDLIBS) $(MY_LDLIBS)

TOPDIR = ./

CC = $(CROSS)gcc

EXEC = sqlitetest
CSRC = sqlitetest.c
OBJS = $(patsubst %.c,%.o, $(CSRC))

all: $(EXEC)

$(OBJS): %.o : %.c
	$(CC) $(CFLAGS) -c $< -o $@

$(EXEC): $(OBJS)
	$(CC) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@

clean:
	-rm -f $(EXEC) *.elf *.gdb *.o

运行make编译测试程序,生成的程序大小约300KB:

linux:/home/work/sqlite # ll
总用量 688
drwxr-xr-x  2 root root    264 2006-10-09 11:25 .
drwxr-xr-x  4 root root    160 2006-10-09 11:21 ..
-rw-------  1 root root    982 2006-10-09 11:25 Makefile
-rwxr--r--  1 root root 315584 2006-10-09 11:25 sqlitetest
-rw-------  1 root root    788 2006-10-09 11:21 sqlitetest.c
-rwxr-xr-x  1 root root 396538 2006-10-09 11:25 sqlitetest.gdb
-rw-r--r--  1 root root   1600 2006-10-09 11:25 sqlitetest.o

接着将测试程序下载到目标板,测试运行结果如下:

# /home/sqlitetest /home/testdb.db "CREATE TABLE my_table(id int, name varchar(20))"
# /home/sqlitetest /home/testdb.db "INSERT INTO my_table values(1, 'jianglj')"
# /home/sqlitetest /home/testdb.db "INSERT INTO my_table values(2, 'Hily Jiang')"
# /home/sqlitetest /home/testdb.db "SELECT * FROM my_table"
id = 1
name = jianglj

id = 2
name = Hily Jiang

#

 
继续寻找更小的数据库,知道的朋友不妨推荐一下 :-)

-- EOF --

uClinux上Berkeley DB v4.5.20移植手记

Berkeley DB 是一个很棒的开源的嵌入式数据库,它主要运行在Unix/Linux上。现在它已成为Oracle的一部分,叫作Oracle Berkeley DB
下面主要介绍一下它在我最近玩的uClinux上的移植过程。

Hily Jiang
Email&Gtalk: hilyjiang at Gmail
Blog: http://hily.me/blog/

下载页面:
http://dev.sleepycat.com/downloads/releasehistorybdb.html
我使用的是当前最新版的4.5.20(点击下载)

linux:/home/work/db # ll
总用量 9078
drwxr-xr-x   2 root root       80 2006-10-08 12:36 .
drwxr-xr-x  11 root root     1120 2006-10-08 12:33 ..
-r-xr-xr-x   1 root users 9281894 2006-10-08 12:36 db-4.5.20.tar.gz

 

(一)解压

linux:/home/work/db # tar -zxf db-4.5.20.tar.gz
linux:/home/work/db # cd db-4.5.20/
linux:/home/work/db/db-4.5.20 # ls
.              db_checkpoint  db_upgrade     libdb_java  README
..             db_deadlock    db_verify      LICENSE     rep
btree          db_dump        dist           lock        repmgr
build_unix     db_dump185     docs           log         rpc_client
build_vxworks  db_hotbackup   env            mod_db4     rpc_server
build_windows  dbinc          examples_c     mp          sequence
clib           dbinc_auto     examples_cxx   mutex       tcl
common         db_load        examples_java  os          test
crypto         dbm            fileops        os_vxworks  txn
cxx            db_printlog    hash           os_windows  xa
db             db_recover     hmac           perl
db185          dbreg          hsearch        php_db4
db_archive     db_stat        java           qam

docs目录下有我们需要的文档,包括快速入门、各种语言的API手册等资料。
(二)配置和编译
建立一个脚本以方便配置。由于unix/linux编译时的工作路径必须是build_unix,因此我们需要在build_unix目录下创建脚本。
我创建了一个名为myconfig的脚本,内容如下:

linux:/home/work/db/db-4.5.20/build_unix # cat -n myconfig
     1  #!/bin/sh
     2
     3  CC=arm-elf-gcc \
     4  CFLAGS="-Os -D__uClinux__ -fno-builtin -I/home/uClinux-dist/linux-2.4.x/include -I/home/uClinux-dist/lib/uClibc/include -I/home/uClinux-dist/lib/uClibc/include/../ " \
     5  LDFLAGS="-Wl,-elf2flt -Wl,-move-rodata -L/home/uClinux-dist/lib/uClibc/lib -L/home/uClinux-dist/lib/uClibc/lib/../ -lc " \
     6  ../dist/configure \
     7    --prefix=/home/work/db/Berkeley.DB \
     8    --build=i686-linux \
     9    --host=arm-elf-linux \
    10    --disable-cryptography \
    11    --disable-hash \
    12    --disable-queue \
    13    --disable-replication \
    14    --disable-statistics \
    15    --disable-verify \
    16    --disable-compat185 \
    17    --disable-cxx \
    18    --disable-debug \
    19    --disable-debug_rop \
    20    --disable-debug_wop \
    21    --disable-diagnostic \
    22    --disable-dump185 \
    23    --disable-java \
    24    --disable-mingw \
    25    --disable-o_direct \
    26    --disable-posixmutexes \
    27    --disable-pthread_api \
    28    --disable-rpc \
    29    --disable-smallbuild \
    30    --disable-tcl \
    31    --disable-test \
    32    --disable-uimutexes \
    33    --enable-umrw \
    34    --disable-shared \
    35    --enable-static \
    36    --enable-fast-install \
    37    --disable-libtool-lock \
    38    --disable-largefile

关于configure配置参数的含义,可以运行”../dist/configure –help”查看帮助,这里不再介绍。
要强调的一点是uClibc只能用静态编译,因此一定要选择–disable-shared。
接着执行./myconfig运行配置并编译安装函数库:

linux:/home/work/db/db-4.5.20/build_unix # ./myconfig >/dev/null
configure: WARNING: In the future, Autoconf will not detect cross-tools
whose name does not start with the host triplet.  If you think this
configuration is useful to you, please write to autoconf@gnu.org.
cat: /etc/ld.so.conf.d/*.conf: No such file or directory
linux:/home/work/db/db-4.5.20/build_unix # make >/dev/null && make install >/dev/null
../dist/../hmac/sha1.c:96: warning: `R0' redefined
/usr/local/lib/gcc-lib/arm-elf/2.95.3/../../../../arm-elf/include/sys/ucontext.h:40: warning: this is the location of the previous definition
../dist/../hmac/sha1.c:97: warning: `R1' redefined
/usr/local/lib/gcc-lib/arm-elf/2.95.3/../../../../arm-elf/include/sys/ucontext.h:42: warning: this is the location of the previous definition
../dist/../hmac/sha1.c:98: warning: `R2' redefined
/usr/local/lib/gcc-lib/arm-elf/2.95.3/../../../../arm-elf/include/sys/ucontext.h:44: warning: this is the location of the previous definition
../dist/../hmac/sha1.c:99: warning: `R3' redefined
/usr/local/lib/gcc-lib/arm-elf/2.95.3/../../../../arm-elf/include/sys/ucontext.h:46: warning: this is the location of the previous definition
../dist/../hmac/sha1.c:100: warning: `R4' redefined
/usr/local/lib/gcc-lib/arm-elf/2.95.3/../../../../arm-elf/include/sys/ucontext.h:48: warning: this is the location of the previous definition
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
warning: .rodata section contains relocations
strip: /home/work/db/Berkeley.DB/bin/db_archive: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_checkpoint: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_deadlock: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_dump: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_hotbackup: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_load: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_printlog: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_recover: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_stat: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_upgrade: 不可识别的文件格式
strip: /home/work/db/Berkeley.DB/bin/db_verify: 不可识别的文件格式

编译过程中会出现一些warning,不用理它们。
安装完后,会在指定的安装目录/home/work/db/Berkeley.DB下生成函数库:

linux:/home/work/db/db-4.5.20/build_unix # cd /home/work/db/Berkeley.DB/
linux:/home/work/db/Berkeley.DB # ls
.  ..  bin  docs  include  lib
linux:/home/work/db/Berkeley.DB # ll lib/
总用量 1962
drwxr-xr-x  2 root root     104 2006-10-08 12:57 .
drwxr-xr-x  6 root root     144 2006-10-08 12:57 ..
-rw-r--r--  1 root root 1002266 2006-10-08 12:57 libdb-4.5.a
-rw-r--r--  1 root root 1002266 2006-10-08 12:57 libdb.a

(三)数据库操作测试
创建一个测试程序如下:

linux:/home/work/db/Berkeley.DB # cat -n testdb.c
     1  #include
     2  #include
     3  #include
     4
     5  #define DESCRIPTION_SIZE 20
     6  int main()
     7  {
     8      DB *dbp;           /* DB structure handle */
     9      u_int32_t flags;   /* database open flags */
    10      int ret;           /* function return value */
    11      char *description = "Grocery bill.";
    12      char *description1[DESCRIPTION_SIZE + 1];
    13      DBT key, data;
    14      float money;
    15
    16      /* Initialize the structure. This
    17       * database is not opened in an environment,
    18       * so the environment pointer is NULL. */
    19      ret = db_create(&dbp, NULL, 0);
    20      if (ret != 0) {
    21        /* Error handling goes here */
    22          printf("Create fail!\n");
    23      }
    24
    25      /* Database open flags */
    26      flags = DB_CREATE;    /* If the database does not exist,
    27                             * create it.*/
    28
    29      /* open the database */
    30      ret = dbp->open(dbp,        /* DB structure pointer */
    31                      NULL,       /* Transaction pointer */
    32                      "/home/my_db.db", /* On-disk file that holds the database. */
    33                      NULL,       /* Optional logical database name */
    34                      DB_BTREE,   /* Database access method */
    35                      flags,      /* Open flags */
    36                      0);         /* File mode (using defaults) */
    37      if (ret != 0) {
    38        /* Error handling goes here */
    39          printf("Created new database.\n");
    40      }
    41
    42      money = 122.45;
    43
    44      /* Zero out the DBTs before using them. */
    45      memset(&key, 0, sizeof(DBT));
    46      memset(&data, 0, sizeof(DBT));
    47
    48      key.data = &money;
    49      key.size = sizeof(float);
    50
    51      data.data = description;
    52      data.size = strlen(description) +1;
    53
    54      ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE);
    55      if (ret == DB_KEYEXIST) {
    56          dbp->err(dbp, ret,
    57            "Put failed because key %f already exists", money);
    58      }
    59
    60      memset(&data, 0, sizeof(DBT));
    61
    62      data.data = &description1;
    63      data.ulen = DESCRIPTION_SIZE + 1;
    64      data.flags = DB_DBT_USERMEM;
    65      dbp->get(dbp, NULL, &key, &data, 0);
    66
    67      printf("data: %s\n", (char *)data.data);
    68
    69      /* When we're done with the database, close it. */
    70      if (dbp != NULL)
    71          dbp->close(dbp, 0);
    72
    73      return 0;
    74  }

这个程序会在目标板上/home/目录下创建一个文件名为my_db.db的数据库,接着增加一条记录,然后从数据库中读取出新添加的这条记录,最后关闭数据库。
程序要烧写到目标板上,需要进行交叉编译:

linux:/home/work/db/Berkeley.DB # arm-elf-gcc -O3 -Wall -mapcs-32 -mtune=arm7tdmi -fno-builtin -msoft-float -Os -D__uClinux__ -D__ARM_CPU__ -I/home/work/uClinux-dist/lib/uClibc/include -I/home/uClinux-dist/linux-2.4.x/include -I/home/work/db/Berkeley.DB/include -D_DEBUG_ -c testdb.c -o testdb.o
linux:/home/work/db/Berkeley.DB # arm-elf-gcc testdb.o -nostartfiles -Wl, -elf2flt -L/home/uClinux-dist/lib/uClibc/lib -L/home/work/db/Berkeley.DB/lib /home/uClinux-dist/lib/uClibc/lib/crt0.o /home/uClinux-dist/lib/uClibc/lib/crti.o /home/uClinux-dist/lib/uClibc/lib/crtn.o -lc -ldb -o testdb
linux:/home/work/db/Berkeley.DB # ll
总用量 1217
drwxr-xr-x   6 root root    280 2006-10-08 13:22 .
drwxr-xr-x   4 root root    144 2006-10-08 12:50 ..
drwxr-xr-x   2 root root    376 2006-10-08 12:57 bin
drwxr-xr-x  14 root root    384 2006-10-08 12:57 docs
drwxr-xr-x   2 root root     96 2006-10-08 12:57 include
drwxr-xr-x   2 root root    104 2006-10-08 12:57 lib
-rwxr--r--   1 root root 584476 2006-10-08 13:22 testdb
-rw-r--r--   1 root root   2171 2006-10-08 13:22 testdb.c
-rw-------   1 root root   2163 2006-10-08 13:09 testdb.c~
-rwxr-xr-x   1 root root 673683 2006-10-08 13:22 testdb.gdb
-rw-r--r--   1 root root   1540 2006-10-08 13:22 testdb.o

生成的可执行文件比较大,将近600KB。
烧写到目标机上后运行,结果如下:

# /home/testdb
data: Grocery bill.

搞定~ 

总的来说,Berkeley DB还是比较易用的。就是生成的可执行文件还是太大些 :-(

— EOF —