五月 29, 2006

Graphviz - Fonts

Graphviz缺省使用Times Roman字体,所以在Windows上使用时没有任何问题,但是Fedora Core 5上并没有这个字体,dot命令会报错,说找不到该字体,并打印所有的搜索路径。

解决方法是,直接把Windows上的times.ttf复制到dot搜索目录中,或者按照Fedora FAQInstall Fonts安装更多的字体,然而由于安装目录不在dot的搜索目录中,所以要做一个符号链接,使dot能找到这些字体。如:

$ ln -s /usr/share/msttcorefonts /usr/X11R6/lib/X11/fonts/TrueType

五月 26, 2006

Grahpviz - Basics

Graphviz是用来画无环的有向图和无向图的,方法是:我们先用Graphviz特定语法描述这幅图,存为一个文本文件,然后利用Graphviz提供的dot程序将其转化为特定格式的图片,也可以直接用dot格式浏览器直接打开文本文件观看。

文本相对于二进制文件有很多好处,比如可以版本控制。一个经典游戏是找出两幅图中的不同之处。然而,如果这两幅图是由文本文件描述的,我们就可以使用diff程序来发现不同,这样观察不同版本之间的变化就非常容易。另一个好处是可以把自己程序里的数据结构(自动或手动)输入成dot文件,然后可视化其复杂关系。

前面一个例子很复杂,当然也展示了Graphviz的威力。这里展示两个简单的小例子,其文法简单明了,也无需我多做解释。第一个例子展示了编译器的工作:

Compiler reads c source file and generates assembly file as its output

相应的dot文件内容为:

digraph G {
    source_file -> compiler -> assembly_file;

    source_file [label="hello.c", shape=box];
    compiler [label="gcc"];
    assembly_file [label="hello.s", shape=box];
}

第二个例子类似doxygen生成类层次图的方式:

class hierarchy diagram

相应的dot文件内容为:

digraph G {
    shape -> circle [dir=back];
    shape -> rectangle [dir=back];
}

五月 25, 2006

Graphviz - Introduction

开发了一个perl脚本,自认为代码写得还算清晰,可以在添加一个功能的时候仍然要想半天,当然,这个新功能使得整个逻辑更加复杂。于是画了一幅图出来,一目了然。

程序逻辑图

然而,这幅图可不是我用手画出来的(最烦这种摆来摆去的工作,画个图麻烦死了)而是用GraphViz生成出来的,下面这段代码才是我真正输入的:

digraph G {
handle_options -> start_test -> check_directory_file;
check_directory_file -> get_cvs_branch -> working_revision_available;
working_revision_available -> cvs_status_changes [label="No"];
working_revision_available -> create_cvs_log_command [label="Yes"];
cvs_status_changes -> exit_test [label="No"];
cvs_status_changes -> get_working_revision [label="Yes"];
get_working_revision -> create_cvs_log_command -> split_checkin_message;
split_checkin_message -> exit_test [label="Test Report Only"];
split_checkin_message -> cvs_update [label="Real Work"]
cvs_update -> apply_codereview_patch [label="Before Check In"];
cvs_update -> build_compiler [label="After Check In"];
apply_codereview_patch -> build_compiler;
build_compiler -> generate_unique_compiler_executable;
generate_unique_compiler_executable -> submit_test;
submit_test -> exit_test [label="Other Branch"];
submit_test -> apply_cppunit_patch [label="MSA"];
apply_cppunit_patch -> make_selftest -> exit_test;
}

然后把这段代码存为flowgraph.dot,最后运行命令:

$ dot -Tpng flowgraph.dot -o flowgraph.png

这样,就得到了上面那幅图,怎么样,还不错吧。

五月 23, 2006

Emacs Show - Open

千里之行,始于足下。

只有不断地学习、实践,才能掌握Emacs的精髓,而Emacs本身也在不断发展变化中。另外,在学习过程中我深深地感到,学习使用Emacs是从Windows世界向GNU/Linux世界转变的最佳途径,因为Emacs很多强大功能正是来自于这块肥沃的土壤。所以,对于在Windows上使用Emacs的用户来说,在学会基本的编辑功能后,可能会需要安装Cygwin,才能使用一些高级功能,尤其是一些程序员每天都会用到的包。

Emacs是开放的,只要你愿意,它就是你的。Emacs像一扇门,打开它,展现在面前的,是人类无穷无尽的智慧,只要你愿意,便可以分享。

五月 22, 2006

Emacs Show - Self Study

Emacs的功能多得数不清,如果没有一颗好奇心,没有坚定的毅力,很难掌握其精髓。Emacs的开发者深知这一点,因此开发了一个在线帮助系统,并编写了非常高质量的帮助。正是在边学边练的过程中,我感受到Emacs的开发者确实牛,不仅程序写得好,帮助也写得特别棒。

Emacs的帮助系统叫info,熟悉Linux的一定知道,Linux提供了两种格式的帮助,一种是man,另一种就是info。Emacs内置了info阅读器,不仅可以浏览Emacs自己的帮助,还可以浏览系统里其它工具提供的info格式的帮助。所以,学习Emacs的第一步是从学习如何使用info阅读器开始的。打开Emacs后,按C-h i进入info阅读器,通常上面列出的第一项就是info,把光标移动到那一行然后按回车(RET)就可以开始学习使用info阅读器的历程了。(注:info的方式是m info RET

Emacs的学习过程应该是一个边学边练的过程,先看完所有帮助再开始使用的想法是不现实的,因此,能在使用过程中查看特定功能的帮助就显得非常重要,这有点类似于常见的F1功能。这种帮助信息是内嵌于每个函数和变量内部的,用于浏览这种帮助的系统也并非info。当我们需要了解某个特定函数或变量时,使用C-h f或者C-h v,当我们想知道某个快捷键绑定到哪个命令,使用C-h k然后输入想要了解的快捷键。比如想知道C-h f实际上调用了哪条命令,可以输入C-h k C-h f,Emacs会在一个名为*Help*的buffer里显示,C-h f实际调用的是describe-function这个Emacs Lisp函数。这时我们会猜,C-h v调用的大概是describe-variable吧,如果想知道还有哪些describe函数,可以使用命令C-h a describe RET,这个功能有点类似于关键字搜索。

正是在提供了快捷便利的帮助系统,以及内容详实的帮助信息后,学习Emacs的过程才显得不那么痛苦。在熟练使用Emacs的帮助系统后,我们不仅可以开始学习如何用Emacs开发软件,还可以学习如何用其写文档(docbook或者latex)、网页,如何使用Calendar/Diary做日程管理和日记,使用各种package收发email或阅读新闻组,以及如何定制、扩展Emacs,等等等等。比如,Sucha就用Emacs撰写并发布blog。甚至有人写了一个atom-blogger package用来发布blog到Blogger.com

emacs wiki是一个非常好的学习emacs的网络资源,时常去那里看看,可以提醒自己不要志得意满,其实离高手的距离还差得远呢。:-)

学无止境啊!

五月 17, 2006

Redefine assert for CppUnit

我们在写程序时会使用很多assert做防御性编程,然而这些assert却会给单元测试带来麻烦。一般地,assert是定义在assert.h里面的宏,因此,我们可以通过改变宏定义的方式,把这些assert定义为CppUnit里面使用的断言。方法如下:

  • 添加一个编译选项:-DCPPUNIT_ENABLE_NAKED_ASSERT=1
  • #include <assert.h>改为#include <cppunit/TestAssert.h>

这样就把assert(condition)改变为CPPUNIT_ASSERT(condition)

五月 10, 2006

IPC::Run

原来在Cygwin下用的一个Perl脚本拿到Fedora Core 5下用,结果IPC::Run出问题,错误信息是“输入/输出错误: read( 3 ) at /usr/lib/perl5/site_perl/5.8.8/IPC/Run/IO.pm line 547”。无论是Fedora的package还是直接从CPAN上装都一样,在Google上也没找到答案,非常郁闷。

晚上回家还一直在想这个问题,突然灵机一动,也许是语言环境的问题吧,为了使用中文,我的LANG环境变量设为zh_CN.UTF-8。早上来了一试,果然。

解决方法是在命令前把语言改回en_US,如:

$ LANG=en_US perl yourscript

五月 06, 2006

Emacs Show - Development

在开发过程中,我们往往要用到很多工具,如编辑器、编译器、调试器等等,随着软件越来越复杂,集成开发环境(IDE)出现了,它通过统一的界面把很多工具隐藏起来,并且还提供了索引功能,如跳到函数(或变量)声明(或定义)处等等。IDE在Windows平台发展得非常火,以至于有些Windows程序员只知道IDE,如微软的Visual Studio或Borland的Delphi等等,却不甚明了具体使用了那些工具。然而,IDE在*NIX平台上却鲜有问津,我想,部分原因可以归结于Emacs的开放性和可扩展性。

Emacs支持多种编程语言,常见的如:C、C++、Java、Perl、Python、Ruby等,每种语言都有一个相应的Mode,这个Mode提供基本的语法高亮、缩进、快捷键管理等功能,还有快速定位光标,注释代码块等等。Emacs的缩进功能十分方便,不得不提。对于绝大多数Windows上的编辑器来说,当光标位于当前行第一个非空格字符前的时候,按一次TAB键,该行就向右缩进一级,实际上就是插入一个TAB键或一定数量的空格。而在Emacs里,TAB键实际就是一个缩进键,因此,无论光标处于当前行的任何位置,只需按一次TAB键就可以完成缩进,不论实际上需要缩进几级。Emacs这么设计是有道理的,试想,我们写程序的时候,是需要改变缩进的时候多,还是需要插入TAB键的机会多?恐怕后者出现的机会少之又少吧。所以,Emacs把输入TAB键的方式改为C-q TAB

更炫的是,Emacs提供快捷键(C-M-\)缩进当前选中的region。比如说,我们发现一段代码实际上应该只在某个条件下才需要执行,那么就用一条if语句将这段代码包围起来,然后需要做的就是改变其缩进。如果只有三行,那么按照Windows方式一行行地做缩进也还凑合,如果是十行、三十行呢?Emacs的操作序列是这样的:

  1. 在输入完if语句的右大括号之后,按C-space建立一个mark;
  2. C-M-p将光标移动到对应的左大括号处,相应地,这一对大括号所包围的区域就成了当前的region;
  3. C-M-\缩进选中的region。

虽然Emacs不提供项目管理功能,但我们仍然可以在Emacs里编译,命令是:M-x compile。缺省的,Emacs调用make完成编译功能,编译输出信息显示在一个单独的buffer里,它可以高亮显示编译错误,点击该错误或在该行按回车键,Emacs会自动显示语法错所在的文件并将光标定位到相应的行,这与IDE所做的一模一样。当然也可以配制成其它方式来做编译,因为本质上就是调用一个外部命令然后将输出导入到一个buffer里。另外,Emacs也可以调用gdbperl -d等外部命令调试程序,由于Emacs可以用一个单独的buffer显示源文件,所以要比直接在命令行上运行调试命令方便得多。

软件开发必然少不了版本控制。Emacs与版本控制工具(如CVS)结合得相当完美,我们可以很方便地察看log(C-x v l)、与repository上的代码做比较(C-x v =)、查看以前的版本(C-x v ~)等等。Emacs提供了两个包:VC和PCL-CVS,VC通常是针对单个文件的,当我们打开一个文件的时候,它会检查是否有与这个文件相关的版本控制信息,比如该文件所在目录是否有个CVS目录,有的话则将其与该文件关联起来。这样,我们就可以完成上面提到的一些操作了。而PCL-CVS则是针对整个模块的。更绝的是,Emacs为每个命令的输出都作了高亮处理,毕竟,看没有高亮的diff结果可不是很容易的。

Emacs还提供了etags和ebrowse做索引,这样就可以在代码间跳来跳去了,etags支持多种语言,而ebrowse则为面向对象语言提供了特殊的支持。

看到这里也许觉得Emacs就是一个IDE嘛。实际上,相对于IDE来说,Emacs具有更强的程序设计语言中立性和集成工具中立性,而这些,正是Emacs的开放性和可扩展性带来的。所以我更愿意说,Emacs不是IDE,胜似IDE。