|
1.4 应用APR
我们首先make install一下,比如我们在Makefile中指定prefix=$(APR)/dist,则make install后,在$(APR)/dist下会发现4个子目录,分别为bin、lib、include和build,其中我们感兴趣的只有include和lib。下面是一个APR app的例子project。
该工程的目录组织如下:
$(apr_path)
dist
- lib
- include
- examples
- apr_app
- Make.properties
- Makefile
- apr_app.c
我们的Make.properties文件内容如下:
#
# The APR app demo
#
CC = gcc -Wall
BASEDIR = $(HOME)/apr-1.1.1/examples/apr_app
APRDIR = $(HOME)/apr-1.1.1
APRVER = 1
APRINCL = $(APRDIR)/dist/include/apr-$(APRVER)
APRLIB = $(APRDIR)/dist/lib
DEFS = -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_DEBUG_
LIBS = -L$(APRLIB) -lapr-$(APRVER) \
-lpthread -lxnet -lposix4 -ldl -lkstat -lnsl -lkvm -lz -lelf -lm -lsocket ?Cladm
INCL = -I$(APRINCL)
CFLAGS = $(DEFS) $(INCL)
Makefile文件内容如下:
include Make.properties
TARGET = apr_app
OBJS = apr_app.o
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) ${CFLAGS} -o $@ $(OBJS) ${LIBS}
clean:
rm -f core $(TARGET) $(OBJS)
而apr_app.c文件采用的是$(apr_path)/test目录下的proc_child.c文件。编译运行一切OK。
1.5 APR的可移植性
正如前面所描述,APR的目前的首要目标就是设计为一个跨平台的通用库,因此在APR的整个设计过程中无不体现了可移植的思想,APR附带一个简短的设计文档,文字言简意赅,其中很多的移植设计思想都值得我们所借鉴,主要从四个方面谈。
1.5.1APR类型
为了支持可移植性,APR中的一个策略就是尽量使用APR自定义的类型来代替平台相关类型。这样的好处很多,比如便于代码移植,避免数据间进行不必要的类型转换(如果你不使用APR自定义的数据类型,你在使用某些APR提供的接口时,就需要进行一些参数的类型转换);自定义数据类型的名字更加具有自描述性,提高代码可读性。APR提供的基本自定义数据类型包括apr_byte_t,apr_int16_t,apr_uint16_t,apr_size_t等等。通常情况下这些类型都定义在apr.h中,不过你找遍整个APR包也不会找到apr.h这个文件,不过include目录下倒是存在类似于apr.h的apr.h.in和apr.hw,这两个文件是生成apr.h的模版,在apr.h.in中通用APR类型定义如下:
typedef unsigned char apr_byte_t;
typedef @short_value@ apr_int16_t;
typedef unsigned @short_value@ apr_uint16_t;
typedef @int_value@ apr_int32_t;
typedef unsigned @int_value@ apr_uint32_t;
typedef @long_value@ apr_int64_t;
typedef unsigned @long_value@ apr_uint64_t;
typedef @size_t_value@ apr_size_t;
typedef @ssize_t_value@ apr_ssize_t;
typedef @off_t_value@ apr_off_t;
typedef @socklen_t_value@ apr_socklen_t;
@xxx@变量的值是可变的,不同的平台其值可能不一样。其值由configure配置过程自动生成,configue脚本中设置@xxx@变量的部分大致如下:
AC_CHECK_SIZEOF(char, 1)
AC_CHECK_SIZEOF(short, 2)
AC_CHECK_SIZEOF(int, 4)
AC_CHECK_SIZEOF(long, 4)
AC_CHECK_SIZEOF(long long, 8)
if test "$ac_cv_sizeof_short" = "2"; then
short_value=short
fi
if test "$ac_cv_sizeof_int" = "4"; then
int_value=int
fi
if test "$ac_cv_sizeof_int" = "8"; then
int64_value="int"
long_value=int
elif test "$ac_cv_sizeof_long" = "8"; then
int64_value="long"
long_value=long
elif test "$ac_cv_sizeof_long_long" = "8"; then
int64_value="long long"
long_value="long long"
elif test "$ac_cv_sizeof_longlong" = "8"; then
int64_value="__int64"
long_value="__int64"
else
AC_ERROR([could not detect a 64-bit integer type])
fi
if test "$ac_cv_type_size_t" = "yes"; then
size_t_value="size_t"
else
size_t_value="apr_int32_t"
fi
if test "$ac_cv_type_ssize_t" = "yes"; then
ssize_t_value="ssize_t"
else
ssize_t_value="apr_int32_t"
fi
.. ..
Configure的具体的细节并不是本书描述的细节,如果你想了解更多细节,你可以去阅读GNU的AutoConf、AutoMake等使用手册。
变量类型
硬件平台
I686
I386
alpha
IA64
M68k
MIPS
Sparc
Spar64
apr_byte_t
1
1
1
1
1
1
1
1
apr_int16_t
2
2
2
2
2
2
2
2
apr_uint16_t
2
2
2
2
2
2
2
2
apr_int32_t
4
4
4
4
4
4
4
4
apr_uint32_t
4
4
4
4
4
4
4
4
apr_int64_t
4
4
8
8
4
4
4
4
apr_uint64_t
4
4
8
8
4
4
4
4
不过不同的操作系统中,定义各不相同,在Red Hat 9.0 Linux中,生成的定义如下:
typedef short apr_int16_t; //16位整数
typedef unsigned short apr_uint16_t; //16位无符号整数
typedef int apr_int32_t; //32位整数
typedef unsigned int apr_uint32_t; //32位无符号整数
typedef long long apr_int64_t; //64位整数
typedef unsigned long long apr_uint64_t; //64位无符号整数
typedef size_t apr_size_t; //
typedef ssize_t apr_ssize_t;
typedef off64_t apr_off_t;
typedef socklen_t apr_socklen_t; //套接字长度
通用数据类型的另外一个定义之处就是文件apr_portable.h中,APR中提供了通用的数据类型以及对应的操作系统依赖类型如下表:
通用类型
含义
Win32类型
BEOS类型
UNIX
apr_os_file_t
文件类型
HANDLE
int
Int
apr_os_dir_t
目录类型
HANDLE
dir
DIR
apr_os_sock_t
套接字类型
SOCKET
int
int
apr_os_proc_mutex_t
进程互斥锁
HANDLE
apr_os_proc_mutex_t
pthread_mutex_t
apr_os_thread_t
线程类型
HANDLE
thread_id
pthread_t
apr_os_proc_t
进程类型
HANDLE
thread_id
pid_t
apr_os_threadkey_t
线程key类型
int
pthread_key_t
apr_os_imp_time_t
FILETIME
struct timeval
SYSTEMTIME
struct tm
tm
apr_os_dso_handle_t
DSO加载
HANDLE
image_id
void*
apr_os_shm_t
共享内存
HANDLE
void*
void*
一旦定义了这些通用的数据类型,APR不再使用系统类型,而是上述的APR类型。不过由于系统底层仍然使用系统类型,因此在使用通用类型的时候一项必须的工作就是用实际的类型来真正替代通用类型,比如apr_os_file_t,如果是Win32平台,则必须转换为HANDLE。对于上面表格的每一个通用数据类型,Apache都提供两个函数支持这种转换:
APR_DECLARE(apr_status_t) apr_os_XXX_get(…);
APR_DECLARE(apr_status_t) apr_os_XXX_put(…);
get函数用于将通用的数据类型转换为特定操作系统类型;而put函数则是将特定操作系统类型转换为通用数据类型。比如对于file类型,则对应的函数为:
APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile,
apr_file_t *file);
APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file,
apr_os_file_t *thefile,
apr_int32_t flags, apr_pool_t *cont);
前者将通用的文件类型apr_os_file_t转换为特定操作系统类型apr_file_t,后者则是将apr_file_t转换为apr_os_file_t。
在后面的分析中我们可以看到,对于每一个组件类型,比如apr_file_t中都会包含系统定义类型,APR类型都是围绕系统类型扩充起来的,比如apr_file_t,在Unix中为:
struct apr_file_t
{
int filedes; //UNIX下的实际的文件系统类型
… …
}
而在Window中则是:
struct apr_file_t
{
HANDLE filedes; //Window下的实际的文件系统类型
……
}
因此apr_os_file_get函数无非就是返回结构中的文件系统类型,而apr_os_file_put函数则无非就是根据系统文件类型创建apr_file_t类型。
类似的例子还有apr_os_thread_get和apr_os_thread_put等等。
1.5.2函数
APR中函数可以分为两大类:内部函数和外部接口函数。顾名思义,内部函数仅限于APR内部使用,外部无法调用;而外部结构函数则作为API结构,由外部程序调用。
1.5.2.1内部函数
|