<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>阿当正传 &#187; linux</title>
	<atom:link href="http://www.adamjiang.com/archives/tag/linux/feed" rel="self" type="application/rss+xml" />
	<link>http://www.adamjiang.com</link>
	<description>长脑袋的个人博客</description>
	<lastBuildDate>Tue, 15 May 2012 16:53:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>以Funtoo为基础的Linux桌面系统（2）</title>
		<link>http://www.adamjiang.com/archives/1154</link>
		<comments>http://www.adamjiang.com/archives/1154#comments</comments>
		<pubDate>Tue, 15 May 2012 16:53:14 +0000</pubDate>
		<dc:creator>jcadam</dc:creator>
				<category><![CDATA[Linux tips]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[源代码]]></category>
		<category><![CDATA[环境配置]]></category>
		<category><![CDATA[自由]]></category>

		<guid isPermaLink="false">http://www.adamjiang.com/?p=1154</guid>
		<description><![CDATA[构建自己的Linux桌面系统的第一步，就是根据Funtoo网站上提供的wiki页面，编译，安装和配置基础系统（base system）。这包括 制作一个SysRescureCD的live USB。&#187;详情 通过SysRescureCD提供的工具初始化硬盘，并且在硬盘上安装stage3——也就是最基础的根文件系统。 配置这个最基础的系统。 利用该文件系统提供的基础工具编译安装Linux内核。 安装grub2作为bootloader。 如果你对类Unix系统的基本概念非常了解，这个过程看上去应该是水到渠成的。安装的细节虽然无需多言，Funtoo提供的指南已经十分详尽，但这里却有一些非常有趣的概念值得讨论。 第一，这个安装过程的全部魔法都在chroot命令上。我一直以为这个命令是类Unix操作系统设计的精华之一。为什么这么说呢？众所周知，Linux操作系统对它的跟文件系统有一个必要的假设。即，根文件系统是一棵树。而这个树的根就是“/”。像硬盘，SSD之类的块设备可以通过“挂载”（mount）的方式，将实体的存储设备挂载到这棵逻辑中存在的树的任意节点上。当系统在这棵树上创建新文件或者修改任何既有内容时，这种变更就会被反映到实际的存储设备上。树结构的妙处在于，任意一棵子树和拥有该子树的“大树”总是相似的。当你将准备好的硬盘分区挂载到这棵树上，并且chroot进入这个树的子树，你就的到了一个全新的“根文件系统”。但于此同时，系统运行的却是原来大树中预装的Linux内核，由此来帮助新文件系统的生成。这种方法在Windows系统中听起来有点像天方夜谭但是在Linux系统中，却是司空见惯。采用这种方法可也在多个不同的根文件系统之间无缝的切换，比如，你可以在一个64位系统的根文件系统的某一棵子树上创建一个32位系统子树。这对于很多系统测试和环境搭建都不无裨益。一个典型的例子就是debian系统采用chroot的方式帮助开发者创建一个便于创建软件包的标准环境，由此，.deb包才可以避免现有系统不同配置的影响而适用与各种不同配置的系统。 第二，这个安装过程实际上那个暗示了如何从无到有得建造一个操作系统。Linux操作系统的发端就是1990年Linux写给邮件列表的那封信。在已有系统软件——包括编译器，链接器的帮助下，生产内核代码才是可能的。用软件来制造软件。这是一个非常自然的过程。我记得有一句话叫“以机器制造机器标志这第二次工业革命的开始”。而以软件制造软件也是现在软件行业的一个重要标志。也只有当这种衍生和扩展的能力和半导体的几何级数式的蓬勃发展结合起来的时候，这种能力才创造了极大的社会财富。 第三，一些配置和编译的选择也值得讨论一下。 首当其冲的就是UEFI和GPT分区。区别与传统的BIOS和MBR分区，这两个技术都有一些进步。GPT几乎是必要的（desirable）。但是，如果你的系统主板是建立在UEFI之上的话，Linux系统可能会遇到一些问题。这并不是Linux的错，而是因为大多说UEFI固件都缺乏必要的测试问题百出，以至于根本无法保证系统兼容性。对于后面这一点我实在没有什么好的建议，大概能说的只有一条，选择UEFI主板的时候一定要先调查一下再做决定。 创建分区和创建文件系统的分离是让那些在Windows中模糊成一团的操作系统概念变得更加清晰了。对文件系统的选择又是另一个问题。一般来说根据用户的实际应用应该选择不同的文件系统，比如，一些文件在处理“小文件”的时候有明显优势，一些文件系统有灵活配置的特性等等。当然，ext4文件系统适用于大多数桌面应用。虽然这个指南中仅仅提供了传统的采用/dev/sd*方式记述的/etc/fstab，但实际上Funtoo也支持UUID作为标记在/etc/fstab中使用。 对很多中文用户来说，键盘布局不是问题。因为，大多数在中国销售的计算机实际上是直接使用英语键盘布局的，所以/etc/conf.d/keymaps中采用默认值没有什么问题。我的情况比较特殊，因为日语键盘布局与英文键盘布局存在相当大的差异。我必须在上面提到的文件中制定键盘布局为jp106。如果你想在运行时改变系统的键盘布局，可以使用下面的命令。 setxkbmap xx ## xx 是两个字母的国家代码，比如us 当编译安装好的内核和基础系统可以启动以后，我尝试继续跟随Funtoo的指南对基础系统升级并且安装了X Server和必要的系统软件。这样，一个极简洁的Linux操作系统诞生了。]]></description>
			<content:encoded><![CDATA[<p>构建自己的Linux桌面系统的第一步，就是根据Funtoo网站上提供的<a href="http://www.funtoo.org/wiki/Funtoo_Linux_Installation" title="Funtoo installation" target="_blank">wiki页面</a>，编译，安装和配置基础系统（base system）。这包括</p>
<ul>
<li>制作一个SysRescureCD的live USB。&raquo;<a href="http://www.sysresccd.org/Sysresccd-manual-en_How_to_install_SystemRescueCd_on_an_USB-stick" target="_blank">详情</a></li>
<li>通过SysRescureCD提供的工具<a href="http://www.funtoo.org/wiki/Funtoo_Linux_Installation#Prepare_Hard_Disk" target="_blank">初始化硬盘</a>，并且在硬盘上<a href="http://www.funtoo.org/wiki/Funtoo_Linux_Installation#Installing_the_Stage_3_tarball" target="_blank">安装stage3</a>——也就是最基础的根文件系统。</li>
<li><a href="http://www.funtoo.org/wiki/Funtoo_Linux_Installation#Configuring_your_system" target="_blank">配置</a>这个最基础的系统。</li>
<li>利用该文件系统提供的基础工具<a href="http://www.funtoo.org/wiki/Funtoo_Linux_Installation#Configuring_and_installing_the_Linux_kernel" target="_blank">编译安装Linux内核</a>。</li>
<li><a href="http://www.funtoo.org/wiki/Funtoo_Linux_Installation#Installing_a_Bootloader" target="_blank">安装grub2</a>作为bootloader。</li>
</ul>
<p>如果你对类Unix系统的基本概念非常了解，这个过程看上去应该是水到渠成的。安装的细节虽然无需多言，Funtoo提供的指南已经十分详尽，但这里却有一些非常有趣的概念值得讨论。</p>
<p>第一，这个安装过程的全部魔法都在chroot命令上。我一直以为这个命令是类Unix操作系统设计的精华之一。为什么这么说呢？众所周知，Linux操作系统对它的跟文件系统有一个必要的假设。即，<a href="http://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard" target="_blank">根文件系统是一棵树</a>。而这个树的根就是“/”。像硬盘，SSD之类的块设备可以通过“挂载”（mount）的方式，将实体的存储设备挂载到这棵逻辑中存在的树的任意节点上。当系统在这棵树上创建新文件或者修改任何既有内容时，这种变更就会被反映到实际的存储设备上。树结构的妙处在于，任意一棵子树和拥有该子树的“大树”总是相似的。当你将准备好的硬盘分区挂载到这棵树上，并且chroot进入这个树的子树，你就的到了一个全新的“根文件系统”。但于此同时，系统运行的却是原来大树中预装的Linux内核，由此来帮助新文件系统的生成。这种方法在Windows系统中听起来有点像天方夜谭但是在Linux系统中，却是司空见惯。采用这种方法可也在多个不同的根文件系统之间无缝的切换，比如，你可以在一个64位系统的根文件系统的某一棵子树上创建一个32位系统子树。这对于很多系统测试和环境搭建都不无裨益。一个典型的例子就是debian系统采用<a href="http://wiki.debian.org/Debootstrap" target="_blank">chroot的方式</a>帮助开发者创建一个便于创建软件包的标准环境，由此，<code>.deb</code>包才可以避免现有系统不同配置的影响而适用与各种不同配置的系统。</p>
<p>第二，这个安装过程实际上那个暗示了如何从无到有得建造一个操作系统。Linux操作系统的发端就是1990年Linux写给邮件列表的那封信。在已有系统软件——包括编译器，链接器的帮助下，生产内核代码才是可能的。用软件来制造软件。这是一个非常自然的过程。我记得有一句话叫“以机器制造机器标志这第二次工业革命的开始”。而以软件制造软件也是现在软件行业的一个重要标志。也只有当这种衍生和扩展的能力和半导体的几何级数式的蓬勃发展结合起来的时候，这种能力才创造了极大的社会财富。</p>
<p>第三，一些配置和编译的选择也值得讨论一下。</p>
<p>首当其冲的就是UEFI和GPT分区。区别与传统的BIOS和MBR分区，这两个技术都有一些进步。GPT几乎是必要的（desirable）。但是，如果你的系统主板是建立在UEFI之上的话，Linux系统可能会遇到一些问题。这并<a href="https://plus.google.com/102150693225130002912/posts/QLe3tSmtSM4" target="_blank">不是Linux的错</a>，而是因为大多说UEFI固件都缺乏必要的测试问题百出，以至于根本无法保证系统兼容性。对于后面这一点我实在没有什么好的建议，大概能说的只有一条，选择UEFI主板的时候一定要先调查一下再做决定。</p>
<p>创建分区和创建文件系统的分离是让那些在Windows中模糊成一团的操作系统概念变得更加清晰了。对文件系统的选择又是另一个问题。一般来说根据用户的实际应用应该选择不同的文件系统，比如，一些文件在处理“小文件”的时候有明显优势，一些文件系统有灵活配置的特性等等。当然，ext4文件系统适用于大多数桌面应用。虽然这个指南中仅仅提供了传统的采用<code>/dev/sd*</code>方式记述的<code>/etc/fstab</code>，但实际上Funtoo也支持<a href="http://www.cyberciti.biz/faq/linux-finding-using-uuids-to-update-fstab/" target="_blank">UUID作为标记</a>在<code>/etc/fstab</code>中使用。</p>
<p>对很多中文用户来说，键盘布局不是问题。因为，大多数在中国销售的计算机实际上是直接使用英语键盘布局的，所以<code>/etc/conf.d/keymaps</code>中采用默认值没有什么问题。我的情况比较特殊，因为日语键盘布局与英文键盘布局存在相当大的差异。我必须在上面提到的文件中制定键盘布局为<code>jp106</code>。如果你想在运行时改变系统的键盘布局，可以使用下面的命令。</p>
<pre>setxkbmap xx   ## xx 是两个字母的国家代码，比如us</pre>
<p>当编译安装好的内核和基础系统可以启动以后，我尝试继续跟随Funtoo的指南<a href="http://www.funtoo.org/wiki/Funtoo_Linux_First_Steps" target="_blank">对基础系统升级并且安装了X Server和必要的系统软件</a>。这样，一个极简洁的Linux操作系统诞生了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamjiang.com/archives/1154/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>以Funtoo为基础的Linux桌面系统（1）</title>
		<link>http://www.adamjiang.com/archives/1140</link>
		<comments>http://www.adamjiang.com/archives/1140#comments</comments>
		<pubDate>Mon, 14 May 2012 15:46:09 +0000</pubDate>
		<dc:creator>jcadam</dc:creator>
				<category><![CDATA[Linux tips]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[源代码]]></category>
		<category><![CDATA[环境配置]]></category>

		<guid isPermaLink="false">http://www.adamjiang.com/?p=1140</guid>
		<description><![CDATA[这个系列的最初起源是一大堆牢骚。当我觉得自己拯救自己的时候，我问了自己这样的问题——如果Ubuntu是错的，那么什么样的桌面系统是对的？也许我尚未找到答案，但至少我觉得以下几点是一个优秀的Linux桌面系统必须具备的特性 源代码是开源软件的灵魂，优秀的包管理系统是强健的骨骼；这个系统必须无缝的升级并且尽可能的贴近源码。 桌面系统必须是轻量级的；它可以快速的启动和关闭。 使用什么样的应用程序应该由用户选择，而这些应用程序之间可以通过统一接口调用。 第一个要求将我引向了Gentoo。Gentoo Linux是以源代码为基础的发行版。它最重要的特色就是portage/emerge包管理系统。每一个Gentoo软件包全部都会在初次安装时从软件的源代码编译生成。每当软件推出新版本的时候，portage/emerge可以帮助用户重新编译并且安装新版本。同时，portage/emerge还可以根据用户的需要，安装同一个软件的多个不同版本。因为不需要二进制和打包的中间过程，这种升级就真正做到了“无缝”。因为系统组建之间之间无非就是动态链接和静态链接创建的简单耦合。所以，它也消除了以二进制文件为基础的包管理系统所创建的不必要的强耦合关系。这使得用户升级和调试单独软件包是获得了充分的自由。这种自由还体现在一种叫做Overlay的机制上。Overlay就是“覆盖”的意思。Gentoo通过这种机制让用户可以创建自己的软件包,并且将这些软件包按照一定的规则排列成树状结构来覆盖/定制官方默认的编译选项和软件特性。当然，用户也可以给自己的Overlay中添加新软件。很多用户在使用Gentoo的同时会创建自己的Overlay。我也将自己的对软件包的选择固化成了一个Overlay，你可以在这里找到它。Funtoo Linux是在Gentoo项目的基础上发展起来的新项目，它区别于Gentoo的最大特色在于以git为核心的软件包更新机制（虽然现在Gentoo也支持以git为基础的同步和升级）。除此以外，Funtoo还提供了比Gentoo更优秀的用户辅助工具——比如boot-update，所以我选择了Funtoo作为基础来建造自己的桌面系统。 对于第二个问题，我的答案是Openbox。为什么不是Gnome或者KDE这样的Desktop environment？因为Gnome项目已经“误入歧途”，至少这是我通过观察得到的结论。而KDE却也不能称作“轻量级”。那么只有在众多的Window Manager（窗口管理器）中选择一款了。我最初尝试了Fluxbox，它非常优秀，可是对于cjk用户并不友好，因为我的Firefox的窗口标题连不能显示中文或者日语这些双字节文字。于是理所当然的，我选择了Openbox。Openbox的开发相对活跃，并且拥有广泛的用户基础。很多发行版都提供了Openbox软件，更有一款非常引人注目的Crunchbang发行版将Openbox作为桌面系统解决方案的基础。这也正是我学习的对象。 最后一点是最贴近用户的问题。每个人对软件的偏好不一样，所以，桌面系统中使用什么样的软件应该由用户自己来决定。一个Web开发者的桌面系统和一个Android开发者的桌面系统应当有很大的区别。比如，前者可能需要curl，bluefish，python/PHP编辑器和多个不同的浏览器——采用wine或者虚拟机安装的IE，不同版本的Firefox和Chrome——等等；而后者，则需要编译Android软件的必要的库和工具，可以运行虚拟机的Java环境，eclipse集成开发环境等等。核心工具集以外的软件，在大多数情况下只能被称作“冗余”而别无他用。当Ubuntu一股脑塞给我OpenOffice套件和Evolution的时候，往往我在安装结束后做的第一件事情就是卸载掉这些冗余。另一个问题是应用程序之间的接口。比如，Windows的COM组件，还有Mac OS的Apple Script，它们都提供了一个完全或者不完全的统一接口来解决应用程序之间通信和“宏操作”的问题。Linux桌面也同样必须拥有这样的机制，否则可能连copy/paste操作也是问题。DBus就是解决这个问题的不二之选。]]></description>
			<content:encoded><![CDATA[<p>这个系列的最初起源是一大堆<a href="http://www.adamjiang.com/archives/1125" target="_blank">牢骚</a>。当我觉得自己拯救自己的时候，我问了自己这样的问题——如果Ubuntu是错的，那么什么样的桌面系统是对的？也许我尚未找到答案，但至少我觉得以下几点是一个优秀的Linux桌面系统必须具备的特性</p>
<ul>
<li>源代码是开源软件的灵魂，优秀的包管理系统是强健的骨骼；这个系统必须无缝的升级并且尽可能的贴近源码。</li>
<li>桌面系统必须是轻量级的；它可以快速的启动和关闭。</li>
<li>使用什么样的应用程序应该由用户选择，而这些应用程序之间可以通过统一接口调用。</li>
</ul>
<p>第一个要求将我引向了Gentoo。Gentoo Linux是以源代码为基础的发行版。它最重要的特色就是portage/emerge包管理系统。每一个Gentoo软件包全部都会在初次安装时从软件的源代码编译生成。每当软件推出新版本的时候，portage/emerge可以帮助用户重新编译并且安装新版本。同时，portage/emerge还可以根据用户的需要，安装同一个软件的多个不同版本。因为不需要二进制和打包的中间过程，这种升级就真正做到了“无缝”。因为系统组建之间之间无非就是动态链接和静态链接创建的简单耦合。所以，它也消除了以二进制文件为基础的包管理系统所创建的不必要的强耦合关系。这使得用户升级和调试单独软件包是获得了充分的自由。这种自由还体现在一种叫做Overlay的机制上。Overlay就是“覆盖”的意思。Gentoo通过这种机制让用户可以创建自己的软件包,并且将这些软件包按照一定的规则排列成树状结构来覆盖/定制官方默认的编译选项和软件特性。当然，用户也可以给自己的Overlay中添加新软件。很多用户在使用Gentoo的同时会创建自己的Overlay。我也将自己的对软件包的选择固化成了一个Overlay，你可以在<a href="https://github.com/jcadam/picky-overlay" target="_blank">这里</a>找到它。<a href="http://www.funtoo.org/wiki/Welcome" target="_blank">Funtoo Linux</a>是在Gentoo项目的基础上发展起来的新项目，它区别于Gentoo的最大特色在于以git为核心的软件包更新机制（虽然现在Gentoo也支持以git为基础的同步和升级）。除此以外，Funtoo还提供了比Gentoo更优秀的用户辅助工具——比如boot-update，所以我选择了Funtoo作为基础来建造自己的桌面系统。</p>
<p>对于第二个问题，我的答案是Openbox。为什么不是Gnome或者KDE这样的Desktop environment？因为Gnome项目已经“误入歧途”，至少这是我通过观察得到的结论。而KDE却也不能称作“轻量级”。那么只有在众多的Window Manager（窗口管理器）中选择一款了。我最初尝试了Fluxbox，它非常优秀，可是对于cjk用户并不友好，因为我的Firefox的窗口标题连不能显示中文或者日语这些双字节文字。于是理所当然的，我选择了Openbox。Openbox的开发相对活跃，并且拥有广泛的用户基础。很多发行版都提供了Openbox软件，更有一款非常引人注目的<a href="http://crunchbanglinux.org/" target="_blank">Crunchbang</a>发行版将Openbox作为桌面系统解决方案的基础。这也正是我学习的对象。</p>
<p>最后一点是最贴近用户的问题。每个人对软件的偏好不一样，所以，桌面系统中使用什么样的软件应该由用户自己来决定。一个Web开发者的桌面系统和一个Android开发者的桌面系统应当有很大的区别。比如，前者可能需要curl，bluefish，python/PHP编辑器和多个不同的浏览器——采用wine或者虚拟机安装的IE，不同版本的Firefox和Chrome——等等；而后者，则需要编译Android软件的必要的库和工具，可以运行虚拟机的Java环境，eclipse集成开发环境等等。核心工具集以外的软件，在大多数情况下只能被称作“冗余”而别无他用。当Ubuntu一股脑塞给我OpenOffice套件和Evolution的时候，往往我在安装结束后做的第一件事情就是卸载掉这些冗余。另一个问题是应用程序之间的接口。比如，Windows的COM组件，还有Mac OS的Apple Script，它们都提供了一个完全或者不完全的统一接口来解决应用程序之间通信和“宏操作”的问题。Linux桌面也同样必须拥有这样的机制，否则可能连copy/paste操作也是问题。DBus就是解决这个问题的不二之选。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamjiang.com/archives/1140/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows的Copycat及其他</title>
		<link>http://www.adamjiang.com/archives/1125</link>
		<comments>http://www.adamjiang.com/archives/1125#comments</comments>
		<pubDate>Sun, 13 May 2012 14:45:27 +0000</pubDate>
		<dc:creator>jcadam</dc:creator>
				<category><![CDATA[技术漫谈]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[源代码]]></category>
		<category><![CDATA[自由]]></category>

		<guid isPermaLink="false">http://www.adamjiang.com/?p=1125</guid>
		<description><![CDATA[Ubuntu 12.04发布以后，这个Linux发行版就彻底地让我失望了。臃肿的身躯加上人机交互混沌的令人发指的Unity桌面，已经跟我需要的Linux桌面系统已经相去甚远。沙扬挪拉，Ubuntu。作为一个从6.04开始使用Ubuntu的用户，我不得不跟这个桌面系统说一声再见了。不是因为它在Xeon(R) CPU E31240 + Dual-channel 8GB内存的PC上居然启动的比Windows 7还慢，也不是因为它让我连应用程序菜单在哪里都找不到，只是因为它越来越像一个Windows的Copycat。 也许Ubuntu深受很多从Windows系统迁移过来的超级用户喜爱，但是它却已经失去了很多真正的Linux Users。Linux用户与Windows用户最根本区别的在于，前者确切地知道自己真正需要什么并且知道如何获得和实现他们自身的需要——因为开源软件提供了这种自由，而后者则恰恰相反。Windows从诞生以来就是救世主，它给你一切，让你毫不怀疑的享受这种安逸，让你无法主动地寻找自己的真正需要。由此，它越来臃肿越来越庞大越来越多的消耗更多的包括硬盘，内存和计算能力在内的系统资源。其实我并不单独厌恶Windows的这种给与和扩张，因为几乎所有的商业软件都具有极强的扩张性——比如很多字处理软件都包含拼写检查这个重复的功能，而我真正厌恶的是它对用户自由的侵害。为什么这么说？因为它们将用户假设为无法学习的群体，与Windows交互的最宏观的过程可以总结为“You pay, you go”。所有的软件问题都是需要钱才能解决，而且最根本的这些问题只能由拥有源代码的私有公司解决。这是最基础的假设。如果说，对于一个家庭主妇或者某位非计算机行业/专业人士，这大概没有什么问题。但是，在这种环境之中成长起来的程序员却会慢慢失去学习的意愿和能力。如果你想用“我要将目光集中到我自己的业务上去”这样的话来辩驳的时候，你已经错了，如果你是一位程序员的话。因为那些用来调查和调整系统错误的时间——所谓的“浪费”——事实上一种必备的能力。因为你需要知道计算机的一切！ “&#8230;&#8230;，我从来不把安逸和快乐看作是生活目的的本身——这种伦理基础我叫它猪栏理想。” ——爱因斯坦 对一个人来说，停止思考之日便是他的死亡之时。对程序员来说更是如此。闭源软件正在带着停止思考的你我渐渐死去。 Ubuntu有了软件商店，这是一件好事。它本来有机会开拓一个新的开源软件的开发模式。但不幸的是它却偏离的开放源代码软件的初衷。开源软件真正的意义在于“开放源代码”！而不是“免费”。假设，你买到Photoshop套件的同时可以获得它的源码，难道你不开心么，难道你不想要这样的软件么？我想有人会提到“盗版”。看上去会很复杂，但“盗版”和开源事实上不是同一个命题。闭源软件同样会被盗版。真正保护版权的是适当的法律和严格的执行。不要跟我提中国市场上猖獗的盗版，因为中国软件市场，软件人才事实上是被上述猪栏思想和猖獗的盗版所戕害的。 没有哪个商业操作系统或者Linux发行版能够提供给你那个你确切需要的软件平台。只有自己动手，对，就是自己动手，你才有可能重新控制并且掌握你的计算机，才能享受到开源软件提供给你的自由。Ubuntu 6.04推出的时候，它最成功的地方不是它的liveCD，而是那个有大约3000多行的HOWTO——一个简洁明快的Wikipage。它提供给用户一个运行良好的基础系统，并且提供了多达2万的可选软件包。它还写了一份翔实的文档帮助你定制自己的系统。这就是最初的Ubuntu。如果它要模范Windows，或者像Mac OS那样仅仅将开源软件作为架子想“给用户一切”，那它就完全错了。 一声看似潇洒的沙扬挪拉不会解决任何问题。作为一个Linux User我只有自己救自己。]]></description>
			<content:encoded><![CDATA[<p>Ubuntu 12.04发布以后，这个Linux发行版就彻底地让我失望了。臃肿的身躯加上人机交互混沌的令人发指的Unity桌面，已经跟我需要的Linux桌面系统已经相去甚远。沙扬挪拉，Ubuntu。作为一个从6.04开始使用Ubuntu的用户，我不得不跟这个桌面系统说一声再见了。不是因为它在Xeon(R) CPU E31240 + Dual-channel 8GB内存的PC上居然启动的比Windows 7还慢，也不是因为它让我连应用程序菜单在哪里都找不到，只是因为它越来越像一个Windows的Copycat。</p>
<p>也许Ubuntu深受很多从Windows系统迁移过来的超级用户喜爱，但是它却已经失去了很多真正的Linux Users。Linux用户与Windows用户最根本区别的在于，前者确切地知道自己真正需要什么并且知道如何获得和实现他们自身的需要——因为开源软件提供了这种自由，而后者则恰恰相反。Windows从诞生以来就是救世主，它给你一切，让你毫不怀疑的享受这种安逸，让你无法主动地寻找自己的真正需要。由此，它越来臃肿越来越庞大越来越多的消耗更多的包括硬盘，内存和计算能力在内的系统资源。其实我并不单独厌恶Windows的这种给与和扩张，因为几乎所有的商业软件都具有极强的扩张性——比如很多字处理软件都包含拼写检查这个重复的功能，而我真正厌恶的是它对用户自由的侵害。为什么这么说？因为它们将用户假设为无法学习的群体，与Windows交互的最宏观的过程可以总结为“You pay, you go”。所有的软件问题都是需要钱才能解决，而且最根本的这些问题只能由拥有源代码的私有公司解决。这是最基础的假设。如果说，对于一个家庭主妇或者某位非计算机行业/专业人士，这大概没有什么问题。但是，在这种环境之中成长起来的程序员却会慢慢失去学习的意愿和能力。如果你想用“我要将目光集中到我自己的业务上去”这样的话来辩驳的时候，你已经错了，如果你是一位程序员的话。因为那些用来调查和调整系统错误的时间——所谓的“浪费”——事实上一种必备的能力。因为你需要知道计算机的一切！</p>
<p style="background-color: #B8B8B8">
“&#8230;&#8230;，我从来不把安逸和快乐看作是生活目的的本身——这种伦理基础我叫它猪栏理想。” ——爱因斯坦
</p>
<p>对一个人来说，停止思考之日便是他的死亡之时。对程序员来说更是如此。闭源软件正在带着停止思考的你我渐渐死去。</p>
<p>Ubuntu有了软件商店，这是一件好事。它本来有机会开拓一个新的开源软件的开发模式。但不幸的是它却偏离的开放源代码软件的初衷。开源软件真正的意义在于“开放源代码”！而不是“免费”。假设，你买到Photoshop套件的同时可以获得它的源码，难道你不开心么，难道你不想要这样的软件么？我想有人会提到“盗版”。看上去会很复杂，但“盗版”和开源事实上不是同一个命题。闭源软件同样会被盗版。真正保护版权的是适当的法律和严格的执行。不要跟我提中国市场上猖獗的盗版，因为中国软件市场，软件人才事实上是被上述猪栏思想和猖獗的盗版所戕害的。</p>
<p>没有哪个商业操作系统或者Linux发行版能够提供给你那个你确切需要的软件平台。只有自己动手，对，就是自己动手，你才有可能重新控制并且掌握你的计算机，才能享受到开源软件提供给你的自由。Ubuntu 6.04推出的时候，它最成功的地方不是它的liveCD，而是那个有大约3000多行的HOWTO——一个简洁明快的Wikipage。它提供给用户一个运行良好的基础系统，并且提供了多达2万的可选软件包。它还写了一份翔实的文档帮助你定制自己的系统。这就是最初的Ubuntu。如果它要模范Windows，或者像Mac OS那样仅仅将开源软件作为架子想“给用户一切”，那它就完全错了。</p>
<p>一声看似潇洒的沙扬挪拉不会解决任何问题。作为一个Linux User我只有自己救自己。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamjiang.com/archives/1125/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>在mutt中使用Gmail地址簿</title>
		<link>http://www.adamjiang.com/archives/1101</link>
		<comments>http://www.adamjiang.com/archives/1101#comments</comments>
		<pubDate>Fri, 23 Dec 2011 06:54:51 +0000</pubDate>
		<dc:creator>jcadam</dc:creator>
				<category><![CDATA[Linux tips]]></category>
		<category><![CDATA[contact]]></category>
		<category><![CDATA[gmail]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mutt]]></category>

		<guid isPermaLink="false">http://www.adamjiang.com/?p=1101</guid>
		<description><![CDATA[这又是关于mutt的记事。公司的IT着实非常落后，至今我们仍在使用微软的Office outlook作邮件客户端。没有gmail，没有webmail，倒是直到上周才为每位员工购买了一款叫做Good的Android软件来查看邮件。可是无论怎样，mutt一直是我钟爱的一款邮件客户端。它已经长在我的手指上。现在在公司的开发机器上我已经可以使用IMAP和SMTP收发邮件，也可以在mutt中使用全公司的LDAP来查找地址，所以，整个功能跟低效的Outlook没有区别，处理邮件的速度却比使用Outlook提高了至少两倍。特别是遇到跟工程师之间通信需要贴代码或者发git patch的时候尤其如此。当通过mutt使用自己的gmail的时候，我遇到了一问题，就是Gmail本身并没有提供LDAP接口用来查询地址，于是我无法套用使用公司邮件的配置来查找地址了。昨天在github上发现了一个perl脚本可以解决这个问题。 Gmail提供了API可以帮助外部应用程序取得地址簿中的数据。Ajnasz的这个脚本可以取得地址簿数据并且用查询字符串匹配，从而找到联系人的邮件地址。但是，但是原来的脚本有一个小问题——无法使用中文或者日语姓名作为查询字符串。自己动手，丰衣足食。我在原代码的基础只添加了两行代码，现在查询中文姓名也没有问题了。如果你有兴趣可以从这里拿到代码。 git clone git://github.com/jcadam/Google-Contacts-for-Mutt.git gc-mutt 这个脚本需要一个简单的配置文件用来取得Gmail数据的访问权限。你可以仿照下面这个例子做自己的配置文件。 $ vi ~/.google.ini [account] email = 'youraccount@gmail.com' password = 'Passw0rd' 为了防止其他用户访问你的文件增强安全，你可将文件的属性设置成所有者只读。 $ chmod 400 ~/.google.ini 进入contacts.pl脚本所在目录，然后不带任何参数运行这个脚本，你就可以得到整个Gmail联系人名簿。可以先测试一下。 $ cd $ ./contacts.pl 接着，在PATH变量中的任何一个目录中，通常是/usr/local/bin/或者~/bin，建立一个Shell helper了查询数据。 $ vi ~/bin/contracts #!/usr/bin/env bash ${HOME}/github/gc-mutt/contacts.pl ${1} 然后告诉mutt查询联系人时使用这个helper脚本查询。在~/.muttrc中添加如下一行即可。 set query_command="~/bin/contacts '%s'" 测试一下。在mutt中新建邮件(m)，在To:栏中直接输入联系人的名字，比如”Mark Brown”， 然后按”ctrl-t”查找地址簿。 mutt会自动查询地址布并且取回Mark的邮件地址。]]></description>
			<content:encoded><![CDATA[<p>这又是关于mutt的记事。公司的IT着实非常落后，至今我们仍在使用微软的Office outlook作邮件客户端。没有gmail，没有webmail，倒是直到上周才为每位员工购买了一款叫做Good的Android软件来查看邮件。可是无论怎样，mutt一直是我钟爱的一款邮件客户端。它已经长在我的手指上。现在在公司的开发机器上我已经可以使用IMAP和SMTP收发邮件，也可以在mutt中使用全公司的LDAP来查找地址，所以，整个功能跟低效的Outlook没有区别，处理邮件的速度却比使用Outlook提高了至少两倍。特别是遇到跟工程师之间通信需要贴代码或者发git patch的时候尤其如此。当通过mutt使用自己的gmail的时候，我遇到了一问题，就是Gmail本身并没有提供LDAP接口用来查询地址，于是我无法套用使用公司邮件的配置来查找地址了。昨天在github上发现了一个perl脚本可以解决这个问题。</p>
<p>Gmail提供了API可以帮助外部应用程序取得地址簿中的数据。<a href="https://github.com/Ajnasz">Ajnasz</a>的这个脚本可以取得地址簿数据并且用查询字符串匹配，从而找到联系人的邮件地址。但是，但是原来的脚本有一个小问题——无法使用中文或者日语姓名作为查询字符串。自己动手，丰衣足食。我在原代码的基础只添加了两行代码，现在查询中文姓名也没有问题了。如果你有兴趣可以从<a href="http://github.com/jcadam/Google-Contacts-for-Mutt">这里</a>拿到代码。</p>
<pre>
git clone git://github.com/jcadam/Google-Contacts-for-Mutt.git gc-mutt
</pre>
<p>这个脚本需要一个简单的配置文件用来取得Gmail数据的访问权限。你可以仿照下面这个例子做自己的配置文件。</p>
<pre>
$ vi ~/.google.ini
</pre>
<pre>
[account]
email = 'youraccount@gmail.com'
password = 'Passw0rd'
</pre>
<p>为了防止其他用户访问你的文件增强安全，你可将文件的属性设置成所有者只读。</p>
<pre>
$ chmod 400 ~/.google.ini
</pre>
<p>进入contacts.pl脚本所在目录，然后不带任何参数运行这个脚本，你就可以得到整个Gmail联系人名簿。可以先测试一下。</p>
<pre>
$ cd <where_gc-mutt_is>
$ ./contacts.pl
</pre>
<p>接着，在PATH变量中的任何一个目录中，通常是/usr/local/bin/或者~/bin，建立一个Shell helper了查询数据。</p>
<pre>
$ vi ~/bin/contracts
</pre>
<pre>
#!/usr/bin/env bash
${HOME}/github/gc-mutt/contacts.pl ${1}
</pre>
<p>然后告诉mutt查询联系人时使用这个helper脚本查询。在~/.muttrc中添加如下一行即可。</p>
<pre>
set query_command="~/bin/contacts '%s'"
</pre>
<p>测试一下。在mutt中新建邮件(m)，在<code>To:</code>栏中直接输入联系人的名字，比如”Mark Brown”，</p>
<p><a href="http://www.adamjiang.com/wp-content/uploads/2011/12/mutt-1.png"><img src="http://www.adamjiang.com/wp-content/uploads/2011/12/mutt-1.png" alt="" title="mutt-1" width="595" height="57" class="alignnone size-full wp-image-1103" /></a></p>
<p>然后按”ctrl-t”查找地址簿。</p>
<p><a href="http://www.adamjiang.com/wp-content/uploads/2011/12/mutt-2.png"><img src="http://www.adamjiang.com/wp-content/uploads/2011/12/mutt-2.png" alt="" title="mutt-2" width="422" height="57" class="alignnone size-full wp-image-1104" /></a></p>
<p>mutt会自动查询地址布并且取回Mark的邮件地址。</p>
<p><a href="http://www.adamjiang.com/wp-content/uploads/2011/12/mutt-3.png"><img src="http://www.adamjiang.com/wp-content/uploads/2011/12/mutt-3.png" alt="" title="mutt-3" width="447" height="50" class="alignnone size-full wp-image-1105" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamjiang.com/archives/1101/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>﻿Gmail证书变更导致的msmtp错误</title>
		<link>http://www.adamjiang.com/archives/858</link>
		<comments>http://www.adamjiang.com/archives/858#comments</comments>
		<pubDate>Fri, 28 May 2010 09:56:45 +0000</pubDate>
		<dc:creator>jcadam</dc:creator>
				<category><![CDATA[Linux tips]]></category>
		<category><![CDATA[gmail]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mutt]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.adamjiang.com/?p=858</guid>
		<description><![CDATA[大约一年前我写了《通过mutt使用gmail》，之后因为更换新机器有没有时间再将 mutt等工具配置起来；今天重新在新的gentoo系统上配置Mutt使用gmail却发现原 来的方法出错了。 错误消息如下 msmtp: TLS certificate verification failed: the certificate hasn’t got a known issuer. 很显然，google将gmail的cert变更了。单纯的使用msmtp确认一下： % msmtp --serverinfo --host=smtp.gmail.com --tls=on --port=587 --tls-certcheck=off SMTP server at smtp.gmail.com ([74.125.53.109]), port 587: mx.google.com ESMTP r20sm18086225wam.17 TLS certificate information: Owner: Common Name: smtp.gmail.com Organization: Google Inc Locality: Mountain View State or Province: California Country: US Issuer: Common [...]]]></description>
			<content:encoded><![CDATA[<p>大约一年前我写了《<a title="通过mutt使用gmail" href="http://www.adamjiang.com/archives/33" target="_blank">通过mutt使用gmail</a>》，之后因为更换新机器有没有时间再将</p>
<p>mutt等工具配置起来；今天重新在新的gentoo系统上配置Mutt使用gmail却发现原<br />
来的方法出错了。</p>
<p>错误消息如下</p>
<pre>msmtp: TLS certificate verification failed: the certificate hasn’t got a
known issuer.</pre>
<p>很显然，google将gmail的cert变更了。单纯的使用msmtp确认一下：</p>
<pre>% msmtp --serverinfo --host=smtp.gmail.com --tls=on --port=587 --tls-certcheck=off
SMTP server at smtp.gmail.com ([74.125.53.109]), port 587:
    mx.google.com ESMTP r20sm18086225wam.17
TLS certificate information:
    Owner:
        Common Name: smtp.gmail.com
        Organization: Google Inc
        Locality: Mountain View
        State or Province: California
        Country: US
    Issuer:
        Common Name: Google Internet Authority
        Organization: Google Inc
        Country: US
    Validity:
        Activation time: 2010年04月23日 05時02分45秒
        Expiration time: 2011年04月23日 05時12分45秒
    Fingerprints:
        SHA1: 1A:6F:48:8F:BE:5B:FD:92:D8:12:30:F9:22:CE:84:49:B3:43:BD:2C
        MD5:  60:39:DE:FB:0A:D9:9E:43:26:E7:75:AC:60:48:A1:B0
Capabilities:
    SIZE 35651584:
        Maximum message size is 35651584 bytes = 34.00 MB
    STARTTLS:
        Support for TLS encryption via the STARTTLS command
    AUTH:
        Supported authentication methods:
        PLAIN LOGIN</pre>
<p>之前使用过的Thwate Server已经过期了，Issuer字段变成了由google之间给<br />
cert。:(</p>
<p>幸好，修复这个错误非常容易，在debain或者ubuntu系统上可以安装<br />
ca-certificates包来修复这个错误。</p>
<pre># sudo apt-get install ca-certificates
# dpkg -s ca-certificates | grep Version
Version: 20090814</pre>
<p>然后，只要更改~/.msmtprc文件就可以了，将tls_trust_file改正为</p>
<pre>tls_trust_file /usr/share/ca-certificates/mozilla/Equifax_Secure_CA.crt</pre>
<p>gentoo用户需要将这个文件download下来，并且重新指定tls的位置：</p>
<p><a href="http://sysinf0.klabs.be/usr/share/ca-certificates/mozilla/Equifax_Secure_CA.crt?f=download;dist=etch;component=main;arch=i386;pkg=ca-certificates;ver=20070303" title="Equifax_Secure_CA.crt"></p>
<p>http://sysinf0.klabs.be/usr/share/ca-certificates/mozilla/Equifax_Secure_CA.crt?f=download;dist=etch;component=main;arch=i386;pkg=ca-certificates;ver=20070303</p>
<p></a></p>
<p>P.S. 博客并不适合用来记录这样内容，但是，前一篇gmail相关文章已经贴到了博<br />
客，照例还是帖一篇上来吧，各位见谅。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamjiang.com/archives/858/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux内核代码阅读序列(10)-内存模型 之二</title>
		<link>http://www.adamjiang.com/archives/818</link>
		<comments>http://www.adamjiang.com/archives/818#comments</comments>
		<pubDate>Fri, 08 Jan 2010 09:19:10 +0000</pubDate>
		<dc:creator>jcadam</dc:creator>
				<category><![CDATA[Linux kernel]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.adamjiang.com/?p=818</guid>
		<description><![CDATA[内存区段 x86结构CPU上采用了一种叫内存区段的方式来寻址，这样做最大的好处就是可以保护内存中的内容不被非法访问，在这种内存模型中某个地址可以被表示成两部分，线性地址由这两部分计算得出。 LinearAddress = BaseAddress of Segmentation + Offset 其中，段基值存储在段基值寄存器当中，其值总是指向当前正在使用的内存区域的基地址；在x86处理器的32位保护模式中，一个区段的大小时4GB；这是因为32位CPU上，段基值寄存器的位宽是32位(2^32=4G)。x86的原始设计包含三个段基址寄存器， CS Register:CodeSeg 指令段基址寄存器 DS Register:DataSeg 数据段基址寄存器 SS Register:StackSeg 栈段基址寄存器 同时，x86结构上将一个被叫做段描述符(Segmentation Descriptor)的东西存储在两个表(GDT和LDT)之中，需要使用时从表中取出段描述符来找到线性地址；因为Linux操作系统最初的设计目标就是支持x86结构的计算机，所以，Linux内核在构建内存模型的时候也采取了内存区段的方式，但是，为了简化设计和提高可以执行，内核的做法是只保留一个存储段描述符的表(GDT)和一个段基址寄存器，从而让所有的段都开始于同一个位置，而段的大小也正好成为4GB，也就是一般情况下的整个线性地址空间的大小。正因为如此，在大多数情况下，逻辑地址就可以直接被看作线性地址来使用，而逻辑地址到线性地址的转换事实上时内核或者CPU在对用户透明的情况下完成的，这个转换过程不需要特别注意。需要注意的是这里提到的这些名词，以及那个小学算数一般的地址计算方法。此外，Linux内核代码使用的内存区段和若干个宏也最好记住，因为你知道，好记性对一个程序员来说真tmd重要。 Name Macro Base Limit G S Type DPL KernelCodeSeg __KERNEL_CS 0&#215;00000000 0xffffffff 1 1 0xa 0 KernelDataSeg __KERNEL_DS 0&#215;00000000 0xffffffff 1 1 0&#215;10 0 UserCodeSeg __USER_DS 0&#215;00000000 0xffffffff 1 1 0xa 3 UserDataSeg __USER_DS [...]]]></description>
			<content:encoded><![CDATA[<h4>内存区段</h4>
<p>x86结构CPU上采用了一种叫内存区段的方式来寻址，这样做最大的好处就是可以保护内存中的内容不被非法访问，在这种内存模型中某个地址可以被表示成两部分，线性地址由这两部分计算得出。</p>
<pre>LinearAddress = BaseAddress of Segmentation + Offset</pre>
<p>其中，段基值存储在段基值寄存器当中，其值总是指向当前正在使用的内存区域的基地址；在x86处理器的32位保护模式中，一个区段的大小时4GB；这是因为32位CPU上，段基值寄存器的位宽是32位(2^32=4G)。x86的原始设计包含三个段基址寄存器，</p>
<ul>
<li>CS Register:CodeSeg 指令段基址寄存器</li>
<li>DS Register:DataSeg 数据段基址寄存器</li>
<li>SS Register:StackSeg 栈段基址寄存器</li>
</ul>
<p>同时，x86结构上将一个被叫做段描述符(Segmentation Descriptor)的东西存储在两个表(GDT和LDT)之中，需要使用时从表中取出段描述符来找到线性地址；因为Linux操作系统最初的设计目标就是支持x86结构的计算机，所以，Linux内核在构建内存模型的时候也采取了内存区段的方式，但是，为了简化设计和提高可以执行，内核的做法是只保留一个存储段描述符的表(GDT)和一个段基址寄存器，从而让所有的段都开始于同一个位置，而段的大小也正好成为4GB，也就是一般情况下的整个线性地址空间的大小。正因为如此，在大多数情况下，逻辑地址就可以直接被看作线性地址来使用，而逻辑地址到线性地址的转换事实上时内核或者CPU在对用户透明的情况下完成的，这个转换过程不需要特别注意。需要注意的是这里提到的这些名词，以及那个小学算数一般的地址计算方法。此外，Linux内核代码使用的内存区段和若干个宏也最好记住，因为你知道，好记性对一个程序员来说真tmd重要。</p>
<table border="1">
<thead>
<tr>
<td>Name</td>
<td>Macro</td>
<td>Base</td>
<td>Limit</td>
<td>G</td>
<td>S</td>
<td>Type</td>
<td>DPL</td>
</tr>
</thead>
<tbody>
<tr>
<td>KernelCodeSeg</td>
<td>__KERNEL_CS</td>
<td>0&#215;00000000</td>
<td>0xffffffff</td>
<td>1</td>
<td>1</td>
<td>0xa</td>
<td>0</td>
</tr>
<tr>
<td>KernelDataSeg</td>
<td>__KERNEL_DS</td>
<td>0&#215;00000000</td>
<td>0xffffffff</td>
<td>1</td>
<td>1</td>
<td>0&#215;10</td>
<td>0</td>
</tr>
<tr>
<td>UserCodeSeg</td>
<td>__USER_DS</td>
<td>0&#215;00000000</td>
<td>0xffffffff</td>
<td>1</td>
<td>1</td>
<td>0xa</td>
<td>3</td>
</tr>
<tr>
<td>UserDataSeg</td>
<td>__USER_DS</td>
<td>0&#215;00000000</td>
<td>0xffffffff</td>
<td>1</td>
<td>1</td>
<td>0&#215;10</td>
<td>3</td>
</tr>
</tbody>
<tbody></tbody>
</table>
<h4>线性地址在使用上的划分</h4>
<p>普通的x86结构计算机上，从用户的角度看，线性地址是一个连续内存区域。它的最小地址是<code>0x0000 0000</code>，而最大地址是<code>0xffff ffff</code>。这个区域在概念上被分成两个部分，一部分是会根据不同的进程切换而改变的userspace区域，而另一部分，则在系统启动后一直不变的kernel space区域。这个位置的分界点可在内核代码中通过<code>PAGE_OFFSET</code>宏来定义，而<code>PAGE_OFFSET</code>却来自于内核编译的配置文件<code>.config</code>中的<code>CONFIG_PAGE_OFFSET</code>。在x86结构上，它被定义为<code>0xC000 0000</code>；这意味着，用户空间的大小时3GB，而内核仅有1GB可以使用。</p>
<pre> |&lt;---          3GB          ----&gt;|&lt;----  1GB ----&gt;|
 +--------------------------------+----------------+
 |     userspace                  | kernel space   |
 +--------------------------------+----------------+
                            PAGE_OFFSET
                           (0xC000 0000)</pre>
<p>内核在系统启动时被<strong>Bootloader</strong>——x86结构上常用的是GRUB/2——装载到线性地址的<code>0xC000 0000</code>位置以后，而这个线性地址通常被映射到物理地址的<code>0x0010 0000</code>，也就是物理地址最初的1M以后，关于这里点的证明此后详述。在线性地址空间中，紧随内核装载位置之后，Linux会利用一段内存区域来加载物理内存管理需要使用的数据结构，这个区域的大小一般根据系统上可以使用的RAM的大小而改变，而其装载在物理内存中的位置会根据体系结构的不同而改变，但通常会避开前16M，因为最初的16M被用来给ISA设备提供DMA支持，这是物理内存管理中另外一个恼人的地方，且听下下回分解吧。此前提到的这两个区域都时直接的物理内存映射区域，具体的位置用内核宏定义来说的话应该时开始于<code>PAGE_OFFSET</code>，而结束于<code>(VMALLOC_START-VMALLOC_OFFSET)</code>。-_-!!! 抱歉，又说火星语了，但是除此以外还真没有好的描述语言。</p>
<pre>                             VMALLOC_OFFSET(0x0080 0000)
                                  ¥ | ¥
     +-----------+----------------+---+-------------------+
     |KernelImage|PhysicalMMStruct|Gap| vmalloc Add Space |
     +-----------+----------------+---+-------------------+
     ^                                |
     |                           VMALLOC_START
  PAGE_OFFSET
(0xC000 0000)</pre>
<p>显而易见，<code>VMALLOC_START = SizeOf(PhysicalMMStruct) + VMALLOC_OFFSET</code>。后续的线性地址空间被用以支持内核函数<code>vmalloc()</code>，使用这个函数可以申请在线性地址空间连续的却事实上在物理地址上可能不连续的内存区域；如果在支持<code>HIGH_MEM</code>的系统上，在两个PAGE的间隔以后，会有一块区域来支持将高地址转化到低地址的函数<code>kmap()</code>，这个区域的开始位置是<code>PKMAP_BASE</code>。为什么要转换呢？下下下下回分解&#8230;再接下来，还需要划分一片区域来支持编译时就需要定位的内存模块，比如APIC，这段区域采用固定映射(Fixed Mapping)的方式，将线性地址映射到物理地址，所以，利用链接器脚本或者其他方法可以在编译时确认代码被装载的位置；这片内存区域的开始位置是<code>FIXADDR_START</code>，而结束位置时<code>FIXADDR_TOP</code>；<code>FIXADDR_TOP</code>是<code>0xffff f000</code>，而<code>FIXADDR_START</code>会根据宏<code>__FIXADDR_START</code>计算得出。</p>
<pre>     +--------------------+---+--------------+-------------------------+---+
     | vmalloc Add Space  |Gap|kmap Add space|Fixed Virtual Add Mapping|Gap|
     +--------------------+---+--------------+-------------------------+---+
     |           VMALLOC_END  |              |                         |
     |                  PKMAP_BASE           |                  FIXEADDR_TOP
VMALLOC_START                         FIXADDR_START</pre>
<p>正是因为前面提到<code>vmalloc()</code>，<code>kmap()</code>和固定映射地址，内核物理内存区域管理中用到的<code>ZONE_NORMAL</code>的大小才受到限制，而不能占据整个1GB空间。这个限制通过宏定义<code>VMALLOC_RESERVE</code>体现出来，这个值在不同的体系结构上有所不同，但是在x86结构上，它被定义为128MB，理所当然的，ZONE_NORMAL可以使用的线性地址空间大小就变成了<code>1GB - 128MB = 896MB</code>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamjiang.com/archives/818/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux内核代码阅读序列(9)-内存模型 之一</title>
		<link>http://www.adamjiang.com/archives/805</link>
		<comments>http://www.adamjiang.com/archives/805#comments</comments>
		<pubDate>Thu, 07 Jan 2010 14:54:56 +0000</pubDate>
		<dc:creator>jcadam</dc:creator>
				<category><![CDATA[Linux kernel]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.adamjiang.com/?p=805</guid>
		<description><![CDATA[重新开始 2009年的时候信誓旦旦的说要将这个系列坚持写下去，结果未能如愿。抱歉的很。去年前半年奔波劳碌得到处跑，9月以后自己的人生发生了180度的大转弯，自己给自己的shock就已经够大了，更加没有心思写blog。还好还好，上帝给了我一个此前从未有的幸福的开端，也许我可以牵着她的手，安心下来好好补足功课了。愿上帝保佑2010一切都好。愿上帝保佑我能将这个系列按照原来的计划写完。 Linux的内存模型 理解Linux内核所采用的内存模型是弄懂Linux内存管理的第一步。很多介绍Linux源码阅读的书和文章都会建议新手应该从内存管理部分入手。可是，在我看来这并不是一个非常好的建议，因为如果搞不懂Linux内核中内存管理的模型直接阅读代码的话会迷失其中，一个重要原因就是这个部分很多实装方法都牵扯到了不同体系结构的差别。而Linux为了提高可移植性又对某些体系结构上普遍应用的内存模型进行了抽象。在看代码的时候，应该时刻注意区分那些是抽象了的部分，哪些代码是不同体系结构上的实现。 内存管理需要解决的问题 虚拟内存管理(Virtual Memory Management) 虚拟内存是现代操作系统的一个重要特征；采用虚拟内存的方法可以获得很多有点，比如通过这种抽象可以简化应用程序的开发，可以防止内存非法访问提高安全性等等； 物理内存管理(Physical Memory Management) 操作系统的主要功能之一就是进行资源管理，而内存恰恰就是最重要的系统资源； 内核的虚拟内存管理，内核内存分配器(Allocator) 应用程序或者内核内部模块需要内存时需要向内核管理模块申请，分配器帮助这些组件得到自己想要的内存； 虚拟地址空间管理(Virtual Memory Space) 交换(swap)和缓存(cache) 交换，也是计算机系统中利用局部性(locality)特征的一个重要功能，内存管理模块可以通过交换的方式将暂时用不到的内存页“交”给低速的硬盘保存，而需要时又将这些内存内容“换”回到系统主存之中；缓存也是局部性的一个应用，现代的CPU一般都会有高速缓存，高速缓存在CPU和主存之间充当缓冲，为CPU快速得访问数据和指令提供支持。 x86结构上的地址种类 x86结构上，内存地址被分成3类，理论地址，线性地址和物理地址； 逻辑地址，是从正在运行的应用程序的角度来看，某个数据或者指令出现的位置；这个地址有可能直接就是物理地址，也有可能不是；一般来说，各种控制器，比如DMA控制器，PCI控制器对内核提出内存申请的时候所给参数都是逻辑地址； 线性地址，或者被称为平面地址空间(Flat Memory Address)的地址，事实上就是在程序员脑子里的地址，它就是从0开始每个存储单元顺序增加标号的地址。这也是最原始最简单的地址编排方式，除了Intel之外的很多CPU都采用这种地址编排方式；而Intel体系结构的CPU上采用了分段的地址空间，这种方式将线性地址按照64KB(286结构)或者4GB(386以后)为单位进行分段，而且，段地址寄存器中总是存储这当前要使用的那段内存的基址(base address)。虽然这种方式在32位结构上也可以被看作是一整个平面的地址空间，但事实上它却是分段的； 物理地址就是在总线上表示的那个地址。当物理地址和逻辑地址不一致的时候，通过内存管理单元(MMU)，可以将路基地址转换为物理地址。 CPU使用内存区段单元和分页单元可以将逻辑地址转化成为物理地址； Logical Linear Physical Address +--------------+ Address +-------------+ Address --------&#62;&#124;Segmented Unit&#124;--------&#62;&#124; Paging Unit &#124;---------&#62; +--------------+ +-------------+ &#8211; 参考文献 http://www.ibm.com/developerworks/jp/linux/library/l-memmod/index.html]]></description>
			<content:encoded><![CDATA[<h3>重新开始</h3>
<p>2009年的时候信誓旦旦的说要将这个系列坚持写下去，结果未能如愿。抱歉的很。去年前半年奔波劳碌得到处跑，9月以后自己的人生发生了180度的大转弯，自己给自己的shock就已经够大了，更加没有心思写blog。还好还好，上帝给了我一个此前从未有的幸福的开端，也许我可以牵着她的手，安心下来好好补足功课了。愿上帝保佑2010一切都好。愿上帝保佑我能将这个系列按照原来的计划写完。</p>
<h3>Linux的内存模型</h3>
<p>理解Linux内核所采用的内存模型是弄懂Linux内存管理的第一步。很多介绍Linux源码阅读的书和文章都会建议新手应该从内存管理部分入手。可是，在我看来这并不是一个非常好的建议，因为如果搞不懂Linux内核中内存管理的模型直接阅读代码的话会迷失其中，一个重要原因就是这个部分很多实装方法都牵扯到了不同体系结构的差别。而Linux为了提高可移植性又对某些体系结构上普遍应用的内存模型进行了抽象。在看代码的时候，应该时刻注意区分那些是抽象了的部分，哪些代码是不同体系结构上的实现。</p>
<h4>内存管理需要解决的问题</h4>
<ul>
<li>虚拟内存管理(Virtual Memory Management)
<ul>
<li>虚拟内存是现代操作系统的一个重要特征；采用虚拟内存的方法可以获得很多有点，比如通过这种抽象可以简化应用程序的开发，可以防止内存非法访问提高安全性等等；</li>
</ul>
</li>
<li> 物理内存管理(Physical Memory Management)
<ul>
<li> 操作系统的主要功能之一就是进行资源管理，而内存恰恰就是最重要的系统资源；</li>
</ul>
</li>
<li>内核的虚拟内存管理，内核内存分配器(Allocator)
<ul>
<li> 应用程序或者内核内部模块需要内存时需要向内核管理模块申请，分配器帮助这些组件得到自己想要的内存；</li>
</ul>
</li>
<li> 虚拟地址空间管理(Virtual Memory Space)</li>
<li> 交换(swap)和缓存(cache)
<ul>
<li> 交换，也是计算机系统中利用局部性(locality)特征的一个重要功能，内存管理模块可以通过交换的方式将暂时用不到的内存页“交”给低速的硬盘保存，而需要时又将这些内存内容“换”回到系统主存之中；缓存也是局部性的一个应用，现代的CPU一般都会有高速缓存，高速缓存在CPU和主存之间充当缓冲，为CPU快速得访问数据和指令提供支持。</li>
</ul>
</li>
</ul>
<h4>x86结构上的地址种类</h4>
<p>x86结构上，内存地址被分成3类，理论地址，线性地址和物理地址；</p>
<ol>
<li> <strong>逻辑地址</strong>，是从正在运行的应用程序的角度来看，某个数据或者指令出现的位置；这个地址有可能直接就是物理地址，也有可能不是；一般来说，各种控制器，比如DMA控制器，PCI控制器对内核提出内存申请的时候所给参数都是逻辑地址；</li>
<li> <strong>线性地址</strong>，或者被称为平面地址空间(Flat Memory Address)的地址，事实上就是在程序员脑子里的地址，它就是从0开始每个存储单元顺序增加标号的地址。这也是最原始最简单的地址编排方式，除了Intel之外的很多CPU都采用这种地址编排方式；而Intel体系结构的CPU上采用了分段的地址空间，这种方式将线性地址按照64KB(286结构)或者4GB(386以后)为单位进行分段，而且，段地址寄存器中总是存储这当前要使用的那段内存的基址(base address)。虽然这种方式在32位结构上也可以被看作是一整个平面的地址空间，但事实上它却是分段的；</li>
<li> <strong>物理地址</strong>就是在总线上表示的那个地址。当物理地址和逻辑地址不一致的时候，通过内存管理单元(MMU)，可以将路基地址转换为物理地址。</li>
</ol>
<p>CPU使用内存区段单元和分页单元可以将逻辑地址转化成为物理地址；</p>
<pre>Logical                   Linear                  Physical
Address  +--------------+ Address +-------------+ Address
--------&gt;|Segmented Unit|--------&gt;| Paging Unit |---------&gt;
         +--------------+         +-------------+</pre>
<p>&#8211;<br />
参考文献<br />
<a title="Understanding Linux Memory Model" href="http://www.ibm.com/developerworks/jp/linux/library/l-memmod/index.html" target="_blank">http://www.ibm.com/developerworks/jp/linux/library/l-memmod/index.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamjiang.com/archives/805/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Emacs——很漂亮很强大</title>
		<link>http://www.adamjiang.com/archives/622</link>
		<comments>http://www.adamjiang.com/archives/622#comments</comments>
		<pubDate>Sat, 11 Jul 2009 13:32:07 +0000</pubDate>
		<dc:creator>jcadam</dc:creator>
				<category><![CDATA[Linux tips]]></category>
		<category><![CDATA[Emacs]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[opensource]]></category>

		<guid isPermaLink="false">http://www.adamjiang.com/?p=622</guid>
		<description><![CDATA[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) [...]]]></description>
			<content:encoded><![CDATA[<p>Vim我用了5年有余，最近因为接触的项目非常大，大约10W行代码，而且该项目采用包括C和C++还有python的多种语言开发，突然让我觉得使用Vim有些应付不过来。我的主要任务并不是去查看系统细节，而是要在短时间内获得已有系统的情况——包括结构和功能上的信息，所以我需要一个比较强大的代码浏览程序。公司提供的软件库里面搜索了半天，找到十几款代码浏览工具竟然没有一款是我熟悉的。一狠心，我觉得尝试一下Emacs。或许Vim也能够胜任这个工作，但是我尝试拼凑了很久插件也没能找到符合工作需要的集合。总之，破釜沉舟，试一下Emacs。谁知道上手之后我竟然再也放不下Emacs了，彻底被这款编辑器的扩展性和强大功能征服。在使用了Emacs一个月以后，对于我的“重大发现”，我想还是留下一个记录比较好。</p>
<h3>基础软件包</h3>
<p><code><br />
$ sudo apt-get install emacs-snapshot emacs-snapshot-common emacs-snapshot-bin-common emacs-snapshot-el emacs-goodies-el emacs-snapshot-gtk<br />
</code></p>
<h3>漂亮的Emacs</h3>
<p>我并不是个特别喜欢冒险的人，所以刚刚开始的时候，我选择了Emacs22。但是，后来发现，处理日语和中文的字体显示非常繁琐，索性放弃“保守派”的一贯作风，跃迁到还在开发中的Emacs23。在google上搜索得到<a href="http://images.google.co.jp/imgres?imgurl=http://farm4.static.flickr.com/3346/3336195816_817511aa10_o.jpg&amp;imgrefurl=http://flickr.com/photos/sfllaw/3336195816/&amp;usg=__v9gDhwGunQ6e7XAvLyDSFBUp0Ys=&amp;h=4368&amp;w=2912&amp;sz=73&amp;hl=ja&amp;start=9&amp;sig2=c9ZFxGdvK-qzSq3deq9-FQ&amp;um=1&amp;tbnid=3z99E0FRZYeH6M:&amp;tbnh=150&amp;tbnw=100&amp;prev=/images%3Fq%3DAlexandre%2BVassalotti%26hl%3Dja%26client%3Dfirefox-a%26rls%3Dcom.ubuntu:ja:unofficial%26sa%3DN%26um%3D1&amp;ei=lnhYSpfmAobmtgPJ5czIAg">Alexandre Vassalotti</a>写的很流行的一篇博文<a href="http://peadrop.com/blog/2007/01/06/pretty-emacs/">Pretty Emacs</a>，如法炮制，在Ubuntu 9.04上得到了一个让我基本满意的操作界面。这篇博文虽然有用但却非常简略，并没有详细说明CJK字体的反锯齿应该怎样处理。我尝试在~/.Xresource文件中使用包含日语和中文的字体，但是结果并不能让我满意，原因是日语和中文的汉字显示混在了一起，错别字太多。拜google所赐，最终还是找到了解决之法。证据在此。</p>
<p><a href="http://lh6.ggpht.com/_O-FwCW3mN_w/SliQpLvR2-I/AAAAAAAAEPo/bQWHMJ_6SJ8/Screenshot-emacs-3.png"><img title="Emacs screenshot" src="http://lh6.ggpht.com/_O-FwCW3mN_w/SliQpLvR2-I/AAAAAAAAEPo/bQWHMJ_6SJ8/s400/Screenshot-emacs-3.png" alt="" /></a></p>
<p>在.emacs中需要使用字符集来将日语和中文的显示字符区别对待，代码如下：</p>
<pre>;;;------------------------------------------------------------;;;
;;; 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"))
;;;;=========================================================;;;;</pre>
<p>“Vera Sans YuanTi”字体似乎涉嫌侵权，所以现在在互联网上已经难觅其踪，但是我还是非常喜欢这款合成字体，三四年前私自收藏了一直使用。在Ubuntu Jaunty上，读者可以尝试使用文泉驿等字体替代。或者，如果你拥有Windows的授权，使用微软雅黑也会有不错的效果。这里需要注意的是，Ubuntu 8.04或者更早版本上的emacs-snapshot提供的Emacs版本并不支持CJK字体的反锯齿显示。如果你使用比较早版本的Emacs23，可以尝试使用<a href="http://emacs.orebokech.com/">emacs.orebokech.com</a>提供的WeeklyBuild。但是事先应该确认一下在Ubuntu的backport上有没有提供emacs-snapshot的软件包。下面是中文显示效果的截屏。</p>
<p><a href="http://lh4.ggpht.com/_O-FwCW3mN_w/SliRUu1hspI/AAAAAAAAEPs/URgQ7TazitA/Screenshot-emacs-4.png"><img title="Emacs Screenshot Display Chinese" src="http://lh4.ggpht.com/_O-FwCW3mN_w/SliRUu1hspI/AAAAAAAAEPs/URgQ7TazitA/s400/Screenshot-emacs-4.png" alt="" /></a></p>
<h3>安装CEDET</h3>
<p><a href="http://cedet.sourceforge.net/">CEDET</a>是一整套开发环境的集合工具。包括工程管理，代码浏览和自动补全工具。但是，Ubuntu的软件频道中提供的版本并不能和Emacs23一起工作。详情可以看这个Debian的<a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=525613">Bug#525613</a>。我的解决办法是采用新的CEDET版本。<br />
<code><br />
$ wget http://sourceforge.net/projects/cedet/files/cedet/cedet-1.0pre6.tar.gz/download<br />
$ tar zxf cedet-1.0pre6.tar.gz<br />
$ cd cedet-1.0pre6/<br />
$ make<br />
$ make install-info<br />
$ cd ../ &amp;&amp; cp -a cedet-1.0pre6 /usr/share/emacs-snapshot/site-lisp/cedet<br />
</code><br />
这里需要注意的是，必须将编译好的cedet拷贝到/usr/share/emacs-snapshot/site-lisp中，而不能仅仅将这个文件放到load-path中了事。原因是Emacs在初始化的时候，会利用这个目录中的subdirs.el来保证整个目录都添加进入load-path之中。接下来在.emacs中添加下面这几行就基本可以使用了，但是上手之后应该多查看info的内容找到更多的信息。在Emacs中利用组合键Ctrl-h i可以打开info，按s查找CEDET。</p>
<pre>;;;-----------------------------------------------------------------;;;
;;; 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)</pre>
<p>CEDET非常强大，以至于很难几句话将这个工具讲清楚，但是经常查看info和多多实践，马上就会用的非常顺手。</p>
<h3>后记</h3>
<p>最近一些日子，我一直在看Emacs相关的内容。Emacs可以说不仅仅是一款编辑器，而是一个集成并且可以扩展的工作环境。很多年轻的程序员，包括我自己，总是在各种各样的工具之间跳来跳去，一方面可以是因为自己不够坚定，但另一方面只能说很多工具都有自己的局限性，当程序员遇到新的情况的时候就可能很自然的抛弃旧工具。Emacs却不同，它更像一个framework，你可以将自己的技巧，使用习惯以及效率提升工具全部集成其上。如果它不够用了，你可以自己动手写lisp对它进行扩展。又想起那句话，人们往往高估自己短期的能力而低估自己长期的积累。Emacs正是给这种积累提供一种可能性。也许这正是对我来说最要命特性。我的.emacs文件在<a href="https://github.com/jcadam/pemacs/blob/master/_emacs">这里</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamjiang.com/archives/622/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

