Chaospace

Reshape the world by engineering chaos


  • 首页

  • 分类

  • 归档

  • 站点地图

  • 公益 404

  • 搜索

为什么你会不堪重负

发表于 2016-06-08 | 分类于 效率

强迫证明自己

通常情况下都是具有过度的野心。这欲望本是用来证明自己的,但在工作场所,这个欲望往往变成决心和强制性的。

更加努力的工作

为了融入一个不适合自己的组织,为自己定了较高的期望值。为了满足这些期望,他们往往只专注于工作,而且他们愿意承担更多的工作。这往往都会让他们任何事都要亲自作为,这都是为了表明他们是最好的,因为他们不需要他人的帮助完成更多的工作量。

忽略需求

因为他们一心只关注与工作,他们几乎没有时间和精力再做别的事情。与朋友,家人聚餐和吃饭,睡觉一般的生理需求已经被他们视为不重要的了,因为这会浪费他们的时间。

冲突转移

他们开始意识到某些地方不太对劲,但他们无法正确归因。这可能导致他们激烈的内心冲突进而引发一系列的身体症状——这是他们首先表现出身体症状的阶段。

价值观重组

在这个阶段,他们将自己无形中隔离,规避与他人的冲突,并且因为他们认知模式的改变,他们否认或是拒绝自己正当的生理需要。他们的价值观体系也随之改变。工作占据了他们能支配的所有精力,从而他们再没有关照朋友或者家人的功夫。他们新的价值观围绕着工作,并且他们开始变得情感迟钝。

否认暴露的问题

他们开始变得偏执。他们不再喜欢社会生活,如果要他们参加社交活动的话,他们会觉得那几乎无法忍受。对他们了解不多的局外人可能会看到他们显示出更加强烈的攻击性。人们常常会发现,他们越发倾向于抱怨他们的工作是多么庞杂难以完成,他们的时间是如何不够他们支配,而非他们自己是否做出了什么改变。

自闭

他们的社交只维持在最小限度,并且很快他们自己陷入自闭的状态之中。酒精和兴奋性药物可能会被滥用用来在他们满负荷的工作之余排解他们的压力。他们在这个阶段开始常常经历无助感和无方向感。

自显著的行为改变

他们的同事,家人,朋友以及他们社交圈中的其他人会显著注意到他们行为上的改变。

人格解体

他们与自己失去了沟通,也就很难在他们自己或是他人身上看到任何价值之所在。与此同时,他们失去了对自己个人需求的响应。他们对生活的观念下降到只关注现有的时间,他们的人生变成了一系列的机械的功能组合。

内心空虚

他们感到内心空虚。为了规避这一点,他们可能会去找其他乐子,暴饮暴食,乱性,酒精或者毒品。这些行为可能会非常夸张。

抑郁

心力交瘁可能带来抑郁。他们感到疲惫不堪,绝望,冷漠,并且认为未来的生活对他们毫无意义。典型的抑郁症状开始出现。

心力交瘁综合症

身心崩溃。在这个阶段,他们应该立即寻求医疗的帮助。在极端的抑郁状况下,可能会出现自杀意念——自杀被这时的他们视为一种逃离现有状况的方式。但只有很少一部分人会实施自杀。

flashroom

发表于 2016-05-27 | 分类于 软件

最近在做 Corebios (曾经的 Linuxbios)到 EPIA 板子的移植,发现 flashrom 真是好用。

1. 手动安装:

$ svn co svn://coreboot.org/repos/trunk/util/flashrom
$ cd flashrom
$ make
$ sudo make install

2. 直接安装:

Debian

$ sudo aptitude install flashrom

Fedora

$ sudo yum install flashrom

Mandriva

$ urpmi flashrom

openSUSE

$ yast -i coreboot-utils

3 使用方法:

检测主板和芯片是否支持:
$ flashrom

将原有 BIOS 备份读取出来

$ flashrom -r backup.bin

写入新的 BIOS

$ flashrom -wv newbios.bin

4 更详细的信息请查看 Flashrom 的 README

PCI 设备驱动

发表于 2016-05-27 | 分类于 软件

1. PCI 简介

PCI 总线标准是一种将系统外部设备连接起来的总线标准,是 PC 中最重要的总线,实际上是系统的各个部分如何交互的接口。传输速率可达到 133MB/s。在当前的 PC 体系结构中,几乎所有的外部设备采用的各种各样的接口总线,均是通过桥接电路挂接到 PCI 系统上。在这种 PCI 系统中, Host/PCI 桥称为北桥,连接主处理器总线到基础 PCI 局部总线。 PCI 与其他总线的接口称为南桥,其中南桥还通常含有中断控制器、IDE 控制器、USB 控制器和 DMA 控制器等。南桥和北桥组成主板的芯片组。

2. PCI 配置空间

每个 PCI 设备都有自己的配置空间,用于支持即插即用,使之满足现行的系统配置结构。下面对 PCI 配置空间做一下简要介绍。

配置空间是一容量为 256 字节并具有特定结构的地址空间。这个空间又分为头标区和设备有关区两部分。头标区的长度是 64 字节,每个设备都必须配置该区的寄存 器。该区中的各个字段用来唯一地识别设备。其余的 192 字节因设备而异。配置空间的头标区 64 个字节的使用情况如图 1 示。

为了实现即插即用,系统可根据硬件资源的使用情况,为 PCI 设备分配新的资源。因此编写设备驱动程序重点是获得基址寄存器(Base Address)和中断干线寄存器的内容。配置空间共有六个基址寄存器和一个中断干线寄存器,具体用法如下:

PCI Base Address 0 寄存器:系统利用此寄存器为 PCI 接口芯片的配置寄存器分配一段 PCI 地址空间,通过这段地址我们可以以内存映射的形式访问 PCI 接口芯片的配置寄存器。

PCI Base Address 1 寄存器:系统利用此寄存器为 PCI 接口芯片的配置寄存器分配一段 PCI 地址空间,通过这段地址我们可以以 I/O 的形式访问 PCI 接口芯片的配置寄存器。

PCI Base Address 2、3、4、5 寄存器:系统 BIOS 利用这些寄存器分配 PCI 地址空间以支持 PCI 接口芯片的局部配置寄存器 0、1、2、3 的访问。

在所有基址寄存器中,第 0 位均为只读位,表示这段地址映射到存储器空间还是 I/O 空间,如果是“1”表示映射到 I/O 空间,如果是“0”则表示映射到存储器空间。

中断干线寄存器(Interrupt Line):用于说明中断线的连接情况,这个寄存器的值与标准 8259 的 IRQ 编号(0~15)对应。

表 1 PCI 配置空间

3. 设备初始化

PCI 设备驱动程序要完成识别 PCI 器件、寻找 PCI 硬件的资源和对 PCI 器件中断的服务。在驱动程序初始化过程中,使用 HalGetBusData()函数完 成寻找 PCI 设备的工作。在初始化过程中,使用器件识别号(Device ID)和厂商识别号(Vendor ID),通过遍历总线上的所有设备,寻找到指定的 PCI 设备,并获取设备的总线号,器件号与功能号。通过这些配置信息,可以在系统中寻址该设备的资源配置 列表。

在此之后,驱动程序需要从配置空间获取硬件的参数。PCI 设备的中断号、端口地址的范围(I/O)方式、存储器的地址与映射 方式等,都可以从硬件资源列表数据结构中获取。在 Windows NT 中,调用 HalAssignSlotResources()函数来获得指定设备的资源列表数据结构指针,然后通过遍历该列表中的所有资源描述符,获取 该设备的 I/O 端口基地址与长度,中断的中断级、中断向量与模式,存储器基地址与长度等硬件资源数据。

我们设计的 DMA 通信采用总线主控方式进行通信,在 设备初始化时需要对 DMA 适配器进行初始化,使用 HalGetAdapter()获得操作系统分配的适配器对象指针。
示例代码如下:

// 遍历总线,获得指定设备的总线号,器件号与功能号
for (busNumber = 0; busNumber < MAX_PCI_BUSES; busNumber++) {
for (deviceNumber = 0;deviceNumber < PCI_MAX_DEVICES;deviceNumber++) {
slotNumber.u.bits.DeviceNumber = deviceNumber;
for (functionNumber = 0; functionNumber < PCI_MAX_FUNCTION; functionNumber++) {
slotNumber.u.bits.FunctionNumber = functionNumber;
if (!HalGetBusData(PCIConfiguration, busNumber, slotNumber.u.AsULONG,
&pciData,sizeof(ULONG)) ) {
deviceNumber = PCI_MAX_DEVICES;
break;
}

          if (pciData.VendorID == PCI_INVALID_VENDORID) {continue;}

          if (( VendorId != PCI_INVALID_VENDORID) && (pciData.VendorID != VendorId || pciData.DeviceID != DeviceId)) {continue;}
          pPciDeviceLocation->BusNumber = busNumber; 
          pPciDeviceLocation->SlotNumber = slotNumber;
          pPciDeviceLocation = &PciDeviceList->List[++count];
          status = STATUS_SUCCESS;
        } 
    } 
} 
// 获取设备的资源列表数据指针
status = HalAssignSlotResources(RegistryPath,
&pDevExt->ClassUnicodeString,
DriverObject,
DeviceObject,
pDevExt->InterfaceType,
pDevExt->BusNumber,
pDevExt->SlotNumber,
&pCmResourceList );

4. I/O 端口访问

在 PC 机上,I/O 寻址方式与内存寻址方式不同,所以处理方法也不同。I/O 空间是一个 64K 字节的寻址空间,I/O 寻址没有实模式与保护模式之分,在各种 模式下寻址方式相同。在 Windows NT 下,系统不允许处于 Ring3 级的用户程序和用户模式驱动程序直接使用 I/O 指令,对 I/O 端口进行访问,任何对 I/O 的操作都需要借助内核模式驱动 来完成。在访问 I/O 端口时,使用 READ_PORT_XXX 与 WRITE_PORT_XXX 函数来进行读写。I/O 端口基地址使用从配置空间基址寄存器 PCI Base Address 1 中返回的 I/O 端口基地址。

示例代码如下:
RegValue = READ_PORT_ULONG(pBaseAddr+RegOffSet);
WRITE_PORT_ULONG(pBaseAddr+ RegOffset, RegValue);

5. 设备内存访问

Winsows 工作在 32 位保护模式下,保护模式与实模式的根本区别在于 CPU 寻址方式上的不同,这也是 Windows 驱动程序设计中需要着重解决的问题。 Windows 采用了分段、分页机制,使得一个程序可以很容易地在物理内存容量不一样的、配置范围差别很大的计算机上运行,编程人员使用虚拟存储器可以写 出比任何实际配置的物理存储器都大得多的程序。每个虚拟地址由 16 位的段选择字和 32 位段偏移量组成。通过分段机制,系统由虚拟地址产生线性地址。再通过 分页机制,由线性地址产生物理地址。线性地址被分割成页目录(Page Directory)、页表(Page Table) 和页偏移 (Offset) 三个部分。当建立一个新的 Win32 进程时,操作系统会为它分配一块内存,并建立它自己的页目录、页表,页目录的地 址也同时放入进程的现场信息中。当计算一个地址时,系统首先从 CPU 控制器 CR3 中读出页目录所在的地址,然后根据页目录得到页表所在的地址,再根据页表 得到实际代码/数据页的页帧,最后再根据页偏移访问特定的单元。硬件设备读写的是物理内存,但应用程序读写的是虚拟地址,所以存在着将物理内存地址映射到 用户程序线性地址的问题。

从物理内存到线性地址的转换是驱动程序需要完成的工作,可以在初始化驱动程序的进行。在已经获得设备的存 储器基地址后,首先调用 HalTranslateBusAddress()函数将总线相关的内存地址转换成系统的物理地址,然后调用 MmMapIoSpace()函数将系统的物理地址映射到线性地址空间。在需要访问设备内存时,调用 READ_REGISTER_XXX()与 WRITE_REGISTER_XXX ()函数来进行,基地址使用前面映射后的线性地址。在设备卸载时,调用 MmUnmapIoSpace()断开设备内存与线性地址空间的映射。

示例代码如下:
HalTranslateBusAddress(InterfaceType,
BusNumber,
BaseAddress->RangeStart,
&addressSpace,
&cardAddress)

BaseAddress->MappedRangeStart = MmMapIoSpace(cardAddress,
BaseAddress->RangeLength,
MmCached );
……
RegValue = READ_REGISTER_ULONG(pRegister);
WRITE_REGISTER_ULONG(pRegister, pInBuf->RegValue);
……
MmUnmapIoSpace(pBaseAddress->MappedRangeStart, pBaseAddress->RangeLength);

6. 中断处理

中 断的设置、响应与调用在驱动程序中完成。设置中断应该在设备创建时完成,使用从 CmResourceTypeInterrupt 描述符中提取的参数,先调 用 HalGetInterruptVector()将与总线有关的中断向量参数转换为系统的中断向量,然后调用 IoConnectInterrupt() 指定中断服务,注册中断服务函数 ISR(Interrupt Service Routine)的函数指针。

当硬件设备产生中断时,系统 会自动调用 ISR 函数来响应中断。ISR 函数运行的中断请求级较高,主要完成对硬件设备中断的清除,不适合执行过多的代码。在传输大块数据时,需要使用延 迟过程调用(Delay Process Call,DPC)机制。例如,使用 PCI 设备进行 DMA 通信时,在 ISR 函数中完成对指定设备中断的判断以及清除中断,在退出 ISR 前,调用 DPC 函 数;在 DPC 函数中,完成 DMA 通信的过程,并将数据返回给用户程序。

示例代码如下:
DeviceExtension->InterruptLevel = partialData->u.Interrupt.Level;
DeviceExtension->InterruptVector = partialData->u.Interrupt.Vector;
DeviceExtension->InterruptAffinity = partialData->u.Interrupt.Affinity;
if (partialData->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
{
DeviceExtension->InterruptMode = Latched;
} else {
DeviceExtension->InterruptMode = LevelSensitive;
}
……
vector = HalGetInterruptVector(pDevExt->InterfaceType,
pDevExt->BusNumber,
pDevExt->InterruptLevel,
pDevExt->InterruptVector,
&irql,
&affinity );

status = IoConnectInterrupt(&pDevExt->InterruptObject,
(PKSERVICE_ROUTINE)PciDmaISR,
DeviceObject,
NULL,
vector,
irql,
irql,
pDevExt->InterruptMode,
TRUE,
affinity,
FALSE );

7. DMA 通信过程

DMA 通信在驱动程序中实现,需要多个例程才能完成一次 DMA 通信。

1) DriverEntry 例程
构造 DEVICE_DESCRIPTION 结构,并调用 HalGetAdapter,找到与设备关联的 Adapter 对象,并将返回的 Adapter 对象的地址和映射寄存器的数目保存在设备扩展的数据结构中。

示例代码:
// 申请 DMA 的适配器对象
deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
deviceDescription.Master = TRUE;
deviceDescription.ScatterGather = pDevExt->ScatterGather;
deviceDescription.DemandMode = FALSE;
deviceDescription.AutoInitialize = FALSE;
deviceDescription.Dma32BitAddresses = TRUE;
deviceDescription.BusNumber = pDevExt->BusNumber;
deviceDescription.InterfaceType = pDevExt->InterfaceType;
deviceDescription.MaximumLength = pDevExt->MaxTransferLength;
pDevExt->AdapterObject = HalGetAdapter(&deviceDescription,
&numberOfMapRegisters
);
……

2)Start I/O 例程

该例程请求 Adapter 对象的拥有权,然后把其余的工作留给 AdapterControl 回调例程。

a) 调用 KeFlushIoBuffers 从 CPU 的 Cache 把数据清到物理内存,然后计算映射寄存器的数目和用户缓冲区的大小,及在第一次设备操作中传输的字节数。
b) 调用 MmGetMdlVirtualAddress,从 MDL 中恢复用户缓冲区的虚地址,并存入设备扩展数据结构中。
c) 调用 IoAllocateAdapterChannel 请求 Adapter 对象的拥有权。如果调用成功,其余的设置工作由 AdapterControl 例程去做;如果失败了,则完成本次 IRP 包处理,开始处理下一个 IRP。

3) AdapterControl 例程
该例程完成初始化 DMA 控制器,并启动设备的工作。
a) 调用 IoMapTransfer,装入 Adapter 对象的映射寄存器。
b) 向设备发送合适的命令开始传输操作。
c) 返回值 KeepObject 保留 Adapter 对象的拥有权。

4)中断服务(ISR)例程
在设备中断时,由系统调用。
a) 向硬件设备发出中断响应的指令。
b) 调用 IoRequestDpc 在驱动程序的 DpcForIsr 中继续处理该请求。
c) 返回 TRUE,表示已经服务了本次中断。

5)DpcForIsr 例程
由 ISR 在每个部分数据传输操作的结束时触发,完成当前 IRP 请求。
a) 调用 IoFlushAdapterBuffers,清除 Adapter 对象的 Cache 中的任何剩余数据。
b) 调用 IoFreeMapRegisters,释放所使用的映射寄存器。
c) 检查有未传完的剩余数据,如果有,则计算下次设备操作中需要传输的字节数,调用 IoMapTransfer 重设映射寄存器,并启动设备;如果没有剩余数据,则完成当前 IRP 请求,并开始下一个请求。

initrd

发表于 2016-05-27 | 分类于 Linux

内存磁盘(RAM Disk),就是把内存的一部分当成磁盘使用。作为一个临时文件系统,可以提高系统速度。而初始内存磁盘 (initrd) 则在系统启动的时候提供了一个临时根文件系统,以支持内核的两步启动过程。这个内存磁盘包含了必要的可执行程序和驱动,以挂载硬盘上真正的文件系统。在桌面系统中,初始内存磁盘的寿命很短暂,仅仅是启动真正根文件系统的一个桥梁,挂载完根文件系统之后就会释放其所占内存;而在许多嵌入式系统中,不存在硬盘上的文件系统,所以 initrd 作为最终的系统一直使用。

一. initrd 的意义

内核直接启动不就行了,为什么需要两步启动?

内核要挂载硬盘等存储设备,就需要这些设备的驱动程序。一种方式就是把已知硬件的驱动直接编译进内核,这在单个系统上是可行的。可以不需要 initrd 就启动系统。但是对于安装面广泛的发行版来说,就等于需要把所有有关存储的驱动都编译进内核,是无法接受的。所以就采取了安装系统后,根据检测到的硬件信 息自动生成 initrd 的方式,把需要的驱动放入,并提供加载驱动,挂载真实文件系统所需要的各个程序(常由 Busybox 提供)。

二. initrd 工作原理

既然内核没有驱动,读取不了硬盘,那么 initrd 又是怎么被加载的?
initrd 的加载,是由启动管理器 Grub 完成的。这时候的内核并未被启动,硬盘设备的初始化由 BIOS 初始化。Grub 把 initrd 和内核镜像文件载如到内存之后,就会通过 boot 命令启动内核,此时内核可能并无法识别硬盘,但是内存是没问题的,所以内核可以先挂载 initrd 这个精简系统,装入必要驱动然后挂载硬盘中的真实系统。

三. initrd 的生成

大部分发行版都有 initrd 的工具,比如 mkinitrd, mkinitramfs 等。实际就是一个 Shell 脚本,可以直接利用这些脚本建立 initrd。 如果需要定制自己的 initrd ,则可以用文本编辑器打开这些程序查看并进行相应修改。

四. 内核通过 initrd 启动的机制

内核启动的代码大都位于 init 子目录,其中 main.c 中的 init() 就是执行的入口地址。在执行了各个子系统的初始化工作之后,调用 do_mounts_initrd.c 中的 initrd_load() 函数,initrd_load 调用 rd_load_image() 将内存中的 initrd 镜像载入到内核的地址空间之中。这样就可以进行下一步的挂载。然后调用 do_mounts.c 的 mount_root() 函数将内存磁盘挂载到内核中,最终调用 fs/namespace.c 中的 sys_mount()挂载根文件系统。

根文件系统挂载完成之后,返回 init() 主程序,并调用 run_init_process() 函数,这个函数就一句话,通过 kernel_execve 调用系统初始文件比如 linuxrc , 开始应用程序的启动工作。

完整的函数调用流程:
init/main.c:init
init/do_mounts.c:prepare_namespace
init/do_mounts_initrd.c:initrd_load
init/do_mounts_rd.c:rd_load_image
init/do_mounts_rd.c:identify_ramdisk_image
init/do_mounts_rd.c:crd_load
lib/inflate.c:gunzip
init/do_mounts.c:mount_root
init/do_mounts.c:mount_block_root
init/do_mounts.c:do_mount_root
fs/namespace.c:sys_mount
init/main.c:run_init_process
kernel_execve

五. 解压查看

以前的 initrd 是一个独立的文件系统,需要挂载到一个目录才能查看。现在的 initrd 基本都是由 cpio 生成,用如下方法查看:
$ gunzip -c /boot/initrd > /tmp/my_initrd
$ mkdir ~/initrd_dir
$ cd ~/initd_dir
$ cpio -i < /tmp/my_initrd 参考:

编程之道

发表于 2016-05-27 | 分类于 代码

The Silent Void

Book One

Thus spake the master programmer:

编程大师如是说:

“When you have learned to snatch the error code from the trap frame, it will be time for you to leave.”

“当你从我手中夺走水晶球时,就是你离开的时候了。”

1.1

Something mysterious is formed, born in the silent void. Waiting alone and unmoving, it is at once still and

yet in constant motion. It is the source of all programs. I do not know its name, so I will call it the Tao of

Programming.

寂静的虚空里诞生了神秘的东西,这种东西恒久存在永不消失,它是所有程序的根源所在,我不知道怎么形容它,姑且称它为编程之道。

If the Tao is great, then the operating system is great. If the operating system is great, then the compiler is

great. If the compiler is greater, then the applications is great. The user is pleased and there is harmony in

the world.

如果道是完美的,那么操作系统就是完美的,如果操作系统是完美的,那么编译嚣就是完美的,如果编译嚣是完美的,那么应用程序

就是完美的,所以用户心满意足,整个世界因此和谐。

The Tao of Programming flows far away and returns on the wind of morning.

编程之道去如黄鹤来如晨风。

1.2

The Tao gave birth to machine language. Machine language gave birth to the assembler.

道生机器语言,机器语言生汇编嚣。

The assembler gave birth to the compiler. Now there are ten thousand languages.

汇编器生编译器,最后产生上万种高级语言。

Each language has its purpose, however humble. Each language expresses the Yin and Yang of software. Each

language has its place within the Tao.

不论多么的微不足道,每种语言都有它自己的目的,每种语言都表达了软件的阴阳两极。每种语言都各得其道。

But do not program in COBOL if you can avoid it.

但是尽量不要用 COBOL 语言。

1.3

In the beginning was the Tao. The Tao gave birth to Space and Time. Therefore, Space and Time are the Yin and Yang of

programming.

道之初,带来了空间和时间,所以,空间和时间是编程的阴阳两极。

Programmers that do not comprehend the Tao are always running out of time and space for their programs.

Programmers thatcomprehend the Tao always have enough time and space to accomplish their goals.

不懂编程之道的程序员常常把空间和时间消耗殆尽,得道的程序员则总是有足够的空间和时间去完成编程任务。

How could it be otherwise?

否则会是什么样呢?

1.4

The wise programmer is told about the Tao and follows it. The average programmer is told about the Tao and searches for it. The foolish programmer is told about the Tao and laughs at it.

上士闻道,从而行之。中士闻道,谨而寻之。下士闻道,大笑之。

If it were not for laughter, there would be no Tao.

大笑不足为道。

The highest sounds are the hardest to hear. Going forward is a way to retreat. Greater talent shows itself late in life.

Even a perfect program still has bugs.

希音不闻,进即是退,大嚣晚成。任何程序都有漏洞。


The Ancient Masters

Book Two

Thus spake the master programmer:

编程大师如是说:

“After three days without programming, life becomes meaningless.”

三日不编程,食肉无味。

2.1

The programmers of old were mysterious and profound. We cannot fathom their thoughts, so all we do is describe their appearance.

远古时代的编程大师们高深莫测,我们不能揣测他们的所思所想,只能描述外表所见。

Aware, like a fox crossing the water. Alert, like a general on the battlefield. Kind, like a hostess greeting her guests. Simple, like uncarved blocks of wood. Opaque, like black pools in darkened caves.

他达明,如狐狸过水;机警,如战场上的将军;和善,如主妇款待客人;简单,呆若木鸡;混沌,如深渊之水。

Who can tell the secrets of their hearts and minds?

谁能道尽他们的所有?

The answer exists only in the Tao.

答案仅存于道。

2.2

Grand Master Turing once dreamed that he was a machine. When he awoke he exclaimed:

超级大师图灵曾梦见自己是一台机器,醒后他这样回忆:

“I don’t know whether I am Turing dreaming that I am a machine, or a machine dreaming that I am Turing!”

“我不知道是图灵梦见自己变成机器还是机器梦见自己变成图灵。”

2.3

A programmer from a very large computer company went to a software conference and then returned to report to his manager, saying: “What sort of programmers work for other companies? They behaved badly and were unconcerned with appearances. Their hair was long and unkempt and their clothes were wrinkled and old. They crashed out hospitality suites and they made rude noises during my presentation.”

一个大公司的程序员参加一个软件会议后向他的主管汇报:“那些别的公司的程序员都是些什么样的人呀?他们举止不雅,不修边幅,头发蓬乱,衣服破旧,根本不热情好客,还在我说话的时候乱嚷嚷。”

The manager said: “I should have never sent you to the conference. Those programmers live beyond the physical world. They consider life absurd, an accidental coincidence. They come and go without knowing limitations. Without a care, they live only for their programs. Why should they bother with social conventions?”

他的主管说:“我不应该让你参加这次会议,这些程序员生活在现实世界之外。他们认为生活是可笑的,一场意外的偶然而已。他们来去自由,无所牵挂,他们只为他们的程序生活。为什么要用世俗的烦扰去扰乱他们呢?”

“They are alive within the Tao.”

“他们生活在道中”。

2.4

A novice asked the Master: “Here is a programmer that never designs, documents, or tests his programs. Yet all who know him consider him one of the best programmers in the world. Why is this?”

一个初学者问主管经理:“有一个程序员,他从来不预先设计,也不写文档,甚至不测试他的程序,但是知道他的人都认为他是世界上最伟大的程序员,为什么呢?”

The Master replies: “That programmer has mastered the Tao. He has gone beyond the need for design; he does not become angry when the system crashes, but accepts the universe without concern. He has gone beyond the need for documentation; he no longer cares if anyone else sees his code. He has gone beyond the need for testing; each of his programs are perfect within themselves, serene and elegant, their purpose self-evident. Truly, he has entered the mystery of the Tao.”

经 理说:“那个程序员掌握了道。他不需要预先进行设计;系统崩溃时他也从不烦燥,只是接受发生的一切而不管发生的事是好是坏 。他不需要写文档,他从不顾及有没有人看他写的代码。他也不需要进行测试;他写的每个程序都有一个完美的自我,平静而优雅,它们的目的不言自明。他已经真 正掌握了道的精髓。”


Design

Book Three

Thus spake the master programmer:

编程大师如是说:

“When program is being tested, it is too late to make design changes.”

“程序被测试时再去改变它的设计已经太晚了。”

3.1

There once was a man who went to a computer trade show. Each day as he entered, the man told the guard at the door:

曾经有一个人参加计算机展览,每天他进门时都对门卫说:

“I am a great thief, renowned for my feats of shoplifting. Be forewarned, for this trade show shall not escape unplundered.”

“先警告你,我是偷盗高手,我入室偷盗的本领闻名遐迩。这次展览会也再劫难逃。”

This speech disturbed the guard greatly, because there were millions of dollars of computer equipment inside, so he watched the man carefully. But the man merely wandered from booth to booth, humming quietly to himself.

警卫因此大动干戈,因为里面有价值百万的计算机设备,所以他牢牢盯紧了这个人,但是这个人只是从一个摊位逛到另一个摊位,一边平静地喃喃自语。

When the man left, the guard took him aside and searched his clothes, but nothing was to be found.

当这个人离开时,警卫搜了他的身,但是什么也没有发现。

On the next day of the trade show, the man returned and chided the guard saying: “I escaped with a vast booty yesterday, but today will be even better.” So the guard watched him ever more closely, but to no avail.

展览会的第二天,这个人又对警卫说:“昨天我满载而归,但是今天我会收获更大。”所以警卫更加小心地盯紧他,但是这样做完全于事无补。

On the final day of the trade show, the guard could restrain his curiosity no longer. “Sir Thief,” he said, “I am so perplexed, I cannot live in peace. Please enlighten me. What is it that you are stealing?”

展览会的最后一天,警卫再也不能忍住他的好奇心了。“小偷先生,”他说,“ 你说我惊慌不安,请告诉我,你到底偷了什么?”。

The man smiled. “I am stealing ideas,” he said.

这个人笑笑说:“我在偷想法。”

3.2

There once was a master programmer who wrote unstructured programs. A novice programmer, seeking to imitate him, also began to write unstructured programs. When the novice asked the master to evaluate his progress, the master criticized him for writing unstructured programs, saying: “What is appropriate for the master is not appropriate for the novice. You must understand the Tao before transcending structure.”

有一位编程大师,他写非结构化的程序,一位初学者刻意模仿他,也写非结构化的程序。当他让大师看他的进步时,大师批评了他的非结构化程序:“ 对一位编程大师合适的东西未必对一个初学者同样合适,在超越结构化之前,你必须理解编程之道。”

3.3

There was once a programmer who was attached to the court of the warlord of Wu. The warlord asked the programmer: “Which is easier to design: an accounting package or an operating system?”

### 有人问一位程序员,“一个财务软件和一个操作系统哪个更容易设计?”

“An operating system,” replied the programmer.

“是操作系统”,这位程序员回答说。

The warlord uttered an exclamation of disbelief. “Surely an accounting package is trivial next to the complexity of an operating system,” he said.

此人大惑不解。他说:“显然一个财务软件比起操作系统来说其复杂性是微不足道的”。

“Not so,” said the programmer, “when designing an accounting package, the programmer operates as a mediator between people having different ideas: how it must operate, how its reports must appear, and how it must conform to the tax laws. By contrast, an operating system is not limited my outside appearances. When designing an operating system, the programmer seeks the simplest harmony between machine and ideas. This is why an operating system is easier to design.”

程 序员说:“不,设计财务软件时,一个程序员 必须成为持不同意见的用户与计算机的一个中介,他必须了解用户的操作习惯,报表要是什么形式,如何遵循税法。相反,一个操作系统完全与这些外部的东西无 关。设计操作系统,程序员只需要达到自己的设想与机器之间的简单的和谐。这就是为什么操作系统反而比财务软件更容易设计。”

The warlord of Wu nodded and smiled. “That is all good and well, but which is easier to debug?”

这些人笑着说。“不错,但是哪一个更容易调试呢?”

The programmer made no reply.

程序员没有回答。

3.4

A manager went to the master programmer and showed him the requirements document for a new application. The manager asked the master: “How long will it take to design this system if I assign five programmers to it?”

一个项目经理带给编程大师一个项目的需求,然后问大师:“如果我给你 5 个程序员,要多少时间设计这个项目?”

“It will take one year,” said the master promptly.

“一年”,大师说。

“But we need this system immediately or even sooner! How long will it take it I assign ten programmers to it?”

“但是我们等不了那么长时间,越快越好,如果 10 个程序员呢?”

The master programmer frowned. “In that case, it will take two years.”

大师皱了一下眉头说:“那就要花 2 年”。

“And what if I assign a hundred programmers to it?”

“那,100 个程序员呢?”

The master programmer shrugged. “Then the design will never be completed,” he said.

大师耸了耸肩说:“那这个项目就永远完不成了。”


Coding

Book Four

Thus spake the master programmer:

编程大师如是说:

“A well-written program is its own heaven;

a poorly-written program is its own hell.”

“写的好的程序是它自己的天堂,写的不好的程序是它自己的地狱”

4.1

A program should be light and agile, its subroutines connected like a strings of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little nor too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity.

一个程序应该是轻灵自由的,它的子过程就象串在一根线上的珍珠。自始至终,目标明确。增之一字节则太长,减之一字节则太短。既没有不必要的循环也没有没有被引用的变量,既不缺少结构化也不至于僵硬呆板。

A program should follow the Law of Least Astonishment. What is this law? It is simply that the program should always respond to the user in the way that astonishes him least.

一个程序应该遵循”最小惊讶原则’’,什么是”最小惊讶原则’’?就是说一个程序应该最小程度地引起用户的惊讶。

A program, no matter how complex, should act as a single unit. The program should be directed by the logic within rather than by outward appearances.

无论一个程序无论有多么复杂都应该是一个单一的整体。程序是被它的内部逻辑所指引而不是它的外观表现。

If the program fails in these requirements, it will be in a state of disorder and confusion. The only way to correct this is to rewrite the program.

如果一个程序不能满足所要的需求,它就会处于混乱无序的状态中。唯一的出路就是重写这个程序。

4.2

A novice asked the master: “I have a program that sometimes runs and sometimes aborts. I have followed the rules of programming, yet I am totally baffled. What is the reason for this?”

一个初学者问大师:“我的一个程序有时正常有时不正常。我已经完全遵循编程的规则,而且我完全被它弄糊涂了,到底是什么原因会导致这样呢?”

The master replied: “You are confused because you do not understand the Tao. Only a fool expects rational behavior from his fellow humans. Why do you expect it from a machine that humans have constructed? Computers simulate determinism; only the Tao is perfect.

大师说:“你困惑是因为你不了解道。只有傻瓜才会相信只要遵循别人所说就能得到想当然的结果。为什么你要从一个人类自己构造的机器中去得到想当然的结果呢?计算机只是决定论的产物;只有道才是唯一完美的。

The rules of programming are transitory; only the Tao is eternal. Therefore you must contemplate the Tao before you receive enlightenment.

任何编程的规则都只适合于特定的情况,只有道才是永恒不变的。所以在你受到指引之前要先去思考道。

“But how will I know when I have received enlightenment?” asked the novice.

“但是我怎么知道我何时受到指引呢?”

“Your program will then run correctly,” replied the master.

“当你的程序正确运行时”。大师说。

4.3

A master was explaining the nature of the Tao to one of his novices, “The Tao is embodied in all software – regardless of how insignificant,” said the master.

初学者请大师解释“道法自然”。大师说:“道存在于任何软件中--无论是多么没有意义的软件”。

“Is the Tao in a hand-held calculator?” asked the novice.

“难道也存在于手持式的计算嚣里?”,初学者问。

“It is,” came the reply.

“是的,”

“Is the Tao in a video game?” continued the novice.

“也在游戏机里?”,初学者又问到。

“It is even in a video game,” said the master.

“是的,甚至也存在于游戏机里”。大师说。

“And is the Tao in the DOS for a personal computer?”

“也存在于个人计算机的 DOS 里吗?”

The master coughed and shifted his position slightly. “The lesson is over for today,” he said.

大师咳嗽了一声,稍微动了一下,说,“今天的课就到这里”。

4.4

Price Wang’s programmer was coding software. His fingers danced upon the keyboard. The program compiled without an error message, and the program ran like a gentle wind.

### 编程大师编写软件时,手指在键盘上快速飞舞。程序编译时没有一条错误信息,程序运行起来就象一阵微风吹过。

Excellent!” the Price exclaimed, “Your technique is faultless!”

太精彩了!你的技巧已经无可挑剔了。

“Technique?” said the programmer, turning from his terminal, “What I follow is the Tao – beyond all technique. When I first began to program I would see before me the whole program in one mass. After three years I no longer saw this mass. Instead, I used subroutines. But now I see nothing. My whole being exists in a formless void. My senses are idle. My spirit, free to work without a plan, follows its own instinct. In short, my program writes itself. True, sometimes there are difficult problems. I see them coming, I slow down, I watch silently. Then I change a single line of code and the difficulties vanish like puffs of idle smoke. I then compile the program. I sit still and let the joy of the work fill my being. I close my eyes for a moment and then log off.”

“技巧?”,大师转过身说,“我所遵循的是道–它 超乎所有的技巧。当我开始编程时我看到的是整个一大块的程序,三年后我看到的是子过程。现在我什么也看不到了。我的整个存在是没有任何形式的虚无。我感觉 很悠闲,总之,事实上是我的程序自己在写,有时我看到一些问题,我看到它们,就停下来静静地观察它们,然后我改变了一行代码,难题就象一阵轻烟一样化为乌 有。然后我编译程序。坐在那里享受工作的喜悦。闭了一会眼睛然后退出系统。

Price Wang said, “Would that all of my programmers were as wise!”

“什么时候我的程序员才能都达到这样的境界!”

Mainteance

Book Five

Thus spake the master programmer:

编程大师如是说:

“Though a program be but three lines long, someday it will have to be maintained.”

“既使一个程序只有三行长,也总有一天需要去维护它”

5.1

A well-used door needs no oil on its hinges.

A swift-flowing steam does no grow stagnant.

Neither sound nor thoughts can travel through a vacuum.

Software rots if not used.

经常使用的门不需要往门轴里上油。

流动的东西就不会停滞不前。

流水不腐,户枢不蠹。–王磊

声音和思想都不能在真空里传播。

软件不用就会腐朽。

These are great mysteries.

5.2

A manager asked a programmer how long it would take him to finish the program on which he was working. “I will be finished tomorrow,” the programmer promptly replied.

经理问程序员要多长时间才能完成他的项目。“明天”

“I think you are being unrealistic,” said the manager. “Truthfully, how long will it take?”

“太不着边际了,老实说,要多久?”

The programmer thought for a moment. “I have some features that I wish to add. This will take at least two weeks,” he finally said.

程序员想了一想说。“还有一些新的功能要加进去,可能至少要两个星期吧。”

“Even that is too much to expect,” insisted the manager, “I will be satisfied if you simply tell me when the program is complete.”

“即使两个星期恐怕也太夸张了,什么时候你只要告诉我说程序已经完成就好了。”

The programmer agreed to this.

Several years slated, the manager retired. On the way to his retirement lunch, he discovered the programmer asleep at his terminal. He had been programming all night.

几年后,这个经理已经退休了,在他的离职午餐上,他发现这些程序员在他的终端前睡着了,他整夜都在编程。

5.3

A novice programmer was once assigned to code a simple financial package.

一个初学者被要求编写一个财务软件。

The novice worked furiously for many days, but when his master reviewed his program, he discovered that it contained a screen editor, a set of generalized graphics routines, and artificial intelligence interface, but not the slightest mention of anything financial.

他疯狂地工作了很多天,但他的主管检视他的程序时发现,它写了一个编辑嚣,一个图形程序集,和人工智能的界面,但是看不到任何跟财务有关的东西。

When the master asked about this, the novice became indignant. “Don’t be so impatient,” he said, “I’ll put the financial stuff in eventually.”

主管要求解释时,程序员被激怒了:“你太没耐心了,我会在最后写财务的部分。”

5.4

Does a good farmer neglect a crop he has planted?

Does a good teacher overlook even the most humble student?

Does a good father allow a single child to starve?

Does a good programmer refuse to maintain his code?

一个好的农民不会不管他的庄稼。

一个好的老师不会不管哪怕是最差的学生。

一个好的父亲不会让他的任何一个孩子挨饿。

一个好的程序员不应拒绝维护他的程序。


Management

Book Six

Thus spake the master programmer:

编程大师如是说:

“Let the programmer be many and the managers few – then all will be productive.”

“增加程序员,减少经理–这样他们都可提高效率。”

6.1

When managers hold endless meetings, the programmers write games. When accountants talk of quarterly profits, the development budget is about to be cut. When senior scientists talk blue sky, the clouds are about to roll in.

经理们忙于无休无止的会议时,程序员们在写游戏。财务主管在谈论季度盈利时开发预算将会被削减。当老科学家在谈天空的蓝色时,云团蜂拥而至。

Truly, this is not the Tao of Programming.

这不是编程之道。

When managers make commitments, game programs are ignored. When accountants make long-range plans, harmony and order are about to be restored. When senior scientists address the problems at hand, the problems will soon be solved.

经理分配任务时不会包括游戏,会计师做长期计划时,应该做到面面俱到,皆大欢喜。科学家提出一个问题,就会很快得到解决。

Truly, this is the Tao of Programming.

这才是编程之道。

6.2

Why are programmers non-productive? Because their time is wasted in meetings.

为什么程序员没有效率,因为他们把时间都浪费在开会上了。

Why are programmers rebellious? Because the management interferes too much.

为什么程序员难于管理?因为管理者的干预太多了。

Why are the programmers resigning one by one? Because they are burnt out.

为什么程序员一个接一个地辞职,因为他们累坏了。

Having worked for poor management, they no longer value their jobs.

在糟糕的管理下工作,他们享受不到工作的乐趣。

6.3

A manager was about to be fired, but a programmer who worked for him invented a new program that became popular and sold well. As a result, the manager retained his job.

一个经理将被解雇,但他手下的一个程序员写了一个流行的软件并且销路很旺。所以经理保住了他的工作。

The manager tried to give the programmer a bonus, but the programmer refused it, saying, “I wrote the program because I though it was an interesting concept, and thus I expect no reward.”

经理为程序员分红,但程序员拒绝了,他说:“我写程序是因为写程序很有趣,所以我并没想过得资金”。

The manager, upon hearing this, remarked, “This programmer, though he holds a position of small esteem, understands well the proper duty of an employee. Lets promote him to the exalted position of management consultant!”

这位经理说,“这位程序员,不管他现在是什么位置,他都能理解一个雇员的职责所在。我们要把他提升为管理顾问”。

But when told this, the programmer once more refused, saying, “I exist so that I can program. If I were promoted, I would do nothing but waste everyone’s time. Can I go now? I have a program that I’m working one.”

这位程序员又一次拒绝了,他说:“我是一个程序员所以我可以编程,如果我被提升了,除了浪费别人的时间什么也做不了,现在我可以走了吗?我还有一个程序没写完。”

6.4

A manger went to his programmers and told them: “As regards to your work hours: you are going to have to come in at nine in the morning and leave at five in the afternoon.” At this, all of them became angry and several resigned on the spot.

经理对程序员说,“你们的工作时间是早上 9 点到正午点。”,所有的程序员都很不满。

So the manager said: “All right, in that case you may set your own working hours, as long as you finish your projects on schedule.” The programmers, now satisfied, began to come in a noon and work to the wee hours of the morning.

经理又说:“好吧,那随你们的便,只要能按时完成任务。”,程序员们这下满意了,他们中午上班,一直工作到凌晨。


Corporate Wisdom

Book Seven

Thus spake the master programmer:

编程大师如是说:

“You can demonstrate a program for a corporate executive, but you can’t make him computer literate.”

###

“你可以向一位公司主管演示一套程序,但你不能让他的电脑变得象人一样。”

7.1

A novice asked the master: “In the east there is a great tree-structure that men call ‘Corporate Headquarters’. It is bloated out of shape with vice-presidents and accountants. It issues a multitude of memos, each saying ‘Go, Hence!’ or ‘Go, Hither!’ and nobody knows what is meant. Every year new names are put onto the branches, but all to no avail. How can such an unnatural entity exist?”

一 个新学问大师:“在东方,有一个庞大的机 构,人们称作总部。它由为数众多的大小领导。每天发出大量的备忘录,每个备忘录都说:‘干这个,干那个’,没有一个人知道它是什么意思。每年这个机构都会 有更多的人加进来而变得越来越大,但是去没有人去做事情。怎么烩样奇怪的东西还能存在呢?”

The master replies: “You perceive this immense structure and are disturbed that it has no rational purpose. Can you not take amusement from its endless gyrations? Do you not enjoy the untroubled ease of programming beneath its sheltering branches? Why are you bothered by its uselessness?”

大师说:“你已经知道这个巨大的机构并不合理,你就不能不管它为什么这样吗?你尽管享受它的好处就是了,干吗要去管它到底是没有效率呢?”

7.2

In the east there is a shark which is larger than all other fish. It changes into a bird whose winds are like clouds filling the sky. When this bird moves across the land, it brings a message from Corporate Headquarters. This message it drops into the midst of the program- mers, like a seagull making its mark upon the beach. Then the bird mounts on the wind and, with the blue sky at its back, returns home.

在遥远的东方,传说有一只巨大的鱼,叫鲲,它变成了一只大鸟,叫鹏,鹏的翅膀可以遮天蔽日,这只大鸟经过陆地的时候,它带来了一个消息,它把这个消息丢在程序员中,就象一只海鸥在海滩上做的记号,然后鹏背负蓝天,乘风而上,回家去了。

The novice programmer stares in wonder at the bird, for he understands it not. The average programmer dreads the coming of the bird, for he fears its message. The master programmer continues to work at his terminal, for he does not know that the bird has come and gone.

初学者惊恐地看着这只鸟,根本不敢相信,中级程序员担心这只鸟的到来,因为它害怕它带来的消息,编程大师则继续在他的终端前工作他根本不知道这只鸟曾经来过。

7.3

The Magician of the Ivory Tower brought his latest invention for the master programmer to examine. The magician wheeled a large black box into the master’s office while the master waited in silence.

一个学究带着他的最新发明去见编程大师,他把一个大黑盒子推进大师的办公室。

“This is an integrated, distributed, general-purpose workstation,” began the magician, “ergonomically designed with a proprietary operating system, sixth generation languages, and multiple state of the art user interfaces. It took my assistants several hundred man years to construct. Is it not amazing?”

“这是综合的、分布式的通用工作站,”,学究开始介绍了,“按人体工学设计的

The Cathedral and Bazaar - 大教堂和市集

发表于 2016-05-27 | 分类于 Linux

一. 大教堂和市集

Linux 的影响是非常巨大的。甚至在5年以前,有谁能够想象一个世界级的操作系统能够仅仅用细细的 Internet 连接起来的散布在全球的几千个开发人员有以业余时间来创造呢?

我 当然不会这么想。在1993年早期我开始注意 Linux 时,我已经参与 Unix 和自由软件开发达十年之久了。我是八十年代中期 GNU 最早的几个参与 者之一。我已经在网上发布了大量的自由软件,开发和协助开发了几个至今仍在广泛使用的程序(Nethack,Emacs VC 和 GND 模式,xlife 等等)。我想我知道该怎样做。

Linux 推翻了许多我认为自己明白的事情。我已经宣扬小工具、快速原型和演 进式开发的 Unix 福音多年了。但是我也相信某些重要的复杂的事情需要更 集中化的,严密的方法。我相信多数重要的软件(操作系统和象 Emacs 一样的真正大型的工具)需要向建造大教堂一样来开发,需要一群于世隔绝的奇才的细心 工作,在成功之前没有 beta 版的发布。

Linus Torvalds 的开发风格(尽早尽多的发布,委托所有可以委托的事,对所有的改动和融合开放)令人惊奇的降临了。这里没有安静的、虔诚的大教堂的建造工 作——相反,Linux 团体看起来像一个巨大的有各种不同议程和方法的乱哄哄的集市(Linux 归档站点接受任何人的建议和作品,并聪明的加以管理),一 个一致而稳定的系统就象奇迹一般从这个集市中产生了。

这种设计风格确实能工作,并且工作得很好,这个事实确实是一个冲击。在我的研究过程中,我不仅在单个工程中努力工作,而且试图理解为什么 Linux 世界不仅没有在一片混乱中分崩离析,反而以大教堂建造者们不可想象的速度变得越来越强大。

到 了1996年中,我想我开始理解了。我有一个极好的测试我的理论的机会,以一个自由软件计划的形式,我有意识的是用了市集风格。我这样做了,并取得了很 大的成功。在本文的余下部分,我将讲述这个计划的故事,我用它来明确一些自由软件高效开发的格言。并不是所有这些都是从 Linux 世界中学到的,但我们将 看到 Linux 世界给予了它们一个什么样的位置。如果我是正确的,它们将使你理解是什么使 Linux 团体成为好软件的源泉,帮助你变得更加高效。

二. 邮件必须得通过

1993 年以前我在一个小的免费访问的名为 Chester County InterLink 的 ISP 的做技术工作,它位于 Pennsylvania 的 West Chester。(我协助建立了 CCIL,并写了我们独特的多用户 BBS 系统——你可以 telnet 到 locke.ccil.org 来检测一下。今天它在 十九条线上支持三千的用户)。这个工作使我可以一天二十四小时通过 CCIL 的 56K 专线连在网上,实际上,它要求我怎么做!

所以,我对 Internet email 很熟悉。因为复杂的原因,很难在我家里的机器(snark.thyrsus.com)和 CCIL 之间用 SLIP 工作。最后我终于成功了,但我发 现不得不时常 telnet 到 locke 来检查我的邮件,这真是太烦了。我所需要的是我的邮件发送到 snark, 这样 biff(1)会在它到达时通知我。

简 单地 sendmail 的转送功能是不够的,因为 snark 并不是总在网上而且没有一个静态地址。我需要一个程序通过我的 SLIP 连接把我的本地发送的邮 件拉过来。我知道这种东西是存在的,它们大多使用一个简单的协议 POP(Post Office Protocol)。而且,locke 的 BSD/OS 操作系统已经自带了一个 POP3 服务器。

我需要一个 POP3 客户。所以我到网上去找 到了一个。实际上,我发现了三、四个。我用了一会 pop-perl,但它却少一个明显的特征:抽取收到的邮件的 地址以便正确回复。问题是这样的:假设 locke 上一个叫“joe”的人向我发了一封邮件。如果我把它取到 snark 上准备回复时, 我的邮件程序会很高兴 地把它发送给一个不存在的 snark 上的“joe”。手工的在地址上加上“@ccil.org”变成了一个严酷的痛苦。这显然应是计算机替我做的事。(实 际上,依据 RFC1123 的 5.2.18 节,sendmail 应该做这件事)。但是没有一个现存的 POP 客户知道怎样做!于是这就给我们上了第一课:

1. 每个好的软件工作都开始于搔到了开发者本人的痒处。

也 许这应该是显而易见的(“需要是发明之母”长久以来就被证明是正确的),但是软件开发人员常常把他们的精力放在它们既不需要也不喜欢的程序,但在 Linux 世界中却不是这样——这解释了为什么从 Linux 团体中产生的软件质量都如此之高。那么,我是否立即投入疯狂的工作中,要编出一个新的 POP3 客户与现存的那些竞争呢?才不是哪!我仔细考察了手头上的 POP 工具,问自己“那一个最接近我的需要?”因为:

2. 好程序员知道该写什么,伟大的程序员知道该重写(和重用)什么。

我 并没有声称自己是一个伟大的程序员,可是我试着效仿他们。伟大程序员的一个重要特点是建设性的懒惰。他们知道你是因为成绩而不是努力得到奖赏,而且从一 个好的实际的解决方案开始总是要比从头干起容易。例如,Linux 并不是从头开始写 Linux 的。相反的它从重用 Minix(一个 386 机型上的类似 Unix 的微型操作系统)的代码和思想入手。最后所有的 Minix 代码都消失或被彻底的重写了,但是当它们在的时候它为最终成为 Linux 的雏形做了铺 垫。秉承同样的精神,我去寻找良好编码的现成的 POP 工具,用来作为基础。

Unix 世界中的代码共享传统一直对代码重用很友好(这正是为 什么 GNU 计划不管 Unix 本身有多么保守而选取它作为基础操作系统的原因)。 Linux 世界把这个传统推向技术极限:它有几个 T 字节的源代码可以用。所以在 Linux 世界中花时间寻找其他几乎足够好的东西,会比在别处带来更好的结 果。

