存档

‘乱七八糟’ 分类的存档

杂七杂八的链接

2010年11月3日 16hot 没有评论

http://code.google.com/p/chunzhenshmphp/

http://code.google.com/p/richard-log/

http://www.itlearner.com/article/4056

http://www.itlearner.com/article/4055

http://www.kumouse.com/?p=598

http://www.cnblogs.com/sunli/archive/2010/03/25/1696183.html

http://github.com/nmathewson/libevent-book/

http://www.wangafu.net/~nickm/libevent-book/

virtualbox serial console:

https://gist.github.com/284940/11e6354f170be602c9c2f67b59d489ed49ebd143

http://www.thismail.org/bbs/thread-3921-1-1.html

dlmalloc:

http://blog.chinaunix.net/u/26524/article_112202.html

ftp://g.oswego.edu/pub/misc/

http://bbs.chinaunix.net/viewthread.php?tid=1184699

http://www.oschina.net/news/20794/22-awesome-admin-panels-for-web-developers

分类: 乱七八糟 标签:

[业界] 华为没有秘密 任正非没有密码

2008年12月12日 16hot 没有评论

任正非荣膺“2008年度25位最具影响力的企业领袖”终身成就奖,感觉虽然有点迟到,但确实是众望所归。任正非以自己沉默的力量,影响了华为公司,影响了中国的企业和企业家,也正在影响着全球的通讯行业。我们有理由向他表示敬意和献礼,他也有资格获得这一殊荣。

  但是,以本人对他的了解,任正非一如既往地又要使主办单位小小的尴尬一下,他肯定不会出席颁奖大会。

  但有一点是肯定的,任正非会对他的员工讲:“我在技术上、管理上、财务上,基本是个半明白人,处在边学习、边实践的状态。因此,他必须,也只有谦虚地 团结一群人,发挥集体管理的作用去推动企业的发展。我是一个很普通的人,即使有一点影响力,也仅仅在华为内部。”“对外界和媒体的各种议论大家不要太在 乎,还是好好地努力工作。我也一样,也不会背上包袱的,也会像您们一样活泼、轻松、记性不好的,还会继续为公司的未来而努力工作的。”(引自任正非被《时 代周刊》评为2005年度“全球最具影响力的100人”时的内部讲话)

  本人认为,这些话可以作为任正非终身成就奖的获奖感言。

  经过了20年,借着中国改革开放的大潮,任正非领导的华为公司经过艰苦奋斗,在屡战屡败,屡败屡战中搏杀,今天已成为中国企业界的翘楚,成为中国制造 的楷模、典范和标杆,在激烈的市场竞争中华为已脱颖而出,成为国内知名的电信制造商,加入“巨大中华”的行列,而且让其按规模顺序颠倒过来,而且改变了世 界通信制造业的竞争格局。

  今天,华为已经拥有近9万员工,2007年销售规模达到125.7亿美元,超越北电,进入全球通讯设备制造前五强。2008年,预计华为销售额将达到230亿美元(约合1570亿元人民币),同比增长近44%。

  仅从数字上看,华为还很弱小——虽然已经由“土狼”变成了狮子,与那些企业丛林中的巨人相比,还存在着一定的距离,还有更长的路要走。但是,十几年前 任正非所讲的“十年之后,世界通信行业三分天下,华为将占一份”,或许在不远的将来将成为现实。华为董事长孙亚芳女士曾讲:“我们不想成为世界第一,但我 们不得不走在成为世界第一的路上。”

  任正非领导的华为已经成为一种现象。对于华为和任正非,国内学界和企业界给予了很多的关注,从不同角度探讨不可复制的“华为现象”和创造这一现象的企 业家,以便供中国企业来复制和学习,而实际上往往是徒劳无益。华为没有秘密,任正非没有密码。倒是有几组数字值得中国的企业和企业家们深思:

  至少在十年前,任正非就将“我们保证按销售额的10%拨付研发经费,有必要且可能时还将加大拨付的比例”写进了《华为公司基本法》。去年华为以 1365件专利申请数跃居世界总排名的第四位,紧跟松下、飞利浦和西门子之后,成为拥有专利最多的中国企业;华为的销售收入中,有72%来自国际市场,今 年这一比例还将扩大。

可以说,任正非具备了企业领袖所共有的天赋、素质和能力。

  十余年的军旅生涯,给予他的是坚毅、果敢、坚韧、谦恭、责任、执行、务实、使命、奉献、信仰、自律、敬畏、开放和合作;

  二十年的华为管理实践,给予他的是对商业规律与商业模式的领悟,对企业运作与成长规律的深刻思考,对公司内外部环境变化的敏锐感知,对国内外市场与行业发展的正确判断,对客户需求及其变化的准确把握;

  二十年管理华为的实践,任正非系统地思考和梳理,形成了自己的管理哲学和管理理念:坚守均衡、灰色和妥协,关注大势、方向和节奏,坚持不断地自我批 判,信守在商言商和实事求是,追求无为而治,崇尚天道酬勤和艰苦奋斗,坚信“从泥坑里爬起来的人是圣人”、“是太阳总会升起的”、“烧不死的鸟是凤凰 ”;

  几十年的跌宕起伏的人生苦难,给予他的是对人生的顿悟,对人性的深刻把握,对生活和生命的热诚,对事业的执着与偏执,对利益相关者的诚信,对家人和员工的关爱,对自己的持续不断的自我批判;

  几十年孜孜不倦的学习与领悟,给予他的是不断地进步、成长和提升。他是“华为公司进步最快的人”,其成功之道是“读万卷书,行万里路,干一件事 ”。看《莫斯科保卫战》,他悟出的是中层不决策;看《野战排》,他悟出的是不同领导者对于团队的影响作用;看《汉武大帝》,他思考的是如何对待个人的荣 辱;看《千手观音》和《可可西里》,他诠释了华为文化的内涵;听《北国之春》和《喀秋莎》,他想到的是“我们每一个人的成功,都来自亲人的无私奉献,我们 生活、工作和事业的原动力,首先来自妈妈御冬的寒衣,来自沉默寡言的父兄,故乡的水车、小屋、独木桥,还有曾经爱过你但已分别的姑娘……”

  作为企业领袖,任正非的上述特质,可能具有共性,其特性来自于所领导与管理的公司与事业。华为的成长,又反证了其作为企业领袖的巨大影响力。如果说,管理学是人们对企业成功实践的总结,企业领袖则是以其巨大的影响力对企业成功实践的造就。

  在任正非的领导下,华为成为中国高科技企业成长的领先者,其标杆意义在于,探索出一条在中国发展与管理高科技企业的道路,这条路因之由混沌而变得清晰。

  在任正非的领导下,华为成功地探索出有中国特色又与国际接轨的商业模式、经营模式、营运流程、内在机制和管理体系,并创造性地解决了国际先进企业管理模式如何在中国成功落地的课题,实现国外先进管理体系的中国化。

  在任正非的领导下,华为成功地探索出IT企业的企业价值观体系、战略管理体系、研发管理体系、市场营销体系、干部管理体系、人力资源管理体系、财务管控体系、供应链体系。

  在任正非的领导下,华为成功地迈出了由“活下去”到“走出去”,再到“走上去”的惊险一跳,依靠独特的国际化战略,改变行业竞争格局,让竞争对手由“忽视”华为到“平视”华为,到“重视”华为。

  在任正非的领导下,华为成功地探索出有特色管理知识员工、激励与约束知识员工、回报知识员工、分享知识的管理平台,实现了知识资本化和资本知识化的成功结合,体现了知识的价值,开发知识的潜力,提高知识工作者的效率。

  在任正非的领导下,《华为公司基本法》成为改革开放以来第一部企业宪章,不仅引领了中国企业对企业文化建设实践,而且华为的企业文化建设实践为中国企业所效仿。

  在外部人面前,任正非给人的印象肯定是神秘,不接受记者采访,不在电视台露面,不出席各种峰会。《中国企业家》杂志社社长刘东华认为:“任正非几乎是中国最有静气和最有定力的一个企业家。”

 其实任总并不神秘,他的解释是:“我为什么不见媒体,我有自知之明,见媒体说什么,说好恐怕言过其实;说不好别人又不相信,甚至还认为虚伪,只好不见为 好。因此,我才耐得住寂寞,甘于平淡。我知道自己的缺点并不比优点少,并不是所谓的刻意低调。”“外界总喜欢将成绩扣到一个人头上,不然不生动,以虚拟的 方法塑造一个虚化的人。我不认为自己像外界传说的那样有影响力,但是很敬业、无私、能团结人。这些年华为有一点成绩,是全体员工的团结努力,以及在核心管 理团队的集体领导下取得的。只是整个管理团队也很谦虚,于是就把一些虚荣虚拟地加到了我的头上,其实难符。”

  在华为内部,任正非也低调但并不神秘。他是个性情中人,有个性,有喜怒哀乐,有儿女情长;他没有专车,没有专职司机,没有专门的餐厅,每天按时驾私家 车上班,边开车边听四十分钟的外语;身患多种疾病,国内外出差很少带秘书,周末自己拖着行李箱,抱着书在世界各地机场出没;自掏腰包买公司的手机;自签文 件对自己的失误进行惩罚;自动申请降薪;自我稀释股份,让公司85%的员工持股;自愿申请买断工龄,将001的工号变成十万多号。他也曾失败过,也曾痛苦 过,也曾忧郁过,也经常被妖魔化过;这才是一个真实的企业家,一个没有被神化或妖魔化的企业家。

  在刻意或者无意保持低调的同时,任正非以自己的思考、理性、智慧和勤奋,不断地让中国企业界分享着他的思考。《华为的红旗能打多久》、《华为的冬 天》、《北国之春》、《华为的核心价值观》、《在理性与平和中发展》等都成为许多中国企业的管理读本,其中许多名言还被传颂:“什么叫成功?是像日本那些 企业那样,经九死一生还能好好地活着。”“十年来我天天思考的都是失败,对成功视而不见,也没有什么荣誉感、自豪感,而是危机感……”

  至于许多人关注的华为是否会上市,任正非从没有排斥过。正因为他对资本市场有着深刻的理解,所以他对此保持高度的审慎和敬畏。当看到一个个高扬资本运 作大旗,最终被资本运作得满地找牙的企业时,我们能够理解任正非的用心良苦。笔者倒不希望华为短期上市,一个非上市的、中国的、民营的、高科技的企业(而 不是“集团”),如果能早日成为世界级企业,或许更有非典型意义。

  至于华为的接班人问题,任正非也并没有回避。其实早在十几年前,他就深思熟虑过这个问题,并在《华为公司基本法》第一百零二条有明文规定。笔者认为,选择接班人并不重要,重要的在于缔造企业优秀接班人的生成机制。华为的问题不是人选太少,而是可选择的人太多。

  任正非和华为的未来还会像以往一样,充满艰辛与坎坷,还会历经磨难,但对于经历过IT严寒冬天并到经受十余年严冬的日本取过经的企业家来讲,相信他一定会从容淡定地应对;对于一个以活下去为目标的怕死的企业来讲,相信它一定会好好活着,一定会长寿。

  (本文作者为中国人民大学公共管理学院博士生导师、知名管理学家)

  任正非,沙漠里的孤独“狐狸”

  在对改革开放30年的总结关口上,

  《中国企业家》评价任总,这是相当有意义的 文 | 深圳万科股份有限公司董事长 王石

  《中国企业家》今年把任总评为“终身成就奖”,我非常高兴。

  这个奖对任总来说晚吗?在2008年不合时宜吗?我觉得不存在这些问题。作为2007年“终身成就奖”得主,我对这个奖的理解是,我们不是评圣人榜,也不是评一个劳资关系大奖,而是评中国企业家在对30年改革开放的贡献奖。

  至于说任总一直有危机感、“过冬论”,因此,这个奖在今年冬天是不是更有意义?我觉得,有危机感是很多企业家的经营风格,“终身成就奖”并不一定凸显这一点。

  我感受最深的,华为对新一代企业、尤其是民营企业来说,是他的经营模式,在国际舞台上叫板,他完全是硬碰硬打出去的。中国面临改革开放30年后的大转 型,我们看华为做技术转型实际上做了一个样本,它已经改变了简单的来料加工、赚血汗钱的商业模式,它是有技术含量的,而且发挥了中国人的聪明、低成本优 势,我觉得肯定任总的价值点在这里。实际上万科也正在学习华为的这种模式,从营销生产型向研发技术型转变。

  在对改革开放30年的总结上,《中国企业家》评价任总,这是相当有意义的。我们转型往哪里走?华为做了非常好的样本,这是我非常非常佩服的地方。只不过在这个节骨眼上,全球金融危机带来的调整跟困难的时候,显得更危机性一些,那只是巧合。

  评价30年的贡献,重要的是他30年来做了什么。比如牟其中,他在某个历史阶段扮演了角色,但显然我们对任总这样的一个奖励、肯定,我觉得前瞻未来他的价值更大。

  我跟任总交流应该说不是很多,也就是两三年见一次面,吃一顿饭。任总说话表现是很随和,但实际上话里有不露声色的很强硬的东西和坚持不变的东西。这点 是我印象非常深的。另外他为人低调,这恐怕是40年代末50年代初出生的一代人的共同特征,像柳传志、张瑞敏、鲁冠球——我是个例外了,比较张扬、彰显。 任总那就更像沙漠上一只孤独的狐狸了。(或者狼?)他自己说是狼,但我觉得狐狸更确切。

  他本身是很愿意跟人交流的,从谈吐当中可以感觉到他国际商界政界的交际面很广。他在生活上是很有品质的,比如他对工作环境的营造是相当有品位的。华为 不是外界想像的那样苦兮兮的。我去各地探险,在南美、非洲的机场经常遇到华为的员工,他们不是工作而是度假。我跟任正非一起吃饭聊天,相当多的由头,不是 我找他,而是他找我——不是向我请教,他是买万科的房子啊,谈如何营造他们生活的环境,满足配套要求。

  我也希望你们这次借着任总的这个荣誉,还原一个真实、深入的华为和任正非。

来源:中国企业家网

分类: 乱七八糟 标签:

定价的7大错误

2008年10月16日 16hot 没有评论

  文/Brad Sugars

  任何公司面临的最大挑战之一就是定价。

  这规律不仅适用于创业企业,也适用于成熟企业,尤其在那些利润率低、竞争激烈的行业。多数定价问题的共同核心是风险:价格设定太高的风险——可能会失去潜在的客户;价格设定太低的风险——利润减少了。

  这种“定价矛盾”驱使多数企业家采取折扣策略。然而,多数情况下的风险可以通过获取更多的信息来消除。通常,你了解得越多,可能承受的风险就越少。从这个角度上说,定价的实质就是尽可能多地获得信息:你所在的市场、客户以及决定利润的企业内部数据。

  生意上没有秘密,只有你还不知道的信息。说到定价问题,以下是在创业阶段避免犯错的7种方法。如果你能避免这些错误,就不仅能在竞争中领先,还能超越多数其他企业。

  1.价格太低,总在减价:对有些公司来说,这并不是错误,这完全是战略,但并不是非常好的战略。价格总是走低可能会获得较高的营业收入,但也可能会损失你的利润底线,这关系到企业的生存问题。你需要平衡利润和价格的关系。

  2.所有产品保持同样的毛利率:没有规则说所有的产品都需要同样的毛利率。事实上,周转慢的项目需要更高的毛利率。如果销量很大那么还可以用低些的毛利率。即使是这样,你还是应该寻找既能增加销量又能提高毛利率的方式。

  3.不理解毛利与加价率的差别:毛利率总是基于销售价格。而加价率总是基于进货成本。我曾有一个客户不理解其中的差别,以100%的加价率报出了一系列产品的价格,然后又减掉50%达成销售。最终的结果?实际上这家商店基本上是以成本价销售。别犯同样的错误。

  4.总是遗漏某些成本因素:为了正确地定价,需要识别每一项成本。即使是微不足道的项目,像信用卡处理费,通常也会增加每笔交易1%~2%的成本。其它的项目,像送货或运输成本,也能在不知不觉中增加成本。出售商品的成本对你的生存底线有着重大影响。

  5.与竞争者采取类似策略:不要跟风竞争,多做点功课,发现你真正能为顾客提供的价值。然后根据这种价值给商品定价。这样做你就处于非常有利的位置,能抵御竞争保持价格。只要你有了自己的充足“理由”,你的报价就值这个价。

  6.基于销售价格及利润百分比设定销售佣金:对于使用基于佣金制度的销售队伍的公司来说,这和毛利率/加价率之间的区别是类似的。采用何种基数来计算佣金将直接影响公司的利润。利润是惟一重要的数字。从营业收入中支付佣金意味着你将公司的部分利益让给了销售人员。

   7.打折没有增加价值,只是减少了利润价值:打折10%,通常可能需要多销售50%的产品才能保持利润底线。在打折的游戏中成本也会增加,所以这样做的 公司差不多是将自己驱逐出商场。不要在交易中削减要价,你应该问自己是否有增加产品或服务价值的方法。这种“附加值”意味着你能“放弃”一些不能产生利润 的东西。正确实施后,它也能改善客户体验。好体验是获得回头客的关键,利润也会随之增加。

  熟练处理所谓的“定价矛盾”,你就会对所在的领域得心应手。一旦你处理得好,你就会对自己产品和服务的价值有信心,而竞争对手则往往会急于放弃价格底线。       (译/梁晓平)

分类: 乱七八糟 标签:

李一男2003年在港湾给开发人员培训时的语录

2008年10月9日 16hot 没有评论

【1】好好规划自己的路,不要跟着感觉走!根据个人的理想决策安排,绝大部分人并不指望成为什么院士或教授,而是希望活得 滋润一些,爽一些。那么,就需要慎重安排自己的轨迹。从哪个行业入手,逐渐对该行业深入了解,不要频繁跳槽,特别是不要为了一点工资而转移阵地,从长远 看,这点钱根本不算什么,当你对一个行业有那么几年的体会,以后钱根本不是问题。频繁地动荡不是上策,最后你对哪个行业都没有摸透,永远是新手!

【2】可以做技术,切不可沉湎于技术。千万不可一门心思钻研技术!给自己很大压力,如果你的心思全部放在这上面,那么注定你将成为孔乙己一类的人物!适可而止为之,因为技术只不过是你今后前途的支柱之一,而且还不是最大的支柱,除非你只愿意到老还是个工程师!
 
【3】 不要去做技术高手,只去做综合素质高手!在企业里混,我们时常瞧不起某人,说他“什么都不懂,凭啥拿那么多钱,凭啥升官!”这是普遍的典型的工程师的迂腐 之言。8051很牛吗?人家能上去必然有他的本事,而且是你没有的本事。你想想,老板搞经营那么多年,难道见识不如你这个新兵?人家或许善于管理,善于领 会老板意图,善于部门协调等等。因此务必培养自己多方面的能力,包括管理,亲和力,察言观色能力,攻关能力等,要成为综合素质的高手,则前途无量,否则只 能躲在角落看示波器!技术以外的技能才是更重要的本事!!从古到今,美国日本,一律如此!

【4】多交社会三教九流的朋友!不要只和工程师 交往,认为有共同语言,其实更重要的是和其他类人物交往,如果你希望有朝一日当老板或高层管理,那么你整日面对的就是这些人。了解他们的经历,思维习惯, 爱好,学习他们处理问题的模式,了解社会各个角落的现象和问题,这是以后发展的巨大的本钱,没有这些以后就会笨手笨脚,跌跌撞撞,遇到重重困难,交不少学 费,成功的概率大大降低!

【5】知识涉猎不一定专,但一定要广!多看看其他方面的书,金融,财会,进出口,税务,法律等等,为以后做一些积累,以后的用处会更大!会少交许多学费!!

【6】 抓住时机向技术管理或市场销售方面的转变!要想有前途就不能一直搞开发,适当时候要转变为管理或销售,前途会更大,以前搞技术也没有白搞,以后还用得着。 搞管理可以培养自己的领导能力,搞销售可以培养自己的市场概念和思维,同时为自己以后发展积累庞大的人 脉!应该说这才是前途的真正支柱。。?

【7】 逐渐克服自己的心里弱点和性格缺陷!多疑,敏感,天真(贬义,并不可爱),犹豫不决,胆怯,多虑,脸皮太薄,心不够黑,教条式思维。。。这些工程师普遍存 在的性格弱点必须改变!很难吗?只在床上想一想当然不可能,去帮朋友守一个月地摊,包准有效果,去实践,而不要只想!不克服这些缺点,一切不可能,甚至连 项目经理都当不好–尽管你可能技术不错!

【8】工作的同时要为以后做准备!建立自己的工作环境!及早为自己配置一个工作环境,装备电 脑,示波器(可以买个二手的),仿真器,编程器等,业余可以接点活,一方面接触市场,培养市场感觉,同时也积累资金,更重要的是准备自己的产品,咱搞技术 的没有钱,只有技术,技术的代表不是学历和证书,而是产品,拿出象样的产品,就可技术转让或与人合作搞企业!先把东西准备好,等待机会,否则,有了机会也 抓不住!

【9】要学会善于推销自己!不仅要能干,还要能说,能写,善于利用一切机会推销自己,树立自己的品牌形象,很必要!要创造条件让 别人了解自己,不然老板怎么知道你能干?外面的投资人怎么相信你?提早把自己推销出去,机会自然会来找你!搞个个人主页是个好注意!!特别是培养自己在行 业的名气,有了名气,高薪机会自不在话下,更重要的是有合作的机会…

分类: 乱七八糟 标签:

docbook经验记录

2008年9月29日 16hot 没有评论

