BlenderDev/SconsMan
Wikipedia,自由的百科全书
手册原地址:http://www.scons.org/doc/HTML/scons-user/book1.html
- JanusLe(LeYan)翻译 http://janusle.linuxsky.net
Contents |
前言
感谢你花时间来阅读Scons的一切。Scons是一款次世代软件构建工具,或者说生成工具,一种可以构建软件(或其他文件)的软件,使构建的软件及时升级而不需要管它的底层文件是否有变化。
Scons独特的东西在于,它的配置文件其实是用Python编程语言写成的脚本。和其他的构造工具相比,它发明了一种新的工具来配置。当然,scons还是有自己的学习曲线的,你至少需要知道怎么调用一些功能来完成一个恰当的编译。但是它的底层语法的用法其实就跟使用python脚本是一个道理。
简而言之,使用python作为配置文件格式可以让非程序员很快掌握scons使用。比起其他的建立工具,一个程序员为其他程序员发明一种神秘语言,scons能更好的被掌握。使用python还和它的稳定性和可读性有关。为很多熟练的程序员提供一个以脚本为基础的配置文件系统来做更复杂的事情,事实上是很偶然也是必须的。
scons 主义
这里有几条主要的原则是scons在设计时需要达到的
准确性
Scons就算牺牲一些性能,也要保证构建工程的正确。我们千方百计的保证准确性,不论软件是如何编写,怎样的结构,构建次数多少等等。
稳定性
在保证准确的前提下,我们尽量让scons快速的工作,在默认准确能够达到的情况下,我们仍然提供了一系列的优化构建速度的工具。
方便易用
Scons尽最大可能的为你检测你的构建环境:检查你系统中正确的构建工具并使用他们来构建你的软件。
总之,我们努力让scons做正确的事情。以极小的错误来正确建立软件。
手册不完全的提示
由于人手因素,本文档的更新速度不能够和scons的版本一样快。这也是开放源代码软件的通常行为,如果要获得scons的最新使用方法,可以查看它的man文档,它是随scons一同发布的。
感谢
Scons有很多人的辛勤劳作,感谢他们根本不能用只言片语来解决。
http://www.scons.org/doc/HTML/scons-user/x62.html
联系
最好最便捷的能获得scons技术帮助的地方是邮件列表。
http://www.scons.org/doc/HTML/scons-user/x83.html
编译安装scons
安装python。 从预编译包安装scons
简单构建
在这一章里,你将看到几个通过极为简易的编译配置文件(build consifurations)使用SCons的例子。它将证明利用SCons在不同系统上编译几种不同的编程语言的源文件是一件极其简单的事情。
构建简单的C/C++程序
这里是著名的“Hello, World!”的C代码
int
main()
{
printf("Hello, world!\n");
}
这里说明了如果使用SCons编译它。输入如下的代码到一个名叫SConstruct的文件中
Program('hello.c')
这个最小的配置文件给SCons两条信息:你要编译的什么(一个可执行的程序)[注1],和要编译的文件名(the hello.c file)。Program是一个创建方法,一个告诉SCons你要将一个源文件编译成可执行文件的Python过程。
现在执行scons命令编译程序。在一个POSIX-compliant操作系统像Linux或者UNIX,你将看到一些信息类似于下面
% scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -c -o hello.o hello.c
cc -o hello hello.o
scons: done building targets.
在一个Windows操作系统上将使用Microsoft Visual C++的编译器,你将看到一些信息类似于下面
C:\>scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cl /nologo /c hello.c /Fohello.obj
link /nologo /OUT:hello.exe hello.obj
scons: done building targets.
首先,注意你只需要指定源文件名,SCons会通过源文件名正确的生成目标程序名和可执行文件名。
其次,注意同样的SConstruct文件,不需要做任何更改,就会产生正确的输出文件在两个不同的系统上。在POSIX 系列的操作系统(Linux or UNIX)上产生hello.o和hello,在Windows操作系统上产生hello.obj和hello.exe。这是一个简单的例子,它显示了利用SCons使编译程序变得极为简单(译者注:这句翻译不好This is a simple example of how SCons makes it extremely easy to write portable software builds.)
[注1: 原文是what you want to build (an executable program),我的理解是,你要编译什么样的源文件,是C的还是JAVA或者是其他的]
构建目标文件
Program建造方法只是众多建造方法中的一个。SCons提供了创建不同类型文件的方法。另一个建造方法是Object,它告诉SCons通过源文件生成目标文件
Object(‘hello.c’)
现在当你执行 scons命令建立程序,在一个POSIX 操作系统(Linux or UNIX)上,它将仅仅生成hello.o目标文件
% scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -c -o hello.o hello.c
scons: done building targets.
它将只生成hello.obj目标文件在一个Windows操作系统上(使用Microsoft Visual C++构建器)
C:\>scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cl /nologo /c hello.c /Fohello.obj
scons: done building targets.
简单构建JAVA程序
SCons 同样可以简单的构建JAVA程序。不像Program和Object方法,JAVA建造方法需要你指定用来存放class文件的目标文件夹和存放.java文件的源代码文件夹
Java('classes', 'src')
如果src目录下包含hello.java目录,那么当执行scons后你将看到类似于如下的输出
% scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
javac -d classes -sourcepath src src/hello.java
scons: done building targets.
我们将省略Java方法的一些更多的细节,包括诸如Java archive(.jar)等等。这些将在called Java Builds这个章节中讲述
构建后清除
当你使用SCons后,你不需要使用特别的命令,或者目标名字去清除你用scons建立的输出文件(目标程序,可执行文件)。你只需使用-c或者—clean选项当你调用SCons,SCons会清除建立的文件。所以如果我们构建了刚才的例子的源文件那么可以调用scons –c。在POSIX操作系统上的输出将会类似于下面
% scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -c -o hello.o hello.c
cc -o hello hello.o
scons: done building targets.
% scons -c
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed hello.o
Removed hello
scons: done cleaning targets.
在一个Windows下的输出类似于下面
C:\>scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cl /nologo /c hello.c /Fohello.obj
link /nologo /OUT:hello.exe hello.obj
scons: done building targets.
C:\>scons -c
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed hello.obj
Removed hello.exe
scons: done cleaning targets.
注意,SCons会改变它的输出来告诉你它清除的目标并完成清除。
Sconstruct文件
如果你习惯于使用建造系统类似于make,你可能已经察觉SConstruct文件类似于makefile 确实如此,SConstruct文件是一个输入文件,SCons通过读取它的内容来控制建造(build)
SConstruct文件是Python脚本
然而,SConstruct文件和Makefile的一个重大的区别是:SConstruct文件实际上是一个Python脚本。如果你不熟悉Python,不要担心。这个用户手册将逐步介绍一小部分与SConstruct相关的Python语言,你将明白如何通过写SConstruct文件来使SCons变得有效。并且你将发现Python是一个非常容易学习的语言。
使用Python作为脚本语言意味着你可以在你的SConstruct文件中使用Python风格的注释。那就是在注释前添加’#’,这样,’#’号后的那一行将被(编译器)省略
# Arrange to build the "hello" program.
Program('hello.c') # "hello.c" is the source file.
你将看到在这本手册后面的部分里,使用一个真正强大的脚本语言能够使实际工程(real-world Buildes)中复杂的需求变的简单。(意思是说通过使用Python写SConstruct,能够使实际工程中复杂的需求简单化。如果你用过Make,那么肯定有所体会。要写一个功能复杂的Makefile是多么的辛苦,所以诞生了Automake------------译者)
SCons 中的方法可以是无规则
SConstruct文件和普通的Python脚本不完全相同。或者说某些特性和Makefile类似,那就是在SConstruct文件中的函数并不是按你所写的次序被SCons调用的。也就是说,当你调用Program建造方法(或者其他建造方法), 换句话说,当你调用这个程序创建器 (或者其他的构件方法), 你并不是让scons立刻就用这个构件方法创建程序。相反,你是在让scons用你需要的方式创建这个程序,比如,一个程序是由hello.c创建出来的,而且它是依赖于当你需要的时候才创建。比如,一个程序由hello.c创建,它依靠scons来编译程序(译者:等待修改,需要更好翻译方案)
比如,通过编译hello.c的源文件建造一个项目,SCons将立即编译那些需要编译的文件。(在Dependencies这一章中我们将学习更多关于SCons如何决定一个文件是否需要编译或者重新编译)[注2] 注2:意思是说,假设hello.c依赖于a.c,但是不依赖于目录中的另一个b.c,那么SCons会聪明的只编译hello.c和a,c,但是不编译b.c)
使SCons的输出尽可能详细
你已经看到SCons如何显示它正在做什么。随着SConstruct中的命令被执行,你将看到类似于如下的输出
C:\>scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cl /nologo /c hello.c /Fohello.obj
link /nologo /OUT:hello.exe hello.obj
scons: done building targets.
这些信息强调了SCons工作的先后次序:all of the configuration files (generically referred to as SConscript files) are read and executed first,and only then are the target files built. 除了一些用处之外,这些信息帮助辨别SCons读取配置文件和编译目标文件时的错误。
但是这些信息使得输出变的混乱,幸运的是,它们能够通过使用-Q参数被禁止掉。
C:\>scons -Q
cl /nologo /c hello.c /Fohello.obj
link /nologo /OUT:hello.exe hello.obj
由于我们希望这本参考手册把注意力都放在SCons实际所做的工作上,因而我们将在今后的例子中使用-Q参数去除多余的信息
特别简单的构建事务实例
(上面那个标题谁帮忙翻译一下) 在这一章里,(你将看到几个例子,)你可以得到一些简单的配置使用Scons来创建工程的实际例子。(you will see several examples of very simple build configurations using SCons).他们将证明使用SCons在不同的操作系统上,编译不同编程语言的源程序是多么简单的事情。
指定目标文件(Output)文件的名字
你将看到,当你调用Program建造方法的时候。他将把目标程序的名字命名为和源代码文件同名。这就是说,你调用一个建造方法的时候去编译一个名为hello.c的源文件后,建造方法将建造一个名为hello的可执行文件(POSIX系统上)或者生成一个hello.exe的可执行文件(Windwos操作系统上) Program('hello.c')
如果你想指定目标文件的名字,你只需要在建造方法中添加一个参数(这个参数就是你指定的目标文件名字)
Program('new_hello', 'hello.c')
(SCons首先需要目标文件名,随后才是源文件名,这个是模仿了大多数程序设计语言,包括Python: “program = source files” )
现在SCons 将在一个POSIX操作系统上建造一个名为new_hello的可执行程序。
% scons -Q
cc -c -o hello.o hello.c
cc -o new_hello hello.o
SCons 将在一个Windows操作系统上建立一个名为new_hello.exe的可执行文件 C:\>scons -Q
cl /nologo /c hello.c /Fohello.obj
link /nologo /OUT:new_hello.exe hello.obj
编译多个源文件
你已经看到如何配置SCons来编译单个源程序。但是通常情况是你要编译多个源文件,并只有单单一个。为此,你需要把源文件放到一个Python列表里(加上方框),类似于
Program(['main.c', 'file1.c', 'file2.c'])
上面的例子的执行结果可能是
% scons -Q
cc -c -o file1.o file1.c
cc -c -o file2.o file2.c
cc -c -o main.o main.c
cc -o main main.o file1.o file2.o
注意SCons根据列表中的第一个源文件名作为目标文件名。这就是说,如果第一个源文件是prog.c,那么SCons将把目标程序名定为prog(在Windows上是prog.exe)如果你想要指定目标文件名,那么(如同我们前面叙述的那样)你把指定的名称放在列表之前。类似于这样: Program('program', ['main.c', 'file1.c', 'file2.c'])
在Linux上,可能输出结果如下
% scons -Q
cc -c -o file1.o file1.c
cc -c -o file2.o file2.c
cc -c -o main.o main.c
cc -o program main.o file1.o file2.o
在Windows上输出如下
C:\>scons -Q
cl /nologo /c file1.c /Fofile1.obj
cl /nologo /c file2.c /Fofile2.obj
cl /nologo /c main.c /Fomain.obj
link /nologo /OUT:program.exe main.obj file1.obj file2.obj
Specifying Single Files Vs. Lists of Files
我们现在演示通过两种方式指定源文件,一种是通过列表 Program('hello', ['file1.c', 'file2.c'])
另一种是通过单个文件
Program('hello', 'hello.c')
实际上你可以把单个文件放在列表里面。这样更能表现出与多个文件的同一性(这句话翻译不好,希望有人能够帮忙一下――译者)
Program('hello', ['hello.c'])
SCons函数将接受列表中的单个文件。事实上,SCons把所有的输入都当作列表来处理,但是(SCons)允许你在只有单个输入的时候省略方框。(意思是说,当你Program(‘hello’,’hello.c’)的时候,SCons其实也是把后面的那个hello.c当作[hello.c]的。―――译者)
重要: 尽管SCons把单个字符串和列表当作同一样东西来处理。但是Python对他们进行严格的区别。SCons把单个字符串或者列表当作同样的东西,如下
- The following two calls both work correctly:
Program('program1', 'program1.c')
Program('program2', ['program2.c'])
但是你把列表和字符串混合在一起,将产生一个错误
common_sources = ['file1.c', 'file2.c']
# THE FOLLOWING IS INCORRECT AND GENERATES A PYTHON ERROR
# BECAUSE IT TRIES TO ADD A STRING TO A LIST:
Program('program1', common_sources + 'program1.c')
# The following works correctly, because it's adding two
# lists together to make another list.
Program('program2', common_sources + ['program2.c'])
(这个错误来源于Python编译器,而不是SCons---译者)
使列表更容易阅读(Making List of Files Easier to Read)
使用Python的列表的一个缺点是,每个源文件必需被包含在括号里。这可能导致当源文件很多时,列表变的很长,从而难以阅读。幸运的是,SCons和Python推出了一些方法来使得SConstruct文件变的容易阅读。
为了让包含较多的源代码文件名的列表更容易处理,(SCons provides a Split function that takes a quoted list of file names, with the names separated by spaces or other white-space characters, and turns it into a list of separate file names.这句话翻译不好―――译者)通过使用Split函数使得先前的例子变成
Program('program', Split('main.c file1.c file2.c'))
(如果你熟悉Python,你会发现,这个很类似于Python中string模块的split()方法。然而,与string.split()不同的是,这个Split函数不需要一个字符串作为输入,split会将一个非string对象包含在一个列表里,如果输入已经是一个列表,那么split将对其不做改变。这样你就可以很容易的把参数传递给SCons函数,而不需要手动检查它的类型。)
把要编译的文件名放在Split函数中,并将Split函数嵌在Program函数中(前面的Program('program', Split('main.c file1.c file2.c')――――译者)依旧难以处理。一个好的办法是将Split返回的值赋给一个变量,然后将变量传递给Program函数类似于这样
list = Split('main.c file1.c file2.c')
Program('program', list)
Split函数不关心两个文件名之间有多少空白字符(空格,制表符之类的―――译者)。这意味着你可以在两个文件名之间插入空行,这样可以让编辑更加容易 list = Split("""main.c
file1.c
file2.c""")
Program('program', list)
(注意上面那个例子,我们使用了Python三引号的语法,它允许一个字符串可以包含空行,The three quotes can be either single or double quotes.这句话没有看懂什么意思――译者)
参数关键字/关键变元(Keyword Arguments不知道这么翻译对不对)
SCons同样允许你指定输出输入文件通过使用Python的关键变元。.输出文件可以称为target,源文件称为source。这样脚本可以这么写
list = Split('main.c file1.c file2.c')
Program(target = 'program', source = list)
因为关键字特别指定了每个变元,所以你甚至可以改变传给Program参数的顺序。
list = Split('main.c file1.c file2.c')
Program(source = list, target = 'program')
你是否使用关键变元来指定目标和源文件,纯属个人喜好。SCons函数将不管这些。
编译多个程序(Compiling Multiple Programs)
为了把编译多个不同的文件的要求在一个SConstruct文件里面实现,只需要简单的多次调用Program方法就可以了,
Program('foo.c')
Program('bar', ['bar1.c', 'bar2.c'])
SCons会编译如下文件
% scons -Q
cc -c -o bar1.o bar1.c
cc -c -o bar2.o bar2.c
cc -o bar bar1.o bar2.o
cc -c -o foo.o foo.c
cc -o foo foo.o
注意到SCons不一定根据你SConstruct文件中指定的编译顺序来编译文件。SCons会判断出一个独立的目标文件必须在哪些文件编译完之后再编译。(意思是说假设main.c调用了a.c中的一个函数,就是main.c依赖a.c。SCons会先编译a.c,再编译main.c,哪怕你在SConstruct中指定的顺序是先编译main.c再编译a.c----译者)我们将在“依赖性”(Dependencies)这个章节更深入的讨论这个问题。
多个程序共享源文件
在多个程序中共用相同的源文件是非常普遍的现象。一种做法就将源文件创建成库,然后将这个库连接到目的程序。(在构建和连接库这章将做讨论)
更简单的来讲,让多个程序共享源文件,可以将通用文件放在每个程序中,虽然这样不方便。
Program(Split('foo.c common1.c common2.c'))
Program('bar', Split('bar1.c bar2.c common1.c common2.c'))
Scons会明白common1.c 和 common2.c的目标文件只需要构建一次,尽管最终目标文件被连接到两个最终的可执行程序中。
% scons -Q
cc -c -o bar1.o bar1.c
cc -c -o bar2.o bar2.c
cc -c -o common1.o common1.c
cc -c -o common2.o common2.c
cc -o bar bar1.o bar2.o common1.o common2.o
cc -c -o foo.o foo.c
cc -o foo foo.o common1.o common2.o
如果更多的程序共享了一大堆的共用源文件,在列表中为每个程序重复所有的共用源文件将会对程序维护带来灾难,假如你想对某个文件改动的话。你可以通过创建不同的python表存储这些共用文件名来简化这个事情,然后用Python的+操作来和其他的python表联合。
common = ['common1.c', 'common2.c']
foo_files = ['foo.c'] + common
bar_files = ['bar1.c', 'bar2.c'] + common
Program('foo', foo_files)
Program('bar', bar_files)
此例和前面那个是等效的。
创建和连接库文件
将软件的各个功能部分聚集到一起作为库来使用,在大型的软件工程中是非常有用的。Scons为这种方法提供了简便的手段。