这也适合我。加上我先前发现的,第二次寻找找到了 9 个候选者——fetchPOP,PopTart,get- mail,gwpop,pimp,pop- perl,popc,popmail 和 upop)。我首先选定的是“fetchpop”。我加入了头标重写功能,并且做了一些被作者加入他的 1.9 版中的改进。但是几个星期之后,我偶然发现了 Carl Harris 写的“popclient”的代码,然后发现有个问题,虽然 fetchpop 有一些好的原始思想 (比如它的守护进程模式),它只能处理 pop3,而且编码的水平相当业余(Seung-Hong 是个很聪明但是经验不足的程序员),Carl 的代码更好一些,相当专业和稳固,但他的程序缺少几 个重要的相当容易实现的 fetchpop 的特征(包括我自己写的那些)。

继续呢还是换一个? 如果换一个的话,作为得到一个更好开发基础的代价,我就要扔掉我已经有的那些代码。换一个的一个实际的动机是支持多协议,pop3 是用的最广的邮局协议, 但并非唯一一个,Fetchpop 和其余几个没有实现 POP2.RPOP,或者 APOP,而且我还有一个为了兴趣加入 IMAP(Internet Message Access Protocol,最近设计的最强大的邮局协议)的模糊想法。但是我有一个更加理论化的原因认为换一下会是一个好主意,这是我在 Linux 很久以前学到 的:

3.“计划好抛弃,无论如何,你会的”(Fred Brooks,《人月神化》第 11 章)

或者换句话说,你常常在第一次实现一个解决方案之后才能理解问题所在,第二次你也许才足够清楚怎样做好它,因此如果你想做好,准备好推翻重来至少一次。好吧 (我告诉自己),对 fetchpop 的尝试是我第一次的尝试,因此我换了一下。

当 我在 1996 年 6 月 25 日把我第一套 popclient 的补丁程序寄给 Carl Harris 之后,我发现一段时间以前他已经对 popclient 基本上失去了兴趣,这些代码有些陈旧,有一些次要的错误,我有许多修改要做,我们很快达 成一致,我来接手这个程序。不知不觉的,这个计划扩大了,再也不是我原先打算的在已有的 pop 客户上加几个次要的补丁而已了,我得维护整个的工程,而且我 脑袋里涌动着一些念头要引起一个大的变化。在一个鼓励代码共享的软件文化里,这是一个工程进化的自然道路,我要指出:

  1. 如果你有正确的态度,有趣的问题会找上你的,但是 Carl Harris 的态度甚至更加重要,他理解:

5. 当你对一个程序失去兴趣时,你最后的责任就是把它传给一个能干的后继者。

甚至没有商量,Carl 和我知道我们有一个共同目标就是找到最好的解决方案,对我们来说唯一的问题是我能否证明我有一双坚强的手,他优雅而快速的写出了程序,我希望轮到我时我也能做到。

三. 拥有用户的重要性

于是我继承了 popclient,同样重要的是,我继承了 popclient 的用户基础,用户是你所拥有的极好的东西,不仅仅是因为他们显示了你正在满足需要,你做了正确的事情,如果加以适当的培养,他们可以成为合作开发者。

Unix 传统另一有力之处是许多用户都是黑客,因为源优码是公开的,他们可以成为高效的黑客,这一点在 Linux 世界中也被推向了令人高兴的极致,这 对缩短调试时间是极端重要的,在一点鼓励之下,你的用户会诊断问题,提出修订建议,帮你以远比你期望快得多的速度的改进代码。

  1. 把用户当做协作开发者是快速改进代码和高效调试的无可争辩的方式。

这种效果的力量很容易被低估,实际上,几乎所有我们自由软件世界中的人都强烈低估了用户可以多么有效地对付系统复杂性,直到 Linus 让我们看到了这一点。

实 际上,我认为 Linus 最聪明最了不起的工作不是创建了 Linux 内核本身,而是发明了 Linux 开发模式,当我有一次当着他的面表达这种观点时, 他微笑了一下,重复了一句他经常说的话:“我基本上是一个懒惰的人,依靠他人的工作来获取成绩。”象狐狸一样懒惰,或者如 Robert Heinlein 所说,太懒了而不会失败。

回顾起来,在 GNU Emacs Lisp 库和 Lisp 代码集中可以看到 Linux 方法的成功,与 Emacs 的 C 内核和许多其他 FSF 的工具相比,Lisp 代码库的演化是流动性的和用户驱 动的,思想和原型在达到最终的稳定形式之前往往要重写三或四次,而且经常利用 Internet 的松散合作。

实际上,我自己在 fetchmail 之前最成功的作品要算 Emacs VC 模式,它是三个其他的人通过电子邮件进行的类似 Linux 的合作,至今我只见过其中一个人 (Richard Stallman),它是 SCCS、RCS 和后来的 CVS 的前端,为 Emacs 提供“one-touch”版本控制操作,它是从一个微型的、粗糙的别人写 好的 sccs.el 模式开始演化的,VC 开发的成功不像 Emacs 本身,而是因为 Emacs Lisp 代码可以很快的通过发布/测试/改进的过程。

(FSF 的试图把代码放入 GPL 之下的策略有一个未曾预料到的副作用,它让 FSF 难以采取市集模式,因为他们认为每个想贡献二十行以上代码的人都必须 得到一个授权,以使受到 GPL 的代码免受版权法的侵扰,具有 BSD 和 MITX 协会的授权的用户不会有这个问题,因为他们并不试图保留那些会使人可能受到质 询的权力)。

四. 早发布、常发布

尽量早尽量频繁的发布是 Linux 开发模式的一个重要部分,多数开发人员 (包括我) 过去都相信这对大型工程来说是个不好的策略,因为早期版本都是些充满错误的版本,而你不想耗光用户的耐心。

这 种信仰强化了建造大教堂开发方式的必要性,如果目标是让用户尽可能少的见到错误,那你怎能不会仅仅每六个月发布一次 (或更不经常),而且在发布之间象一 只狗一样辛勤“捉虫”呢? Emacs C 内核就是以这种方式开发的,Lisp 库,实际上却相反,因为有一些有 FSF 控制之外的 Lisp 库,在那里你可以独立于 Emacs 发布周期地找寻新的和开 发代码版本。

这其中最重要的是 Ohio 州的 elisp 库,预示了今天的巨大的 Linux 库的许多特征的精神,但是我们很少真正仔细考虑我 们在做什么,或者这个库的 存在指出了 FSF 建造教堂式开发模式的什么问题,1992 年我曾经做了一次严肃的尝试,想把 Ohio 的大量代码正式合并到 Emacs 的官方 Lisp 库中, 结果我陷入了政治斗争中,彻底失败了。

但是一年之后,在 Linux 广泛应用之后,很清楚,一些不同的更加健康的东西诞生了,Linus 的开发模式正好与建造教堂方式相反,Sunsite 和 tsx-11 的库开始成长,推动了许多发布。所有这些都是闻所未闻的频繁的内核系统的发布所推动的。

Linus 以所有实际可能的方式把它的用户作为协作开发人员。

  1. 早发布、常发布、听取客户的建议

Linus 的创新并不是这个(这在 Unix 世界中是一个长期传统),而是把它扩展到和他所开发的东西的复杂程度相匹配的地步,在早期一天一次发布对他 来说都不是罕见的! 而且因为他培育了他的协作开发者基础,比其他任何人更努力地充分利用了 Internet 进行合作,所以这确实能行。

但是它是怎样进行的呢? 它是我能模仿的吗? 还是这依赖于 Linus 的独特天才?

我 不这样想,我承认 Linus 是一个极好的黑客 (我们有多少人能够做出一个完整的高质量的操作系统内核?),但是 Linux 并不是一个令人敬畏的概念 上的飞跃,Linus 不是(至少还不曾是) 象 Richard stallman 或 James Gosling 一样的创新天才,在我看来,Linus 更象一个工程天才,具有避免错误和开发失败的第六感觉,掌握了发现从 A 点到 B 点代价最小的路径的决 窍,确实,Linux 的整个设计受益于这个特质,并反映出 Linus 的本质上保守和简化设计的方法。

如果快速的发布和充分利用 Internet 不是偶然而是 Linus 的对代价最小的路径的洞察力的工程天才的内在部分,那么他极大增强了什么? 他创建了什么样的方法?

问题回答了它自己,Linus 保持他的黑客用户经常受到激励和奖赏:被行动的自我满足的希望所激励,而奖赏则是经常 (甚至每天) 都看到工作在进步。

Linus 直接瞄准了争取最多的投入调试和开发的人时,甚至冒代码不稳定和一旦有非常棘手的错误而失去用户基础的险,Linus 似乎相信下面这个:

  1. 如果有一个足够大的 beta 测试人员和协作开发人员的基础,几乎所有的问题都可以被快速的找出并被一些人纠正。

或者更不正式的讲:“如果有足够多的眼睛,所有的错误都是浅显的”(群众的眼睛是雪亮的),我把这称为“Linus 定律”。

我最初的表述是每个问题“对某些人是透明的”,Linus 反对说,理解和修订问题的那个人不一定非是甚至往往不是首先发现它的人,“某个人发现了问题”,他说,“另一个理解它,我认为发现它是个更大的挑战”,但是要点是所有事都趋向于迅速发生。

我 认为这是建造教堂和集市模式的核心区别,在建造教堂模式的编程模式看来,错误和编程问题是狡猾的、阴险的、隐藏很深的现象,花费几个月的仔细检查, 也不能给你多大确保把它们都挑出来的信心,因此很长的发布周期,和在长期等待之后并没有得到完美的版本发布所引起的失望都是不可避免的。

以 市集模式观点来看,在另一方面,我们认为错误是浅显的现象,或者至少当暴露给上千个热切的协作开发人员,让他们来对每个新发布进行测试的时候,它们 很快变得浅显了,所以我们经常发布来获得更多的更正,作为一个有益的副作用,如果你偶尔做了一个笨拙的修改,也不会损失太多。也许我们本不应该这样的惊 奇,社会学家在几年前已经发现一群相同专业的 (或相同无知的) 观察者的平均观点比在其中随机挑选一个来得更加可靠,他们称此为“Delhpi 效应”, Linus 所显示的证明在调试一个操作系统时它也适用——Delphi 效应甚至可以战胜操作系统内核一级的复杂度。

我受 Jeff Dutky (dutky @ wam.umd.edu)的启发指出 Linus 定律可以重新表述为“调试可以并行”,Jeff 观察到虽然调试工作需要调试人员和对应的开发人员相交流,但 它不需要在调试人员之间进行大量的协调,于是它就没有陷入开发时遇到的平方复杂度和管理开销。

在实际中,由于重复劳动而导致的理论上的丧失效率的现象在 Linux 世界中并不是一个大问题,“早发布、常发布策略”的一个效果就是利用快速的传播反馈修订来使重复劳动达到最小。

Brooks 甚至做了一个与 Jeff 相关的更精确的观察:“维护一个广泛使用的程序的成本一般是其开发成本的 40%,奇怪的是这个成本受到用户个数的强烈影响,更多的用户发现更多的错误”(我的强调)。

更 多的用户发现更多的错误是因为更多的用户提供了更多测试程序的方法,当用户是协作开发人员时这个效果被放大了,每个找寻错误的人都有自己稍微不同的 感觉和分析工具,从不同角度来看待问题。“Delphi 效应”似乎因为这个变体工作变得更加精确,在调试的情况下,这个变体同时减小了重复劳动。

所以加入更多的 beta 测试人员虽不能从开发人员的 P.O.V 中减小“最深”的错误的复杂度,但是它增加了这样一种可能性,即某个人的工具和问题正好匹配,而这个错误对这个人来说是浅显的。

Linus 也做了一些改进,如果有一些严重的错误,Linux 内核的版本在编号上做了些处理,让用户可以自己选择是运行上一个“稳定”的版本,还是冒 遇到错误的险而得到新特征,这个战略还没被大多数 Linux 黑客所仿效,但它应该被仿效,存在两个选择的事实让二者都很吸引 人。

五. 什么时候玫瑰不是玫瑰?

在研究了 Linus 的行为和形成了为什么它成功的理论之后,我决定在我的工程 (显然没有那么复杂和雄心勃勃) 里有意识的测试这个理论。

但 我首先做的事是熟悉和简化 Popclient。 Carl Harris 的实现非常好,但是有一种对许多 C 程序来说没有必要的复杂性。他把代码当作核心而把数据结构当作对代码的支持,结果是代码非常漂亮但是数据结 构设计得很特别,相当丑陋 (至少对以这个老 LISP 黑客的标准来看),然而除了提高代码和数据结构设计之外,重写它还有一个目的,就是要把它演化为我彻底 理解的东西,对修改你不理解的程序中的错误负责可不是一件有趣的事。

第一个月我只是在领会 Carl’s 的基本设计的含义,我所做的第一个 重大修改是加入了 IMAP 支持,我把协议机重新组织为一个通用驱动程序和三个方法 表 (对应 POP2、POP3 和 IMAP),这个前面的修改指出一个需要程序员(特别是象 C 这种没有自然的动态类型支持的语言) 记在脑中的一般原理:

  1. 聪明的数据结构和笨拙的代码要比相反的搭配工作的更好

Fred Brooks 也在他第 11 章中讲道:“让我看你的[代码],把你的[数据结构] 隐藏起来,我还是会迷惑;让我看看你的 [数据结构],那我就不需要你的[代码] 了,它是显而易见的”。

实际上,他说的是“流程图”和“表”,但是在三十年的术语/文化演进之后,事情还是一样的。

此时 (1996 年 9 月初,在从零开始六个月后),我开始想接下来修改名字——毕竟,它已不仅仅是一个 POP 客户,但我犹豫了,因为还没有什么新的漂亮设计呢,我的 popclient 版本需要有自己的特色。

当 fetehmail 学会怎样把取到的邮件转送到 SMTP 端口时,事情就完全改变了,但是首先:上面我说过我决定使用这个工程来测试我关于 Linus Torualds 所做的行为的理论,(你可能会问)我怎样做到这点呢? 以下面的方式:

  1. 我尽早尽量频繁的发布 (几乎从未少于每十天发布一次;在密集开发的时候是每天一次)。

  2. 我把每一个和我讨论 fetchmail 的人加入一个 beta 表中。

  3. 每当我发布我都向 beta 表中的人发出通告,鼓励人们参与。

  4. 我听取 beta 测试员的意见,向他们询问设计决策,对他们寄来的补丁和反馈表示感谢。

这些简单的手段立即收到的回报,在工程的开始,我收到了一些错误报告,其质量足以使开发者因此被杀掉,而且经常还附有补丁、我得到了理智的批评,有趣的邮件,和聪明的特征建议,这导致了:

  1. 如果你象对待最宝贵的资源一样对待你的 beta 测试员,他们就会成为你最宝贵的资源。

六. popclient 变成了 Fetchmail

这个工程的真正转折点是 Harry Hochleiser 寄给我他写的代码草稿,他把邮件转发到客户端机器的 SMTP 端口,我立即意识到这个特征的可靠实现将淘汰所有其他的递送模式。

几个星期以来我一直在修改而不是改进 fetchmail,因为我觉得界面设计虽然有用但是太笨拙琐碎了,到处充满了太多的粗陋的细小选项。

当 我思考 SMTP 转发时我发现 popclient 试图做的事太多了,它被设计成既是一个邮件传输代理 (MTA) 也是一个本地递送代理 (MDA)。使用 SMTP 转发,它就可以从 MDA 的事务中解脱出来而成为一个纯 MTA,而象 sendmail 一样把邮件交给本地递送程序来处理。

既然端口 25 在所有支撑 TCP/IP 的平台上早已被预留,为什么还要为一个邮件传输代理的配置或为一个邮箱设置加锁的附加功能而操心呢? 尤其是当这意味着抽取的邮件就象一个正常的发送者发出的 SMTP 邮件一样,而这就是我们需要的。

这里有几个教益:第一,SMTP 转发的想法是我有意识地模拟 Linus 的方法以来的最大的单个回报,一个用户告诉我这个非同寻常的想法——我所需做的只是理解它的含义。

  1. 想出好主意是好事,从你的用户那里发现好主意也是好事,有时候后者更好。

很 有趣的是,你很快将发现,如果你完全承认你从其他人那里得到多少教益的话,整个世界将会认为所有的发明都是你做出的,而你会对你的天才变得谦虚。我 们可以看到这在 Linus 身上体现得多明显!(当我在 1997 年 8 月的 Perl 会议上发表这个论文时,Larry Wall 坐在前排,当我讲到上面的观点时,他激动的叫了出来:“对了! 说对了! 哥们!”所有的听众都哄堂大笑起来,因为他们知道同样的事情也发生在 Perl 的发明者身上)。

于是在同样精神指导下工程进行了几个星期,我开始不光从我的用户那儿也从听说我的系统的人那儿得到类似的赞扬,我把一些这种邮件收藏起来,我将在我开始怀疑自己的生命是否有价值时重新读读这些信。:)但是有两个更基本的,非政治性的对所有设计都有普遍意义的教益。

  1. 最重要和最有创新的解决方案常常来自于你认识到你对问题的概念是错误的。

一个衡量 fetchmail 成功的有趣方式是工程的 beta 测试人员表 (fegtchmail 的朋友们) 的长度,在创立它的时候已经有 249 个成员了,而且每个星期增加两到三个。

实 际上,当我在 1997 年 5 月校订它时,这张表开始因为一个有趣的原因而缩短了,有几个人请求我把他们从表中去掉,因为 fetchmail 已经工作的如此 之好,他们不需要看到这些邮件了! 也许这是一个成熟的市集风格工程的生命周期的一部分。我以前一直在解决错误的问题,把 popclient 当作 MTA 和具 有许多本地递送模式的 MDA 的结合物,Fetchmail 的设计需要从头考虑为一个纯的 MTA,做为一个普通 Internet 邮件路径的一部分。

当你在开发中碰了壁时 (当你发现自己很难想通下一步时),那通常不是要问自己是否找到正确答案,而是要问是否问了正确问题,也许需要重新构造问题。

于是,我重新构造了我的问题,很清楚,要做的正确的事是 (1) 把 SMTP 转发支持放在通用驱动程序中,(2)把它做为缺省模式,(3)最终分离所有其他的递送模式,尤其是递送到文件和标准输出的选项。

我在第三步上犹豫了一下,担心会让 popdiant 的长期用户对新的递送方法感到烦心,在理论上,他们可以立即转而转发文件或者他们的非 sendmail 等价物来得到同样的效果,在实际中这种转换可能会很麻烦。

但是当我这么做之后,证明好处是巨大的,驱动程序代码的冗余的部分消失了,配置完全变得简单了——不用屈从于系统 MDA 和用户的邮箱,也不用为下层 OS 是否支持文件锁定而担心了。

而 且,丢失邮件的唯一漏洞也被堵死了,如果你选择了递送到一个文件而磁盘已满,你的邮件就会丢失,这在 SMTP 转发中不会发生,因为 SMTP 侦听器不会返 回 OK 的,除非邮件可以递送成功或至少被缓冲留待以后递送。还有,性能也改善了 (虽然在单次执行中你不会注意到),这个修改的另一个不可忽视的好处是手册 变得大大简单了。后来,为了允许处理一些罕见的情况,包括动态 SLIP,我必须回到让用户定义本地 MDA 递送上来,但是我发现了一个更加简单的方法。

所有这些给了我们什么启发呢? 如果可以不损失效率,就要毫不犹豫抛弃陈旧的特性,Antonine de Saint-Exupery(在他成为经典儿童书籍作家之前是一个飞行员和飞机设计师)曾说过:

  1. “最好的设计不是再也没有什么东西可以添加了,而是再也没有什么东西可以去掉。”

当 你的代码变得更好和更简单时,这就是你知道它是正确的时候了,而且在这个过程中,fetehmail 的设计具有了自己的特点,而区别于其前身 popclient。现在是改名的时候了,这个新的设计看起来比老 popclient 更象一个 sendmail 的复制品,它们都是 MTA,但是 Senmail 是推然后递送,而新的 popclient 是拉然后递送。于是,在两个月之后,我把它重新命名为 fetehmail。

七. Fetchmail 成长起来

现 在我有了一个简洁和富有创意的设计,工作得很好的代码,因为我每天都用它,和一直在增长的 beta 表,它让我渐渐明白我已经不是在从事只能对少数其他人 有用的工作中,我写了一个所有有一个 Unix 邮箱和 SLIP/PPP 邮件连接的人都真正需要的程序。通过 SMTP 转发功能,它成为一个潜在的“目录杀 手”,远远领先于它的竞争者,这个程序如此能干以至于其他的程序不但被放弃简直被忘记了。

我知道你不可以真得瞄准或计划出这样的结果,你只能努力去设计这些强大的思想,以后这些结果就好象是不可避免的、自然的、注定了的,得到这种思想的唯一办法是获取许多思想,或者用工程化的思考其他人的好主意而超过原来想到它的人的设想。

Andrew Tanenbanm 原来设想建造一个适合 386 的简单的 Unix 用做教学,Linus Torvalels 把 Andrew 的可能想到的 Minix 可以做什么的概念推进了一步,成长为一个极好的东西,同样的 (虽然规模较小),我接受了 Card Harris 和 Harry Hochheiser 的想法,把它们变得更强大,我们都不是人们所浪漫幻想的天才的创始人,但是大多数科学和工程和软件开发不是被天才的创始人完成的,这 和流传的神话恰恰相反。

结果总是执着的原因——实际上,它是每个黑客为之生存的成功! 而且它们意味着我必须把自己的标准定高一点,为了把 fetchmail 变得和我所能设想 的那样好,我必须不仅为我自己的需要写代码,而且也要包括对在我生活围主页外的人们的需求的支持,而且同时也要保证程序的简单和健壮。在实现它之后我首先 写的最重要的特征是支持多投——从集中一组用户的邮件的邮箱中取出邮件,然后把它路由到每个人手中。

我之所以加上多投功能部分是因为有些用户一直在闹着要它,更是因为我想它可以从单投的代码中揭露出错误来,让我完全一般地处理寻址,而且这被证明了。 正确解释 RFC822 花了我相当长的时间,不仅因为它的每个单独部分都很难,而且因为它有一大堆相互依赖的苛刻的细节。

但是多投寻址也成为一个极好的设计决策,由此我知道:

  1. 任何工具都应该能以预想的方式使用,但是一个伟大的工具提供你没料到的功能。

Fetchmant 多投功能的一个没有料到的用途是在 SLIP/PPP 的客户端提供邮件列表、别名扩展。这意味着一个使用个人机器的人不必持续访问 ISP 的别名文件就能通过一个 ISP 帐户管理一个邮件列表。我的 beta 测试员提出的另一个重要的改变是支持 8 位 MIME 操作,这很容易做,因为我已经仔 细的保证了 8 位代码的清晰,不仅因为我预见到了这个特性的需求,而且因为我忠实于另一准则:

  1. 当写任何种类的网关型程序时,多费点力,尽量少干扰数据流,永远不要抛弃信息,除非接收方强迫这么作!

如果我不遵从这个准则,那么 8 位 MIME 支持将会变得困难和笨拙,现在我所需要做的,是只读一下 RFC 1652,在产生信头的逻辑加上一点而已。

一些欧洲用户要求我加上一个选项来限制每次会话取得消息数 (这样他们就可以从昂贵的电话网中控制花费了),我很长一段时间拒绝这样做,而且我仍然对它不很高兴,但是如果你是为了世界而写代码,你必须听取顾客的意见——这并不随他们不付给你钱而改变。

八. 从 Fetchmail 得来的另一些教益

在他们回到一般的软件工程问题以前,还有几个从 fetchmail 得到的教益需要思考。

rc 文件语法包括可选的“noise”关键字,它被扫描器完全忽略了,当你把它们全抽取出的时候,关键字/值对 更具可读性。当我注意到 rc 文件的声明在多大程度上开始象一个微型命令语言时,这是一个 Late-night 的体验 (这也是我为什么把 popclient 原来的“server”关键字改成了“poll”)。

对我来说似乎把这个微型命令语言变得更象英语可能会使它更容易使用。现在,虽然我对经过 Emacs 和 HTML 及 许多数据库引擎所证实的“把它做成一个语言”的设计方式确信不疑,但是我并不是一个通常的“类英语”语法的狂热拥护者。传统程序员容易控制语法使它尽量精 确和紧凑,完全没有冗余,这是计算机资源还很昂贵时遗留下的一种文化传统,所以扫描策略需要尽可能的廉价和简单,而具有 50% 冗余度的英语,看来好象是一 个非常不合适的模型。

这并不是我不用类英语语法的原因,我提到这一点是为了推翻它,在更廉价的时钟周期与核心的时代,简洁并没有走到尽头,今天对一个语言来说,对人更方便比对机器更廉价来的更加重要。

然而,有几个原因提醒我们小心一点,一个是扫描策略的复杂度开销——你并不想把它变成一个巨大的错误来源和让用户困惑,另一个是试图使语言表面上的类似可以和传统语言一样令人困惑 (你可以在许多 4GL 和商业数据库查询语言上看到这一点)。

Fetchmail 的控制语法避免了这些问题,因为语言的领域是极其有限的。它一点也不象一个一般性的语言,它很简单地描述的东西并不复杂,所以很少可能在英语的一个小子集与实际的控制语言之间发生混淆,我想这有一个更广泛的教益:

  1. 如果你的语言一点也不象是图灵完备的,严格的语法会有好处。

另一个教益是关于安全的,一些 fetchmail 用户要求我修改软件把口令加密存贮在 rc 文件里,这样觑探者就 不能看到它们了。我没有这样做,因为这实际上起不到任何保护作用,任何有权读取你的 rc 文件的人都可以以你的名义运行 fetchmail——如果他们要破 你的口令,它们可以从 fetchmail 的代码中找到制作解码器的方法。

所以 fetchmail 口令的加密都会给那些不慎重思考的人一种安全的错觉,这里一般性的准则是:

  1. 一个安全系统只能和它的秘密一样安全,当心伪安全。

九. 集市风格的必要的先决条件

本文的早期评审人员和测试人员坚持提出成功的市集模式开发的先决条件,包括工程领导人的资格问题和在把项目公开和开始建造一个协作开发人员的社团的时候代码的状态。

相当清楚,不能以一个市集模式从头开发一个软件,我们可以以市集模式、测试、调试和改进,但是以市集模式从头开始一个项目将是非常困难的,Linus 没有这样做,我也没有,初期的开发人员的社团应该有一此可以运行和测试的东西来玩。

当你开始创建社团时,你需要演示的是一个诺言,你的程序不需要工作的很好,它可以很粗糙、很笨拙、不完整和缺少文档、它不能忽略的东西是要吸引哪些人卷入一个整洁的项目。

Linux 和 fetchmail 都是以一个吸引人的基本设计进入公共领域的,许多和我一样在思考市集模式的人已经正确的认为这是非常关键的,然后得出了一个结论,工程领导者的高度的设计直觉和聪颖是必不可少的。

但是 Linus 是从 Unix 得到他的设计的,我最初是从先前的 popmail 得到启发的 (虽然相对 Linux 而言,它最后改变巨大),所以市集风格的领导人/协调人需要有出众的设计才能,或者他可以利用别人的设计才能?

我认为能够提出卓越的原始设计思想对协调人来说不是最关键的,但是对他/她来说绝对关键的是要能把从他人那里得到的好的设计重新组织起来。

Linux 和 fetchmail 项目都显示了这些证据,Linus(如同前面所说)并不是惊人的原始设计者,但他显示了发现好的设计并把它集成到 Linux 内核中的强大决窍。还有我也描述了怎样从别人那里得到了 fetchmail 中最强大的设计思想 (SMTP 转发)。

本文的早期读者称赞我,说因为我做了许多关于原始设计的事,所以倾向于低估原始设计在市集项目中的价值,也许有些是对的吧,但是设计 (而不是编码或调试) 本来就是我最强的能力。

变得聪明和软件设计的原始创作的问题是它会变成一个习惯,当需要保持事物健壮和简洁的时候,你却开始把事情变得漂亮但却复杂。我曾经犯过错误,使得一些项目因我而崩溃了,但我努力不让它发生在 fetchmail 身上。

所以我相信 fetchmail 项目的成功部分是因为我抑制自己不要变得太聪明,这说明 (至少) 对市集模式而言原 始设计并不是本质的,请考察一下 Linux 假设 Linus Torvalds 在开发时试图彻底革新操作系统设计,它还会象今天我们所拥有的内核那样稳定和成功吗?

当然基本的设计和编码技巧还是必需的,但我希望每个严肃考虑发起一个市集计划的人都已至少具备这些能力,自由软件社团的内部市场对人们有某些微妙的压力,让他们不要发起自由不能搞定的开发,目前为止,这工作得仍然相当好。

对市集项目来说,我认为还有另一种通常与软件开发无关的技能和设计能力同样重要——或者更加重要,市集项目的协调人或领导人必须有良好的人际和交流能力。

这是很显然的,为了建造一个开发社团,你需要吸引人,你所做的东西要让他们感到有趣,而且要保持他们对他们正在做的工作感到有趣,而且要保持他们对他们正在做的工作感到高兴,技术方面对达成这些目标有一定帮助,但这远远不是全部,你的个人素质也有关系。

并不是说 Linus 是一个好小伙子,让人们喜爱并乐于帮助他,也并不是说我是个积极外向的,喜欢扎堆儿工作,有出众的幽默感的人,对市集模式的工作而言,至少有一点吸引人的技巧是非常有帮助的。

十. 自由软件的社会学语境

下述如实:最好的开发是从作者解决每天工作中的个人问题开始的,因为它对一大类用户来说是一个典型问题,所以它就推广开来了,这把我们带回到准则 1,也许是用一个更有用的方式来描述:

18. 要解决一个有趣的问题,请从发现让你感兴趣的问题开始。

这 是 Carl Harris 和原先的 popclient 的情形,也是我和 fetchmail 的情形,但这已在很长一段时间被大家知晓了,Linux 和 fetchmail 的历史要求我们注意的有趣之处是下一个阶段——软件在一个庞大的活跃的用户和协作开发人员的社团中的进化。

在《人月神话》一书 中,Fred Brooks 观察到程序员的工作时间是不可替代的:在一个误了工期的软件项目中增加开发人员只会让它拖得更久,他声称项目的复杂度和通讯开销以开发人员的 平方增长,而工作成绩只是以线性增长,这个说法被称为“Brooks 定律”,被普遍当作真理,但如果 Brooks 定律就是全部,那 Linux 就不可能成 功。

几年之后,Gerald Weinbeng 的经典之作“The Psychology Of Computer Progromming”为我们更正了 Brooks 的看法,在他的“忘我 (egoless) 的编程”中,Weinberg 观察到在开发人员不顽固保守自己 的代码,鼓励其他人寻找错误和发展潜力的地方,软件的改进的速度会比其他地方有戏剧性的提高。

Weinberg 的用词可阻止了他的分析得到应有的接受,人们对把 Internet 黑客称为“忘我”的想法微笑,但是我想今天他的想法比以往任何时候都要引人注目。

Unix 的历史已经为我们准备好了我们正在从 Linux 学到的 (和我在更小规模上模仿 Linus 的方法所验证的) 东西,这就是,虽然编码仍是一个人干 的活,真正伟大的工作来自于利用整个社团的注意和脑力,在一个封闭的项目中只利用他自己的脑力的人会落在知道怎样创建一个开放的、进化的,成百上千的人在 其中查找错误和进行修改的环境的开发人员之后。

但是 Unix 的传统中有几个因素阻止把这种方法推到极致。一个是各种授权的法律约束、商业机密和商业利益,另一个 (事后来看) 是 Internet 还不够好。

在 Internet 变得便宜之前,有一些在地理上紧密的社团,它们的文化鼓励 Weingberg 的“忘我”编程,一个开发人员很容易吸引许多熟练的人和协 作开发人员,贝尔实验室,MIT A1 实验室,UC Berkeley,都成为传统的、今天仍然是革新的源泉。

Linux 是第一个有意识的成功的利用整个世界做为它的头脑库的项目,我不认为 Linux 的孕育和万维网的诞生相一致是一个巧合,而且 Linux 在 1993-1994 的一段 ISP 工业大发展和对 Internet 的兴趣爆炸式增长的时期中成长起来,Linus 是第一个学会怎样利用 Internet 的新 规的人。

廉价的 Internet 对 Linux 模式的演化来说是一个必要条件,但它并不充分,另一个关键因素是领导风格的开发和一套协作的氛围使开发人员可以吸引协作开发人员和最大限度地利用媒体。

但 是这种领导风格与氛围到底是什么呢? 它不能建立在权力关系之上——甚至如果它们可以,高压的领导权力不能产生我们所看到的结果,Weinberg 引用了 19 世纪俄国的无政府主义者 Kropotkin 的“Memoris of a Revolutionist”来证明这个观点:

“我从小生 活在一个农奴主的家庭中,我有一个活跃的生活,象我们时代的所有年轻人一样,我深信命令、强制、责骂、惩罚等等的必要性。但是当我 (在早 期) 必须管理一个企业,和 (自由) 人打交道时,当每一个错误都会产生严重后果时,我开始接受以命令和纪律为准则来行动和以普通理解为准则来行动的区别。前 者在军事阅兵中工作的很好,但是它在现实生活中一文不值,目标达成只是靠许多愿望的聚合的简单后果。”“许多聚合在一起的愿望的直接后果”精确地指出了象 Linux 的项目所需要的东西。“命令的准则”在 Internet 这种无政府主义的天堂中一群自愿者之中是没有市场的,为了更有效的操作和竞争,想领导协 作项目的黑客们必须学会怎样以 Kropotkins 含糊指出的“理解的准则”模式来恢复和激活社团的力量,他们必须学会使用 Linus 定律。

前 面我引用“Delhpi 效应”来作为 Linus 定律的一个可能的解释,但是来自生物学和经常学的自适应系统的更强大的分析也提出了自己的解释, Linus 世界的行为更象一个自由市场或生态系统,由一大群自私的个体组成,它们试图取得 (自己) 最大的实效,在这个过程中产生了比任何一种中央计划都细 致和高效的自发的改进的结果,所以,这里就是寻找“理解的准则”的地方。

Linux 黑客取得的最大化的“实际利益”不是经典的经济利益, 而是无形的他们的自我满足和在其他黑客中的声望,(有人会说他们的动机是“利他的”, 但这忽略了这样的事实:利他主义本身是利他主义者的一种自我满足的形式),自愿的文化以这种方式工作的实际上并非不寻常,我已参与一个科幻迷团体很长时间 了,它不象黑客团体一样,显式地识别出“egoboo”(一个人在其他爱好者之中的声望的增长)作为自愿者活动背后的基础驱动力)。

Linus 成功地把自己置于项目的守门人的位置,在项目中开发大部分是别人做的,他只是在项目中培养兴趣直到它可以自己发展下去,这为我们展示了对 Kropokin 的“共同理解原则”的敏锐把握,对 Linux 这种类似经济学的观点让我们看到这种理解是怎样应用的。

我 们可以把 Linus 的方法视为创建一个高效的关于“egoboo”(而不是钱)的市场,来把自私的黑客个体尽可能紧密的联系起来,达成只能通过高度 协作才能得到的困难的结果,在 fetchmail 项目中我展示了 (在较小规模上) 这种模式可以复制,得到良好的结果,也许我比他更有意识一点、更加系统一 点。

许多人 (尤其是哪些由于政治原因不信任自由市场的人) 会盼望自我导向的自我主义者的文化破碎、报废、秘密和敌对,但这种盼望很明显地 被 Linux 的文 档的多样性、质量和深度打破了,程序员讨厌写文档似乎已是圣训,但 Linux 的黑客们怎么产生了这么多? 显然 Linux 的 egoboo 自由市场比有大量资 金的商业软件产品的文档部在产生有品德的、他人导向的行为方面工作的更好。

Fetchmail 和 Linux 内核项目都表明,通过恰当的表彰许多其他黑客,一个强大的开发者/协调者可以用 Internet 得到许多协同开发人员而不是让项目分崩离析为一片混乱,所以关于 Brooks 定律我得到了下面的想法:

  1. 如果开发协调人员有至少和 Internet 一样好的媒介,而且知道怎样不通过强迫来领导,许多头脑将不可避免地比一个好。

我认为自由软件的将来将属于那些知道怎样玩 Linus 的游戏的人,把大教堂抛之脑后拥抱市集的人,这并不是说个人的观点与才气不再重要,而是,我认为自由软件的前沿将属于从个人观点和才气出发的人,然后通过共同兴趣自愿社团的高效建造来扩展。

可能不只是自由软件的将来,在解决问题方面,没有任何商业性开发者可以与 Linux 社团的头脑库相匹敌,很少有人能负担起雇佣 200 多个为 fetchmail 出过力的人!   也许最终自由软件文化将胜利,不是因为协作在道德上是正确的或软件“囤积居奇”在道德上是错的(假设你相信后者,Linus 和我都不),而仅仅是因为商业世界在进化的军备竞赛中不能战胜自由软件社团,因为后者可以把更大更好的开发资源放在解决问题上。

Master-boot-record

发表于 2016-05-27 | 分类于 软件

硬盘的 0 磁道的第一个扇区称为 MBR,它的大小是 512 字节,而这个区域可以分为三个部分。第一部分为 pre-boot 区(预启动区),占 446 字节;第 二部分是分区表(Partition Table),占 64 个字节,硬盘中分区有多少以及每一分区的大小都记在其中。第三部分是 magic
number,占 2 个字节,固定为 55AA。

MBR 通常由 fdisk 等类似命令创建,系统上电自检之后,会调用 INT 19 中断 (CTRL+ALT+Delete 同样引发这个中断) 。INT 19 会查找活动分区(用第一个字符为 80 标记) 载入并跳转到 0000:7C00 开始执行程序。若未找到活动分区,则自动执行启动硬盘的 MBR 0000:7C00 地址程序。因为每个操作系统的启动区格式都不相同,所以这里的这段程序会查找操作系统的启动代码或者启动管理器例如 Grub 等。

以下是一个 MBR 的十六进制和 ASCII 码,后面会分段介绍具体内容。

OFFSET 0 1 2 3 4 5 6 7 8 9 A B C D E F *0123456789ABCDEF*
000000 fa33c08e d0bc007c 8bf45007 501ffbfc *.3.....|..P.P...*
000010 bf0006b9 0001f2a5 ea1d0600 00bebe07 *................*
000020 b304803c 80740e80 3c00751c 83c610fe *...<.t..<.u.....*
000030 cb75efcd 188b148b 4c028bee 83c610fe *.u......L.......*
000040 cb741a80 3c0074f4 be8b06ac 3c00740b *.t..<.t.....<.t.*
000050 56bb0700 b40ecd10 5eebf0eb febf0500 *V.......^.......*
000060 bb007cb8 010257cd 135f730c 33c0cd13 *..|...W.._s.3...*
000070 4f75edbe a306ebd3 bec206bf fe7d813d *Ou...........}.=*
000080 55aa75c7 8bf5ea00 7c000049 6e76616c *U.u.....|..Inval*
000090 69642070 61727469 74696f6e 20746162 *id partition tab*
0000a0 6c650045 72726f72 206c6f61 64696e67 *le.Error loading*
0000b0 206f7065 72617469 6e672073 79737465 * operating syste*
0000c0 6d004d69 7373696e 67206f70 65726174 *m.Missing operat*
0000d0 696e6720 73797374 656d0000 00000000 *ing system......*
0000e0 00000000 00000000 00000000 00000000 *................*
0000f0 TO 0001af SAME AS ABOVE
0001b0 00000000 00000000 00000000 00008001 *................*
0001c0 0100060d fef83e00 00000678 0d000000 *......>....x....*
0001d0 00000000 00000000 00000000 00000000 *................*
0001e0 00000000 00000000 00000000 00000000 *................*
0001f0 00000000 00000000 00000000 000055aa *..............U.*

上面代码反汇编的结果如下:1. 首先,代码会把自己复制到 0000:0600BEGIN: NOW AT 0000:7C00, RELOCATE

0000:7C00 FA CLI disable int's
0000:7C01 33C0 XOR AX,AX set stack seg to 0000
0000:7C03 8ED0 MOV SS,AX
0000:7C05 BC007C MOV SP,7C00 set stack ptr to 7c00
0000:7C08 8BF4 MOV SI,SP SI now 7c00
0000:7C0A 50 PUSH AX
0000:7C0B 07 POP ES ES now 0000:7c00
0000:7C0C 50 PUSH AX
0000:7C0D 1F POP DS DS now 0000:7c00
0000:7C0E FB STI allow int's
0000:7C0F FC CLD clear direction
0000:7C10 BF0006 MOV DI,0600 DI now 0600
0000:7C13 B90001 MOV CX,0100 move 256 words (512 bytes)
0000:7C16 F2 REPNZ move MBR from 0000:7c00
0000:7C17 A5 MOVSW to 0000:0600
0000:7C18 EA1D060000 JMP 0000:061D jmp to NEW_LOCATION
  1. 从分区表中查找活动分区

设置表指针

NEW_LOCATION: NOW AT 0000:0600
0000:061D BEBE07 MOV SI,07BE point to first table entry
0000:0620 B304 MOV BL,04 there are 4 table entries

第一遍查找

SEARCH_LOOP1: SEARCH FOR AN ACTIVE ENTRY

0000:0622 803C80 CMP BYTE PTR [SI],80 is this the active entry?
0000:0625 740E JZ FOUND_ACTIVE yes
0000:0627 803C00 CMP BYTE PTR [SI],00 is this an inactive entry?
0000:062A 751C JNZ NOT_ACTIVE no
0000:062C 83C610 ADD SI,+10 incr table ptr by 16
0000:062F FECB DEC BL decr count
0000:0631 75EF JNZ SEARCH_LOOP1 jmp if not end of table
0000:0633 CD18 INT 18 GO TO ROM BASIC

找到活动分区

FOUND_ACTIVE: FOUND THE ACTIVE ENTRY

0000:0635 8B14 MOV DX,[SI] set DH/DL for INT 13 call
0000:0637 8B4C02 MOV CX,[SI+02] set CH/CL for INT 13 call
0000:063A 8BEE MOV BP,SI save table ptr

第二遍查找以保证只有一个活动分区

SEARCH_LOOP2: MAKE SURE ONLY ONE ACTIVE ENTRY

0000:063C 83C610 ADD SI,+10 incr table ptr by 16
0000:063F FECB DEC BL decr count
0000:0641 741A JZ READ_BOOT jmp if end of table
0000:0643 803C00 CMP BYTE PTR [SI],00 is this an inactive entry?
0000:0646 74F4 JZ SEARCH_LOOP2 yes

无活动分区,则打印信息,挂起系统

NOT_ACTIVE: MORE THAN ONE ACTIVE ENTRY FOUND

0000:0648 BE8B06 MOV SI,068B display "Invld prttn tbl"

DISPLAY_MSG: DISPLAY MESSAGE LOOP

0000:064B AC LODSB get char of message
0000:064C 3C00 CMP AL,00 end of message
0000:064E 740B JZ HANG yes
0000:0650 56 PUSH SI save SI
0000:0651 BB0700 MOV BX,0007 screen attributes
0000:0654 B40E MOV AH,0E output 1 char of message
0000:0656 CD10 INT 10 to the display
0000:0658 5E POP SI restore SI
0000:0659 EBF0 JMP DISPLAY_MSG do it again

HANG: HANG THE SYSTEM LOOP

0000:065B EBFE JMP HANG sit and stay!
  1. 找到活动分区之后,会读取启动信息

    READ_BOOT: READ ACTIVE PARITION BOOT RECORD
    
    0000:065D BF0500 MOV DI,0005 INT 13 retry count
    
    INT13RTRY: INT 13 RETRY LOOP
    
    0000:0660 BB007C MOV BX,7C00
    0000:0663 B80102 MOV AX,0201 read 1 sector
    0000:0666 57 PUSH DI save DI
    0000:0667 CD13 INT 13 read sector into 0000:7c00
    0000:0669 5F POP DI restore DI
    0000:066A 730C JNB INT13OK jmp if no INT 13
    0000:066C 33C0 XOR AX,AX call INT 13 and
    0000:066E CD13 INT 13 do disk reset
    0000:0670 4F DEC DI decr DI
    0000:0671 75ED JNZ INT13RTRY if not zero, try again
    0000:0673 BEA306 MOV SI,06A3 display "Errr ldng systm"
    0000:0676 EBD3 JMP DISPLAY_MSG jmp to display loop
    
    INT13OK: INT 13 ERROR
    
    0000:0678 BEC206 MOV SI,06C2 "missing op sys"
    0000:067B BFFE7D MOV DI,7DFE point to signature
    0000:067E 813D55AA CMP WORD PTR [DI],AA55 is signature correct?
    0000:0682 75C7 JNZ DISPLAY_MSG no
    0000:0684 8BF5 MOV SI,BP set SI
    0000:0686 EA007C0000 JMP 0000:7C00 JUMP TO THE BOOT SECTOR
    WITH SI POINTING TO
    PART TABLE ENTRY
    
  2. 后面是一些显示字符

    0000:0680 ........ ........ ......49 6e76616c * Inval*
    0000:0690 69642070 61727469 74696f6e 20746162 *id partition tab*
    0000:06a0 6c650045 72726f72 206c6f61 64696e67 *le.Error loading*
    0000:06b0 206f7065 72617469 6e672073 79737465 * operating syste*
    0000:06c0 6d004d69 7373696e 67206f70 65726174 *m.Missing operat*
    0000:06d0 696e6720 73797374 656d00.. ........ *ing system. *
    
  3. 接着是一段没有用的空区域

    0000:06d0 ........ ........ ......00 00000000 * .....*
    0000:06e0 00000000 00000000 00000000 00000000 *................*
    0000:06f0 00000000 00000000 00000000 00000000 *................*
    0000:0700 00000000 00000000 00000000 00000000 *................*
    0000:0710 00000000 00000000 00000000 00000000 *................*
    0000:0720 00000000 00000000 00000000 00000000 *................*
    0000:0730 00000000 00000000 00000000 00000000 *................*
    0000:0740 00000000 00000000 00000000 00000000 *................*
    0000:0750 00000000 00000000 00000000 00000000 *................*
    0000:0760 00000000 00000000 00000000 00000000 *................*
    0000:0770 00000000 00000000 00000000 00000000 *................*
    0000:0780 00000000 00000000 00000000 00000000 *................*
    0000:0790 00000000 00000000 00000000 00000000 *................*
    0000:07a0 00000000 00000000 00000000 00000000 *................*
    0000:07b0 00000000 00000000 00000000 0000.... *............ *
    
  4. 后面是分区表信息,启示位置为 0000:07be,每个分区表占 16 字节,这里只有一个主分区,开头的 80 表明这是一个启动分区。

    0000:07b0 ........ ........ ........ ....8001 * ....*
    0000:07c0 0100060d fef83e00 00000678 0d000000 *......>....x....*
    0000:07d0 00000000 00000000 00000000 00000000 *................*
    0000:07e0 00000000 00000000 00000000 00000000 *................*
    0000:07f0 00000000 00000000 00000000 0000.... *............ *
    
  5. 最后是 55AA 标记

    0000:07f0 ........ ........ ........ ....55aa *..............U.*
    

如果奇怪为什么用 55AA 这个值,写成二进制就清楚了:

0x55aa=(0101010110101010)2

Linux From Scratch

发表于 2016-05-27 | 分类于 Linux

2007-05-11 15:34

花了两天半的时间,搞完了 Linux from Scratch ,对编译器、系统、编译器之间的鸡生蛋、蛋生鸡的问题有了实际的认识。

基本按步骤一步一步来的,更多的时间是等待编译,只不过在最后的时候 Grub 没有重写 MBR,而是直接在 现有系统上加了一个启动项。

手动添加

Wincat >> /boot/grub/menu.lst << "EOF"
title Windows
rootnoverify (hd0,0)
chainloader +1
EOF

用命令讲故事

发表于 2016-05-27 | 分类于 代码

picture alt

pkgconfig

发表于 2016-05-27 | 分类于 代码

2008-06-20 09:59
你在 Unix 下开发过软件吗?写完一个程序,编译运行完全正常,在你本机上工作得好好的,你放到源代码管理系统中。然后,告诉你的同事说,你可以取下来用了。这时,你长长的出了一口气,几天的工作没有白费,多么清新的空气啊,你开始飘飘然了。

“Hi,怎么编译不过去?”你还沉浸在那种美妙的感觉之中,双臂充满着力量,似乎没有什么问题能难倒你的。正在此时,那个笨蛋已经冲着你嚷开了。

“不会吧,我这边好好的!”表面上你说得很客气,其实,你心里已经骂开了,真笨,不知道脑子干嘛用的。也许,你想的没错,上次,他犯了一个简单的错误,不是你一去就解决了吗。

他喊三次之后,你不得不放下你手上的工作,刚才那种美妙的感觉已经消失得无影无踪了,要不是你把情绪控制得很好,一肚子气就要撒在他身上了。你走到他的电脑前,键入 make,优雅的按下回车。怎么可能出错呢?你信心十足。然而,屏幕上的结果多少有点让人脸红,该死的,libxxx.so 怎么会让不到呢?

你在 /usr 目录中查找 libxxx.so,一切都逃不过你的眼睛。奇怪,libxxx.so 怎么在 /usr/local/lib 下,不是应该在 /usr/lib 下的吗?这你可不能怪别人,别人想安装在哪里都行,下次还可能安装到 /lib 目录下呢。

以 上的场景并非虚构,我都经历过好几次,明明在本机上好好的,在别人的机器上连编译都过不去。可能两人的操作系统一模一样,需要的库都安装上,只是由于个人 喜好不同,安装在不同的目录而已。遇到这种情况,每次都技巧性的绕过去了,用的补丁型的方法,心里老惦记其它地方能不能工作。

今天我们要介绍的 pkgconfig,为解决以上问题提供了一个优美方案。从此,你再也不为此担忧了。Pkgconfig 提供了下面几个功能:

  • 检查库的版本号。如果所需要的库的版本不满足要求,它会打印出错误信息,避免链接错误版本的库文件。
  • 获得编译预处理参数,如宏定义,头文件的位置。
  • 获得链接参数,如库及依赖的其它库的位置,文件名及其它一些连接参数。
  • 自动加入所依赖的其它库的设置。

这一切都自动的,库文件安装在哪里都没关系!

在使用前,我们说说 pkgconfig 的原理,pkgconfig 并非精灵,可以凭空得到以上信息。事实上,为了让 pkgconfig 可以得到这些信息,要求库的提供者,提供一个.pc 文件。比如 gtk+-2.0 的 pc 文件内容如下:

prefix=/usr

exec_prefix=/usr

libdir=/usr/lib

includedir=/usr/include

target=x11

gtk_binary_version=2.4.0

gtk_host=i386-redhat-linux-gnu

Name: GTK+

Description: GIMP Tool Kit (${target} target)

Version: 2.6.7

Requires: gdk-${target}-2.0 atk

Libs: -L${libdir} -lgtk-${target}-2.0

Cflags: -I${includedir}/gtk-2.0

这个文件一般放在 /usr/lib/pkgconfig/ 或者 /usr/local/lib/pkgconfig/ 里,当然也可以放在其它任何地方,如像 X11 相关的 pc 文件是放在 /usr/X11R6/lib/pkgconfig 下的。为了让 pkgconfig 可以找到你的 pc 文件,你要把 pc 文件所在的路径,设置在环境变量 PKG_CONFIG_PATH 里。

使用方法很简单,比如,我们要使用 gtk+ 的库编译一个程序:

gcc -g arrow.c -o arrow `pkg-config "gtk+-2.0 > 2.0.0" --cflags --libs`

只要安装了 gtk+2.0,不管它在哪里,编译都是正常的。这是不是简单很多了?

1234…18

Feng Chao

178 日志
14 分类
1 标签
RSS
GitHub E-Mail Twitter
© 2006 — 2018 Feng Chao
由 Hexo 强力驱动
|
主题 — NexT.Mist