`

scons 学习

阅读更多

scons 学习
作者:Sam(甄峰) sam_code@hotmail.com

http://www.scons.org/

Sam有个好朋友是做游戏的,整天嘲笑做嵌入式的用的工具多土多原始。gdb不是图形化,DDD又没VC调试好用,只会写Makefile等等。
刚好最近有需要使用scons。所以Sam准备学习之以回击这种挑衅。呵呵。

scons简介:
scons是一个Python写的自动化构建工具,从构建这个角度说,它跟GNU make是同一类的工具。

scons与其它工具最显著的差别就是:scons配置文件是Python script.

它的思想是跟GNU make完全不同的。GNU make的核心是“依赖关系”,我要做的事情,就是告诉系统,一个目标依赖什么东西,并且,当被依赖的东西发生变化时,我要做什么。
例如:
all: main.c
$(CC) $(CFLAGS) $(LFLAGS) main.c -o BT_remote -lbluetooth -lBluetooth_remote -lm -lpthread
意思是:all依赖于main.c。 如果main.c有了变化,作下面这些事。


这样做可以解决相当多的问题,但是也带来了一个最大的问题:我如何判别这个目标依赖什么?

对于一个两个,甚至十几个文件,我当然还比较容易搞清楚,谁依赖谁。但是当文件有成百上千个时,要分清楚谁依赖谁可就没这么容易了。尤其是C/C++头文件的依赖,如果手工分析的话,工程量可是不小。为了解决这个问题,GNU又提供了另外一套工具:Automake,使用程序来分析依赖性,然后辅助你产生 makefile。

于是乎,就有人想了,既然如此,我干吗费那劲,用程序分析依赖性,然后生成一个文件,再交给另外一个程序去处理呢?既然依赖性需要用程序来分析,那么就直接交给构建工具本身去做不就好了吗?对的,这是一个非常自然的思路,于是,Java世界有了Ant,而 Python世界有了scons。

scons就是这样一个构建工具:你告诉它要做的任务,以及完成这个任务需要的输入,以及这个任务产生的输出,怎么做这个任务(当然其中就包括依赖性分析),就交给工具本身完成。


例 1:
只有一个 test.c文件,需要编译成可执行文件。
创建SConstruct,内容为:
Program('test.c')
这句话透露2层意思:
1.编译方法:想要编译成什么类型。(Program:可执行文件)
2.哪个东西想编译(test.c)
#scons
% scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -o test.o -c test.c
cc -o test test.o
scons: done building targets.

clean:
#scons -c
则把编译出的东西又删除了,类似make clean


例2:
只有一个文件,想编译成object文件。
Object('test.c')
1. 编译方法:想要编译成什么类型。(Object: .o文件)
2.哪个东西想编译(test.c)

#scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -o hello.o -c hello.c
scons: done building targets.

清空:
#scons -c
则把编译出的东西又删除了,类似 make clean

例3:
有多个.c文件,并想指定生成的程序名:
Program('program', ['prog.c', 'file1.c', 'file2.c'])
生成可执行文件 program, 由prog.c file1.c file2.c 生成。
#scons -Q
cc -o file1.o -c file1.c
cc -o file2.o -c file2.c
cc -o prog.o -c prog.c
cc -o program prog.o file1.o file2.o

甚至可以这样写:
common_sources = ['file1.c', 'file2.c']
Program('program2', common_sources + ['program2.c'])



例4:
有很多个.c文件,不想一个一个指定,类似Makefile中 *.o: *.c
Program('test', Glob('*.c'))


不管使用common_sources = ['file1.c', 'file2.c'] 还是Program('test1.c'....'testn.c')
每个文件名都需要被单或者双引号包起来。这太不方便了。
SCons 提供了Split函数
Program('program', Split('main.c file1.c file2.c'))
或:
src_files = Split('main.c file1.c file2.c')
Program('program', src_files)



例5:
SCons还对 output file和source file有关键字,可以用来指定

src_files = Split('main.c file1.c file2.c')
Program(target = 'program', source = src_files)
因为有关键字指定,多以可以换前后:
Program(source = src_files, target = 'program')


例6:
创建库:
Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o'])
#scons -Q
cc -o f1.o -c f1.c
cc -o f3.o -c f3.c
ar rc libfoo.a f1.o f2.o f3.o f4.o
ranlib libfoo.a

例7:建立静态和动态库:
静态库:其实使用Library也是建立静态库。
StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])
动态库:
SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])

% scons -Q
cc -o f1.os -c f1.c
cc -o f2.os -c f2.c
cc -o f3.os -c f3.c
cc -o libfoo.so -shared f1.os f2.os f3.os

例8:使用静态和动态库:
使用$LIBS 来指定库,使用$LIBPATH 指定库位置。
Library('foo', ['f1.c', 'f2.c', 'f3.c'])
Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')
% scons -Q
cc -o f1.o -c f1.c
cc -o f2.o -c f2.c
cc -o f3.o -c f3.c
ar rc libfoo.a f1.o f2.o f3.o
ranlib libfoo.a
cc -o prog.o -c prog.c
cc -o prog prog.o -L. -lfoo -lbar


Program('prog.c', LIBS = ['m'], LIBPATH = ['/usr/lib', '/usr/local/lib'])
% scons -Q
cc -o prog.o -c prog.c
cc -o prog prog.o -L/usr/lib -L/usr/local/lib -lm




以BTX为例使用scons:
Sam 创建了一个SConstruct,(类似于GNU make的Makefile文件,是scons的默认文件名).

Sam首先想生成 BTX library.
然后想将library 和 main.c和成一个可执行文件:BTX_Test
内容如下:
#指定生成文件名为:libBTX.a. 由BTX.c生成的。-I'/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include -I../include
StaticLibrary('BTX', ['BTX.c'], CPPPATH=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include', '../include'])
Program('BTX_Test', ['main.c'], CPPPATH=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include', '../include'], LIBS=['BTX','blu\etooth','pthread'], LIBPATH=['.', '/usr/lib'])

#scons
提示之不到bluetooth库,Sam在 /usr/lib中将 libbluetooth.so 软连接到libbluetooth.so.2。
于是编译成功,所以,Sam觉得Scons和 Makefile很类似,只需要编译时指定-I ,-L, -l就好了。对应关系如下:
-I:CPPPATH=['/opt/hisilicon/toolchains/arm-uclibc- linux-soft/include', '../include']
-L:LIBPATH=['.', '/usr/lib']
-l: LIBS=['BTX','bluetooth','pthread']
CPPPATH,LIBPATH,LIBS,CC等从:
http://www.scons.org/doc/1.2.0/HTML/scons-user/a4774.html#cv-CPPPATH 中找到
同时请注意,最好在每个关键字赋值后面都跟 [],里面有多个时用逗号分开。


X5 Version:
StaticLibrary('BTX', ['BTX.c'], CC=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/bin/arm-uclibc-linux-gcc'], CPPPATH=['/opt/his\ilicon/toolchains/arm-uclibc-linux-soft/include', '../include'])
Program('BTX_Test', ['main.c'], CC=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/bin/arm-uclibc-linux-gcc'], CPPPATH=['/opt/his\ilicon/toolchains/arm-uclibc-linux-soft/include', '../include'], LIBS=['BTX','bluetooth','pthread'], LIBPATH=['./', '../resource/']\)



scons只需要描述任务,并不需要指定依赖关系,甚至我们都没有指出头文件,但是你修改BTX.h的时候仍然会触发构建。这是因为scons内部有个scanner,可以帮助扫描包含文件的关系。
我们还发现,这里我们根本没有指定编译器,也没有指定编译选项,但scons仍然很聪明的选择了gcc. 这是因为scons内置提供了很多编译器及其对应选项的选择,然后对于不同的平台,会有一个默认项。



Environments:
Scons有3种环境变量:
1. External Environment
2. Construction Environment
3. Execution Environment

当想要使用External Environment,必须通过os.environ。这意味着首先要加入:
import os
之后就可以在SConscript文件中使用os.environ来初始化 construction environments 为用户环境变量了。

1.创建Construction Environment
env = Environment()

例如:
import os
env = Environment(CC = 'gcc', CCFLAGS = '-O2')
env.Program('foo.c')



最重要的环境变量是:Construction Environment
它在复杂的工程中非常重要,例如,不同的源文件需要不同的编译选项。或者不同的可执行程序需要链接不同的库。scons提供Construction Environment。让我们可以创建不同的Construction Environment来创建不同的编译选项。

1. 创建Construction Environment ,使用Environment function。
env = Environment() 所有的Construction Environment 项目值全用scons自己找到的。
env = Environment(CC = 'gcc', CCFLAGS = '-O2') ,其他的与上一个相同,但只有CC和CCFLAGS 自定义。

2. 察看Construction Environment 每个项目值:注[1]
需要使用Dictionary() function
env = Environment()
dict = env.Dictionary()
keys = dict.keys()
keys.sort()
for key in keys:
print "construction variable = '%s', value = '%s'" % (key, dict[key])
打印所有Construction Environment项目。








scons中Python模块的导入:
1. import os
os 模块包含普遍的操作系统功能。如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的。即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在Linux和Windows下运行。一个例子就是使用os.sep可以取代操作系统特定的路径分割符。


os.name 字符串指示你正在使用的平台。比如对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'。
os.getcwd() 函数得到当前工作目录,即当前Python脚本工作的目录路径。
os.getenv()和os.putenv()函数分别用来读取和设置环境变量。
os.listdir()返回指定目录下的所有文件和目录名。
os.remove()函数用来删除一个文件。
os.system() 函数用来运行shell命令。
os.linesep字符串给出当前平台使用的行终止符。例如,Windows使用'\r\n',Linux使用' \n'而Mac使用'\r'。
os.path.split()函数返回一个路径的目录名和文件名。
os.environ Shell variables
这里重点说os.environ:
它应该是Linux环境变量。

例 1:
想要得到当前Linux环境变量 PATH,LD_LIBRARY_PATH,HOME等。(这与前面讲的环境变量对应起来了)

#导入OS模块
import os
#创建一个Construction Environment
env=Environment()
print "HOME: ", os.environ["HOME"]
则打印结果为HOME:/home/sam。这样就得到了Linux环境变量。

例 2:
想要用当前Linux环境变量ARMGCC来设置toolchain.

首先:在Linux下:
export ARMGCC=arm-linux-gcc

之后,修改config
#导入OS模块
import os
#创建一个Construction Environment
env=Environment()
if os.environ.has_key('ARMGCC'):
env.Replace(CC = os.environ['ARMGCC'])
则使用arm-linux-gcc取代了Construction Environment中的CC。



2. import sys
sys模块包含系统对应的功能.sys模块包含了与Python解释器和它的环境有关的函数.
import sys
if sys.byteorder == 'little' or env['PLATFORM'] == 'win32':
env.Append(CPPDEFINES = ['LSB_FIRST'])


3. import platform
platform得到编译信息:
platform.processor() ---i686
platform.python_build()---('r251:54863', 'Jun 4 2007 15:03:52')
platform.python_compiler()----'GCC 3.4.4 20050721 (Red Hat 3.4.4-2)'
platform.python_version()----'2.5.1'
platform.release()----'2.6.9-22.ELsmp'
platform.system()----'Linux'
platform.version()----'#1 SMP Mon Sep 19 18:32:14 EDT 2005'
platform.uname()----('Linux', 'nec', '2.6.9-22.ELsmp', '#1 SMP Mon Sep 19 18:32:14 EDT 2005', 'i686' , 'i686')
platform.machine()----'i686'
platform.libc_ver()----('glibc', '2.0')




注[1]:
所有Construction Variables可以在下面找到:
Construction Variables可用在:
1. CPPPATH,LIBS,LIBPATH。(在BTX例子中可见)
2. Construction Environment(env=Environment)中的项目。

Appendix A. Construction Variables

分享到:
评论

相关推荐

    scons用户手册(英文)

    scons类似于makefile,只是scons是python编写的,并且搭建scons比搭建makefile简单,其中python语言也很容易学习,不过这个文档没有详细的一个大型项目的搭建用例,请注意是英文版

    Scons使用手册

    SCons脚本编辑器,和Makefile相似。但是,新手学习比较快,简单易行!

    scons指南中文翻译

    是中文翻译版本哦!关于SCons最独特的事情是,它的配置文件实际上是用...当然,SCons仍然有一个学习曲线,因为你必须知道要调用哪些函数来正确设置你的构建,但是任何看过Python脚本的人都应该熟悉所 使用的基础语法。

    cmake实践,学习cmake的一本好书

    CMake是一个跨平台的安装(编译)工具,可以用简单...这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。

    高通平台驱动开发文档(花了五千大洋培训得来的资料哦)

    在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流程分析 qcril 流程分析,设置sim卡锁 python scons 语法学习 Python 语言之 scons 工具流程分析

    httpserver:学习socket网络编程,学习C++类的封装

    学习socket网络编程,学习C++类的封装 参考我总结的网络编程实践 试图解决其中提到的一些问题。 第一期任务 (已经完成) 2015/03/04 完成了基本的框架搭建,使用scons管理项目 完成了tcp socket的简单封装 实现最简单...

    Libjingle 通过vs2005编译

    目前GOOGLECODE上的最新更新删除了libjingle.vcproj文件,采用scons脚本进行编译,增加了学习门槛,本次下载包增加了libjingle.vcproj文件并且已经通过了vs2005编译,方便大家学习使用。 Libjingle - Google Talk ...

    em算法matlab代码-ML:机器学习摘要和测试-深度学习,高斯过程等

    em算法matlab代码ML 机器学习片段 我深度学习之旅的游乐场。 未来的增加还包括现有的机器学习代码(其中一些需要从Matlab进行重构),例如使用EM的高斯混合模型(GMM),k-均值,k-medoids,...++,SCons)和其他商品。

    开源的FreeNOS

    除了是一个操作系统的实现,另外从中也能很好的学习到OOP的设计方式,整个代码风格特别好,完全基于面相对象,还有一些常见的设计模式,在接触了这个开源项目之后,才了解,代码风格,注释,doxygen,scons,设计...

    Selection-Chess

    这目前是Aggie Coding Club的学习者项目,因此我们目前不在寻求外部帮助。 这更多是为了使我们能够在业余时间构建出色的算法。 不管是从废弃到全面开放,这都会在将来发生变化。 如何编译 我们使用 。 一旦在计算机...

    嵌入式系统/ARM技术中的《嵌入式Linux应用程序开发标准教程》(第2版)-第10章、嵌入式Linux网络编程

    本书主要分为3个部分,包括Linux基础、搭建嵌入式Linux环境和嵌入式Linux的应用开发... 本书可作为高等院校电子类、电气类、控制类等专业高年级本科生、研究生学习嵌入式Linux的教材,也可供希望转入嵌入式领域的科研

    cmake-3.15.5-win64-x64.rar

    CMake是一个跨平台的安装(编译)工具,可以用简单...这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。

    awtk所需的所有环境资源及源码和例程

    awtk资源: 环境资源:vs2017 , vscode ,python2.7 ,scons_3.1.1 ,nod.js, awtk集成的开发软件 源码:awtk源码及例程

    FaceRecognition2:FaceRecognition2是人脸检测与识别的一个实现项目。 使用MTCNN算法进行人脸检测,并使用LightenedCNN算法进行人脸识别

    EAIDK演示 EAIDK-Demo是人脸检测和识别的实施项目。 使用MTCNN算法进行人脸检测,并使用...sudo apt-get install git cmake scons protobuf-compiler libgflags-dev libgoogle-glog-dev libblas-dev libhdf5-seria

    AlgAudio:音乐表演的音频处理框架

    AlgAudio是一个音频处理框架,旨在易于在现场表演中学习和使用。 用户通过创建数据流程图来定义信号操作网络。 AlgAudio带有一组构建块,并且可以通过自定义外部模块轻松扩展。 v1.99.1二进制文件。 API文档。 ...

    cmake 基础教程 多平台工程构建工具

    (admin/Makefile.common),在经历了unsermake, scons以及cmake的选型和尝试之后,KDE4决定使用cmake作为自己的构建系统。在迁移过程中,进展异常的顺利,并获得了cmake开发者的支持。所 以,目前的KDE4开发版本已经...

    suffixlemmatizer:适用于高屈折性语言的简单幼稚统计词形分解器

    该库/程序是一个统计词法分析器,用于学习最可能的变形词形->词法化词缀的后缀替换。 它主要是从爱沙尼亚语言的角度设计的,但是可能与任何屈折的语言一起使用,因为不同的词形共享一个共同的前缀。 建造 要构建...

    git-warp-time:Rust库和CLI实用程序将文件时间戳重置为回购状态

    git扭曲时间 CLI实用程序(和Rust库)将文件系统元数据中最后修改的时间戳记为修改每个文件的最后一次提交的时间。... 一些依赖校验和(例如SCons)并保留“最后见到”文件状态的单独数据库,但是由于这需要额外的存

Global site tag (gtag.js) - Google Analytics