今天学到一点docbook经验:

(1)一个比较全面的docbook样式指引: DocBook XSL: The Complete Guide http://www.sagehill.net/docbookxsl/index.html

(2)如果图片过大,超出PDF右边界,有时候可以简单地设置图片居中让图片显示全:

<imagedata fileref="images/status/cs_status.png" align="center" />

或者更好的办法:

Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE 对任何会超过 PDF 宽度的图片都可以这样把图片限制在宽度内 :

<imagedata fileref="images/api_jbpm.png" align="center" width="100%" scalefit="1" />

 

(3)自定义表格宽度: colwidth="1*"表示此column为标准长度1倍,colwidth="4*"表示此column为标准列长度的4倍:

Xml代码 
  1. <title>状态变化表</title>  
  2. <table>  
  3.  <tgroup cols="3">  
  4.   <colspec colnum="1" colname="col1" colwidth="4*" />  
  5.   <colspec colnum="2" colname="col2" colwidth="6*" />  
  6.   <colspec colnum="3" colname="col3" colwidth="1*" />      
  7.   <thead>  
  8.    <row>  

 

 

分类: 乱七八糟, 开发 标签:

docbook使用教程

2008年9月29日 16hot 没有评论

使用Docbook发布文档,需要安装以下的工具:
*DocBook DTD
*DocBook XSL 样式单
*XSLT处理程序
*XSL-FO处理程序

下面详细介绍各个工具的安装。

1.安装DocBook DTD

Docbook DTD可以到OASIS的网站上下载(http://www.oasis-open.org/docbook/xml/),在这里你可以找到zip格式的压缩包。目前的最新版本是4.2。

事实上可以不下载Docbook DTD。如果你的文档DTD声明这样写:

<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">

根 据这样的定义,大部分XML处理器能够从网络上获取DTD。这样做的好处是编辑的Docbook文档移植性好,可以在没有安装Docbook DTD的机器上使用。不过由于Docbook DTD比较庞大,通过网络获取DTD会影响处理速度,在低速网络或者网络比较糟糕的情况下,影响尤为显著。

如果选择使用本地DTD,文档的DTD引用应该这样写:

Linux:
<!DOCTYPE book SYSTEM "/usr/share/docbook-4.2/docbookx.dtd">

Windows:
<!DOCTYPE book SYSTEM "file:///C:/xml/docbook42/docbookx.dtd">

Docbook提供了一种方式,让用户可以使用相同的DTD声明,但可以在使用网络获取DTD和使用本地DTD之间切换,同时拥有两者的优势。这就是catalog文件的作用。典型的catalog的声明如下:

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<group id="DocbookDTD" prefer="public">
<system
systemId="http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
uri="file:///usr/share/xml/docbook42/docbookx.dtd"/>
</group>
</catalog>

这个声明把网络DTD映射到本地DTD。如果使用支持Catalog的XSLT Processor,它首先会查找本地文件,如果本地文件不存在,再查找网络。

2.安装Docbook XSL样式单

http://docbook.sourceforge.net上可以下载到Docbook XSL样式单,目前最新的版本是1.67.2。

解压之后,有几个比较主要的目录:
*common – 包含的是公用的模块,诸如语言之类的文件都在这里。
*extensions – 针对特定的XSLT Processor编写的扩展代码。
*fo – 生成XSL-FO文件所需的XSL样式单。
*html – 生成HTML文件所需的XSL样式单。
*images – 生成文档时所需要的图片。
*doc – 有关XSL样式单的文档,同样是Docbook文档。

其他还有像htmlhelp之类的目录,但不是生成HTML或XSL-FO所必须的。

3.安装XSLT Processor

目前有许多免费的XSLT Processor,最常用的是
*Saxon – 使用Java实现,http://saxon.sourceforge.net/
*Xalan – 有Java和C++版本,http://xml.apache.org/xalan-j/index.html
*xsltproc – 使用C实现,是最快的处理程序,http://xmlsoft.org/XSLT/

因为Saxon和Xalan都有Java版本,所以按照一般的Java程序的安装方式安装即可。下面介绍xsltproc的安装,因为它速度快,是我比较喜欢的处理程序。

如果你使用windows平台,那么你有两个方法可选:

*第一,直接下载为windows平台预编译的版本,可以在
ftp://ftp.zlatkovic.com/libxml/
上找到。你需要下载libxml, libxslt, 和iconv,它们都是zip格式,解压之后,在环境变量PATH中添加xsltproc.exe和.dll文件的路径。

如果你不想编辑环境变量,一个简单的办法是把下面这些文件复制到C:WindowsSystem32:
libxslt.dll
libxml2.dll
libexslt.dll
iconv.dll
xsltproc.exe

这样在命令行就可以直接找到这些文件了。完成之后,运行
xsltproc -version
打印出版本号则表明完成安装。

*第二,在Cygwin下安装,这是我选择使用的方式。Cygwin是一个在Windows下模拟Linux Shell的应用程序。如果你喜欢以Linux命令的方式来使用xsltproc,可以到
http://www.cygwin.com/
下载Cygwin安装程序。Cygwin的是通过网络安装的,首先你从它提供的包列表中选择libxslt,然后安装程序会根据依赖关系自动选择libxml2,确定之后,安装程序下载并安装xsltproc。完成安装之后,你就可以运行
xsltproc -version
来检查是否安装成功。

*第三,如果使用Linux,很有可能系统已经安装了xsltproc。运行
xsltproc -version
检查一下是否已经安装。如果运行命令失败,或者版本太老,那么访问下面两个URL获取最新的RPM包:
http://rpmfind.net/linux/rpm2html/search.php?query=libxml2
http://rpmfind.net/linux/rpm2html/search.php?query=libxslt

然后切换到root权限,安装新的包:
rpm -Uv libxml2-2.6.17-2.i386.rpm
rpm -Uv libxslt-1.1.12-4.i386.rpm

完成之后,就可以运行
xsltproc -version
检查安装是否完成。

安装之后,就可以使用xsltproc来生成HTML或者XSL-FO文件。

譬如,下面是根据Docbook文档生成HTML的例子:
xsltproc –output myfile.html docbook-xsl/html/docbook.xsl myfile.xml

或者根据docbook文档生成XSL-FO文档的例子:
xsltproc –output myfile.fo docbook-xsl/fo/docbook.xsl myfile.xml

http://xmlsoft.org/XSLT/xsltproc2.html上列出了所有xsltproc的命令行参数,或者直接运行
xsltproc也会打印出参数列表。

如果你只要发布HTML文档,那么到此为止。如果你还想发布PDF或是PS文档,那么需要安装XSL-FO处理程序。

4. 安装XSL-FO处理程序

XSL-FO处理程序根据XSLT处理程序生成的XSL-FO文件生成PDF或者PS文件。目前可供选择的XSL-FO处理程序远不如XSLT处理程序那么多,这是因为:
a. XSL-FO标准比XSLT标准的制订晚两年;
b.XSL-FO标准及其庞大而复杂,该标准的作者也发现其实现上的难度,从而将该标准分为基本、扩展和完整三个级别。

现在可用的免费的XSL-FO处理程序有:

*FOP – 来自Apache XML项目(http://xml.apache.org/fop/)。目前最新的版本是0.20.5,还在开发当中,还有很多特性不支持,不过已经可以满足一般的使用。

*PassiveTeX – 来自Sebastian Rahtz (http://www.tei-c.org.uk/Software/passivetex/)一款基于TeX的XSL-FO处理程序。同样也在开发中,较FOP要复杂的多。

另外有一些商业产品可供选择,可能生成的文档质量要比开源代码好,譬如:

*XEP(http://www.renderx.com)

*XSL Formatter(http://www.antennahouse.com)

下面介绍如何安装FOP。

4.1.首先需要安装JDK,这个不必多说。

4.2. 到http://www.apache.org/dyn/closer.cgi/xml/fop/下载FOP,可以选择tar或者zip压缩包。下载之后解压到本地。

4.3. 下载图形代码库。FOP自己不支持PNG之类的图片,如果在你的文档里会涉及到图片,那么需要下载额外的代码库。可以选择JAI(http://java.sun.com/products/java-media/jai/current.html),或者Jimi(http://java.sun.com/products/jimi/)。0.20.5之前的版本只能使用Jimi。下载之后,将jai_core.jar和jai_codec.jar(JAI),或者JimiProClasses.jar(Jimi)复制到FOP安装目录的lib目录下,然后在fop.bat(Windows平台)中添加

set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%jai_core.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%jai_codec.jar
或是
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%JimiProClasses.zip

如果使用fop.sh(Linux平台),会自动搜索。

4.4. 添加扩展代码。如果Docbook XSL样式单有针对FOP的扩展代码(目前没有),像上面一样把它们添加到FOP安装目录下lib目录。

现在就可以使用FOP来生成PDF文档了。FOP提供两个脚本fop.bat(Windows平台)和fop.sh(Unix和Linux平台)以方便使用。生成PDF的命令行如下:
Linux或Unix:
fop.sh -xsl /docbook-xsl/fo/docbook.xsl -xml myfile.xml -pdf myfile.pdf

Windows:
fop.bat -xsl /docbook-xsl/fo/docbook.xsl -xml myfile.xml -pdf myfile.pdf

在处理过程中,可能会提示某些属性不支持或尚未实现,不用理会这些提示,因为FOP仍处于开发中,这并不影响生成PDF文档。

到此,一个Docbook发布系统配置完成,并可以用来发布文档了。你完全可以在Linux上编写任务,通过该系统自动发布技术文档。

分类: 乱七八糟, 开发 标签:

qemu on freebsd

2008年9月23日 16hot 没有评论

http://wiki.freebsd.org/qemu

分类: 乱七八糟, 开发 标签:

实用的 SSH 通道例子

2008年9月22日 16hot 没有评论

在freebsd手册里看到的一个例子,摘录出来,以便以后查找使用。

14.11.8.1.1 加强 POP3 服务的安全

  工作时, 有一个允许外来连接的 SSH 服务器。 同一个办公网络中有一个邮件服务器提供 POP3 服务。 这个网络, 或从您家到办公室的网络可能不, 或不完全可信。 基于这样的原因, 您需要以安全的方式来查看邮件。 解决方法是创建一个到办公室 SSH 服务器的连接, 并通过这个连接来访问 POP3 服务:

% ssh -2 -N -f -L 2110:mail.example.com:110 user@ssh-server.example.comuser@ssh-server.example.com's password: ******

  当这个通道连上时, 您可以把 POP3 请求发到 localhost 端口 2110。 这个连接将通过通道安全地转发到 mail.example.com

14.11.8.1.2 绕过严厉的防火墙

  一些大脑长包的网络管理员会使用一些极端的防火墙策略, 不仅过滤进入的连接, 而且也过滤连出的连接。 一些时候您可能只能连接远程机器 22 端口,以及 80 端口用来进行 SSH 和网页浏览。

  您可能希望访问一些其它的 (也许与工作无关的) 服务, 例如提供音乐的 Ogg Vorbis 流媒体服务器。 如果 Ogg Vorbis server 在 22 或 80 端口以外的端口播放音乐, 则您将无法访问它。

  解决方法是建立一个到您的网络的防火墙之外的网络上的 SSH 服务器, 并通过它提供的通道连接到 Ogg Vorbis 服务器上。

% ssh -2 -N -f -L 8888:music.example.com:8000 user@unfirewalled-system.example.orguser@unfirewalled-system.example.org's password: *******

  现在您可以把客户程序指定到 localhost 的 8888 端口, 它将把请求转发给 music.example.com 的 8000 端口, 从而绕过防火墙。

分类: 乱七八糟 标签:

使用diff, patch和quilt制作补丁(2)

2008年9月18日 16hot 没有评论

2 quilt

我们自己的项目可以用cvs或svn管理全部代码。但有时我们要使用其他开发者维护的项目。我们需要修改一些文件, 但又不能直接向版本管理工具提交代码。自己用版本管理工具重建整个项目是不合适的,因为大多数代码都是别人维护的,例如Linux内核。我们只是想管理好 自己的补丁。这时可以使用quilt。

2.1 基本概念

quilt是一个帮助我们管理补丁的程序。quilt的命令格式类似于cvs:

quilt 子命令 [参数]

0.46版的quilt有29个子命令。

掌握quilt的关键是了解使用quilt的流程。使用quilt时,我们会在一个完整的源代码树里工作。只要我们 在源代码树里使用了quilt命令,quilt就会在源代码树的根目录建立两个特殊目录:patches和.pc。quilt在patches目录保存它 管理的所有补丁。quilt用.pc目录保存自己的内部工作状态,用户不需要了解这个目录。

patches/series文件记录了quilt当前管理的补丁。补丁按照加入的顺序排列,早加入的补丁在前。quilt用堆栈的概念管理补丁的应用。

我们在应用补丁A前,必须先应用所有早于补丁A的补丁。所以,patches/series中的补丁总是从上向下应 用。例如:上图中,补丁1到补丁5是已经应用的补丁。我们可以将已应用的补丁想象成一个向下生长的堆栈,栈顶就是已应用的最新补丁。应用补丁就是将补丁入 栈,撤销补丁就是将补丁出栈。

我们在源代码树中作任何修改前,必须用"quilt add"命令将要修改的文件与一个补丁联系起来。在完成修改后,用"quilt refresh"命令将修改保存到已联系的补丁。下面我们通过一篇流程攻略来认识一下quilt的命令。

2.2 导入补丁

我们把 old-prj.tar.bz2 想象成Linux内核,我们把它解压后,进入代码树的根目录:

$ mkdir qtest; cd qtest; tar xvjf ../old-prj.tar.bz2; mv old-prj prj; cd prj

在修改代码前,我们通常要先打上官方补丁。在quilt中,可以用import命令导入补丁:

$ quilt import ../../prj.diff

Importing patch ../../prj.diff (stored as prj.diff)

执行improt命令后, prj 目录会多出一个叫 patches 的子目录:

$ find patches/ -type f

patches/prj.diff

patches/series

quilt在这个目录存放所有补丁和前面介绍的series文件。quilt的大多数命令都可以在代码树的任意子目录运行,不一定要从根目录运行。我们可以用applied命令查询当前已应用的补丁。

$ quilt applied

No patches applied

目前还没有应用任何补丁。unapplied命令查询当前还没有应用的补丁,top命令查询栈顶补丁,即已应用的最新补丁:

$ quilt unapplied

prj.diff

$ quilt top

No patches applied

我们可以使用push命令应用补丁,例如:

$ quilt push -a

Applying patch prj.diff

patching file src/drv/drv1.h

patching file src/sys/sys1.c

patching file src/sys/sys1.h

patching file src/usr/usr1.c

patching file src/usr/usr1.h

Now at patch prj.diff

push的"-a"参数表示应用所有补丁。在使用push命令后,prj 目录会多了一个叫.pc的隐含子目录。quilt用这个目录保存内部状态,用户不需要了解这个目录。应用补丁后,我们再使用applied、unapplied和top命令查看:

$ quilt applied

prj.diff

$ quilt unapplied

File series fully applied, ends at patch prj.diff

$ quilt top

prj.diff

2.3 修改文件

我们必须将对源代码树所作的任何改动都和一个补丁联系起来。add命令将文件的当前状态与补丁联系起来。add命令的格式为:

quilt add [-P 补丁名] 文件名

如果未指定补丁名,文件就与栈顶补丁联系起来。目前,我们的栈顶补丁是官方补丁。我们不想修改这个补丁,可以用new命令新建一个补丁:

$ quilt new drv_p1.diff

Patch drv_p1.diff is now on top

$ quilt top

drv_p1.diff

$ quilt applied

prj.diff

drv_p1.diff

$ quilt unapplied

File series fully applied, ends at patch drv_p1.diff

然后用add命令向栈顶补丁添加一个准备修改的文件:

$ cd src/drv; quilt add drv2.h

File src/drv/drv2.h added to patch drv_p1.diff

add命令为指定补丁保存了指定文件的当前快照,当我们执行refresh命令时,quilt就会检查文件 的变化,将差异保存到指定补丁中。使用"quilt diff -z [-P 补丁名] [文件名]"可以查看指定补丁指定文件的当前改动。省略-P参数表示查看当前补丁的改动,省略文件名表示查看所有改动。我们修改drv2.h后,执行 diff命令:

$ quilt diff -z

Index: prj/src/drv/drv2.h

===================================================================

— prj.orig/src/drv/drv2.h 2008-03-02 13:37:34.000000000 +0800

+++ prj/src/drv/drv2.h 2008-03-02 13:38:53.000000000 +0800

@@ -1,7 +1,7 @@

-#ifndef APP1_H

-#define APP1_H

+#ifndef DRV2_H

+#define DRV2_H

 

-#include "def1.h"+#include "def2.h" #endif

 

只要文件已经与我们希望保存改动的补丁联系过了,我们就可以多次修改文件。使用"quilt files [补丁名]"命令可以查看与指定补丁关联的文件。使用"quilt files -val"可以查看所有补丁联系的所有文件。"-v"参数表示更友好的显示,"-a"参数表示显示所有补丁,"-l"参数显示补丁名。例如:

$ quilt files

src/drv/drv2.h

$ quilt files -val

[prj.diff] src/drv/drv1.h

[prj.diff] src/sys/sys1.c

[prj.diff] src/sys/sys1.h

[prj.diff] src/usr/usr1.c

[prj.diff] src/usr/usr1.h

[drv_p1.diff] src/drv/drv2.h

"quilt refresh [补丁名]"刷新补丁,即将指定补丁的文件变化保存到补丁。省略文件名表示刷新栈顶补丁。我们refresh后,查看补丁文件:

$ quilt refresh

Refreshed patch drv_p1.diff

$ cat ../../patches/drv_p1.diff

Index: prj/src/drv/drv2.h

===================================================================

— prj.orig/src/drv/drv2.h 2008-03-02 12:42:21.000000000 +0800

+++ prj/src/drv/drv2.h 2008-03-02 12:46:25.000000000 +0800

@@ -1,7 +1,7 @@

-#ifndef APP1_H

-#define APP1_H

+#ifndef DRV2_H

+#define DRV2_H

 

-#include "def1.h"

+#include "def2.h"

 

#endif

 

"quilt diff -z"命令不会显示已经保存的差异。"quilt diff"显示所有的差异,不管是否保存过。

2.4 再做几个补丁

在增加文件前,我们要先将准备增加的文件与补丁联系起来。我们新建一个补丁,然后新增两个文件src/applet/applet1.h和src/applet/applet1.c。

$ cd ..; quilt new more_p1.diff

Patch more_p1.diff is now on top

$ quilt add applet/applet.c

File src/applet/applet.c added to patch more_p1.diff

$ quilt add applet/applet.1

File src/applet/applet.1 added to patch more_p1.diff

 

看看我们增加的文件:

$ quilt files

src/applet/applet.1

src/applet/applet.c

 

哎呀,文件名写错了。我们可以用"remove"命令从补丁中删除关联文件:

$ quilt remove applet/applet.1

rm: remove write-protected regular empty file `.pc/more_p1.diff/src/applet/applet.1'? y

File src/applet/applet.1 removed from patch more_p1.diff

$ quilt remove applet/applet.c

rm: remove write-protected regular empty file `.pc/more_p1.diff/src/applet/applet.c'? y

File src/applet/applet.c removed from patch more_p1.diff

$ quilt files

$ quilt add applet/applet1.h

File src/applet/applet1.h added to patch more_p1.diff

$ quilt add applet/applet1.c

File src/applet/applet1.c added to patch more_p1.diff

$ quilt files

src/applet/applet1.c

src/applet/applet1.h

 

好了,现在可以创建新文件:

$ mkdir applet

$ echo -e "#ifndef APPLET1_Hn#define APPLET1_Hn#include "def1.h"n#endif">applet/applet1.h

$ echo -e "#include "applet1.h"">applet/applet1.c

$ quilt refresh more_p1.diff

Refreshed patch more_p1.diff

 

刷新补丁后,我们再修改文件drv2.h。修改前一定要先将文件与准备保存改动的补丁联系起来:

$ quilt add drv/drv2.h

File src/drv/drv2.h added to patch more_p1.diff

$ vi drv/drv2.h

$ quilt diff -z drv/drv2.h

Index: prj/src/drv/drv2.h

===================================================================

— prj.orig/src/drv/drv2.h 2008-03-02 14:19:35.000000000 +0800

+++ prj/src/drv/drv2.h 2008-03-02 14:31:28.000000000 +0800

@@ -1,7 +1,7 @@

#ifndef DRV2_H

#define DRV2_H

 

-#include "def2.h"

+#include "def1.h"

 

#endif

 

我们再新建一个补丁,然后删除两个文件。删除文件前也要先为文件建立关联:

$ quilt new more_p2.diff

Patch more_p2.diff is now on top

$ quilt add app/*

File src/app/app1.c added to patch more_p2.diff

File src/app/app1.h added to patch more_p2.diff

File src/app/app2.c added to patch more_p2.diff

File src/app/app2.h added to patch more_p2.diff

$ rm -rf app

$ quilt refresh

Refreshed patch more_p2.diff

 

我们再修改applet/applet1.h:

$ quilt edit applet/applet1.h

File src/applet/applet1.h added to patch more_p2.diff

$ quilt refresh

Refreshed patch more_p2.diff

 

"quilt edit"在调用"quilt add"后自动启动编辑器。用refresh命令刷新补丁。

对了,前面为more_p1.diff修改drv2.h后还没有刷新呢。我们查看修改并刷新:

$ quilt diff -z -P more_p1.diff

Index: prj/src/drv/drv2.h

===================================================================

— prj.orig/src/drv/drv2.h 2008-03-02 14:19:35.000000000 +0800

+++ prj/src/drv/drv2.h 2008-03-02 14:31:28.000000000 +0800

@@ -1,7 +1,7 @@

#ifndef DRV2_H

#define DRV2_H

 

-#include "def2.h"

+#include "def1.h"

 

#endif

 

Warning: more recent patches modify files in patch more_p1.diff

$ quilt refresh more_p1.diff

More recent patches modify files in patch more_p1.diff. Enforce refresh with -f.

$ quilt refresh -f more_p1.diff

Refreshed patch more_p1.diff

quilt会抱怨更新的补丁修改了补丁more_p1.diff的文件。这是在说more_p2.diff修改了applet1.h。我们知道这和我们要刷新的drv2.h没关系,所以可以用-f参数强制刷新。

2.5 管理补丁

series命令可以查看series文件中的补丁:

$ quilt series

prj.diff

drv_p1.diff

more_p1.diff

more_p2.diff

"quilt patches 文件名"显示修改了指定文件的所有补丁,例如:

$ quilt patches drv/drv2.h

drv_p1.diff

more_p1.diff

"quilt annotate 文件名"显示指定文件的修改情况,它会指出哪个补丁修改了哪一行。例如:

$ quilt annotate drv/drv2.h

1 #ifndef DRV2_H

1 #define DRV2_H

 

2 #include "def1.h"

#endif

1 drv_p1.diff

2 more_p1.diff

我们可以使用push和pop命令应用补丁或撤销补丁,例如:

$ quilt pop -a

Removing patch more_p2.diff

Restoring src/app/app1.c

Restoring src/app/app2.c

Restoring src/app/app2.h

Restoring src/app/app1.h

Restoring src/applet/applet1.h

 

Removing patch more_p1.diff

Restoring src/drv/drv2.h

Removing src/applet/applet1.h

Removing src/applet/applet1.c

 

Removing patch drv_p1.diff

Restoring src/drv/drv2.h

 

Removing patch prj.diff

Restoring src/sys/sys1.c

Restoring src/sys/sys1.h

Restoring src/drv/drv1.h

Removing src/usr/usr1.c

Removing src/usr/usr1.h

No patches applied

$ quilt top

No patches applied

$ quilt next

prj.diff

$ quilt previous

No patches applied

"quilt pop -a"撤销所有补丁。top命令显示栈顶命令,即当前应用的最新的补丁。next命令显示下一个可以应用的补丁。previous显示上一条应用过的补丁。"push 补丁A"将从上到下依次应用所有早于补丁A的补丁,最后应用补丁A。例如:

$ quilt push more_p1.diff

Applying patch prj.diff

patching file src/drv/drv1.h

patching file src/sys/sys1.c

patching file src/sys/sys1.h

patching file src/usr/usr1.c

patching file src/usr/usr1.h

Applying patch drv_p1.diff

patching file src/drv/drv2.h

Applying patch more_p1.diff

patching file src/applet/applet1.c

patching file src/applet/applet1.h

patching file src/drv/drv2.h

Now at patch more_p1.diff

$ quilt top

more_p1.diff

$ quilt next

more_p2.diff

$ quilt previous

drv_p1.diff

"quilt push -a"应用所有补丁:

$ quilt push -a

Applying patch more_p2.diff

patching file src/app/app1.c

patching file src/app/app1.h

patching file src/app/app2.c

patching file src/app/app2.h

patching file src/applet/applet1.h

Now at patch more_p2.diff

"quilt graph -all"可以为栈顶补丁的依赖关系生成dot文件。Graphviz的dot可以根据dot文件产生图片,例如:

$ quilt graph –all > ../../more_p2.dot

$ cd ../..; dot -Tpng more_p2.dot -o more_p2.png

2.6 发布补丁

只要将patches目录打包发布就可以了。例如:

$ cd prj; tar cvjf prj-0.1-patches.tar.bz2 patches; mv prj-0.1-patches.tar.bz2 ../..

用户先下载、解压补丁包对应的源代码树:

$ cd ../..; mkdir user; cd user; tar xvjf ../old-prj.tar.bz2; mv old-prj/ prj

然后下载、解压补丁:

$ cd ../..; tar xvjf prj-0.1-patches.tar.bz2; cd user/prj

最后把补丁目录链接到源代码树的patches目录,然后应用所有补丁:

$ ln -sfn ../../patches/ patches

$ quilt push -a

Applying patch prj.diff

patching file src/drv/drv1.h

patching file src/sys/sys1.c

patching file src/sys/sys1.h

patching file src/usr/usr1.c

patching file src/usr/usr1.h Applying patch drv_p1.diff

patching file src/drv/drv2.h

Applying patch more_p1.diff

patching file src/applet/applet1.c

patching file src/applet/applet1.h

patching file src/drv/drv2.h

Applying patch more_p2.diff

patching file src/app/app1.c

patching file src/app/app1.h

patching file src/app/app2.c

patching file src/app/app2.h

patching file src/applet/applet1.h

Now at patch more_p2.diff

3 结束语

在上面的流程攻略中,我们演示了19个quilt命令:add, annotate, applied, diff, edit, files, graph, import, new, next, patches, pop, previous, push, refresh, remove, series, top, unapplied。

本次Linux之旅到此结束,欢迎您再次参加Linux之旅,一起探索浩瀚的Linux世界。

分类: 乱七八糟, 开发 标签:

使用diff, patch和quilt制作补丁(1)

2008年9月18日 16hot 没有评论

diff和patch是在Linux环境为源代码制作和应用补丁的标准工具。diff可以比较文件或目录的差异,并 将差异记录到补丁文件。patch可以将补丁文件应用到源代码上。quilt也是一个制作和应用补丁的工具,它适合于管理较多补丁。quilt有自己的特 有的工作方式。本文通过简单的例子介绍这三个常用的工具。

0 示例工程

我们先准备一个用来做实验的工程,它包含若干子目录和文件。可以用find命令列出文件清单:

$ find old-prj/ -type f
old-prj/inc/def1.h
old-prj/inc/def2.h
old-prj/src/sys/sys1.c
old-prj/src/sys/sys1.h
old-prj/src/app/app1.c
old-prj/src/app/app2.c
old-prj/src/app/app2.h
old-prj/src/app/app1.h
old-prj/src/drv/drv1.h
old-prj/src/drv/drv2.c
old-prj/src/drv/drv1.c
old-prj/src/drv/drv2.h
old-prj/build/Makefile

find命令的"-type f"参数选择普通文件,可以省略掉目录。希望自己操作的读者可以下载这个示例工程

1 diff和patch

1.1 比较一个文件

将old-prj.tar.bz2放到我们的工作目录,然后建立一个子目录,进入后解压示例工程:

$ mkdir test1; cd test1; tar xvjf ../old-prj.tar.bz2

用分号分隔多个命令可以节省篇幅。将old-prj复制到new-prj:

$ cp -a old-prj/ new-prj

让我们编辑一个文件。src/drv/drv1.h的内容本来是:

$ cat -n old-prj/src/drv/drv1.h
     1  #ifndef DRV1_H
     2  #define DRV1_H
     3
     4  #include "def1.h"
     5
     6  typedef struct {
     7    int p1;
     8    int p2;
     9    int p3;
    10  } App1;
    11
    12  void do_app1(void);
    13
    14  #endif

cat命令的"-n"参数可以增加行号。我们用vi将它修改成:

$ cat -n new-prj/src/drv/drv1.h
     1  #ifndef DRV1_H
     2  #define DRV1_H
     3
     4  #include "def1.h"
     5
     6  typedef struct {
     7    int a;
     8    int b;
     9  } App1;
    10
    11  void do_app1(void);
    12
    13  #endif

现在可以用diff命令比较文件了:

$ diff -u old-prj/src/drv/drv1.h new-prj/src/drv/drv1.h
--- old-prj/src/drv/drv1.h      2008-03-01 12:59:46.000000000 +0800
+++ new-prj/src/drv/drv1.h      2008-03-01 13:07:14.000000000 +0800
@@ -4,9 +4,8 @@
 #include "def1.h"
 
 typedef struct {
-  int p1;
-  int p2;
-  int p3;
+  int a;
+  int b;
 } App1;
 
 void do_app1(void);

diff程序按行比较文本文件。比较文件的diff命令格式是:

$ diff -u 旧文件 新文件

"-u"参数指定diff命令使用 unified 格式,这是一种最常用的格式,我们来看看它的含义。

1.2 diff的 unified 格式

以"—"开头的行是旧文件信息,以"+++"开头的行是新文件信息:

--- old-prj/src/drv/drv1.h      2008-03-01 12:59:46.000000000 +0800
+++ new-prj/src/drv/drv1.h      2008-03-01 13:07:14.000000000 +0800

unified 格式默认在变化部分的前后各显示三行上下文。在上例中,旧文件的7、8、9行被替换成新文件的7、8行。旧文件的变化部分是7-9行,前后多显示3行,因 此显示4-12行。新文件的变化部分是7-8行,前后多显示3行,因此显示4-11行。以"@@"包围的行指示补丁的范围:

@@ -4,9 +4,8 @@

'-4,9'中,'-'表示旧文件,'4,9'表示从第4行开始,显示9行,即显示4-12行。'+4,8' 中,'+'表示新文件,'4,8'表示从第4行开始,显示8行,即显示4-11行。"@@"行之后是上下文和变化的文本,其中'-'开头的行是旧文件特有 的,'+'开头的行是新文件特有的,其它行是两个文件都有的,即补丁的上下文。例如:

 #include "def1.h"
 
 typedef struct {
-  int p1;
-  int p2;
-  int p3;
+  int a;
+  int b;
 } App1;
 
 void do_app1(void);

1.3 制作和应用补丁

所谓制作补丁就是diff的输出重定向到一个文件,这个文件就是补丁文件。例如:

$ diff -u old-prj/src/drv/drv1.h new-prj/src/drv/drv1.h>../drv1.diff

我们将old-prj解压到另一个目录,准备应用这个补丁:

$ cd ..; mkdir test2; cd test2; tar xvjf ../old-prj.tar.bz2; mv old-prj myprj; cd myprj

在真实场景中,test2目录通常是在用户2的电脑上。用户2可能不使用 old-prj 作为第一级目录的名字。例如:用户1的第一级目录名是 linux-2.6.23.14, 用户2的第一级目录名是linux。所以我们将 old-prj 改为 myprj 以模拟这种情况。

我们在 myprj 目录使用patch命令应用补丁:

$ patch -p1 < ../../drv1.diff
patching file src/drv/drv1.h

patch命令行中为什么没有出现要打补丁的文件?这是因为patch命令可以使用补丁文件中的文件信息:

--- old-prj/src/drv/drv1.h      2008-03-01 12:59:46.000000000 +0800

"-pn"参数(上例中n=1)中的n表示要从补丁文件的文件路径中去掉几层目录,可以理解为去掉几个'/'。例 如:p1表示去掉一层目录,"old-prj/src/drv/drv1.h"去掉一层就成为"src/drv/drv1.h"。patch命令在 myprj 目录找到"src/drv/drv1.h"后应用补丁。

我们通常都在代码树的上一层目录制作补丁,在代码树的根目录应用补丁。因此,最常用的patch命令格式是:

$ patch -p1 < 补丁文件

1.4 比较目录

我们回到test1目录,再对 new_prj 做一些改动。这次我们删除掉src/sys目录及其中的文件。再建立src/usr目录,并在该目录增加两个文件usr1.h和usr1.c。

$ cd ../../test1; rm -rf new-prj/src/sys; mkdir new-prj/src/usr
$ echo -e "#ifndef USR1_Hn#define USR1_Hn#include "def1.h"n#endif">new-prj/src/usr/usr1.h
$ echo -e "#include "usr1.h"">new-prj/src/usr/usr1.c

echo命令的"-e"参数打开对转义符的支持,bash默认是不支持转义符的。

现在我们比较目录并制作补丁:

$ diff -Nur old-prj/ new-prj/ > ../prj.diff

读者可以cat这个补丁文件的内容。根据前面的介绍,读者应该能看懂补丁文件了吧。

比较目录的常用命令是:

$ diff -Nur 旧目录 新目录 > 补丁文件

$ diff -Naur 旧目录 新目录 > 补丁文件

"-u"参数前面已经介绍过了。"-N"参数将不存在的文件当作空文件。如果没有这个参数,补丁就不会包含孤儿文件(即另一方没有的文件)。"-r"参数表示比较子目录。"-a"参数表示将所有文件当作文本文件。

我们再准备一个目录来应用补丁:

$ cd ..; mkdir test3; cd test3; tar xvjf ../old-prj.tar.bz2; mv old-prj myprj; cd myprj

在源代码树的根目录应用补丁:

$ patch -p1 < ../../prj.diff
patching file src/drv/drv1.h
patching file src/sys/sys1.c
patching file src/sys/sys1.h
patching file src/usr/usr1.c
patching file src/usr/usr1.h

好了,读者可以用"diff -Nur"比较一下"test1/new_prj"和"test3/myprj",没有输出就表示完全相同。

$ cd ../..; diff -Nur test1/new-prj test3/myprj

1.5 很多的补丁…

一个大项目可能有不同开发者提供很多补丁。这些补丁可能还存在依赖关系,例如补丁B必须打在补丁A上。我们当然可以凭着程序员的“心细如发”去管理好这些补丁,不过有一个叫quilt的工具可以使我们轻松一些。当然,即使有工具的帮助,细心和认真也是必需的。 

附录

为了简单起见,前面只介绍了一个"diff -Nur 老目录 新目录"的用法。有时候,新目录里只放了修改过的文件。这时可以不使用-N参数以忽略孤儿文件,即"diff -ur 老目录 新目录"。diff会输出孤儿文件的提示,我们可以删除或保留这些提示,它们对patch没有影响。

使用diff时可以用–exclude排除文件和目录,例如:

diff -ur -exclude=.* --exclude=CVS prj_old prj_new

上例排除了源代码树中以'.'开头的文件和所有CVS目录。其实对于CVS项目,可以直接在源代码树根目录中执行:

cvs diff -u3 > 补丁文件名

u3表示输出3行上下文的unified 格式。打补丁时在源代码树根目录中执行:

patch -p0 < 补丁文件名

"cvs diff"会自动忽略CVS项目外的文件。通过CVS的tag和补丁文件,我们可以方便地保存工作快照。

分类: 乱七八糟, 开发 标签: