`
zealot2007
  • 浏览: 10537 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Rake简明教程之一(翻译)

阅读更多

本文是Rake教程的一篇翻译。原文:http://docs.rubyrake.org/tutorial/chapter01.html

Rake是ruby写的构建工具,采用ruby作为构建语言。Rake在作用和目的上与make类似。Rake一个简单的ruby构建程序与make类似。
Rake有以下特征:
1.  Rakefiles(Rake版本的Makefiles)完全采用ruby语法定义,不需编辑xml文件,不需要担心古怪的makefile语法。(到底是tab还是space?)
2. 用户可以指定含先决条件的工作。
3. Rake支持规则模式来匹配动态的工作。
4. Rake是轻量级的。可以作为单独文件分布到其他工程中。依赖于rake的工程并不需要在目标系统中安装rake。


一。Rake简介
  近来很多人有类似的讨论,他们真地喜欢Rake,但是对如何入门有些困难。虽然Rake的文档相当地完整,但是都基于用户对其他的构建工具,如ant和make很熟悉这样的假设。真正对于新手入门的材料很少。
  这篇教程设法弥补这个缺失。我们将以一个简单的问题开始: 构建简单的C程序。
 问题
我们以一个非常简单的构建问题入手。最初使用make构建,现在使用rake。
假设我有一个非常简单的C程序,包含以下几行:

main.c
1 #include "greet.h"
2 int main() {
3 greet ("World");
4 return 0;
5 }
greet.h
1 extern void greet(const char * who);

 

greet.c
1 #include <stdio.h>
2 void greet (const char * who) {
3 printf ("Hello, %s\n", who);
4 }
 

(是的,这真是传统的helloworld程序。我说过的我们从基本开始!)
要编译并运行这些文件,需要如下一个简单的shell脚本。

 

build.sh
1 #include <stdio.h>
2 void greet (const char * who) {
3 printf ("Hello, %s\n", who);
4 }
 

(cc是C编译器,它根据列出的源文件列表生成输出文件(由-o参数指定))
运行,获得下面的结果。。。

 

output
1 $ build.sh
2 $ ./hello
3 Hello, World

 

构建C程序
编译C程序分为两步。首先,编译所有的源文件生成目标文件。 然后将生成的目标文件进行链接生成可执行程序。

下面的图示表明了从源文件到目标文件到可执行程序的过程。
我们的程序规模很小,所以上述的3行构建脚本已经足够。 然而,随着工程规模的扩大,需要管理越来越多的源文件和目标文件。对于某一源文件的某一行的变化而要重新编译整个系统是很不划算的。较有效的方法是重编译少量修改的文件并重新链接。
但是我们如何知道需要重编译的内容呢?如果我们设法手工去跟踪修改会很容易发生错误。此时Rake就变得有用。

文件依赖
首先,让我们看一下何时需要重编译。考虑到main.o,很显然,如果main.c文件改变,我们需要重编译生成main.o。但是其他文件修改是否会触发main.o的重编译呢?
实际上是这样。 从main.c源文件,我们看到它包含greet.h头文件。这意味着对greet.h的任何改变都可能影响到main.o文件。
我们说main.o依赖于main.c和greet.h。在Rake中我们可以用以下代码表示。

Rakefile fragment
1 file "main.o" => ["main.c", "greet.h"]
 

rake依赖的定义使用标准的ruby代码。这样的好处是我们在应用中可以构造hash类型的参数,并且由于ruby方法调用的参数不需要括号,因此建立一个file工作的代码可以非常自然的读懂。而且它仍旧是ruby代码。
同样,我们可以为构建greet.o定义依赖。

 

Rakefile fragment
1 file "greet.o" => ["greet.c"]
 

greet.c包含stdio.h,但stdio.h是系统头文件,不会经常改变。我们将它删除出依赖列表。
最后,我们可以为可执行程序hello定义依赖,它依赖于两个目标文件。

 

 

Rakefile fragment
1 file "hello" => ["main.o", "greet.o"]
 

注意我们要定义hello的直接依赖,是的,hello依赖main.o进而依赖main.c。但是.c文件不是直接用于构建hello,所以可以安全地从依赖列表中忽略。
构建文件
我们已经仔细地指定了文件是如何被关联的。现在我们需要说当需要构建时,rake到底做了什么。
这部分相当简单。我们开始时的3行构建脚本包含了所有的需要用于构建程序的命令。我们仅仅以正确的依赖集来执行这些命令。用ruby的do/end块来捕捉操作。。。
结果如下:

 

Rakefile
1 file 'main.o' => ["main.c", "greet.h"] do
2 sh "cc -c -o main.o main.c"
3 end
4
5 file 'greet.o' => ['greet.c'] do
6 sh "cc -c -o greet.o greet.c"
7 end
8
9 file "hello" => ["main.o", "greet.o"] do
10 sh "cc -o hello main.o greet.o"
11 end
 
让我们试一试。
好的,可以工作。

 

output
1 $ rake hello
2 (in /home/jim/pgm/rake/intro)
3 cc -c -o main.o main.c
4 cc -c -o greet.o greet.c
5 cc -o hello main.o greet.o
 

命令行rake hello指示rake去浏览工作列表并发现叫做hello的工作。然后检查hello的依赖并构建它。最后,当所有的环节就绪,rake通过执行C编译器命令去构建hello可执行程序。
 rake会忠实地报告所做的工作。我们能看到每次编译调用以正确的顺序执行完成,最终构建main程序。 然而程序能工作吗? 让我们试试。

 

output
1 $ ./hello
2 Hello, World
 

成功。
但是当我们修改一个文件会发生什么呢。让我们修改greet.c中的greet函数以打印'hi'来代替'hello'。

 

output
1 $ emacs greet.c
2 $ rake hello
3 (in /home/jim/pgm/rake/intro)
4 cc -c -o greet.o greet.c
5 cc -o hello main.o greet.o
6 $
7 $ ./hello
8 Hi, World
 

注意rake重编译了greet.c构建一个新的greet.o。这需要用新构建的greet.o重链接hello。 完成。这不需要重编译main.c因为它从未修改过。
如果我们再次运行rake会发生什么呢?

 

output
1 $ rake hello
2 (in /home/jim/pgm/rake/intro)
3 $
 

是的,没有任何操作。每个操作都是最新的。所以不需rake做任何工作。
好的。rake对这个只有两个源文件和一个头文件的工程有些矫枉过正。但是设想包含数百个文件和依赖的大工程呢,像rake这样的工具一下子变得吸引人了。

总结
我们学到了什么呢?构建Rakefile需要明确依赖和需要建立目标文件的操作。接下来定义操作和依赖就像些标准 ruby代码一样简单了。Rake最后处理构建的细节。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics