标签 Configure 下的文章

也谈Configure脚本问题的解决

开了一个下午的技术交流会,回到办公室时离下班时间已经不远,天气预报说今晚有暴雪,外面阴沉的天气似乎也证实了这一点。这时一个同事遇到了一个软件包编译的问题,一时无法解决,向我求助。

这是一个libmemcached的编译问题,我们用的是libmemcached 0.34版本,我的同事在PC Solaris上执行libmemcached的configure脚本时遇到如下错,Configure脚本提示:

checking for pthread-config… no
configure: error: could not find libpthread

但经过确认系统中明明在/usr/lib下有pthread相关库的存在:
Tony Bai-[~/libmemcached-0.34]526:>ll /usr/lib|grep pthread
lrwxrwxrwx   1 root     root          26 2009   9月 10 llib-lpthread.ln -> ../../lib/llib-lpthread.ln
lrwxrwxrwx   1 root     root          23 2009   9月 10 llib-lpthread -> ../../lib/llib-lpthread
lrwxrwxrwx   1 root     root          25 2009   9月 10 libpthread.so.1 -> ../../lib/libpthread.so.1*
lrwxrwxrwx   1 root     root          25 2009   9月 10 libpthread.so -> ../../lib/libpthread.so.1*

又确认了一下用户的环境变量设置,LD_LIBRARY_PATH也包含了这些库的目录。

经验告诉我,这个错误是假象,向上翻Configure的输出结果,的确发现些奇怪的Check结果,如下:

checking for ANSI C header files… no
checking for sys/types.h… no
checking for sys/stat.h… no
checking for stdlib.h… no
checking for string.h… no
checking for memory.h… no
checking for strings.h… no
checking for inttypes.h… no
checking for stdint.h… no
checking for unistd.h… no

第一感觉,这怎么可能呢?这些标准C库头文件居然都Check失败了!在网上用“checking for ANSI C header files… no”搜了一下,也没有找到很好的答案。

我对Configure了解也不多,但是还是让我发现了config.log这根救命稻草。config.log这个文件详细地记录了Configure的每一步校验的执行内容和结果,其中对于标准C头文件的Check是这样做的:

configure:4827: checking for ANSI C header files
configure:4857: gcc -c -g -O2 -m64  conftest.c >&5
conftest.c:1: sorry, unimplemented: 64-bit mode not compiled in
configure:4864: $? = 1
configure: failed program was:
| /* confdefs.h.  */
| #define PACKAGE_NAME "libmemcached"
| #define PACKAGE_TARNAME "libmemcached"
| #define PACKAGE_VERSION "0.34"
| #define PACKAGE_STRING "libmemcached 0.34"
| #define PACKAGE_BUGREPORT "http://tangent.org/552/libmemcached.html"
| /* end confdefs.h.  */
| #include
| #include
| #include
| #include
|
| int
| main ()
| {
|
|   ;
|   return 0;
| }
configure:4995: result: no

再往下看,检测sys/types.h等标准库头文件的错误都是:
conftest.c:1: sorry, unimplemented: 64-bit mode not compiled in
configure:5047: $? = 1

看来并非是系统没有包含标准头文件,而是Configure采用了64-bit编译的方法去测试头文件存在的时候出错。随意创建一个testm64.c的源文件,输入:

/* testm64.c */
int main() {
    ;
    return 0;
}
用gcc -g -m64 testm64.c执行编译,得到与之前相同的错误结果:
testm64.c:1: sorry, unimplemented: 64-bit mode not compiled in

查看Gcc版本,发现是3.4.6,突然恍然大悟,这不是之前发现在Solaris 10 for x86上Gcc 64位编译的一个问题吗,在Solaris 10 for x86上如果要进行64位编译,要使用/usr/sfw/bin下的gcc 3.4.3版本,不能用3.4.6版本。

除了更换Gcc之外,如果你想编译32位版本的话,还可以这样来做:修改Configure脚本,打开Configure,将-m64字样全部删除。这样Configure后编译libmemcached就一切顺利了。

以上关于Configure脚本问题的解决方法,有一定的通用性,因此记之。

APR源代码分析-设计篇

作为一个可移植的运行时环境,APR的设计当然是很精妙的,但精妙的同时对使用者有一些限制。

APR附带一个简短的设计文档,文字言简意赅,其中很多的设计思想都值得我们所借鉴,主要从三个方面谈。

1、类型
1) APR提供并建议用户使用APR自定义的数据类型,好处很多,比如便于代码移植,避免数据间进行不必要的类型转换(如果你不使用APR自定义的数据类型,你在使用某些APR提供的接口时,就需要进行一些参数的类型转换);自定义数据类型的名字更加具有自描述性,提高代码可读性。APR提供的基本自定义数据类型包括:
typedef unsigned char  apr_byte_t;
typedef short    apr_int16_t;
typedef unsigned short   apr_uint16_t;                                              
typedef int    apr_int32_t;
typedef unsigned int   apr_uint32_t;                                              
typedef long long   apr_int64_t;
typedef unsigned long long  apr_uint64_t;
这些都是在apr.h中定义的,而apr.h在UNIX平台是通过configure程序生成的,在不同平台APR自定义类型的实际类型是完全有可能不一致的。

2) 还有一点值得提的是在APR的设计文档中,它称“dso、mmap、process、thread”等为“base types”。很难用中文理解之,估计是指apr_mmap_t这些类型吧。权且这么理解吧^_^

3) 另外的一个特点就是大多APR类型中都包含一个apr_pool_t类型的字段,该字段用于分配APR内部使用的内存,任何APR函数需要内存都可以通过它分配。如果你创建一个新的类型,你最好在该类型中加入一个apr_pool_t类型的字段,否则所有操作该类型的APR函数都需要一个apr_pool_t类型的参数。

2、函数
1) 理解APR的函数设计对阅读APR代码很有帮助。看了APR代码你会发现很多类似APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool)带APR_DECLARE宏的函数声明,到底是什么意思呢?为什么要加一个APR_DECLARE呢?在apr.h中有这样的解释:“APR的固定个数参数公共函数的声明形式APR_DECLARE(rettype) apr_func(args);而非固定个数参数的公共函数的声明形式为APR_DECLARE_NONSTD(rettype) apr_func(args, …);”。在Unix上的apr.h中有这两个宏的定义:
#define APR_DECLARE(type)            type
#define APR_DECLARE_NONSTD(type)     type
在apr.h文件中解释了这么做就是为了在不同平台上编译时使用“the most appropriate calling convention”,这里的“calling convention”是一术语,翻译过来叫“调用约定”。[注1]
常见的调用约定有:stdcall、cdecl、fastcall、thiscall和naked call,其中cdecl调用约定又称为C调用约定,是C语言缺省的调用约定。

2) 如果你想新增APR函数,APR建议你最好能按如下做,这样会和APR提供的函数保持最好的一致性:
 a) 输出参数为第一个参数;
 b) 如果某个函数需要内部分配内存,则将一个apr_pool_t参数放在最后。
 
3、错误处理
大型的系统程序的错误处理是十分重要的,APR作为一通用的库接口集合详细的说明了使用APR时如何进行错误处理。
1) 错误处理的第一步就是“错误码和状态码分类”。APR的函数大部分都返回apr_status_t类型的错误码,这是一个int型,在apr_errno.h中定义,和它在一起定义的还有apr所用的所有错误码和状态码。APR定义了5种错误码类型,它们分别为“0”[注2]、APR_OS_START_ERROR、APR_OS_START_STATUS、APR_OS_START_USEERR和APR_OS_START_SYSERR,它们每个都拥有自己独自的偏移量。

2) 如何定义错误捕捉策略?
由于APR是可移植的,这样就可能遇到这样一个问题:不同平台错误码的不一致。如何处理呢?APR给我们提供了2种策略:
a) 跨多平台返回相同的错误码
这种策略的缺点是转换费时且在转换时有错误码损耗。比如Windows操作系统定义了成百上千错误码,而POSIX才定义了50错误码,如果都转换为规范统一的错误码,势必会有错误码含义丢失,有可能得不到拥有真正含义的错误码。执行流程如:
make syscall that fails
        convert to common error code
        return common error code
——————————————————————-
            decide execution based on common error code

b) 返回平台相关错误码,如果需要将它转换为通用错误码
程序的执行路线往往要根据函数返回错误码来定,这么做的缺点就是把这些工作推给了程序员。执行流程如:
make syscall that fails
        return error code
——————————————————————-
            convert to common error code (using ap_canonical_error)
            decide execution based on common error code

[注1] 调用约定
我们知道函数调用是通过栈操作来完成的,在栈操作过程中需要函数的调用者和被调用者在下面的两个问题上做出协调,达成协议:
a) 当参数个数多于一个时,按照什么顺序把参数压入堆栈
b) 函数调用后,由谁来把堆栈恢复原来状态
在像C/C++这样的中、高级语言中,使用“调用约定”来说明这两个问题。

[注2] 特殊“0”
每个平台都有0,但是都没有实际的定义,0又的确是一个errno value的offset,但是它是“匿名的”,它不像EEXIST那样有着可以“自描述”的名字。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats