标签 Blogger 下的文章

发掘Scons

发现或者说知道SCons是缘于Google的comp.lang.c group上的一则名为"Best Build Tool for large C projects "的帖子,帖子的作者列出了11条他认为"Best Build Tool"应该具备的特点,并欲找到这样的Build Tool。在该帖子的回复中,有人提到了Scons,说来惭愧,这是我第一次听说到有这样一个工具。一直在Unix下编写C程序,习惯了Make,也对Make的复杂度和较为陡峭的学习曲线有所了解,曾经尝试使用AutoconfAutomake,但是都因上手困难而放弃。自己心底也一直想找到一个更简单一些的但又不失功能的适合C的Build Tool,Scons是否能满足的需要的呢?好奇心驱使着我去发掘一下Scons。

工具的进化一直在持续着。高手能把Make玩弄于股掌之中,但是大多数人水平还是一般的,在经历了"Make hell"后他们要寻求更简单、更人性的工具,这也是工具进化的动力之一。Scons是用Python实现的一款跨平台的开源Build Tool,用Python实现意味着Scons比Make所使用的类Shell语言更贴近于自然语言,更易于理解和控制;用Python实现的另一个好处也是Make所不具备的就是很好的跨平台能力,一次编写Build脚本,在多种平台上无需修改即可运行无误,特别是从Unix->Windows这样的移植,如果使用Make则势必要修改。

先简单说说Scons的安装,要运行Scons势必你的机器上要有Python,虽然Python 3.0已经Release,但目前主流Python开源项目仍然在用2.x版本。我的机器上安装的就是Python 2.5。下载Scon-1.10稳定版,unzip,进入unzip后的目录,执行安装命令:python setup.py install即可。Scons会被安装到默认目录下,如果你想指定安装目标目录的话,可以使用–prefix=YOUR_INSTALL_DIR参数。

按照惯例,我们先来一个"Hello, World!"的例子,在你的测试目录下,编写一个HelloWorld.c
/* HelloWorld.c */
#include <stdio.h>
 
int main(int argc, char* argv[])
{
   printf("Hello, world!\n");
   return 0;
}
在同一级目录下,建立一个新文件SConstruct,编辑该文件,输入内容:
Program(‘HelloWorld.c’)
在命令行下执行scons,一个名为HelloWorld.exe的可执行文件(在Unix下可执行文件为HelloWorld)被编译链接成功。第一次上手成功会给使用者带来莫大的成就感,提高该使用者继续发掘该工具的可能性。

SConstruct是个什么文件?SConstruct之于Scons就好比Makefile之于Make;它是Scons的输入,SConstruct中的内容采用的是Python的语法,而Python的语法比较简单,这样很容易被接受,而Program则只是一个方法调用。Program(‘HelloWorld.c’)意味着告诉Scons我要将HelloWorld.c编译成一个名为‘HelloWorld.exe’的可执行文件,当然了Scons会自动分析HelloWorld.c,自动得出目标程序名字。

我们日常工作构建代码的类型不外乎如下几种:简单一点的包括编译object文件、构建静态库、构建动态链接库和构建可执行程序;复杂的则是要对一个拥有众多目录和几十万、上百万行代码的项目进行整体体系构建,而复杂的构建也是由一系列的简单构建组合而成的,我们先说说简单类构建。

HelloWorld例子只是一个最简单的由单个源文件构建程序的例子,现实中我们构建可执行程序可能依赖的不止是一个文件,可能还有头文件或链接其他第三方库;下面这个SConstruct文件中的语句就是一个稍微复杂些的例子:
Program(target = ‘test’, source = ['main.c', 'file1.c', 'file2.c'], LIBS = ['lib1', 'lib2'], LIBPATH = ['lib1/lib', 'lib2/lib'], CPPPATH = ['include', '/lib1/include', 'lib2/include'], CCFLAGS=’-D_DEBUG’)

这个例子中具备我们常用的诸多元素,这些参数中:’test’是构建后的程序名,source是一个源文件数组,LIBPATH则是要链接库的目录数组,LIBS是要链接的具体的库文件的名字。CPPPATH则是-I的替代品,是头文件所在目录的数组,CCFLAGS则是负责传递编译器的编译选项参数。

通过这些Keyword Arguments,Scons可以在用户和编译器之间传递信息,并控制编译器完成构建。同样的,编译目标文件,构建静态库、动态库可以由下面的一些builder来完成。

Library(‘foo’, ['f1.c', 'f2.c', 'f3.c'])   #生成名为foo的静态库,在Windows上是foo.lib,在unix上为libfoo.a
<=> StaticLibrary(‘foo’, ['f1.c', 'f2.c', 'f3.c']) #生成名为foo的静态库,在Windows上是foo.lib,在unix上为libfoo.a
SharedLibrary(‘foo’, ['f1.c', 'f2.c', 'f3.c']) #生成名为foo的动态库,在Windows上是foo.dll,在unix上为libfoo.so
Object(‘add.c’) #生成名为add的目标文件,在Windows上是add.obj,在unix上为add.o

Scons没有明显的依赖定义,Scons会为我们自动扫描依赖。我们只需告诉它构建出一个目标需要什么即可。Scons检查依赖关系中的文件变化的方法,除了通过时间戳,还可以通过MD5来判别,你可以通过设置Env来决定使用哪个。另外更强大的是你也可以自己编写文件更新检查方法放到SConstruct中被Scons调用,这些都是高级一些的功能,这里不细说,详情可参见Scons的doc

前面说过,实际项目的代码往往不可能都放到单一目录下,而是按照一定规则被放到有层次结构的目录体系中,Scons提供一个叫SConscript的方法支持这种情形。下面用一个复杂一些的例子来说明这种情形。
我们假设有一项目的目录结构如下:
- Test_Proj
    - SConstruct
    - include
        - base.h
        - module1.h
        - module2.h
    - main
        - main.c
    - module1
        - module1.c
    - module2
        - module2.c
    - xlib
        - include
            - xlib_base.h
            - add.h
            - sub.h
        - add
            - add.c
        - sub
            - sub.c
        - lib
针对该Proj,我们要将整个工程构建为一个可执行程序。简单分析一下,这个程序依赖xlib下的两个库

看西班牙国家德比需要耐心

在今晨的西班牙国家德比之前,我在饭否留下这样一条信息:"Barcelona vs. Real Madrid,比赛未结束前一切皆有可能"。而国家德比的过程也正如我所料,一切皆有可能,不过需要耐心的等待。

昨晚就把闹钟定到了今晨5点,闹钟响了,在床上左右翻转后还是决定起来看西班牙国家德比,毕竟特别喜欢梅西,因梅西而逐渐开始喜欢巴萨。但因西甲联赛的比赛时间特别晚,一般都在北京时间凌晨以后,所以我很少能坚持看巴萨比赛的直播。但巴萨最近状态一直不错,在"魔鬼赛程"阶段取得连胜,而皇家马德里虽然处于低谷,且刚刚换帅,但我想皇马的战士在国家德比时的斗志肯定是不弱的,所以这场比赛无论如何一定要看。打开电视,比赛已经开始3分钟了。场面上基本是巴萨压着皇马打,这也很正常,巴萨目前的攻击力在整个欧洲都是数一数二的,加上主场,加上"国家德比"的历史情绪,疯狂进攻是肯定的了。画面上不断重复着梅西带球、突破、被放倒后的痛苦表情;开场不到20分钟,梅西已经5次被侵犯了。看到这些真是有些心疼啊,生怕梅西受伤下场。

巴萨狂攻了20分钟后,不见起色,场面渐渐变得沉闷,解说员也一直在抱怨巴萨把皇马压的太死,皇马战士都被憋屈到自己的后场,巴萨自己的进攻空间也没了。而这时巴萨也一直没能调整打法,就这样,上半场在些许沉闷中结束。

很是期待巴萨主帅瓜迪奥拉能对下半场的战术做些调整,让巴萨不仅能有70%以上的控球率,而且还要有精彩进球才行。经典比赛所应该具备的元素目前还未一一展现出来,真不想看到比赛就在这样的沉闷中0:0结束,我也有些着急,想看到巴萨进球,更想看到梅西上演精彩表演。

下半场开始,双方都没有做出人员调整,巴萨依旧是压着皇马,古德约翰森下半场表现与上半场相比判若两人,又慢失误又多。第60分钟,瓜迪奥拉觉醒了,终于用小将布斯克茨换下了古德。皇马在换下伊瓜因后就更没有太好的反击机会了。比赛依旧在沉闷中进行,梅西也渐渐失去活力了,我的耐心也渐渐要被打磨殆尽了,困意袭来,有拿起遥控器关机的想法。

"点球"!,第70分钟,复出的老将萨尔加多在禁区内对布斯克茨犯规,被主裁判点球。昏昏欲睡的我立刻被激活,起身站在电视前,目不转睛的看着埃托奥如何射出这粒点球。埃托奥这个点球居然射失了,球被最近状态低迷的卡西扑了出来。射失点球也是经典比赛的一个元素,权当心理安慰吧。比赛再次回归沉闷,随着时间的流逝,球员变得急躁起来,就连梅西也忍不住对加戈采取"报复"了。这时大多人都会认为巴萨无法削去最近三个赛季以来主场不赢皇马的耻辱了,球迷们的耐心再次进入煎熬期。

好在巴萨的球员们没有放弃,第83分钟,本场比赛一直"擅离职守"的普约尔头球摆渡到门前,埃托奥门前一个非常规射门动作将球捅入网内,诺坎普顿时沸腾了。埃托奥脱衣庆祝领得黄牌一张,值了。能给球队带来久违的国家德比胜利这张黄牌又算得了什么呢。皇马的球员们已经尽力了,他们今天已经做得很好了,如果皇马依旧是以前的状态的话,今天早就被打成筛子了。

比赛继续,埃托奥、哈维先后被换下以接受全场球迷的掌声,比赛尾声,场上的对抗已不再那么激烈,巴萨的进攻空间渐渐显露出来,91分钟,巴萨反击,亨利的传球让快速插上的梅西得到了应得的待遇- 一个进球,梅西快速将球带到门前,在卡西封堵前一个聪明的挑射,尽管卡纳瓦罗奋力抢救,球依然稳稳落入网窝。梅西进球后兴奋的脱下外衣,与埃托奥的净身不同,梅西球衣里面还是绅士的穿了一件衣服的,但仍然没有逃脱黄牌警告。比赛随之结束。看到梅西进球,我太兴奋了。看这场比赛更多是想看到梅西在国家德比中进球,但是皇马对梅西的重兵盯防以及不耻的犯规,让梅西也很不适,但是回过头来一想,皇马主帅还有其他招术么,除非买通瓜迪奥拉不让梅西参加比赛^_^

比赛算不上经典,但绝对考验球迷的耐心,也绝对值得半夜爬起来一看,Oh, Yeah^_^!

估计如果不出意外的话,08-09赛季第二场西班牙国家德比入场时,皇马将士将在入口两旁站立欢迎巴萨球员入场了。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats