Kubuntu 9.04 KDE4 问题

这些问题也未必是 Kubuntu 的问题,很有可能是 KDE4 本身的问题。

1. .gtkrc-2.0-kde4 实际不能用。

GTK 的程序在 KDE4 下显示太难看了,尤其是菜单那块,整整突出来一个方块。Firefox 和 Thunderbird 还好,可以更换个主题啥的。像 Pidgin, scim 之类,那个难看呀,和 KDE4 的主题一点儿都不搭。

都说在 System Settings->Appearance->GTK Styles and Fonts 中选择 Use my KDE style in GTK applications 就可以了(需要先安装 gtk-qt-engine-kde4),但我发现一个很奇怪的问题。选择了该选项之后,是会在家目录下新建一个名为 .gtkrc-2.0-kde4 的文件,里面是 GTK 主题的设置:

# This file was written by KDE
# You can edit it in the KDE control center, under "GTK Styles and Fonts"

include "/usr/share/themes/Qt4/gtk-2.0/gtkrc"

style "user-font"
{
    font_name="DejaVu Sans"
}
widget_class "*" style "user-font"

gtk-theme-name="Qt4"
gtk-font-name="DejaVu Sans 9"

systemsettings 还提示需要重新登录 KDE 之类的话。但是一旦重新登录,这个 .gtkrc-2.0-kde4 就会被删除,无论把该文件的权限设置成啥样,然后 GTK 程序还是老样子。真的搞不清楚是谁跟这个文件有仇,见了它就删。

我登来登去实在没辙了,干脆直接把它改名为 .gtkrc-2.0,没想到 GTK 程序的主题立马 OK,根本不用重新登录。你说 KDE4 的方法和提示这不是害人吗?

PS: 我在另外一台电脑上发现,当先装 Ubuntu,再安装 kubuntu-desktop 时,那个 .gtkrc-2.0-kde4 是有作用的。

2. 用户帐户图片无法更改。

在 System Settings->About Me 中,提示说 Click to change your image,点击根本没用,会弹出来一个:Your administrator has disallowed changing your image. 甚至使用 root 权限,更改 root 用户的 image,也是这个提示。而 KDE4 目前没有提供一个像以前版本的 kcontrol 中进入管理员模式的按钮,所以我实在不知道该怎么办了。这个错误好像在 SUSE, Fedora, Gentoo 的邮件列表中都有报告,没看到有可用的解决方法。而且这个提示也太恶心,谁是 Your administrator?root 的 administrator 是谁?在哪里 disallowed 的?是 user privilege 不够吗?我深深地怀疑是不是 KDE4 目前没有实现这个东西,搞个提示唬人的。

PS: 我知道本文涉及到了 Linux 世界的两大战争:发行版之争和桌面系统之争,评论请就事论事,不要涉及这两点。

Patch for Libjingle with GCC 4.2.4 on Ubuntu

It is a svn diff result, not a patch, actually.

So, what is Libjingle? Quoted from http://code.google.com/p/libjingle/:

Libjingle, the Google Talk Voice and P2P Interoperability Library, is a set of components we provide to interoperate with Google Talk's peer-to-peer file sharing and voice calling capabilities. The package includes source code for Google's implementation of Jingle and Jingle-Audio, two proposed extensions to the XMPP standard that are currently available in draft form.

You can check out the head revision of Libjingle from its svn repository using command:

svn checkout http://libjingle.googlecode.com/svn/trunk/ libjingle-read-only

Then ``./autogen.sh'' and ``make'' as we usually do for building a *nix software. You will find many errors during ``./autogen.sh'' and ``make''. To fix them, first, some LIBs should be installed:

sudo apt-get install build-essential libexpat1-dev libglib2.0-dev libogg-dev libssl-dev libasound2-dev libspeex-dev openssl libortp7-dev libmediastreamer0-dev libavcodec-dev

I am not very sure if these LIBs are enough. If you have some problem with this, please let me know.

Even if you have all of these LIBs installed, you will still get some errors such as:

../../talk/base/stringutils.h:272: error: extra qualification 'talk_base::Traits::' on member 'empty_str'
../../talk/base/base64.h:26: error: extra qualification ‘talk_base::Base64::’ on member ‘Base64Table’
../../talk/base/base64.h:27: error: extra qualification ‘talk_base::Base64::’ on member ‘DecodeTable’

So here is a patch for source code errors like this. IMPORTANT NOTE: gcc version 4.2.4 on Ubuntu 8.04, libortp7.

Index: talk/p2p/base/sessionmanager.h
===================================================================
--- talk/p2p/base/sessionmanager.h    (revision 7)
+++ talk/p2p/base/sessionmanager.h    (working copy)
@@ -156,7 +156,7 @@

   // Creates and returns an error message from the given components.  The
   // caller is responsible for deleting this.
-  buzz::XmlElement* SessionManager::CreateErrorMessage(
+  buzz::XmlElement* CreateErrorMessage(
       const buzz::XmlElement* stanza,
       const buzz::QName& name,
       const std::string& type,
Index: talk/session/phone/linphonemediaengine.cc
===================================================================
--- talk/session/phone/linphonemediaengine.cc    (revision 7)
+++ talk/session/phone/linphonemediaengine.cc    (working copy)
@@ -80,24 +80,24 @@
     }
#endif
#ifdef HAVE_SPEEX
-    if (i->name == speex_wb.mime_type && i->clockrate == speex_wb.clock_rate) {
-      rtp_profile_set_payload(&av_profile, i->id, &speex_wb);
-    } else if (i->name == speex_nb.mime_type && i->clockrate == speex_nb.clock_rate) {
-      rtp_profile_set_payload(&av_profile, i->id, &speex_nb);
+    if (i->name == payload_type_speex_wb.mime_type && i->clockrate == payload_type_speex_wb.clock_rate) {
+      rtp_profile_set_payload(&av_profile, i->id, &payload_type_speex_wb);
+    } else if (i->name == payload_type_speex_nb.mime_type && i->clockrate == payload_type_speex_nb.clock_rate) {
+      rtp_profile_set_payload(&av_profile, i->id, &payload_type_speex_nb);
     }
#endif

     if (i->id == 0)
-      rtp_profile_set_payload(&av_profile, 0, &pcmu8000);
+      rtp_profile_set_payload(&av_profile, 0, &payload_type_pcmu8000);

-    if (i->name == telephone_event.mime_type) {
-      rtp_profile_set_payload(&av_profile, i->id, &telephone_event);
+    if (i->name == payload_type_telephone_event.mime_type) {
+      rtp_profile_set_payload(&av_profile, i->id, &payload_type_telephone_event);
     }
    
     if (first) {
       LOG(LS_INFO) << "Using " << i->name << "/" << i->clockrate;
       pt_ = i->id;
-      audio_stream_ = audio_stream_start(&av_profile, 2000, "127.0.0.1", 3000, i->id, 250);
+      audio_stream_ = audio_stream_start(&av_profile, 2000, (char *)"127.0.0.1", 3000, i->id, 250);
       first = false;
     }
   }
@@ -106,7 +106,7 @@
     // We're being asked to set an empty list of codecs. This will only happen when
     // working with a buggy client; let's try PCMU.
      LOG(LS_WARNING) << "Received empty list of codces; using PCMU/8000";
-    audio_stream_ = audio_stream_start(&av_profile, 2000, "127.0.0.1", 3000, 0, 250);
+    audio_stream_ = audio_stream_start(&av_profile, 2000, (char *)"127.0.0.1", 3000, 0, 250);
   }
 
}
@@ -114,12 +114,12 @@
bool LinphoneMediaEngine::FindCodec(const Codec &c) {
   if (c.id == 0)
     return true;
-  if (c.name == telephone_event.mime_type)
+  if (c.name == payload_type_telephone_event.mime_type)
     return true;
#ifdef HAVE_SPEEX
-  if (c.name == speex_wb.mime_type && c.clockrate == speex_wb.clock_rate)
+  if (c.name == payload_type_speex_wb.mime_type && c.clockrate == payload_type_speex_wb.clock_rate)
     return true;
-  if (c.name == speex_nb.mime_type && c.clockrate == speex_nb.clock_rate)
+  if (c.name == payload_type_speex_nb.mime_type && c.clockrate == payload_type_speex_nb.clock_rate)
     return true;
#endif
#ifdef HAVE_ILBC
@@ -171,8 +171,8 @@
#ifdef HAVE_SPEEX
   ms_speex_codec_init();

-  codecs_.push_back(Codec(110, speex_wb.mime_type, speex_wb.clock_rate, 0, 1, 8));
-  codecs_.push_back(Codec(111, speex_nb.mime_type, speex_nb.clock_rate, 0, 1, 7));
+  codecs_.push_back(Codec(110, payload_type_speex_wb.mime_type, payload_type_speex_wb.clock_rate, 0, 1, 8));
+  codecs_.push_back(Codec(111, payload_type_speex_nb.mime_type, payload_type_speex_nb.clock_rate, 0, 1, 7));
  
#endif

@@ -181,8 +181,8 @@
   codecs_.push_back(Codec(102, payload_type_ilbc.mime_type, payload_type_ilbc.clock_rate, 0, 1, 4));
#endif

-  codecs_.push_back(Codec(0, pcmu8000.mime_type, pcmu8000.clock_rate, 0, 1, 2));
-  codecs_.push_back(Codec(101, telephone_event.mime_type, telephone_event.clock_rate, 0, 1, 1));
+  codecs_.push_back(Codec(0, payload_type_pcmu8000.mime_type, payload_type_pcmu8000.clock_rate, 0, 1, 2));
+  codecs_.push_back(Codec(101, payload_type_telephone_event.mime_type, payload_type_telephone_event.clock_rate, 0, 1, 1));
   return true;
}

Index: talk/xmpp/xmppclient.h
===================================================================
--- talk/xmpp/xmppclient.h    (revision 7)
+++ talk/xmpp/xmppclient.h    (working copy)
@@ -138,7 +138,7 @@
     }
   }

-  std::string XmppClient::GetStateName(int state) const {
+  std::string GetStateName(int state) const {
     switch (state) {
       case STATE_PRE_XMPP_LOGIN:      return "PRE_XMPP_LOGIN";
       case STATE_START_XMPP_LOGIN:  return "START_XMPP_LOGIN";
Index: talk/third_party/mediastreamer/msrtprecv.c
===================================================================
--- talk/third_party/mediastreamer/msrtprecv.c    (revision 7)
+++ talk/third_party/mediastreamer/msrtprecv.c    (working copy)
@@ -26,7 +26,7 @@
MSMessage *msgb_2_ms_message(mblk_t* mp){
     MSMessage *msg;
     MSBuffer *msbuf;
-    if (mp->b_datap->ref_count!=1) return NULL; /* cannot handle properly non-unique buffers*/
+    if (mp->b_datap->db_ref!=1) return NULL; /* cannot handle properly non-unique buffers*/
     /* create a MSBuffer using the mblk_t buffer */
     msg=ms_message_alloc();
     msbuf=ms_buffer_alloc(0);
@@ -120,7 +120,7 @@
         gint got=0;
         /* we are connected with queues (surely for video)*/
         /* use the sync system time to compute a timestamp */
-        PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
+        PayloadType *pt=rtp_profile_get_payload(r->rtpsession->rcv.profile,r->rtpsession->rcv.telephone_events_pt);
         if (pt==NULL) {
             ms_warning("ms_rtp_recv_process(): NULL RtpPayload- skipping.");
             return;
Index: talk/third_party/mediastreamer/audiostream.c
===================================================================
--- talk/third_party/mediastreamer/audiostream.c    (revision 7)
+++ talk/third_party/mediastreamer/audiostream.c    (working copy)
@@ -112,7 +112,7 @@
             RtpSession **recvsend){
     RtpSession *rtpr;
     rtpr=rtp_session_new(RTP_SESSION_SENDRECV);
-    rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
+    rtp_session_set_recv_buf_size(rtpr,MAX_RTP_SIZE);
     rtp_session_set_profile(rtpr,profile);
     rtp_session_set_local_addr(rtpr,get_local_addr_for(remip),locport);
     if (remport>0) rtp_session_set_remote_addr(rtpr,remip,remport);
@@ -133,7 +133,7 @@
     /* creates two rtp filters to recv send streams (remote part)*/
    
     rtps=rtp_session_new(RTP_SESSION_SENDONLY);
-    rtp_session_max_buf_size_set(rtps,MAX_RTP_SIZE);
+    rtp_session_set_recv_buf_size(rtps,MAX_RTP_SIZE);
     rtp_session_set_profile(rtps,profile);
#ifdef INET6
     rtp_session_set_local_addr(rtps,"::",locport+2);
@@ -147,7 +147,7 @@
     rtp_session_set_jitter_compensation(rtps,jitt_comp);
    
     rtpr=rtp_session_new(RTP_SESSION_RECVONLY);
-    rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
+    rtp_session_set_recv_buf_size(rtpr,MAX_RTP_SIZE);
     rtp_session_set_profile(rtpr,profile);
#ifdef INET6
     rtp_session_set_local_addr(rtpr,"::",locport);
@@ -217,8 +217,8 @@
     ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
     ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate);
    
-    ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FMTP, (void*)pt->fmtp);
-    ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FMTP,(void*)pt->fmtp);
+    ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FMTP, (void*)pt->send_fmtp);
+    ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FMTP,(void*)pt->send_fmtp);
     /* create the synchronisation source */
     stream->timer=ms_timer_new();
    
Index: talk/third_party/mediastreamer/msrtpsend.c
===================================================================
--- talk/third_party/mediastreamer/msrtpsend.c    (revision 7)
+++ talk/third_party/mediastreamer/msrtpsend.c    (working copy)
@@ -85,7 +85,7 @@
{
     guint32 clockts;
     /* use the sync system time to compute a timestamp */
-    PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
+    PayloadType *pt=rtp_profile_get_payload(r->rtpsession->snd.profile,r->rtpsession->snd.telephone_events_pt);
     g_return_val_if_fail(pt!=NULL,0);
     clockts=(guint32)(((double)synctime * (double)pt->clock_rate)/1000.0);
     ms_trace("ms_rtp_send_process: sync->time=%i clock=%i",synctime,clockts);
Index: talk/base/base64.h
===================================================================
--- talk/base/base64.h    (revision 7)
+++ talk/base/base64.h    (working copy)
@@ -23,8 +23,8 @@
   static std::string decode(const std::string & data);
   static std::string encodeFromArray(const char * data, size_t len);
private:
-  static const std::string Base64::Base64Table;
-  static const std::string::size_type Base64::DecodeTable[];
+  static const std::string Base64Table;
+  static const std::string::size_type DecodeTable[];
};

} // namespace talk_base
Index: talk/base/stringutils.h
===================================================================
--- talk/base/stringutils.h    (revision 7)
+++ talk/base/stringutils.h    (working copy)
@@ -269,7 +269,7 @@
template<>
struct Traits<char> {
   typedef std::string string;
-  inline static const char* Traits<char>::empty_str() { return ""; }
+  inline static const char* empty_str() { return ""; }
};

///////////////////////////////////////////////////////////////////////////////

You killed all these errors? Congratulations! You can start talking with your gtalk friends with command ``call'' in talk/examples/call/ !

PS: If you are working with GCC 4.3.x, more strict checking is applied on the code. However, most errors can be fixed by adding some C headers into the #include fields, such as: <cstdlib>, <cstring>.

Ubuntu 9.04 安装手记

此次安装是在一台 Dell OptiPlex 740 台式机上进行,处理器 AMD Athlon 64 X2 4400+,显卡 nVIDIA GeForce 6150,声卡 SigmaTel STAC9200。Ubuntu 版本为 9.04 Jaunty Jackalope Alpha 5 amd64 位版,硬盘安装。

1. 硬盘安装时在分区那步仍无法列出分区表,需要 Ctrl-Alt-F2 进入控制台 2 手动 umount -l /hd-media 后重试。

2. 开箱显示正常,但 Compiz 3D 特效无法开启,可能因为没有可用的受限驱动。

3. 默认 ALSA 驱动不支持该声卡,但选择 OSS 驱动可以支持(很奇怪)。必须在音量设备那开启对 capture 设备,才能录入声音,此时可以使用 ALSA 驱动。在使用 Mplayer、SMplayer 之类播放器播放视频时,需要手动在选项中选择声音输出的驱动为 OSS。

4. 安装 smplayer 之后即支持 avi 格式解码,不用手动下载 codecs。在播放 720p 以上高清视频时,最好将 smplayer 的本地缓存调整为 10M 以上(默认为2M),否则容易引起底层 mplayer 内存问题,会无法播放、内存占用过大死机或崩溃。

5. Socks 代理软件 Dante 源代码在该 x86_64 平台上编译后运行会出现段错误;更换为 antinat,经源码编译后运行正常。

6. Libfetion for 64 位 deb 包不可用,异常退出;经源码编译后运行正常。

7. sendsms 编译为 64 位版本会出现段错误,但短信仍能发送成功。

9. 网易的 Ubuntu 软件仓库镜像不包含 Jaunty,cn 的镜像没有总镜像快,security 的连接速度太慢。正式发布后,网易已经有了 Jaunty 源。

10. 使用 Firefox 时可直接安装 Adobe Flash Player 10 64 位版本。

11. 新的状态通知很漂亮,可以显示 Pidgin 上好友的登录和短讯。

12. 根分区使用 ext4 文件系统,数据分区为了与其它系统保持共享仍采用 ext3 文件系统。

13. 安装中文支持时可以选择是否安装该语言用户常用软件,选择是则会增加 PCManX、StarDict 等软件。PCManX 中包含非常全的港台和大陆 BBS 地址簿,但是字体有问题,未解决;QTerm 5.3 会崩溃。

14. 传说中的启动加速没有明显感觉,也许是因为启动的服务太多。

15. Ubuntu 9.04 Jave 程序中文显示不正常,部分文字变成方格。文泉驿字体从 wqy-zenhei.ttf 改为 wqy-zenhei.ttc,导致 java 程序中文字体显示不正常。在 /etc/java-6-sun/fontconfig.properties 中添加 wqy 相关内容,diff 文件可以从这里下载。Java 貌似不可用 ttc 字体,从 8.04 拷来 wqy-zenhei.ttf 到 /usr/share/fonts/truetype/wqy 目录下可解决,wqy-zenhei.ttf 也可以从这里下载。

16. 在另一台笔记本 Dell D630 上安装 9.04 正式版时,发现居然默认不支持 NVS135M 视频驱动,需要配置好网络后,使用命令 sudo apt-get install nvidia-glx-180 安装 Nvidia 180 版本的驱动,或者自己到 NV 网站上下载最新驱动。

应用程序打包技术之三(rpm 篇)

1. 应用程序打包技术之一(源代码篇)
2. 应用程序打包技术之二(deb篇)
3. 应用程序打包技术之三(rpm 篇)
4. 应用程序打包技术之四(exe篇)

rpm 是 RedHat 系 Linux 使用的软件包格式。流行的 Linux 发行版:Fedora, RHEL, OpenSUSE, Oracle 包括国产的红旗 Linux,都采用 rpm 来管理软件包。

我不是很喜欢 rpm 软件包格式,原因主要有两个,一个是它的依赖关系很难处理,另一个是控制文件比较复杂。但是 rpm 包有着非常广泛的应用,也是一个提高生产力的重要工具。

像前一篇文章提到的一样,checkinstall 也可以用来打 rpm 包,但我不是很熟悉这个软件。这里我仅仅介绍如何使用原始的 rpm(rpmbuild) 工具来打 rpm 软件包。

和前面 deb 包使用 fakeroot 一样,rpmbuild 也是利用沙盒的方式来构建软件包,除了控制文件比较繁琐,过程可能还更自动一些。构建 rpm 包的工作目录默认是 /usr/src/redhat,如果您在 Debian 下安装了 rpm 这个软件包,它可能是 /usr/src/rpm。您可以使用 rpm --eval %_topdir 查看自己的 rpm 工作目录。

$ tree `rpm --eval %_topdir`
/usr/src/redhat
|-- BUILD
|-- RPMS
|   |-- athlon
|   |-- i386
|   |-- i486
|   |-- i586
|   |-- i686
|   `-- noarch
|-- SOURCES
|-- SPECS
`-- SRPMS

我们可以看到,/usr/src/redhat/ 下有几个子目录:SOURCES 用来存放源代码包,SPECS 用来存放 spec 控制文件,BUILD 用来解压源代码包和构建软件,RPMS 里存放的是打好的二进制应用程序 RPM 包,SRPMS 里存放的是打好的源代码 RPM 包。但是,我们应该知道 _topdir 是可以在 spec 文件中修改的,否则我们只能用 root 才能在默认的工作目录 /usr/src/redhat 下创建文件和执行命令。我们可以先把工作目录树拷贝到用户自己的目录中:

$ cp -r /usr/src/redhat ~/rpm

这样,我们就可以在用户目录 ~/rpm 下打 rpm 包了。打 rpm 包之前的准备工作只有两件:1. 准备好源代码包并放置在 SOURCES 目录下;2. 准备好 spec 控制文件并放在 SPECS 目录下。如何打源代码包我们已经在 《源代码篇》中介绍过,下面我们主要来介绍 spec 文件的格式。下面是一个实例 spec 文件。

$ more ~/rpm/SPECS/casnet.spec
%define   _topdir    /home/solrex/rpm
Name:     casnet
Version:  1.3
Release:  1
License:  GPL
Packager: Solrex Yang
Summary:  CASNET Client
Group:    Network
Source:   %{name}-%{version}.tar.gz
URL:      http://share.solrex.org/casnet/
Prefix:   /usr

%description
CASNET is a gui client for ip gateway of GUCAS(Graduate University of Chinese
Academy of Sciences), which is written in Python and PyGtk.

%prep
%setup -q

%build

%install
make -e PREFIX=%{prefix} install

%files
%{prefix}/bin/casnetconf
%{prefix}/bin/casnet
%{prefix}/bin/casnet-gui
%{prefix}/share/casnet/casnetconf.py
%{prefix}/share/casnet/casnet.py
%{prefix}/share/casnet/casnet-gui.py
%{prefix}/share/casnet/pics/*.png
%{prefix}/share/applications/casnet.desktop
%{prefix}/share/icons/casnet.png

我们可以看到,spec 文件与 deb 包的 control 文件有很多相似之处:Name, Version, Release, License, Packager, URL 是软件的名称、版本、小版本、使用的协议、维护者和网址;Summary 和 %description 是软件的信息;Group 是软件所归类别。剩下的就有些不同了:Source 是指软件的源代码包名称,rpm 会到 SOURCES 目录下找这个包;Prefix 是软件的默认安装位置;%prep、%build、%install 下分别是软件的预处理、编译和安装命令;%files 是所有需要被打包进去的文件。

因此,作者需要将 spec 文件中的各个域填写正确。%prep 下的 %setup 宏一般是用来将源代码 tar 包释放到 BUILD 目录下;%build 下可以添加 %configure 宏和 make 命令,如果您的软件需要编译的话;%install 下是您的安装命令;%files 下是您程序运行所需要的全部文件,其路径即为您安装完软件后它应该在的位置。%{name} 可以用来指代 Name: 域的内容,%{version } 指代 Version: 域的内容,以此类推。

需要注意的是,rpmbuild 使用 BUILD/%{name}-%{version} 作为您的源代码包释放后的目录,进入其进行编译。因此当您使用 tar 打源代码包时,tar 包的顶层目录名应该为 %{name}-%{version} 而不是仅仅是 %{name},比如:

$ tar czvf casnet-1.3.tar.gz casnet-1.3
$ mv casnet-1.3.tar.gz ~/rpm/SOURCES

现在我们在 ~/rpm/SOURCES 下有了 casnet-1.3.tar.gz,在 ~/rpm/SPECS 目录下有了 casnet.spec,那么我们就可以使用下面的命令生成 rpm 包了。如果您的安装位置 Prefix 选择的是一个系统目录,比如 /usr, /usr/local 之类,您也许需要使用 root 权限来运行 rpmbuild 命令。

$ rpmbuild -ba ~/rpm/SPECS/casnet.spec

这样我们就能在 ~/rpm/RPMS/i386 目录下获得我们生成的 rpm 软件包了。rpmbuild 命令的执行过程是这样的:首先根据 spec 文件定位源代码包,然后将源代码包释放到 BUILD 目录下,使用 spec 文件中给出的命令编译和安装,然后将 spec 中列的文件提取出来,按照包信息打出来 rpm 包。

我们可以使用 rpm -qpi 命令来查看 rpm 包的信息,rpm -qpl 命令来查看 rpm 包所包含的文件列表:

$ rpm -qpi ~/rpm/RPMS/i386/casnet-1.3-1.i386.rpm
Name        : casnet                       Relocations: /usr
Version     : 1.3                               Vendor: (none)
Release     : 1                             Build Date: Thu 26 Feb 2009 08:03:50 PM CST
Install Date: (not installed)               Build Host: laptop
Group       : Network                       Source RPM: casnet-1.3-1.src.rpm
Size        : 40883                            License: GPL
Signature   : (none)
Packager    : Solrex Yang
URL         : http://share.solrex.org/casnet/
Summary     : CASNET Client
Description :
CASNET is a gui client for ip gateway of GUCAS(Graduate University of Chinese
Academy of Sciences), which is written in Python and PyGtk.

$ rpm -qpl ~/rpm/RPMS/i386/casnet-1.3-1.i386.rpm
/usr/bin/casnet
/usr/bin/casnet-gui
/usr/bin/casnetconf
/usr/share/applications/casnet.desktop
/usr/share/casnet/casnet-gui.py
/usr/share/casnet/casnet.py
/usr/share/casnet/casnetconf.py
/usr/share/casnet/pics/casnet.png
/usr/share/casnet/pics/offline.png
/usr/share/casnet/pics/online.png
/usr/share/icons/casnet.png

如果您想了解更详细的内容,您可以进一步参考 Jake's RPM Build Tutorial 这篇文章。

应用程序打包技术之二(deb篇)

1. 应用程序打包技术之一(源代码篇)
2. 应用程序打包技术之二(deb篇)
3. 应用程序打包技术之三(rpm 篇)
4. 应用程序打包技术之四(exe篇)

deb 是 Debian 系 Linux 使用的软件包格式,也是我最欣赏的软件包格式。我所知道的打 deb 软件包的方法有两种,一种是使用 checkinstall,另一种是使用 dpkg。

checkinstall 不仅仅可以用来打 deb 包,还可以打 rpm 和 tgz 包,而且使用方法相对简单。但是 checkinstall 的运行不是那么稳定,我搞不懂它在什么情况下才能正常运行,而且它的定制性不是很强,使用时老是要交互地输入些信息,所以我还是放弃了使用它来打包软件。感兴趣的朋友可以在网上搜索一下这个程序的使用方法。

dpkg 是 Debian 的“原生”包管理软件,但是很多人不太愿意使用 dpkg 来打包 deb。究其原因可能是需要写麻烦的配置文件,但是写配置文件的一个好处就是在下次打包时候可以直接用上次的配置文件,只修改一个版本号就可以了,而不用每次都需要填包信息。在介绍如何打 deb 包之前,我们现看一下如何解 deb 包。

$ sudo apt-get install tree
$ dpkg -X /var/cache/apt/archives/tree_1.5.1.1-1_i386.deb fakeroot
$ cd fakeroot
$ dpkg -e /var/cache/apt/archives/tree_1.5.1.1-1_i386.deb
$ tree
.
|-- DEBIAN
|   |-- control
|   `-- md5sums
`-- usr
    |-- bin
    |   `-- tree
    `-- share
        |-- doc
        |   `-- tree
        |       |-- README
        |       |-- changelog.Debian.gz
        |       |-- changelog.gz
        |       `-- copyright
        `-- man
            `-- man1
                `-- tree.1.gz

dpkg -X 是将 deb 包的内容文件释放出来,dpkg -e 是将 deb 包的控制信息释放出来。前面执行那个 sudo apt-get install tree 是为了将 tree_1.5.1.1-1_i386.deb 下载到本地 apt cache,如果您已经安装过 tree 这个软件,可以为 apt-get 加上 -d 参数,使其只下载而不安装。

从上面 tree 命令的执行结果我们发现,deb 包解开后分两部分:一部分是控制信息,在 DEBIAN 目录下;一部分是安装内容,在 usr 目录下。现在您大概明白为什么我们使用 fakeroot 作为目录名了,因为这个目录就是一个"假根目录",您在这个目录下所有的修改,最后都会被映射到目标机的根目录 / 下。比如 fakeroot/usr/bin/tree 这个文件,就会被安装到 /usr/bin 下,以此类推。

只要您能理解 fakeroot 这个目录映射,您就知道如何安放自己的文件了。为了让生成的包将文件 foo 安装到目录 /usr/xx/yy 目录下,您只用在 fakeroot 目录下建立 usr/xx/yy 目录,并将 foo 拷贝进去就行了。

好,下面进入关键的配置文件部分,关于 control 和 md5sums。

$ more DEBIAN/control
Package: tree
Version: 1.5.1.1-1
Architecture: i386
Maintainer: Ubuntu MOTU Developers
Original-Maintainer: Florian Ernst
Installed-Size: 92
Depends: libc6 (>= 2.6-1)
Section: utils
Priority: optional
Description: displays directory tree, in color
Displays an indented directory tree, using the same color assignments as
ls, via the LS_COLORS environment variable.
.
Homepage: http://mama.indstate.edu/users/ice/tree/

我们可以看到,control 文件中包含的主要是软件的版本和维护者信息,我相信大家都能基本看懂上面这些信息什么意思:Package 包名(tree)、Version 版本(1.5.1.1-1)、Architecture 目标机架构(i386 386及以后)、Maintainer 维护者(Ubuntu MOTU Developers)、Original-Maintainer 原维护者(Florian Ernst)、Installed-Size 安装后大小(92K)、Depends 依赖软件包(libc6 不低于 2.6-1 版本)、Section 包分类(工具)、Priority 优先级(可选)、Description 包描述、Homepage 软件主页。

由于咱们分析这个包是 Ubuntu 发布的包,所以包信息给的比较全,其实并不是上面所有的信息都有必要提供(小声说一句,就算全提供也不是很难吧?除了咱不用的,Original-Maintainer 这种就算了)。关于哪些信息比较重要,以及每个域的具体含义和可选项,可以参考 Debian 的文档 Debian Policy Manual Chapter 5 - Control files and their fields

您也可以依样画葫芦,写一个类似的 control 文件放到 DEBIAN 目录下,提供一些自己软件包的信息,基本有这个配置文件就可以打包了。

$ more DEBIAN/md5sums
d60a3b4736f761dd1108cb89e58b9d4e usr/bin/tree
981ea0343c2a3eb37d5fc8b5ac5562df usr/share/man/man1/tree.1.gz
483a56158a07a730ec60fc36b3f81282 usr/share/doc/tree/README
ea56d78ae0d54693ae8f3c0908deeeff usr/share/doc/tree/copyright
4456e04c3c268eabcd10ee9b949a9b9a usr/share/doc/tree/changelog.gz
ec104db6914cfce2865a0d8c421512bb usr/share/doc/tree/changelog.Debian.gz

md5sums,这文件名一看,就知道是保存着软件包中各文件的 md5 校验值,用来校验软件包是否被损坏了。其实这个文件纯属“腊月三十逮兔子,有它没它都过年”,您可以完全不提供它。

这样呢,我们就准备好了 deb 包的内容文件和控制信息:控制文件放在了 fakeroot/DEBIAN 目录下,内容文件放在 fakeroot/usr 下,目录树就像开头 tree 命令的结果。下面只需要一个命令就能打出来 deb 安装包了:

$ cd ..
$ dpkg -b fakeroot/ foo.deb

这时候当前目录下就出现了 foo.deb。您可以使用 dpkg -I foo.deb 查看 foo.deb 的控制信息,dpkg -c foo.deb 查看 foo.deb 包含了什么文件,sudo dpkg -i 安装 foo.deb。

小技巧:

1. 如果您懒得自己新建一个控制文件和目录树,您完全可以像本文开头那样,找一个简单的软件包,将它的内容和控制信息释放出来,对它进行修改,然后打出来自己的包。

2. 生成 md5sums 文件不是什么难事,您只需要在 fakeroot 目录使用下面这个命令:

$ md5sum `find usr -type f` > DEBIAN/md5sums
或者
$ find usr/ -type f -exec md5sum {} + > DEBIAN/md5sums

3. 将您的可执行文件拷贝到 fakeroot/usr 下并不一定要手动一个个拷。如果您使用 GNU 自动工具集,./configure 时加个参数 --prefix=fakeroot/usr/ 即可;如果您自己写的 Makefile,可以在 Makefile 中使用一个变量 PREFIX=/usr,当您不加参数时,make install 的安装目标就是 /usr 下,您可以使用 Makefile -e PREFIX=fakeroot/usr/ install 来覆盖 Makefile 中的变量设置。

Aspell: 程序员的拼写检查利器

作为一个程序员,尤其是非英语母语国家(ESL or EFL)的程序员,写出漂亮的注释可能要比写出漂亮的代码更难。就比如 Eric 的“来自英语母语国家的”女友就有 “Programmers are English-challenged.“ 的评论。

那么如何在程序的注释中避免犯一些低级语法或者拼写错误呢?Eric 也在 Some useful tools for you to write English articles on Linux 中推荐了几个小工具。我这里算拾人牙慧,稍微写一点儿我非常欣赏的 Aspell 拼写检查工具。

Aspell 是一个强大的拼写检查工具,尤其是对于程序员来说。在 Linux 下,大部分程序员应该是用 Vim 或者 Emacs 写代码,它们有内建拼写检查功能,比如 vim 可以用 :setlocal spell spelllang=en_us 开启对美式英语的拼写检查。不过很少人会安装或者使用拼写检查功能,不是每个人都喜欢写代码时面对一堆高亮的词组(当它们不仅检查注释时,哦,天那!)。幸运的是,我们有 Aspell。

Aspell 使用方法非常简单,比如只想检查 C 或者 C++ 风格的注释和字符串中的拼写错误,就可以用这样的命令:

$ aspell --mode=ccpp -c test.cpp

终端里就会列出一个一个注释中的错误,并给出修改意见。接下来的工作就很简单了,按照窗口下面每个键对应的功能,选择更换单词或者忽略该单词。如下图所示:

Aspell 拼写检查工具(无法看到此图,可能因为您无法连接国外网站)

Aspell 还有更多模式,比如检查 HTML, TeX, XML, Perl 等等一些文档或程序中的拼写,更多内容就请看 Aspell 的帮助吧。

Aspell 的用户习惯保存在 ~/.aspell.en.prepl 和 ~/.aspell.en.pws 两个用户自定义替换和忽略单词列表里,可以通过备份或者修改这两个列表来改变 aspell 对某些单词拼写检查的策略。

《使用开源软件-自己动手写操作系统》Rev 2发布

免费电子书《使用开源软件-自己动手写操作系统》的主页在:http://share.solrex.org/WriteOS/ ,您可以到这里下载 pdf 格式电子书和随书源代码。

免费电子书《使用开源软件-自己动手写操作系统》(无法看到此图,可能因为您无法连接国外网站)

2008 年 2 月 21 日发布第一版,拖了十个月我才发布了第二版。虽然有一些懒惰的原因在里面,但更重要的原因是没有很多可以大块利用的时间。从开始动手,才知道写书是一件非常痛苦的工作,尤其是有代码的书。再加上本书目前的主要代码都是汇编语言,一旦出错就要花好长时间调试,代码运行正确了,要在不同的 Linux 进行编译以确保能正确通过,又要加注释、除去冗余指令,代码的工作结束就要接着关注排版、查资料、填补内容、做插图,总之写一天书下来我累得精神都会振奋不起来。

本来打算十月底就发布第二版,但是因为研究工作稍微耽误了一下,就又拖到了十一月底,总之我还是完成了这一章。这一版虽然只增加了第三章,但页码却从 40 页增加到了 104 页,示例代码也从 2 个增加到 10 个,与第一版的工作量不可同日而语。由于这一版的发布周期过长,我在按版本发布的基础上增加了每周发布,也因此在编写过程中得到了不少帮助。

这本书从计划开始就得到很多朋友的肯定,在编写的过程中也得到了很多朋友的帮助。不计刚发布第一版时几乎每天一千次的下载量,从 2008 年 5 月 9 号把所有源代码迁移到 Google Code 项目后,加上每周发布,就有共计两万一千多次下载。我非常感谢大家对我一如既往的支持,感谢那些在我的博客评论或者发电子邮件给我打气的朋友,尤其感谢那些在邮件中或者错误报告页中指出本书错误或者提供很好建议的朋友!

我尤为高兴的是听一位朋友说北京邮电大学某位教授操作系统课程的老师向同学推荐这本电子书,这正与我写这本书的初衷相合,就像我在前言中所说:

本书的最终目标是成为一本大学“计算机操作系统”课程的参考工具书,为学生提供一个step by step 的引导去实现一个操作系统。这不是一个容易实现的目标,因为我本人现在并不自信有那个实力了解操作系统的方方面面。但是我想,立志百里行九十总好过于踯躅不前。

我将继续努力将这本书写下去,也希望大家能够继续对这本书保持关注,并帮助我完善此书。下面是本书这次发布的章节信息,如果您发现本书中的错误(那是不可避免的),或者有更好的建议,请您一定到本书的错误报告页指出,兄弟我将非常感谢!

第三章进入保护模式
3.1 实模式和保护模式. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.1 一段历史. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.1.2 实模式. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.1.3 保护模式. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.1.4 实模式和保护模式的寻址模式. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.2 与保护模式初次会面. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.2.1 GDT 数据结构. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.2.2 保护模式下的demo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.2.3 加载GDT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.2.4 进入保护模式. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.2.5 特别的混合跳转指令. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.2.6 生成镜像并测试. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.3 段式存储. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.3.1 LDT 数据结构. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.3.2 段描述符属性. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.3.3 使用LDT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.3.4 生成镜像并测试. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.3.5 段式存储总结. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.4 特权级. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.4.1 不合法的访问请求示例. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.4.2 控制权转移的特权级检查. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.4.3 使用调用门转移. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.4.4 栈切换和TSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
3.5 页式存储. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
3.5.1 分页机制. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.5.2 启动分页机制. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
3.5.3 修正内存映射的错误. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
3.5.4 体验虚拟内存. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
3.6 结语. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

DEB Packages of qRFCview and JabRef

由于最近的学习和研究有些不顺利,加上自制力过差,时间的利用上也是无法让自己满意,每每长吁短叹。今天下午心情格外不好,于是就回去闷头大睡到五点。幸好有女朋友劝慰,一通电话后感觉好多了。还是要有勇气,就像奥巴马一样,遇到挫折时吼一句:“Yes We Can!“

下午的时候利用工作时间打包了两个软件:qRFCview 和 JabRef,主要想着为了方便自己使用。反正时间已经浪费了,希望放出来能方便更多人吧。打包这两个软件的主要原因:

qRFCview:这是一个在 Linux 下看 RFC 文档的软件,输入 RFC 的编号就可以自动下载并格式化显示出来。这个软件已经两年多没有更新,想想当今世界两年时间会发生多少事吧!它在软件中限制 RFC 编号的范围是 1-5000,而现在 RFC 已经有 5389 个了,所以我就将这个范围扩大到 1-10000,重新编译了一下,打成 DEB 包,算是一个 bug fix 吧。

JabRef:这是一个文献管理软件,我曾经在博客中推荐过。它在 2008 年 11 月 1 号发布了 2.42 版,而 Ubuntu 软件仓库中的版本仍是 2.31,有很多特性不支持。所以我将新的 Jar 替换了旧的 Jar,重新打了一个 DEB 包。

这两个 DEB 软件包都可以在我的共享网站:http://share.solrex.org/ibuild/ 目录下找到。

定制自己的免费天气预报短信

摘要:这篇博客介绍了一种在 Linux 下使用飞信(libfetion 库)来定时发送天气预报短信的方法。本文的主要贡献是:一、提供了一个 Linux 下发送飞信的命令行程序;二、提供了一个到中国气象网抓取、过滤天气信息并发送短信的脚本。

Libfetion修改了调用接口,而且中国移动现在换IP登录就需要使用验证码。除非我哪天闲得蛋疼,搞一个验证码识别模块出来,否则本项目将不再维护,很抱歉!

天气预报短信一直是移动通信公司提供的一种收费服务,Google 免费天气预报服务打破了这个僵局。但是Google 的服务很不稳定,经常收不到短信,而且天气预报内容的定制性差。我家 xixi 一直有看天气预报的习惯,我就告诉她说我能写个程序每天给你发天气预报消息,她不相信,然后我就写了下面的程序。

首先感谢一下 mirth@bbs.nju.edu.cn,本文的主要内容是基于他在小百合 BBS 上发表的如何用飞信定时给自己发免费天气预报一文做的少许改进。

1. 发送飞信的命令行程序[1, 2, 3, 4, 5]

这个程序主要基于邓东东开发的 libfetion 库。这个库不是开源的,但是作者提供了头文件和库文件(在GUI源代码中),所以我们可以使用它的 API 来写一些自己的程序。下面的程序内容很简单,注释也不少,我就只贴源码,不再解释了(注意,编译时需要 curl 的 dev 库)。你可以在这里下载到我的 sendsms 小程序的源代码

sendsms
|-- Makefile
|-- include
|   |-- common.h
|   |-- datastruct.h
|   |-- event.h
|   |-- fxconfig.h
|   `-- libfetion.h
|-- lib
|   |-- libfetion_32.a
|   `-- libfetion_64.a
|-- sendsms
`-- sendsms.cpp

2. 到中国气象网抓取、过滤天气信息并发送短信的 bash 脚本

你可以从这里下载到下面的 bash 脚本,或者到这里下载几乎同样功能的 python 脚本。脚本就不多做解释了,没几行代码,相信稍微研究一下就能看懂。

天气网经常更新,新的脚本我就不再贴到博客里了。如果您发现天气预报脚本不好用了,就请关注脚本下载的地址,我一般会尽快更新的。

$ more weatherman.sh
#!/bin/bash
# This script fetch user specified citys' weather forecast from
# http://weather.com.cn, and send them using a CLI SMS sender "sendsms"
# which you can get from http://share.solrex.org/dcount/click.php?id=5.
#
# You can look for new or bug fix version
# @ http://share.solrex.org/scripts/weatherman.sh.
# Copyright (C) Solrex Yang <http://solrex.org> with GPL license.
#
# Usage: You should add it to crontab by "crontab -e", and then add a line
# such as:
# 00 20 * * * /usr/bin/weatherman.sh >> ~/bin/log/weatherman.log 2>&1
# which will send weather forecast to your fetion friends at every 8pm.

3. 将脚本设置为定时执行

安装好 sendsms 到 /usr/bin 之后,将上面脚本放到 YOURPATH 下,然后在命令行执行:crontab -e,将下面一行添加进去:

50 19 * * * /YOURPATH/weatherman.sh 1> /tmp/weatherman.out 2> /tmp/weatherman.err

就设置为每天下午 7 点 50 发送天气预报短信。

[1] 应大家要求,在程序中加入了读取 http_proxy 代理服务器环境变量的部分,其它类型的代理服务器可以自行添加(毕竟源代码给你了,随便改),增加了重试登录和发送的代码。

[2] 2008 年 11 月 30 日:增加了群发短信功能(多个接收者用','分隔)。

[3] 2009 年 01 月 11 日:增加从标准输入读入信息支持,可使用管道和输入重定向。这篇博客中的代码就不更新了,请到给出的链接去下载新版本。

[4] 2009 年 4 月 17 日:添加了"-l"选项,支持长短信发送,最长可到 1024 字节。解决了一个从标准输入读取短信的 bug。

[5] 2009 年 12 月 08 日:根据中国天气网的改版,更新抓取页面的脚本。

安装 Ubuntu 8.10 失败记

今天上午四个小时的折腾:

1. 想装个 FreeBSD 6.2,出现未知错误,找不到 /dev 下面的一个东西(仿佛回到了刚开始学 Linux 的时代,盲目呀);

2. 把分区表搞坏,一个扩展 data 分区丢失(这绝对是 FreeBSD 的问题,因为在安装时分区表中居然把这个 ext3 分区标示为 unused)。我也居然愚蠢到认为不到最后时刻它就不会写入分区表,结果导致整个分区数据丢失。还好这只是我工作用电脑,损失还不大;

3. 既然 data 都丢了,就随便再装个 Ubuntu 8.10 玩玩吧,结果遇到安装光盘的 bug。整整花了我两个小时呀,下了 RC 和 dailybuild 两个光盘镜像,都是一个问题,走到分区那一步,新建和修改分区的选项都是空白的,无法选择。到 launchpad.net 就发现不是我一个人在战斗,然后也插了一腿子。这是我自从注册 launchpad 那几天以来第一次登录,也是第一次灌水,注册时间是 2006-06-10。

4. 到了最后,还是用我原来的 Ubuntu 8.04,把分区重新建立挂载起来,下定决心再不折腾了。其实我想用 8.10,仅仅是被那个 nautilus 的标签式浏览诱惑了...

转了一圈,啥也没落着。得了一个教训:不要在双系统上装 FreeBSD,居然会犯 RedHat9.0 都不可能犯的错误,识别出错误的分区表。(话说今天遇到的 Ubuntu 8.10 的问题也类似,不过人家是 RC, 不是正式版。)

A Chance For Linux and Freeware

连着忙了几天,今天闲话几句。

关于微软正版验证

我家希希说:“我要被黑屏了,怎么办呀?我要学 Linux!”

我说:“没关系,你把自动更新服务关掉就行了。”

我家希希说:“我还是想学 Linux!”

微软准备在 2008 年 10 月 20 日对中国用户启动的 WGA 计划这几天被吵得沸沸扬扬,搞得几乎人人自危,生怕被黑屏了。本人的评论如下:

  • 对此措施,我持欢迎态度。这件事起码给中国的盗版用户提了个醒:软件是有知识产权的!用盗版的操作系统很开心,用盗版的应用软件也很开心,到最后是中国整个落后的软件产业不开心,软件民工们也不开心。

  • 对于效果,我持保留态度。我相信中国盗版产业中广大劳动人民的智慧!

  • 对于影响,我持乐观态度。这是一个 Linux 和免费软件的机遇。此次 WGA 计划一出,势必会督促那些已经有学习其它操作系统愿望的用户真正动起手来,也会使那些使惯了盗版 Office 的人考虑一下免费的优秀国产软件 WPS Office,进而认识到许多优秀的免费软件并不比收费软件差

最后友情提醒一下,WPS Office 2007 目前已更新到支持 M$ Office 2007 文件格式( .docx, .xlsx, .pptx ),永中也于本月 13 号推出了免费的永中 Office 2009 个人版,支持 Windows 和 Linux 平台;免费的国产软件 Foxmail 和"进口软件" Thunderbird 都可以替代 Outlook ; Ubuntu 8.10 Linux 操作系统还有 14 天就发布了。

关于看论文

最近被老师逼着快速浏览了大量论文,发现自己以前看论文的效率还是太低。眼高手低的毛病总是改不了,做研究还是要潜心进去。

关于看书

每天睡前逼着自己看一会儿书效率挺高的。豆瓣上我在读的书已经超过二十本了,平日很难分出大块时间看,目前已经利用睡前十分钟解决了两本。躺床上用台灯看书的感觉蛮惬意的,置身于黑暗中的一小片光明,仿佛又回到了中学时代。当然这也得益于现在宿舍的环境布置,床头就是写字桌,要是像以前在中关村时住上铺的话,势必就会影响室友的睡眠了。

关于 writeos

九月份更新了两次,十一假期无暇写字,第三章到现在还没写完,我希望十月底能完成发布第二个版本。上个星期一个墨西哥的小伙子加我 Gtalk,问这本书的问题,开始我还以为是华裔,后来知道人家根本不懂中文,没办法只好推荐他去看代码注释。也许等我再完成两章之后,会和某些朋友合作开始将它翻译成英文。

维度:数学漫步

开放数学电影《维度:数学漫步》(Dimensions: a walk through mathematics)是一部两小时长的 CG 科普电影,共分 9 个章节,讲述了许多深奥的数学知识,如 4 维空间中的正多胞体、复数、分形(fractals)、纤维化理论(fibrations)等等。这部电影以创作共用 署名-非商业用途-禁止演绎 3.0许可证发布,你可以自由下载和复制但不允许修改或商业使用。————援引 Solidot

这部电影我已经下载下来好长时间了,今天才想起来看一点儿,发现有点儿意思。请看这部电影开篇的话:

My name is Hipparchus. I lived in the second century before the birth of Christ, and I don't think I'd be bragging if I told you that I am the father of the sciences of Geography and Astronomy. You know, I wrote more than 14 books but unfortunately they have almost all been lost in the mists of time. I was responsible for the first catalogue of the stars, founded the field of mathematics called trigonometry and even invented the astrolabe. Fortunately, my brilliant successor Ptolemy, three centuries after my time inspired by my work, took up where I left off, and nowadays historians sometimes can't determine what was my contribution and what was his.

我叫喜帕恰斯,生活在耶稣诞生两个世纪之前。如果我说我是地理与天文学之父,请不要觉得我很狂妄。你知道的,我至少写了 14 本书。但不幸的是,它们几乎都遗失了,我曾为星星编写了第一本目录,开创了数学中的三角学,还发明了星盘。不过幸运的是,我杰出的后继者托勒密,三个世纪以后在我的工作启发之下,接手了我剩下的活计。如今,史学家们都无法确定,究竟哪些是我的贡献,哪些是他的。

这不是一部常规意义上的电影,而是用数码图形手段制作的动画。里面并没有什么主人公,制作者通过动画图形来阐述对数学维度的理解。这个电影的网站是:http://www.dimensions-math.org/,网站上提供有下载链接。另外,中国科学院数学研究所的 FTP 也提供该影片英语和法语版本的下载,详情请点击:http://www.math.ac.cn/Dimensions.htm

关于播放

有很多人在播放这部电影时候遇到问题,暴风影音是没办法播放这部电影的,Windows 媒体播放器可以播放但无法加载字幕。这里我推荐两款非常优秀的开源播放器,SMplayerVLC,它们都有 Linux 和 Windows 版本。他们都能播放这部电影,但是由于本片中文字幕使用 UTF-8 编码,字幕加载可能有一些小问题。下面是使这两款播放器能够正常显示本片中文字幕的设置(它们的菜单项在 Windows 下和 Linux 下几乎没有任何不同)。

SMplayer:
Options->Subtitles->Default subtitle encoding: UTF-8
如果是 Windows 系统,可能还需要在 Options->Subtitles->Font 中选择一下系统字体。

VLC Player:
Settings->Preferences->Video->Subtitles/OSD->Text renderer->Font:
Linux(Ubuntu) 下找到:/usr/share/fonts/truetype/wqy/wqy-zenhei.ttf(可以换成系统中其它的中文字体)
Windows 下找到:C:\WINDOWS\Fonts\simsun.ttc
Settings->Preferences->Input/Codecs->Other codecs->Subtitles->Subtitles text encoding: UTF-8

PS: 特别推荐一下 SMplayer

我在 Linux 下和 Windows 下现在都是使用 SMplayer 播放器(不用提醒我它和 mplayer 关系)。除了它的界面在两个系统下保持一致,完美支持 GBK 编码字幕之外,在播放上还有几个好处让我觉得特别顺手(可以说是我原来用暴风影音时候梦寐以求的特性):

一,支持三种速度的快进,分别用左右,上下方向键,上下翻页键。这样想跳过序幕时很方便;
二,支持以行为单位上下翻动字幕,当字幕快了慢了只需要按两个键就能调整过来;
三,自动纪录最后播放位置,再打开时自动跳到上次播放中止处;
四,normalize声音很方便,当视频声音太小时,normalize一下就舒服多了。不是其它播放器没这个功能,只是太难找到,比如暴风用这个功能要过几层菜单。

香港免费 VPN HOWTO

香港网站 Prairie Dog 提供了免费的 VPN 帐户,不要问我这个帐号能干嘛,自己去看。

申请免费 VPN 帐号地址:http://www.pdog-vpn.com/freeaccount.php(一个IP只能申请一个,多账号会被封)。

我不得不感叹中国网民的行动速度,我上午才申请的 pdog 的帐号,下午发文时就无法注册了。不过还有许多好心人收集这些免费 VPN 的信息,请点击 http://blog.119797.com/article/free-vpn/

Windows HOWTO:
http://www.pdog-vpn.com/setup.php

由于它没有 Linux HOWTO,这里我就提供一个

Ubuntu HOWTO:

安装 VPN 软件:
$ sudo apt-get install pptp-linux network-manager-pptp network-manager-vpnc

使用 VPN:
1. 点击 Ubuntu 系统通知栏中的网络连接图标,选择 VPN Connections->Configure VPN。
2. 点 Add 出来对话框之后,点 Forward 进入第二步,Connect to: 选择 PPTP Tunnel,再 Forward。
3. Connection 标签中 Connection Name 填个随便什么名字,我这里就用 pdog,Gateway 填 Prairie Dog 发给您的邮件中的主机名 xxx.pdog-vpn.com,然后 Forward, Apply,Close。
4. 点击网络连接图标,然后 VPN Connections->pdog,弹出窗口,输入用户名密码。然后,网络连接图标就会出来一个金黄色的小锁。
5. 然后访问某些可以查看 IP 地址的网站,比如 www.ip138.com,就会发现自己的 IP 地址变成了来自“香港特别行政区”。

这样,您就可以访问那些由于某些原因无法正常访问的网站了。

PS:我刚刚发现我域名下所有子域名都被我的域名服务商删除,而且无法添加,难道又是因为奥本海默运?

PSS:给域名服务商打了个电话,一个小时后看来已经部分恢复了,也可以添加子域名了。接线员给我的回复是 DNS 设置少了一个,所以系统更新时被当作错误信息删除掉了,看来我过于敏感了。

解决了一个 Linux 版飞信 GUI 的一个重要 Bug

江苏移动一直有飞信答奥运题奖话费的活动,所以我女友每天都有登录飞信答题的习惯。Libfetion 是针对飞信协议开发的第三方程序库,在此基础上有 Linux 和 Mac 版 GUI 软件(GUI 是开源的,但库不是),虽然不算好用吧,但总比没有强。前两天我将 Libfetion 从 0.2.1 升级到 0.2.2 版,忽然发现不能用了,没法在 Linux 下答飞信题,在女友面前很没面子。

于是今天晚上就找了点儿时间将源代码下载下来,加 -g 编译,调试了一下。虽然没有文档帮助,找 bug 的过程还是相当之顺利,用 gdb 跑了三遍就定位到了问题所在,把问题解决,将 patch 提交给了 Libfetion 开发组

自从 0.2.2 更新之后, libfetion 在登录后就会直接退出,我调试了一下,发现其原因在于错误的先 delete 掉 longinWin 对象。下面是 patch:

$ diff -urN fxmain.cpp new_fxmain.cpp
--- fxmain.cpp        2008-07-05 22:48:22.000000000 +0800
+++ new_fxmain.cpp        2008-07-07 20:01:58.000000000 +0800
@@ -66,7 +66,7 @@
        isLoginIn = true;
        mainWin = new FxMainWindow(0);
        loginWin->hide();
-        delete loginWin;
        mainWin->show();
+        delete loginWin;
}

之所以提这件事情就是想说明一点开源软件的优越性:由于所有人都能得到源代码,遇到问题不必非得等官方的补丁,自己动手就可以解决;由于平台或工具的原因,有时候开发者未必意识到的错误,反而可以被某一特定用户解决。在这一点上,闭源软件要差很多,这也是我喜欢开源运动的原因之一。

在 Ubuntu Linux 8.04 上安装永中 Office 2007

这篇文章介绍了在 Ubuntu Linux 8.04上安装永中 Office 2007 遇到的问题以及解决的办法。由于其主要问题在于 Java 虚拟机,其它 Linux 平台如果遇到同样情况也可以借鉴这里的方法。

永中 Office 2007 Linux

目录

1. 介绍
2. 下载
3. 安装问题
4. 运行问题

1. 介绍

用 OpenOffice 总会遇到这样那样的中文问题,有时候怎么也搞不定,很令人沮丧。听说永中 Office 虽然只放出试用版,但在 Linux 下超过试用期后只会提示超期而不会禁止使用,就尝试着装了一下永中 Office。

2. 下载

从官方下载地址:http://www.evermoresw.com.cn/webch/download/downEIOffice.jsp 下载永中 Office 2007 Linux 安装包。

安装之后才知道 Ubuntu 中文源中有打包好的 deb 文件,要从源中直接安装就方便许多了。比如用 CN99 源的话,将:

deb http://ubuntu.cn99.com/ubuntu-cn hardy main restricted universe multiverse

加入 /etc/apt/sources.list 中,然后:

$ sudo apt-get install eio

即可。我没有尝试这一方法,从源直接安装显然不会出现下面的"3. 安装问题",但不知道会不会出现下面讨论的"4. 运行问题"。

3. 安装问题

下载好官方的 Office 2007 Linux 安装包之后,先解压:

$ tar -xzvf EIO2007BetaZH_Lin.tar.gz

然后,进入安装目录,执行安装脚本:

$ cd 4.3.1210.101ZH.L1/
$ sudo sh setup.sh

将会出现下面错误,而且安装窗口显示为空白(窗口空白可能是由于 Beryl 引起的 Java Swing 界面问题):

Decompression in Progress,Please Wait.
Locking assertion failure. Backtrace:
#0 /usr/lib/libxcb-xlib.so.0 [0xb2a66767]
#1 /usr/lib/libxcb-xlib.so.0(xcb_xlib_unlock+0x31) [0xb2a668b1]
...

这个问题可能因为永中 Office 使用自带的 JRE 和系统的某些库不匹配导致的,所以我们只需更改安装脚本,让它使用系统的 JRE。用编辑器(如 vim)打开 setup.sh,按照下面的方法注释掉解压和使用自带 JRE 的两行,添加一行使用系统 JRE 的命令。(注意:使用 gcj 的 jre 也会出现错误,最好使用 Sun 官方的 jre,Ubuntu 下使用 sudo apt-get install sun-java6-jre 安装。)

$ vim setup.sh
#unzip $progdir/Jre.zip -d /tmp/EIOffice/ &> /dev/null
#/tmp/EIOffice/Jre/bin/java -jar $progdir/dispose.jar $1
/usr/lib/jvm/java-6-sun/jre/bin/java -jar $progdir/dispose.jar $1

然后再执行 sudo sh setup.sh 命令,就能出现正常的安装窗口了。下面的安装步骤和 Windows 下软件的安装步骤颇为相似,只是选择安装路径那一项最好将 /usr/local 改成 /opt,因为永中 Office 不是开源软件。

4. 运行问题

安装完成后,运行永中 Office:
$ eio
Locking assertion failure. Backtrace:
#0 /usr/lib/libxcb-xlib.so.0 [0xb7d37767]
#1 /usr/lib/libxcb-xlib.so.0(xcb_xlib_unlock+0x31) [0xb7d378b1]
...

和刚开始安装时一样,出现下面错误,主窗口中也是空白。如前面所说,窗口空白可能是由于使用了 Beryl 窗口管理器引起的 Java Swing 界面问题,可以通过修改永中 Office 的启动文件解决,在 /usr/bin/eio 中正式代码前添加 export AWT_TOOLKIT=MToolkit 一行:

$ sudo vim /usr/bin/eio
#!/bin/bash
export AWT_TOOLKIT=MToolkit
exec 4<&0 0

GUCAS IP 网关 Linux 登录客户端版本 1.1 发布

CAS NET 是中科院内部 IP 控制网关的 Linux 登录客户端,此软件完全使用 Python 语言写成,同时支持命令行和图形界面,使用简单,安装方便,实乃中国科学院 Linux 使用者居家旅行必备之良品 :)。

官方主页

软件特性

  1. 同时提供源代码, .deb 和 .rpm 安装包,方便安装过程。
  2. 客户端同时具有命令行和图形界面,满足不同用户需要。
  3. 可设置选项多,可保存用户设置,登录简单快捷。
  4. 纯 Python 编程,修改简单,扩展性强,可移植到不同操作系统平台。
  5. 开放源代码,确保程序无后门。

最新版本 1.1-1(2008年5月9日发布) 更新

  1. 添加了窗口关闭按钮,关闭时最小化到 System Notification Area。
  2. 添加了 Status Icon 的右键菜单。
  3. 用户登录时自动强制退出在其它 IP 的连线。

Google Code

受到某同学的提醒,今天我把我的两个小项目中科院IP网关登录客户端《使用开源软件-自己动手写操作系统》源代码转移到了 Google Code 上。

CAS NET 本身就是遵从 GPL 协议的,所以我就将所有内容都转移到了 Google Code,原有的官方主页也设置了301永久重定向到 Google Code 页。

《使用开源软件-自己动手写操作系统》的电子书内容是遵从的 CC 协议,所以并没有将电子书的 TeX 源码放到 Google Code 上,只是将书中示例程序的源代码放了上去。原有的官方主页还保留,主要用做发布所有源码(TeX+Demo)用。虽然最近比较忙,第三章还是写了一部分,大概月底能发布第三章吧(不敢保证,因为期末考快到了!)。不像博客,写书总得需要大块的时间,而我能挤出来的时间确实不多。唉,我也想早点儿把它完成。

最近在申请两个公司的暑期实习生,微软和IBM。个人比较喜欢 IBM CRL 那个 Security 的职位,只是,现在由不得咱们挑啊!

在 Dell Latitude D630 上硬盘安装 Ubuntu Linux 8.04

最后更新时间:2008年4月18日

摘要

这份文档主要描述了我在自己的 Dell Latitude D630 上安装 Ubuntu Linux 8.04 的过程。

目录

1. 介绍
2. 安装
3. 效果截图
4. 总结

1. 介绍

虽然一直想忍着等 Ubuntu Linux 8.04(Hardy Heron) 正式发布了再安装它,但最后还是受不了诱惑,在还有 6 天就发布时候当了一次小白。这次 Ubuntu 真的是让我相当相当满意,安装过程什么问题都没有出,所有硬件均一步识别,太爽了!这次写的安装介绍,要比上次那篇简单多了,我真心希望以后的 Ubuntu 版本安装的时候再也不用看别人的安装介绍了。

而且这次 Ubuntu Studio 的 theme 也比 7.10 漂亮许多,Compiz-fusion 的 3D 桌面特效也更好了,真酷!兄弟姐妹们,来玩 Ubuntu 吧!

2. 安装

[安装基本操作系统]
由于我电脑上本来就有 Ubuntu 7.10 和 Cent OS 5.1,所以我的 Ubuntu 8.04 是通过修改 grub 的 menu.lst 来进行硬盘安装的。

首先,下载安装光盘镜像文件:
$ wget -c http://cdimage.ubuntu.com/daily/current/hardy-alternate-i386.iso
由于现在 Ubuntu 8.04 还没有正式发布,所以我是从 daily build 的地址下的,当看到这篇文章时可能它已经发布了,那就请到官方公布的地址下吧。

其次,下载硬盘安装文件:
$ wget http://archive.ubuntu.com/ubuntu/dists/hardy/main/installer-i386/current/images/hd-media/vmlinuz
$ wget http://archive.ubuntu.com/ubuntu/dists/hardy/main/installer-i386/current/images/hd-media/initrd.gz

将这三个文件放在某个分区根目录下,再修改 /boot/grub/menu.lst,在列表最后添加上以下几行:
title Ubuntu 8.04 Install Entry
root (hd0,3)
kernel /vmlinuz root=/dev/ram ramdisk_size=100000 devfs=mount,dall
initrd /initrd.gz
请注意第二行的(hd0,3)是指放镜像文件那个分区编号,请根据自己情况自行修改。一般情况下如果放到了 /dev/sdan 下的话,这个就应该是 (hd0,n-1)。

然后重启电脑,在 grub 中选择引导项 Ubuntu 8.04 Install Entry 进行安装,安装过程不赘述。我一般选择系统语言为英语,地域为中国。

[修改更新源列表]
选择速度最快的源,将 /etc/apt/sources.list 中默认的官方源替换掉,比如我的 sources.list 文件内容就是
deb http://debian.ustc.edu.cn/ubuntu/ hardy main restricted universe multiverse
deb http://debian.ustc.edu.cn/ubuntu/ hardy-updates main restricted universe multiverse
deb http://debian.ustc.edu.cn/ubuntu/ hardy-security main restricted multiverse universe
deb http://debian.ustc.edu.cn/ubuntu/ hardy-backports main restricted universe multiverse

[更新操作系统]
$ sudo apt-get update
$ sudo apt-get upgrade

[安装受限驱动]
在更新完操作系统后,System Notifacation Area(桌面右上角) 中会出现提示安装受限驱动的气泡,点击安装即可。

[安装中文输入法]
在 System->Administration->Language Support 中选择安装中文支持,并在下方勾选上 Enable support to enter complex characters. 系统会自动下载并安装中文支持和中文输入法,安装完后系统会要求重启,重启以后就可以在软件中直接用 Ctrl+Space 调出输入法了。^_^ 比以前的版本配置中文输入法简单太多了!!!

[安装 Windows XP 中文字体]
这是我写的一个小脚本,可以将双系统的 XP 字体拷贝到 Linux 下并使用它们。注意,这将涉及到版权问题,如果不确信的话,请跳过这一步。
$ wget http://share.solrex.org/scripts/install_win_CN_fonts_to_linux.sh
$ sudo sh install_win_CN_fonts_to_linux.sh
然后重新登录 X window

[安装 Ubuntu Studio 主题]
Ubuntu Studio 的黑色桌面主题是我非常喜欢的桌面主题,再配上诺贝尔和平奖得主戈尔的获奥斯卡最佳纪录片奖的电影 An Inconvenient Truth 的灰色背景海报,简直太配了。如果不喜欢,请跳过这一步。
$ sudo apt-get install ubuntustudio-theme
然后在 System->Preference->Appearance 中选择使用 Ubuntu Studio Theme。

[安装 Compiz-Fusion 3D 桌面特效引擎]
$ sudo apt-get install compiz-fusion-plugins-* compizconfig-settings-manager emerald
然后在 System->Preference->Advanced Desktop Effect Settings 中配置喜欢的桌面特效。

[安装 Mplayer/SMplayer 媒体播放器以及解码器]
$ sudo apt-get install mplayer smplayer
下载最新解码器:
$ wget -c http://www.mplayerhq.hu/MPlayer/releases/codecs/all-20071007.tar.bz2
将最新解码器库扔到 /usr/lib/win32 目录下:
$ tar -xjvf all-20071007.tar.bz2
$ sudo mkdir /usr/lib/win32
$ sudo mv all-20071007/* /usr/lib/win32
这样就可以使用 Mplayer/SMplayer 播放几乎任何格式的影片了。

[安装 星际译王(StarDict) 和辞典包]
$ sudo apt-get install stardict
然后到星际译王官方网站下载安装需要的辞典包

[安装 MP3 播放器 Amarok/xmms]
$ sudo apt-get install amarok

[安装 BBS 登录软件 Qterm]
$ sudo apt-get install qterm

[安装聊天工具 Pidgin, Eva]
$ sudo apt-get install pidgin eva

[安装邮件客户端 ThunderMail]
$ sudo apt-get install mozilla-thunderbird

[安装系统启动项管理软件 sysv-rc-conf]
$ sudo apt-get install sysv-rc-conf

[安装 vim 完全版(gvim)]
$ sudo apt-get install vim-full

[安装编译工具库, g++ 和 javac]
$ sudo apt-get install libc6-dev g++ g++-4.2 sun-java6-jdk

[安装压缩解压缩工具 unzip, unrar, 7zip]
$ sudo apt-get install unzip unrar p7zip-full

[安装 Internet 时间同步工具 ntp]
$ sudo apt-get install ntp

[安装程序开发工具 kscope, eclipse, SVN tool, 十六进制文本编辑器, 网络文件系统]
$ sudo apt-get install kscope eclipsesubversion hexedit nfs-client

[安装工程图画图工具]
$ sudo apt-get install dia kivio

[安装摄像头查看工具]
$ sudo apt-get install cheese

[安装 CHM 文件查看工具]
$ sudo apt-get install chmsee kchmviewer

[安装 tex 编辑编译工具]
$ sudo apt-get install texlive cjk-latex kile

[安装 dos unix 文件转换工具]
$ sudo apt-get install tofrodos

[安装 Adobe Reader]
$ sudo apt-get install acroread
如果上面命令不管用,用下面方法下载安装:
$ wget -c http://debian.cn99.com/ubuntu-cn/dists/gutsy/main/binary-i386/adobe/AdobeReader_chs-8.1.1-1.i386.deb
$ sudo dpkg -i AdobeReader_chs-8.1.1-1.i386.deb

3. 效果截图

Amarok 播放器

4. 总结

Ubuntu 8.04 对电脑硬件的支持又进了一步,至少在我以前曾经有问题的显卡和声卡上都没有出现问题,让人很开心。而更好看的桌面主题,更酷的 3D 桌面效果,更简化的安装过程,更完善的多语言支持,真的很赞,我相信 Ubuntu 将借此进一步巩固和扩大它在 Linux 桌面市场占有率。大家都来用 Ubuntu 吧,它可 Windows 酷多了!

中科院 IP 网关 Linux 登录客户端版本 1.0 发布

愚人节和大家开了个 小玩笑,不过这次可不是玩笑了。CAS NET 正式发布版本 1.0,官方主页:http://share.solrex.org/casnet/

CAS Net 是中科院内部 IP 控制网关的 Linux 登录客户端,此软件完全使用 Python 语言写成,同时支持命令行和图形界面,使用简单,安装方便,实乃中国科学院 Linux 使用者居家旅行必备之良品 :)。

最新版本(1.0)特性:

1. 客户端同时具有命令行和图形界面,满足不同用户需要。
2. 可设置选项多,拥有较高扩展性。
3. 可保存用户设置,登录简单快捷。
4. 纯 Python 编程,修改简单,扩展性强,可移植到不同操作系统平台。
5. 开放源代码,确保程序无后门。

软件效果截图:

Ubuntu 7.10 系统下截图
Ubuntu 7.10 系统下截图