游戏人生

颂山川,吟古道,偏失半点笔墨;言世事,问苍生,更差一声长嗟。

vim对于大多数在Ubuntu下使用vim作为常用编辑器的同学来讲,他们遇到的第一个比较大的麻烦来自于vim与外部应用的复制粘贴。

当然,愿意选择ubuntu以及vim的同学肯定是google好手。不幸的是,各大论坛告诉你,你可以在命令模式下使用类似"*p或者"+p的命令将已经复制或剪切到系统剪切板的外部内容粘贴进来,也可以使用类似"*y或者"+y的命令将vim中的内容复制到系统剪切板中。很多同学照此操作解决了这个问题,然而也有一些同学则悲剧的发现,这个方法没有任何作用。

这一切都可以从vim帮助中找到答案。

无论是vim内部抑或外部的复制([y]ank)、删除([d]elete)、粘贴([p]ut),在vim中都是借助registers(寄存器)实现的,vim共有9类寄存器:

  1. 无名(unnamed)寄存器:"",缓存最后一次操作内容;
  2. 数字(numbered)寄存器:"0 - "9,缓存最近操作内容,复制与删除有别;
  3. 行内删除(small delete)寄存器:"-,缓存行内删除内容;
  4. 具名(named)寄存器:"a - "z"A - "Z,指定时可用;
  5. 只读(read-only)寄存器:":, "., "%, "#,分别缓存最近命令、最近插入文本、当前文件名、当前交替文件名;
  6. 表达式(expression)寄存器:"=,只读,用于执行表达式命令;
  7. 选择及拖拽(selection and drop)寄存器:"*, "+, "~,存取GUI选择文本,可用于与外部应用交互,使用前提为系统剪切板(clipboard)可用;
  8. 黑洞(black hole)寄存器:"_,不缓存操作内容(干净删除);
  9. 模式寄存器(last search pattern):"/,缓存最近的搜索模式。

上面的说明为简要概述,并不完全准确,详细说明须参考手册:

:help copy-move

无图形界面的vi或vim下可用的寄存器只包括{a-zA-Z0-9.%#:-"},显然,这里面没有包含上面提到的"*或者"+等选择及拖拽存器。

由此可见,实现vim与外部应用相互复制、粘贴的关键在于系统剪切板对于vim是否可用。查看vim剪切板是否可用的命令为vim --version,下面是我的系统下面的结果(我只保留了xterm_clipboard一项):

VIM - Vi IMproved 7.2 (2008 Aug 9, compiled Apr 16 2010 12:47:47)
包含补丁: 1-330
编译者 buildd@
巨型版本 无图形界面。  可使用(+)与不可使用(-)的功能:
-xterm_clipboard

对于非GUI版本的vim,剪切板是不可用的,解决方案很简单,安装一下就是了:

sudo apt-get install gvim

下面是安装之后的结果:

VIM - Vi IMproved 7.2 (2008 Aug 9, compiled Apr 16 2010 12:40:58)
包含补丁: 1-330
编译者 buildd@
巨型版本 带 GTK2-GNOME 图形界面。
  可使用(+)与不可使用(-)的功能:
+xterm_clipboard

两年之前换手机的时候,舍不得买iphone,彼时android尚不成熟,我也不愿当小白鼠,便买了一部dopod s1,感觉挺鸡肋的一款智能机。倒不是因为windows mobile的系统差,而是作为一款智能机,s1 320*240的分辨率无法充分发挥阅读、网络功能,而且无法升级到wm 6.5,更加致命的是,国产行货没有wifi功能。

后来在用ipod touch的时候,480*320的分辨率明显把电子阅读、网络浏览的观感提升了很多,尤其是wifi功能更为必要。在使用pc时,浏览邮件或订阅往往是走马观花,甚至直接跳过。反而是在touch上浏览时,更加专注和方便。GF经常在成渝两地奔波,为弥补我的愧疚,touch便留给她使用。

如此一来,心里仿佛忽然空了一大截。当然我也不希望再买一个touch,反正手机已经用了两年多,换一个也在情理之中。多方比较了一下,希望在iphone和android手机上做选择,因为实在对windows mobile不感冒。使用touch的经验告诉我,虽然itunes应用很多,但apple对系统的控制让人感觉不很舒服,相比之下,android要开放的多。

刚好这段时间,同事也在考虑换手机,我便极力怂恿他选择i9000。结果,把他说动之前,我自己先被说服了。下午下班之前下的单,转天上午就到了,这种效率也让我心情大好。

手机本身也没有令我失望,速度、操控、显示各方面都比较舒服。之前觉得android在模仿ios,使用之后发现,android系统自身亮点众多。在电源管理、应用程序、账户关联方面给我的印象最好。

目前发现的唯一缺点是联系人无法中文首字母索引,一个常见的解决方案是安装root explorer后,使用root替换一个共享库。经初步测试,i9000下替换系统文件失败。毕竟是第一次使用android,不希望给自己带来太多未定,也因此放弃了其他获取root的方法。反正android中文排序本身正常,无非是无法字母索引,把联系人姓前面加上中文首字母也无伤大雅,于是写了几十行代码,把问题解决了。

为了让这样的流水体现一点价值,把实现的过程记录一下。

== Step 1. 找一张汉字|拼音映射表 ==

这个比较简单,很容易google到,唯一需要注意的是,有些只提供7K+的常用字,最好是找比较完整的29K+汉字表。

== Step 2. 建立字典 ==

考虑到不同语言实现的通用性,我将汉字与拼音的映射存放在一个xml文件中:

<?xml version="1.0" encoding="utf-8"?>
<map>
  <m c="一" g="D2BB" p="yi" u="4E00"/><m c="丁" g="B6A1" p="ding" u="4E01"/>
  <m c="丂" g="8140" p="yu" u="4E02"/><m c="七" g="C6DF" p="qi" u="4E03"/>
  <m c="丄" g="8141" p="shang" u="4E04"/><m c="丅" g="8142" p="xia" u="4E05"/>
  <m c="丆" g="8143" p="myeon" u="4E06"/>
</map>

上面的文件不完整,本文最后提供了完整文件下载。c为汉字,g为GBK码,p为拼音,u为unicode。

== Step 3. 从gmail导出联系人列表 ==

将联系人列表保存在gmail中是一个不错的选择。悲剧的是,我在使用windows mobile的同步软件将手机上的联系人同步到outlook时,不慎将outlook同步到手机中,导致所有联系人丢失。这其中自然有我自己的原因,却也让我对windows更加失望。我只好基于公司通讯录创建新的联系人列表,并从outlook导入gmail,再从gmail导出csv到我的ubuntu。

== Step 4. 改写联系人姓名 ==

我直接从gmail导出的文件编码为utf-16,因为统一使用utf-8,所以需要转换一下。

下面是改写的完整代码:

# -*- coding: utf-8 -*-
# file : contact.py
# author : YuleFox (GMAIL.COM)
# url : http://www.yulefox.com/
# license : http://www.opensource.org/licenses/mit-license.php

import xml.dom.minidom as parser
import codecs, re

def loadDict(file):
    doc = parser.parse(file)
    root = doc.documentElement
    dict = {}
    for n in root.childNodes:
        str = n.getAttribute('p').upper()
        dict[n.getAttribute('c')] = str[0]
    return dict

def prefixName(file, dict):
    with codecs.open(file, 'r', 'utf8') as rf:
        with codecs.open('g.csv', 'w', 'utf8') as wf:
            r = re.compile(ur'^(?P<p>.*,.*,.*,)(?P<fn>[\u4e00-\u9fa5]+)(?P<r>.*$)')
            for l in rf:
                m = r.match(l)
                if m:
                    l = u'{0}{1}{0}{2}{3}\n'.format(dict[m.group('fn')],
                            m.group('p'),
                            m.group('fn'),
                            m.group('r'))
                wf.write(l)
            wf.close()
        rf.close()

if __name__ == '__main__':
    dict = loadDict('hanzi.xml')
    prefixName('google.csv', dict)

由于我是在ubuntu下操作(文件默认编码格式为utf-8),如果你是在windows下(文件默认编码格式为gbk),必须保证google.csv编码格式为utf-8。

== Step 5. 同步 ==

将改写后的g.csv导入gmail,同步android上的账户即可。

下载:hanzi.xml

刚接触Linux时,短暂试用vim之后,出于对其操作中模式理念的陌生,最后转投Emacs门下。随着各种插件的增多,Emacs被我打造成一个不折不扣的IDE,其启动速度也降到和Visual Studio相当,逐渐令我难以接受。于是再次选择vim。

周围很多同事在使用Google Reader阅读各种资讯。每天花半个小时左右的时间接受各种知识对于自我提升有一定的帮助。为了提高时间利用率,推荐大家使用GR自带的快捷键。在GR中按’?'键可以查看快捷键列表,见下图:

google_reader_geek

熟悉vim的同学对于GR提供的快捷键应该有天生的好感,看来,Google的同学还是使用vim的多啊。

一直奢望有一天可以完全不借助鼠标浏览网页,曾经以为这是个幻想,没想到在我比较喜欢的FireFox上有这样一款插件:vimperator,不仅可以抛开鼠标,而且操作方式与vim相同。是的,又是vim,不是Emacs……

世界杯之月,即使像我这样的伪球迷也为之鼓而呼。当然,一个月没有更新并不是因为世界杯,也不是电脑罢工两周,最主要的原因是之前在使用django + ajax时遇到了一些困难,这些困难到现在也没有完全解决,一些工作离我预期的效果还差很多。但但为了不让属于自己的六月显得虚度,还是要象征性的更新一篇。何况,这个月还是有一些值得记录的事情:

  1. 自己又结结实实的长大/老了一岁;
  2. 我的学生时代结束一年之后,女朋友也毕业了;
  3. 女朋友在毕业之前终于确定了自己的工作。

svn备份是一项比较重要的工作,这里主要用到两个工具:svnadmin(1)crontab(1)svnadmin用于对svn版本库进行管理,crontab则用于管理周期事务。

方法比较简单,首先创建一个脚本,内容如下:

#!/bin/sh

project="svn"
svnroot="/var"
backdir="/home/fox/svnbackup"
date=`date +%m%d%Y`
dumpfile=$date.$project.tar.gz
log="svnbak.log"
logtime=``
SVNADMIN=/usr/bin/svnadmin

# all actions can be done under $backdir
cd $backdir

echo " ----------------- BACKUP START ----------------- " >> $log

# omit request in the same day
if [ -f $dumpfile ]
then
echo `date +"%m-%d-%y %H:%M:%S"`" backupfile [$dumpfile] has exist!" >> $log
# backup repos with `svnadmin hotcopy'
else
$SVNADMIN hotcopy $svnroot/$project $project --clean-logs
echo `date +"%m-%d-%y %H:%M:%S"`" backup [$project] done into [$backdir]" >> $log
# compress backup data
tar czvf $dumpfile $project > /dev/null
echo `date +"%m-%d-%y %H:%M:%S"`" compress [$dumpfile] finished" >> $log
# remove temp project dir
rm -rf $project
fi

# remove old dump file [at most 10 copies store here]
olddump=$(date +%m%d%Y --date='10 days ago').$project.tar.gz

if [ -f $olddump ]
then
rm -f $olddump >> $log 2>&1
echo `date +"%m-%d-%y %H:%M:%S"`" [$olddump] delete success!" >> $log
else
echo `date +"%m-%d-%y %H:%M:%S"`" [$olddump] not exist!" >> $log
fi
echo " ----------------- BACKUP ENDED ----------------- " >> $log

这个脚本完成的主要工作是先用svnadmin hotcopy命令备份代码仓库到指定目录,用tar打包保存;另一项工作是会删除10天前(因为我选择的是每天备份,你可以根据需要制定自己的方案)的副本。

简单测试通过后,就可以添加到crontab了,第一次使用crontab -e命令时需要选择编辑器,编辑格式非常简单:

$ crontab -e
no crontab for fox - using an empty one

Select an editor.  To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano        <---- easiest
3. /usr/bin/emacs23
4. /usr/bin/vim.tiny

Choose 1-4 [2]: 3

>>>> 下面是编辑的内容
# m h  dom mon dow   command
0 23 *   *   *     /home/fox/cron/svnbackup.sh

>>>> 保存退出,自动加入事务列表
crontab: installing new crontab

>>>> 查看当前事务
$ crontab -l
# m h  dom mon dow   command
0 23 *   *   *     /home/fox/cron/svnbackup.sh

笔记本上之前装的双系统(Vista + Ubuntu 9.10),在刚拿到机器的时候,把Vista从home换成ultimate,之前OEM的序列号竟然有效,所以就一直开着Windows Update,前段时间终于遭遇了传说中的黑屏。想想算了,自从使用Ubuntu,慢慢觉得使用盗版软件是一件可耻的事情,也就不想再去激活Vista了(当然也不会去买正版),不用就是了。

所以这次Ubuntu 10.04升级失败之后,决定不再要双系统,只装10.04(这次之所以急于安装10.04,是因为10.04开始支持iPhone和iPodTouch了)。我对恢复系统没有十足的把握,本来想好是要备份的,一冲动,只把自己需要的东西转到老婆的电脑上,没有备份/etc/var/usr下面的内容。于是这两天没做什么事情,开始重复噩梦:

==== evince中文支持问题 ====

evince是Ubuntu下默认的pdf阅读器,对于没有内嵌中文字体的pdf文件,evince无法显示。evince使用Poppler作为pdf渲染库,因此需要安装Poppler编码库poppler-data以支持中文显示:

apt-get install poppler-data

==== emacs中文输入问题 ====

Ubuntu中文输入从9.10开始默认使用ibus,安装新的输入法倒是比较简单,但默认的输入法切换使用Ctrl+Space。emacs23内置中文支持,但中文输入还是使用ibus更习惯一些。emacs下Ctrl+Space作为Mark Set快捷。

查了一下,是locale的问题,因为装的是英文环境,默认变量均为en_US.utf8,其中LC_CTYPE定义系统的字符处理编码,在/etc/environment(这是Ubuntu下的环境配置,个人的~/.bashrc文件中也可以)中添加LC_CTYPE="zh_CN.utf8",并在/var/lib/locales/supported.d/zh-hans中加入下面几行:

zh_CN.UTF-8 UTF-8
zh_SG.UTF-8 UTF-8
zh_HK.UTF-8 UTF-8
zh_TW.UTF-8 UTF-8
zh_CN.GB2312 GB2312
zh_CN.GBK GBK
zh_CN.GB18030 GB18030

执行sudo locale-gen,将在/usr/lib/locale/下生成对应的环境编码数据。

==== 本文重点1:安装trac ====

使用了几个月,感觉trac+svn也成了我的个人知识管理(KM)的一个标配。之前没有记录下自己的安装过程,这次重装的时候,顺便理一下整个重装过程(参考TracInstall)。

如果没有特别需求的话,不用svn最新的版本,下载稳定版本的Trac就可以了。

trac使用python(Ubuntu 10.04的python版本为2.6.5)开发,使用easy_install安装,如果没有:

wget http://peak.telecommunity.com/dist/ez_setup.py
sudo python ez_setup.py

可以直接使用下面的命令安装trac、SQLite、Genshi:

sudo easy_install Trac

Searching for Trac
Best match: Trac 0.11.7
Processing Trac-0.11.7-py2.6.egg

还可以选用MySQL、PostgreSQL作db,对于个人来说,SQLite够用了,就一个文件,很方便。

创建trac项目(在~/yulefox下创建名为km的项目),除指定项目名称和代码仓库位置外,其它我都使用了默认配置,所有配置都可以在项目目录下的conf/trac.ini中修改:

trac-admin ~/yulefox/km initenv
Creating a new Trac environment at /home/fox/yulefox/km
...
项目名称:Project Name [My Project]> FoxKM
数据库:Database connection string [sqlite:db/trac.db]>
代码版本管理工具:Repository type [svn]>
代码仓库位置:Path to repository [/path/to/repos]>/home/fox/yulefox/svn
Creating and Initializing Project
...
---------------------------------------------------------------------
Project environment for 'FoxKM' created.
If you'd like to take this new project environment for a test drive,
try running the Trac standalone web server `tracd`:

tracd --port 8000 /home/fox/yulefox/km

Then point your browser to http://localhost:8000/km.
...
Congratulations!

看到Congratulations!我就放心了:),按照上面说的方式就可以测试一下了,不过我们显然希望用apachenginx现在挺时髦的,不知道trac会不会支持nginx)搭建一个合适的Web Server。

Trac提供对CGI、FastCGUI、mod_python的支持(新加对mod_wsgi的支持),我对这一块并不是很熟悉,一般使用Apache + mod_python配置。

配置主机

我在自己的机器上使用fox.com作为虚拟主机名,反正我也不会去访问FOX,就用它了:D。我指定的IP是127.0.1.1,因为我只想在本地访问,你可以指定其他可用的IP:

# Adds virtual hosts to /etc/hosts

$ sudo emacs /etc/hosts
127.0.1.1   fox.com
127.0.1.1   www.fox.com
127.0.1.1   km.fox.com

创建虚拟主机配置:

# Adds one site named 'fox.com'
$ sudo emacs /etc/apache2/sites-available/fox.com

NameVirtualHost 127.0.1.1:80

ServerAdmin Fox
ServerName km.fox.com

DocumentRoot "/home/fox/yulefox/km"
# trac

SetHandler mod_python
PythonInterpreter main_interpreter
PythonHandler trac.web.modpython_frontend
PythonOption TracEnv /home/fox/yulefox/km
PythonOption TracUriRoot /

# trac login

Require valid-user
AuthType Basic
AuthName "TracLogin"
AuthUserFile /etc/home/fox/yulefox/km.passwd

启用虚拟主机配置:

sudo apt-get install libapache2-mod-python libapache2-mod-python-doc
sudo a2ensite fox.com
sudo /etc/init.d/apache2 reload

有可能会得到下面的提示:

apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName

需要在/etc/apache2/conf.d/目录下创建名为fqdn的文件,并添加配置的服务器:

ServerName fox.com

此时再reload Apache就清净了,访问一下http://km.fox.com/,提示:

TracError: The user www-data requires read _and_ write permissions to the database file /home/fox/yulefox/km/db/trac.db and the directory it is located in.

原来是访问权限的问题:

$ sudo chown -R www-data /home/fox/yulefox/km/
$ ls -l yulefox/km
total 44
drwxr-xr-x  9 www-data fox 4096 2010-04-11 16:25 ./
drwxr-xr-x 14 fox      fox 4096 2010-04-11 16:25 ../
drwxr-xr-x  2 www-data fox 4096 2010-04-11 16:25 attachments/
drwxr-xr-x  2 www-data fox 4096 2010-04-11 16:25 conf/
drwxr-xr-x  2 www-data fox 4096 2010-04-11 16:25 db/
drwxr-xr-x  2 www-data fox 4096 2010-04-11 16:25 htdocs/
drwxr-xr-x  2 www-data fox 4096 2010-04-11 16:25 log/
drwxr-xr-x  2 www-data fox 4096 2010-04-11 16:25 plugins/
-rw-r--r--  1 www-data fox   98 2010-04-11 16:25 README
drwxr-xr-x  2 www-data fox 4096 2010-04-11 16:25 templates/
-rw-r--r--  1 www-data fox   27 2010-04-11 16:25 VERSION

搞定!

==== 本文重点2:恢复trac备份 ====

之前的trac我是备份了的,恢复起来也很方便:直接把备份的文件夹内容copy到上面的km中即可:D。关于trac使用的细节和更多丰富功能的插件,本地文档或者官方网站上面都介绍的非常详细,这也是我喜欢使用它的一个原因。

时隔2年,Canonical的第3个LTS(Long Term Support,长期支持)版本Ubuntu 10.04(Lucid Lynx)即将(4月29日)正式发布。

ubuntu 10.04 LTS

LinuxPlanet的最新报告,10.04尚未正式发布,Ubuntu当前用户已达1200万。

使用Ubuntu刚半年,感觉还是比较好。10.04 beta1刚出,就把家里的本子从9.10在线升级10.04 beta1,不幸的是——升级失败:标题栏无法显示,很多快捷键和功能无法使用(Alt+F2、Alt+F7、Alt+F8)。而我又找不到出错的原因,只好考虑把系统备份之后重装。

之前还没有备份过系统,查了一下,关键是几个地方:

* 整理需要备份的内容并确认这些内容的对应的目录和文件;

* 用tar、dpkg等工具备份这些目录和文件及安装的应用列表。

* 整理需要备份的内容并确认这些内容的对应的目录和文件

对于个人用户(非商业应用或服务器应用),需要备份的内容主要包括:

* 个人数据:文档、书籍、代码、图片、音乐、视频、个人配置等,这些内容一般保存在/home下用户目录中;

* 应用程序:安装的一些应用程序及其对应配置:依照文件系统层次标准FHS,/usr中存放的应该是可共享的只读数据,因此除了/usr下的应用、数据、手册、源码等以外,还有这些应用(web、mail、ftp等)的可写配置及数据库等,一般位于/etc、/var中;/opt用于保存外部应用程序安装包,这些数据视需要也可以备份。

有些内容(如大多数应用程序)不一定需要备份,只要你的网络足够好,reinstall的时间也不会长,还有一个原因就是,一些应用更新的速度比较快,备份的意义不大,尤其是在系统升级或更换其他系统的时候,但个人数据和一些应用的配置、数据库等就不是网络好能替代的了。

可以参考一下这篇文章:Backup Basics and Different types of backup

总结一下,需要备份的目录主要是:

/boot
/etc
/home
/opt
/root
/srv
/var/lib/mysql
/usr/local
/var/www
/var/www

* 用tar、dpkg等工具备份这些目录和文件及安装的应用列表

一种简单、直观的方式:

tar cvpzf backup.tgz / –exclude=/backup.tgz –exclude=/dev –exclude=/lost+found –exclude=/media –exclude=/mnt –exclude=/proc –exclude=/sys

如果需要定期备份,可以写入shell,借助/etc/crontab实现自动备份。

对于来自Windows的懒人来说,这些算是比较麻烦的了,ubuntu下安装sbackup工具可以替代上述工作:

sudo apt-get install sbackup

详情见:Backup and Restore Your Ubuntu System using Sbackup

dpkg主要用于备份和恢复安装的所有应用程序:

* 备份

dpkg –get-selections | grep -v dnstall > ~/softlist

* 恢复

sudo dpkg –set-selections < ~/softlist


话说10.04 beta2今天已经发布,这个周末,有的搞。

django

现在已经无法确切地说出最早接触python的时间和动机了,但有几件事或许可以交待出接触python的一些想法,能够折射出自己在一些东西上的后知后觉:

08年10月底,在和网易的两位朋友(Soft也在)聊起脚本语言,了解到python在网易的一些工作室应用比较广泛,主要应该是用到脚本和UI开发吧。当时自己对python没有什么概念,也没动过接触一下的念头。

pygame

09年11月,在跟同事AHC聊天的时侯第一次见识了python(确切地说是pygame),时隔一年,我还是对python没有什么概念,所以也就没有形成什么印象。

09年07月认识了yospaly(只是网上交流过一两次),他应该算是开源软件(或者是自由软件?)的拥趸吧,知道他对django感兴趣,那是我第一次看到这个名字,也没有去深入了解。

django

后来,就常在FallHunter的blog里面见到这个词。自己对互联网仅限于使用,也没想过做开发,所以还是没有去关注。

09年12月,再一次因为服务器的问题搬家的时候,开始对这样折腾blog感到疲倦,想有个安稳的地儿,也想玩点自己的东西。

09年12月,在使用SVN管理代码之后,开始用trac(目前看来,效果还不算坏,之前试图通过googlegroup做交流算是失败),注意到trac是基于python开发的。

突然之间,自己的神经受到了触动,前前后后,这才将python与web联系起来,就想自己也可以做点东西自娱自乐。

刚开始的时候,了解了一些python语法,在读django的文档的时候,还是有些囫囵吞枣,想想还是需要系统的学习一下python,这个过程中想写点东西,因为对web开发知之甚少,所以还是没有继续完成计划的django应用,就绕回到pygame来了。


在接触新的语言或SDK时,最大的问题是参考文档的问题,所幸,大多数语言和SDK都有详尽的文档或手册。但是python的docstrings还是像其缩进语法那样,给我留下了非常深刻的印象。或许,这就是传说中的pythonic?

喜欢python的Easter Egg,尤其是import this

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one– and preferably only one –obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea — let’s do more of those!

最近有点忙,本来要用autoconf+automake把自己的代码梳理一下的,因为工作停了近两周。

本想看看有什么工具可以自动生成Makefile.am,答案是:Automake不支持通配符,而且还口口声声,振振有词。既然说的这么言词凿凿,情深意切,我想我也没有必要用shell生成Makefile.am了。

用着用着,我有点怀疑人生了:不知道什么时候需要用autoconf和automake。如果我只是平时自己写一些toy codes的话,感觉用autoconf和automake有点大炮打蚊子的感觉,而且每次新加代码或者是移除代码、甚至是更改目录,都要重新执行autoconf、automake(不知道我说的对与不对)。对于一个大型项目,执行一次configure和make是很痛苦的一件事,make的中间目标文件或者库文件、执行文件倒是不一定非得完全rebuild,configure的配置检查呢?是不是也有类似机制?反正我在用ogre或者cegui的时候,每次执行./configure是重新配置了的。

实际在开源项目里面也不可能维护两套makefile吧。

看了一下googletest的配置,倒是清爽的很,最大的特点是只有一个Makefile.am,这样在一个项目里面只需要维护一个Makefile.am就够了。

cegui比较常规,每个子目录都会维护一个Makefile.am。

需要特别注意的是ogre从1.7.0开始已经开始使用cmake了……

请听题:管理中小型项目,你倾向于下面哪个工具?

o make:钻木取火,玩的就是个技术,编译代码,只用装B的,不用牛B的,你要是用什么cmake,你都不好意思跟别人打招呼,这么经典的东西,精通需要多久?要我说怎么着也得个把俩月吧,个把俩月?那是入门,至少半年,就这还得有Feldman的悟性,不舍昼夜;

o autoconf+automake:既有群众基础,又有技术含量,你是那样拉轰的男人,不管在什么地方,就好像漆黑中的萤火虫一样,那样的鲜明,那样的出众。你那忧郁的眼神,稀嘘的胡喳子,神乎其技的指法;既可以耻笑原始人的生产力低下,还可以鄙视现代人的不学无术。

o cmake:在MSVCers面前抬不起头,在UNIXers面前似乎更抬不起头;而cmake对WINDOWS和UNIX平台的完美支持,足以让所有的MSVCers和UNIXer在你面前抬不起头,你是公鸡中的战斗机。所以你还是可以趾高气昂的丢下一句:走NB的路,让SB说去吧。

到目前为止,所参与的项目使用过的版本控制(VC)工具全是Windows下的:VSS(Microsoft Visual SourceSafe)和AlienBrain。

只发现一个缺点:

o 版本以文件为核心,回滚、封版本比较麻烦;

和同事讨论之后,决定换用SVN,原因就是SVN fix了上面的缺点。SVN或许不是目前最好、最先进的VC,因为Git其实也是个不错的选择。对比之下,大家对SVN更加熟悉,而且足以解决目前VC中遇到的问题。

因为这事儿我来做,所以,我就按自己的喜好选择了Linux。

在Linux下使用SVN虽然不像Windows下那么方便,但也完全在可控范围之内。

我于Linux并没有太多经验,只是在使用Ubuntu桌面系统而已。因为FreeBSD的广泛应用,于是一开始考虑过使用FreeBSD作代码服务器,没别的理由,就是有人说好,我也觉得FreeBSD专业一点儿,有UNIX的血统在。

找系统部同事装服务器的时间,一位同事结合自己的经验,推荐我使用CentOS。心想,装一个试试吧。装好之后,觉得不太合自己的操作习惯,还是准备安装 FreeBSD。

FreeBSD相比其他系统要复杂的多,我和同事之前都没用过FreeBSD,整个安装和配置过程,一直要查资料,后来实在受不了了,只好放弃。

最后还是选择了自己稍为熟悉的Ubuntu Server版,换成Ubuntu的确舒服多了,很快就配置好了网络和服务器环境。

后面又花时间在上面放了一个blog。

在Ubuntu下虽然没有Windows下那么方便的VisualSVN,但搭建Apache2+SVN的过程也不复杂,并不一定要编译安装。

o 这篇文章详细介绍了Linux下Apache2+SVN的配置过程;

o 这篇文章详细介绍了通过Web修改SVN账号密码的配置过程。

