Posts Tagged ‘opensource’

Emacs——很漂亮很强大

Posted by jcadam - 11/07/09 at 10:07 下午

Vim我用了5年有余,最近因为接触的项目非常大,大约10W行代码,而且该项目采用包括C和C++还有python的多种语言开发,突然让我觉得使用Vim有些应付不过来。我的主要任务并不是去查看系统细节,而是要在短时间内获得已有系统的情况——包括结构和功能上的信息,所以我需要一个比较强大的代码浏览程序。公司提供的软件库里面搜索了半天,找到十几款代码浏览工具竟然没有一款是我熟悉的。一狠心,我觉得尝试一下Emacs。或许Vim也能够胜任这个工作,但是我尝试拼凑了很久插件也没能找到符合工作需要的集合。总之,破釜沉舟,试一下Emacs。谁知道上手之后我竟然再也放不下Emacs了,彻底被这款编辑器的扩展性和强大功能征服。在使用了Emacs一个月以后,对于我的“重大发现”,我想还是留下一个记录比较好。

基础软件包


$ sudo apt-get install emacs-snapshot emacs-snapshot-common emacs-snapshot-bin-common emacs-snapshot-el emacs-goodies-el emacs-snapshot-gtk

漂亮的Emacs

我并不是个特别喜欢冒险的人,所以刚刚开始的时候,我选择了Emacs22。但是,后来发现,处理日语和中文的字体显示非常繁琐,索性放弃“保守派”的一贯作风,跃迁到还在开发中的Emacs23。在google上搜索得到Alexandre Vassalotti写的很流行的一篇博文Pretty Emacs,如法炮制,在Ubuntu 9.04上得到了一个让我基本满意的操作界面。这篇博文虽然有用但却非常简略,并没有详细说明CJK字体的反锯齿应该怎样处理。我尝试在~/.Xresource文件中使用包含日语和中文的字体,但是结果并不能让我满意,原因是日语和中文的汉字显示混在了一起,错别字太多。拜google所赐,最终还是找到了解决之法。证据在此。

在.emacs中需要使用字符集来将日语和中文的显示字符区别对待,代码如下:

;;;------------------------------------------------------------;;;
;;; VIEW
;;; No startup message
(setq inhibit-startup-message t)
;;; GUI font
(set-default-font "Bitstream Vera Sans Mono-12")
;;; JP fonts
(set-fontset-font (frame-parameter nil 'font)
		  'japanese-jisx0208
		  '("M+2VM+IPAG circle" . "unicode-bmp"))
;;; zh-CN fonts
(set-fontset-font (frame-parameter nil 'font)
		  'han
		  '("Vera Sans YuanTi Mono" . "unicode-bmp"))
;;;;===========================================================;;;;
;;; cjk-misc fonts
(set-fontset-font (frame-parameter nil 'font)
		  'cjk-misc
		  '("Vera Sans YuanTi Mono" . "unicode-bmp"))
;;; bopomofo fonts
(set-fontset-font (frame-parameter nil 'font)
		  'bopomofo
		  '("Vera Sans YuanTi Mono" . "unicode-bmp"))
;;; symbol fonts
(set-fontset-font (frame-parameter nil 'font)
		  'symbol
		  '("Vera Sans YuanTi Mono" . "unicode-bmp"))
;;;;=========================================================;;;;

“Vera Sans YuanTi”字体似乎涉嫌侵权,所以现在在互联网上已经难觅其踪,但是我还是非常喜欢这款合成字体,三四年前私自收藏了一直使用。在Ubuntu Jaunty上,读者可以尝试使用文泉驿等字体替代。或者,如果你拥有Windows的授权,使用微软雅黑也会有不错的效果。这里需要注意的是,Ubuntu 8.04或者更早版本上的emacs-snapshot提供的Emacs版本并不支持CJK字体的反锯齿显示。如果你使用比较早版本的Emacs23,可以尝试使用emacs.orebokech.com提供的WeeklyBuild。但是事先应该确认一下在Ubuntu的backport上有没有提供emacs-snapshot的软件包。下面是中文显示效果的截屏。

安装CEDET

CEDET是一整套开发环境的集合工具。包括工程管理,代码浏览和自动补全工具。但是,Ubuntu的软件频道中提供的版本并不能和Emacs23一起工作。详情可以看这个Debian的Bug#525613。我的解决办法是采用新的CEDET版本。

$ wget http://sourceforge.net/projects/cedet/files/cedet/cedet-1.0pre6.tar.gz/download
$ tar zxf cedet-1.0pre6.tar.gz
$ cd cedet-1.0pre6/
$ make
$ make install-info
$ cd ../ && cp -a cedet-1.0pre6 /usr/share/emacs-snapshot/site-lisp/cedet

这里需要注意的是,必须将编译好的cedet拷贝到/usr/share/emacs-snapshot/site-lisp中,而不能仅仅将这个文件放到load-path中了事。原因是Emacs在初始化的时候,会利用这个目录中的subdirs.el来保证整个目录都添加进入load-path之中。接下来在.emacs中添加下面这几行就基本可以使用了,但是上手之后应该多查看info的内容找到更多的信息。在Emacs中利用组合键Ctrl-h i可以打开info,按s查找CEDET。

;;;-----------------------------------------------------------------;;;
;;; CEDET
;;;-----------------------------------------------------------------;;;
;; Load CEDET.
;; See cedet/common/cedet.info for configuration details.
(require 'cedet)

;; Enable EDE (Project Management) features
(global-ede-mode 1)

;; Enable EDE for a pre-existing C++ project
;; (ede-cpp-root-project "NAME" :file "~/myproject/Makefile")

;; Enabling Semantic (code-parsing, smart completion) features
;; Select one of the following:

;; * This enables the database and idle reparse engines
(semantic-load-enable-minimum-features)

;; * This enables some tools useful for coding, such as summary mode
;;   imenu support, and the semantic navigator
(semantic-load-enable-code-helpers)

CEDET非常强大,以至于很难几句话将这个工具讲清楚,但是经常查看info和多多实践,马上就会用的非常顺手。

后记

最近一些日子,我一直在看Emacs相关的内容。Emacs可以说不仅仅是一款编辑器,而是一个集成并且可以扩展的工作环境。很多年轻的程序员,包括我自己,总是在各种各样的工具之间跳来跳去,一方面可以是因为自己不够坚定,但另一方面只能说很多工具都有自己的局限性,当程序员遇到新的情况的时候就可能很自然的抛弃旧工具。Emacs却不同,它更像一个framework,你可以将自己的技巧,使用习惯以及效率提升工具全部集成其上。如果它不够用了,你可以自己动手写lisp对它进行扩展。又想起那句话,人们往往高估自己短期的能力而低估自己长期的积累。Emacs正是给这种积累提供一种可能性。也许这正是对我来说最要命特性。我的.emacs文件在这里

嘿~,如果您喜欢我的博客,您可以通过RSS.链接将本博客的最新文章传输到您喜欢的阅读器。 Subscribe with Google 
订阅到鲜果 订阅到抓虾

民主实践的感受和思考

Posted by jcadam - 13/06/09 at 09:06 下午

参与深圳LUG的讨论后,我得到的一些对民主实践的新的感受。或者,这些感受也有可能与“民主”没有什么关系,现在我只是想把他记录下来。

开放源代码社区和一些类似的自治团体,应当是现在中国社会实践小范围民主自由制度的摇篮。特别是开源社区的氛围和一些约定俗称的制度,非常有利于让以民主方式讨论问题的形式逐步展开。但是,真正的将这个想法付诸时间之后,我才发现这其中却显露出来很多问题。

第一,社区组织形成通常来自于一些爱好者的热情支持,因此,社区在发展过程中会有可能走不出广泛民主实践的道路。比如,我比较关注的深圳LINUX爱好者团体,创建伊始到现在一直靠几位创始人和核心活动成员的的热情得以存在。而且这种松散的线上社区一般都没有明确的行动纲领(guideline)和目标,于是有可能将社区活动最终办成“圈内”人士的自娱自乐。这可以说是开源软件社区相比较商业软件形成的联盟存在的先天性不足吧。

第二,文化和政治环境的限制让民主制度的创新受到限制。我不敢说这是社区实践民主缺乏的首要因素,但至少这一点也是关键因素。说的大一点,即是“民主制度究竟应该怎样搞”这个问题还没有得到解决。我想这个问题的形成,正反应的中国政治教育的失败。政治本身不是一件可怕的事情,这个词字面意义上理解,它应当是一门关于个人如何参与群体决策和体现个人价值的问题。我们从小就没有机会去实践如何发表自己的意见,如何用辩论支撑自己的意见,如何让群体接受自己意见,以及如何根据群体作出的决策进行妥协和让步。可以说,谁也没有教给我们这些能力。而这种能力,又是在社会生活中一种必须的能力。如果我们接受的不是关于愚忠愚孝的而是关于如何实践民主的教育的话,那么相信社会阶层之间可以通过对话和协调的方式缓解社会压力。放到一个小团体的范围内来看,又可以通过这种方式来促进成员之间的相互交流和互信关系,从而促进社区发展。

第三,民主实践能力的缺陷,导致我们的辩论技巧只剩下了谩骂。中国国内的各大论坛,无论是技术论坛还是非技术论坛都充斥这谩骂。当一个人实在不知道用什么方式表达自己意愿的时候,就只能生产视听垃圾了。口舌之利又是似乎比生命还重要,这是在是中国人根深蒂固的毛病之一。但是,可恨之人必定有可怜之处,我们需要用仁慈的心去体会一个个贫乏的灵魂。

第四,也许文革还没有结束。看到很多人谈到过“文化大革命”对中国社会的影响,但是谁曾想过,有一种东西已经植根在很多人心中,生长在我们使用的语言里。肆意的无视规则的人身攻击和死不认错的的态度,完全体现了一种人性的恶。那件事情注定贻害万年。

Ubuntu社区是在开源社区中发展非常好的,最具代表性的是它的开发者进阶制度。我觉得从Ubuntu社区得到的很多经验,非常值得学习和参考。

嘿~,如果您喜欢我的博客,您可以通过RSS.链接将本博客的最新文章传输到您喜欢的阅读器。 Subscribe with Google 
订阅到鲜果 订阅到抓虾

Linux内核源码阅读系列(6)-链接3

Posted by jcadam - 20/01/09 at 02:01 下午

上一篇举例的时候那个例子并不是很恰当,因为用局部变量的生存周期来解释的话,也是行的通的。那个例子只能说是又添加了一种新的解释而已。要找一个比较妖的还挺难,就直接抄书了:

/* foo5.c */
#include <stdio.h>
void f(void);

int x = 15213;
int y = 15212;

int main()
{
	f();
	printf("x = 0x%x y = 0x%x \n",
		x, y);
	return 0;
}
/* bar5.c */
double x;

void f()
{
	x = -0.0;
	^^^---链接器在处理这个符号x的时候,选择了,foo5.c文件中定义的
	      “强符号”int型的x,也就是解释为foo5.c中的x的内存位置写入
	      在这里定义的double型的值。
}

在IA32/Linux机器上,double型是8个字节,而int型是4字节;因此,这里将用double型的”-0.0″覆盖foo5.c中的x和y的内存位置,于是理所当然的程序出了一个意想不到的意外,而且这类错误是不容易被发现。

静态链接库

静态链接库就是把一堆相关的.o文件使用ar工具打包。最著名的静态连接库恐怕就是libc.a了。这是C语言标准库的静态链接版本。程序跟静态连接库链接的时候一般采用如下形式的命令:

$ gcc -O2 -c main.c
$ gcc -static -o swap_sample main.o libswap.a

程序在跟静态库链接的时候,首先链接器会按照命令行输入的从前往后的方向对可重定位文件进行符号解析,找出在模块内部未定义的符号,并将在其后找到包含这个符号定义的那个模块的代码和数据拷贝进入将生成的可执行目标文件,并对其中的符号进行重定位,如果这些未定义的符号全部解决,则链接成功并输出可执行文件,否则链接器会报错。

重定位

重定位就是确定一个对象(包括代码和数据)在存储器中的位置的过程。关于每个需要重定位的符号,链接器有两个方面事情要做,1. 对模块中的符号的定义(definition)进行定位,这个工作主要是合并各个输入模块的代码和数据节,并给每个节和每个符号定义赋以新的存储器地址; 2. 将模块中的引用(reference)指向正确的符号定义位置,这个工作主要依靠“重定位表目”完成,也就是上一篇中提到的实例中的rel.textrel.data节的总览中提到的”R_386_PC32“和”R_386_32“等附带有重定位类型的表目。

重定位表目可以用下面的包括下面代码展示的内容:

typedef struct {
	int offset;	/* 需要被重定位的“引用”在所在节中的偏移量 */
	int symbol:24,	/* 这个引用应该指向的符号 */
	    type:8;	/* 重定位类型 */
}

最重要的两类重定位类型就是”R_386_PC32″和”R_386_32″。

R_386_PC32: 这个类型的重定位信息主要控制的是程序在执行是的跳转。重定位一个使用32位PC(program counter)相关的地址引用。当CPU执行使用PC相关寻址的指令时,它就将在代码中编码的32位值加上PC当前运行时的值,得到有效地址,而PC值通常默认是存储器中的下一条指令的地址。

R_386_32:重定位一个使用32位绝对地址的引用。通过绝对寻址,CPU直接使用在指令中编码的32值作为有效地址。————《深入理解计算机系统》

重定位符号应用的算法伪代码如下:

foreach section s {
	foreach relocation entry r {
		refptr = s + r.offset; /* 指向需要被重定位的引用的指针 */

	/* relocate a PC-relative reference */
	if (r.type = R_386_PC32) {
		refaddr = ADDR(s) + r.offset; /* 引用的运行时地址 */
		*refptr = (unsigned) ((ADDR(r.symbol) + *refptr - refaddr);
	}

	/* relocate an absolute reference */
	if (r.type == R_386_32)
		*refptr = (unsigned) (ADDR(r.symbol) + *refptr);
	}
}

R_386_PC32

在没有跳转的情况下,众所周知程序是按照从上到下的顺序顺序执行的,而这个事实在机器语言级别的直接反应就是PC的值默认情况下都会指向(经过call指令的计算后)当前执行指令的邻近下一条指令的地址。IA32结构中,一条指令的大小是4字节,所以,call指令的默认参数总是”-4″(0xfffffc),以便操作数于PC值相加时,跳转到临近的下一条指令。也就是说上面伪代码中的refptr在PC相关的地址引用中,初始值是”-4″。那么,如果程序发生非顺序执行的跳转,其重点因素就是要给call等类似的指令一个正确的操作数。这个操作数与PC中的值进行计算之后可以跳转到相应的对象(代码)保证程序的正确执行。”R_386_PC32″这种类型的重定位过程就是给call或者类似指令计算一个正确的操作数的过程。上面展示的伪代码中的refptr就是这个操作数。因为在给符号定义(definition)定位的过程中,ADDR(r.symbol)是确定的,所以,refptr就是可以计算的。

R_386_32

这种情况就简单些,计算方法只是将可重定位引用所在节的首地址和其偏移量相加,这样就能确定符号在虚存中的位置。

未完待续。

——写完后偷偷修改的分割线——-
这两天些的东西非常tmd的艰深难懂,但是硬骨头还是要啃的。市面上有很多SourceReview的书,但是读完之后总是觉得只见树木不见森林。我想要一个从上到下看到通通投投的Linux内核“解析体验”,哈哈哈。理论是比较枯燥,细节是比较烦人,但是所有奇妙的计算效果就是用这些东西为基础的,没有办法。很多时候也许真的需要不求甚解,但是,我是个偏执狂,如果遇到自己感兴趣却没有弄通的东西总觉得如鲠在喉。最终结果是写这样的文章难为自己,看这个样的文章吓走朋友,哈哈哈

嘿~,如果您喜欢我的博客,您可以通过RSS.链接将本博客的最新文章传输到您喜欢的阅读器。 Subscribe with Google 
订阅到鲜果 订阅到抓虾