第一次弄的时候,这些东西都折腾了很久,后面稍微熟悉一些之后,觉得Apache和PHP的东西还是都很强大的,都值得花时间去好好消化一下。

从接触和使用make以来,前前后后写了不少Makefile(添添减减、修修补补,累计上千行是有的),今天在重新整理代码的组织结构之后,突然就想:我为什么不使用Autotools呢?

在开始体验功能强大的Autotools之前,简单(详细)回忆总结一下我使用make的经历和思考的过程,反省一下看看自己在接触这些新鲜事物的时候到底走了多少弯路。

o Cygwin

今年3月份,拜Kevin Lynx所赐,每次对Linu浅尝辄止的我终于下决心接触了Cygwin环境,并一发不可收拾。

刚开始的时候,就像大学刚接触编程那样,写“hello, world”,在终端用gcc命令直接编译,然后开始写最简单的只有一个all的Makefile。因为Emacs、GCC、make对我来说都是崭新的 工具,后面重心就不是放在写代码上了,而是急于掌握他们,以求达到在Windows下的开发效率。

去年11月底,当时还没有开始用Cygwin,就买了一本《Managing Projects with GNU Make》,此时也算物尽其用了。慢慢开始使用variables、macros、phony targets、functions,按步就班的系统学习应用。

o Ubuntu

磨磨蹭蹭过了半年,其间因为忙着毕业,对Cygwin和Emacs、GCC、make也算比较熟悉了。

今年10月份,开始使用Ubuntu,刚开始在Windows下用wubi安装,很快就直接用新的硬盘分区物理安装,并随着Ubuntu 9.10的发布,升级到了9.10

这前后写Makefile最大的区别就是,之前纯粹是为了写而写,之后是为了用而写。

随着整个代码结构的不断膨胀和修改,Makefile也不断的变化。

Makefile自身的最大变化是从之前的因为编写错误、通用性差而不断修改,演变到最后代码增减不会影响Makefile,只是为了增加tags、优化结构而改动。

经历了这个过程后,对于Makefile的结构就比较熟悉了,而且可以从其他使用automake的项目的Makefile中学习借鉴了。


之所以想到使用autotools,是因为接触的很多开源项目的代码都使用了这一组工具。

对于用户而言,一般的项目编译安装的过程:

o bootstrap:检测autoconfautomakelibtool及其版本并完成初始化,生成configure;

o configure:检测系统平台及软硬件环境,确定适用本地环境的编译策略,生成Makefiles;

o make:编译、链接;

o make install:安装;

o ldconfig:配置环境变量。

对于开发者而言,则需要通过autoconf、automake为用户组织起上面的过程:

Autoconf 流程

Autoconf 流程

对于这一流程,我的方法是照葫芦画瓢,参考OGRE等项目的相关文件和工具的GNU文档。

写个Hello, Kitty。

操作的流程和期间出现的几个问题总结一下:

o cd project_dir:转到项目目录;

o emacs Hello.cpp

#include <iostream>

int main(int argc, char** argv)
{
std::cout << “Hello, Kitty!” << std::endl;
return 0;
}

o autoscan:生成configure.scan

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.64])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([Hello.cpp])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CXX

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT

o mv configure.scan configure.in:改名;

O emacs configure.in:编辑configure.in

AC_PREREQ([2.64])

# 这个是自动生成的,因为代码中没有相关初始化信息,这里手动修改一下,非必要
AC_INIT([CgFox], [0.0.1], [http://www.yulefox.com])

# 这个是必须的,否则无法生成aclocal.m4
AM_INIT_AUTOMAKE([CgFox], 0.0.1)

AC_CONFIG_SRCDIR([Hello.cpp])

o aclocal:生成aclocal.m4(太长了,还没去仔细了解)和autom4te.cache;

o autoconf:生成configure(也很长,先不看);

o automake –add-missing。

……


本来想等明天(今天)弄完了再详细整理一下。不过我没有打算把这个东西搞成一篇教程。记下来更多的只是为了给自己留下一个lable,知道自己这几天在做什么。

最近又是两点左右睡。脑子里有个家伙告诉我这样不好;另一个家伙告诉我他还不困;还一个家伙告诉我明天还要上班。

我去你大爷的!