SConstruct

一、SConstruct File {{{1

1. Sconstruct 文件 是scons用来控制编译的文件

2. Sconstruct 文件 是一个python脚本

3. SConstruct 文件 是一个类似于makefile一样的东西, 告诉 scons做什么,而不是严格的规定soncs做这件事的步骤

二、scons选项 {{{1

-c Cleaning up After a Build

-Q Making the scons output less verbose

三、SConstruct 脚本的编写基础 {{{1

1. builder method {{{2

Program : generate executable file

Object : generate Object file

Java : 编译java程序, User Guide 2.3, Chapter 25

Library : 静态库, 也可以使用 StaticLibrary替代

SharedLibrary: 动态库

2. 指定目标名 {{{2

Program('hello.c') # 生成 hello.exe

Program('new_hello', 'hello.c') # 生成 new_hello.exe

3. 编译多个文件 {{{2

Program(['prog.c', 'file1.c', 'file2.c']) # 生成 prog.exe

Program('program', ['prog.c', 'file1.c', 'file2.c']) # 生成program.exe

Program('program', ['prog.c', 'file1.obj', 'file2.obj']) # 可以在文件列表中指定.obj文件

3.1 使用Glob 编译所有匹配的文件

Program('program', Glob('*.c') )

Glob原型为:Glob(self, pattern, ondisk=True, source=False, strings=False)

其中pattern 支持unix系统下的文件名匹配: *(任意多个字符), ?(单个字符) 和 [](括号中的任一字符)

3.2 使用Split

Program('program', Split('main.c file1.c file2.c'))

Split以空白字符为分隔符,将字符串分割,因此,你也可以这样写:

Program('program', Split("""

main.c

file1.c

file2.c

""") )

3.3 使用关键字参数

Program(target = 'program', source = 'hello.c')

4. 指定编译选项 {{{2

$CPPFLAGS 指定编译选项

$LINKFLAGS 指定链接选项, 如 /DEBUG

$CPPDEFINES指定预编译器

$LIBS 指定所需要链接的库文件

$LIBPATH 指定库文件(.lib)的搜索目录

$CPPPATH 指定[.h, .c, .cpp]等文件搜索路径

例如:

Library('foo', Split('f1.c f2.c f3.c') )

Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')

注:LIBS和LIBPATH若为一个可以使用字符串,若为多个则使用列表

四、使用Environments {{{1

一个environment是一个影响程序执行的值得集合。

(1) 外部环境 External Environment

外部环境是运行Scons时 用户的环境变量。它们可以通过os.environ获取

(2) 构建环境 Construction Environment

它包含一些变量,这些变量会影响Scons构建目标的行为

(3) 执行环境 Execution Environment

执行环境用于Scons执行外部命令(external command), 以构建一个或多个目标。

注意:它与外部环境不相同

1. Construction Environment {{{2

> 创建 construction Environment

env = Environment()

一个Environment是一个 (name,value)的集合,可以这样查看它的内容:

for item in env.Dictionary():

print '(%s:%s)' % (item, env[item])

> 查看变量

env['CC'] #查看 CC ,即C语言编译器

env.subst('$CC') # 功能同上

它的优势在于,它会将出现在结果中的环境变量转换成最终的值

使用AllowSubstException()函数,使得当subst中的变量不存在时报告错误,

AllowSubstException()

env.subst('$missing') # 出现异常,NameError

> 修改环境变量

拷贝一个环境变量

使用env.Clone #详见user guide 7.2.7

替换一个已经存在的环境变量

env.Replace

为一个没有被定义的变量设置默认值

env.SetDefault

为一个已存在的环境变量增加一个值

env.Append, 例如:

env.Append(CCFLAGS = '-option -O3 -O1')

env.Append(CCFLAGS = ['-option', 'O3'])

为一个环境变量增加一个唯一的值

env.AppendUnique

在最前边添加一个值

env.Prepend

在最前边添加一个唯一的值

env.PrependUnique

合并环境变量

env.MergeFlags, 例如:

flags = {'CCFLAGS':'-option -O3 -O1'}

env.MergeFlags(flags)

flags = {'CPPPATH' : ['/user/opt/include', 'user/local/include']}

env.MergeFlags(flags)

#若参数不是Dictionary, 内部调用ParseFlags将其转化为Dictionary

env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include')

> 一些实用的变量

判断是否是windows:

env['PLATFORM'] == 'win32'

2. Execution Environment {{{2

当scons构建一个目标文件时,它所使用的外部环境和执行scons时的环境变量是不同的。

scons使用$ENV 构建变量 中 存储的目录 作为它执行命令的外部环境变量

> PATH

POSIX 系统中默认的PATH是 /user/local/bin:/user/bin

Window系统中默认的PATH是 command interpreter在注册表中的值

1. 在构建环境中显示初始化PATH

path = ['/user/local/bin', '/bin', '/user/bin']

env = Environment(ENV = {'PATH':path})

上面这种方式,只设置了ENV,如果你想保留其他的变量,可以这么做:

env['ENV']['PATH'] = ['/user/local/bin', '/bin', '/user/bin']

2. 从 外部环境 初始化 PATH

import os

env = Environment(ENV = {'path' : os.environ['PATH']})

你也可以将完整的外部变量传递给执行环境变量:

import os

env = Environment(ENV = os.environ)

这样做的缺点是:如果环境变量目录中,有多个目录包含编译器如gcc,那么,

scons将执行第一个被找到的gcc

3. 使用env.PrependENVPath 和 env.AppendENVPath

例如:将'/user/local/bin' 插入 $PATH中第一个位置

env.PrependENVPath('PATH', '/user/local/bin')

例如:将'/user/local/bin' 插入 $LIB中最后一个位置

env.AppendENVPath('lib', '/user/local/lib')

五、Controlling Build Output {{{1

1. 使用Help 函数 来说明SConstruct脚本

例如:

Help('this is a debug version')

在控制台上使用 scons -h 命令查看此帮助信息

你可以在脚本中多次使用Help,帮助信息会被连接到一起

六、scons 命令行参数 {{{1

用户可以为scons指定三种类型的参数:

> Options : 以 一个或两个(-) 开头 , 详细参考 User Guide 10.1

> Variables : 形式为:variable=value, 详细参考 10.2

> Target : 如果不是一个 Option 或 Variable ,那么就是一个Target , 详细参考 User Guide 10.3

1. 读取命令行的Variable参数

命令行:scons debug=1

SConstruct脚本如下:

debug = ARGUMENTS.get('debug', 0)

if int(debug) :

pass # do something

2. Command-Line Targets

scons提供 COMMAND_LINE_TARGETS 供用户访问命令行参数中的 Targets列表,例如:

if 'bar' in COMMAND_LINE_TARGETS:

print "Don't forget to copy 'bar' to the archivel"

Default(Program('foo.c'))

Program('bar.c')

> 使用 Default函数 定义 默认目标

当你没有在命令行参数中指定目标时,scons会编译每一个目标

例子:

env = Environment()

hello = env.Program('hello.c')

env.Program('goodbye.c')

Default(hello) #如果没有在命令行指定Target,则会编译hello

使用DEFAULT_TARGETS获取 默认目标, 例如:

prog1 = Program('prog1.c')

Default(prog1)

print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)

使用 BUILD_TARGETS 获取要编译的目标

七、控制目标文件的路径 {{{1

1. BINDIR {{{2

>使用Install:如,

test = env.Program('test.cpp')

env.Install('bin', 'test.exe') #表示要将test.exe 放到bin目录下

env.Install('bin', test)

>在指定目标名的时候指定其目录,如:

env.Program('bin/test', 'test.cpp')

>将目标放到其他目录下,并修改名字

test = env.Program('test.cpp')

env.InstallAs('bin/testapp.exe', 'test.exe') #表示将test.exe 拷贝到 bin/testapp.exe

或 这样写

env.InstallAs('bin/testapp', test)

当 需要对多个目标做此操作时,可以这样做:

env = Environment()

hello = env.Program('hello.c')

goodbye = env.Program('goodbye.c')

env.InstallAs(['/usr/bin/hello-new', '/usr/bin/goodbye-new'], [hello, goodbye]) #多个目标

env.Alias('install', '/usr/bin')

2. obj文件路径 {{{2

使用VariantDir函数指定

3. 一份代码构建多个版本的Target {{{2

通常会有这样的需求,一份源码,既要构建它的debug版本,又要构建它的release版本,这种情况下,

>我们需要为不同版本指定不能的obj名字,否则就会产生冲突,导致scons不能工作。简单的示例如下:

         opt = Environment(CCFLAGS = '-O2')
          dbg = Environment(CCFLAGS = '-g')
          o = opt.Object('foo-opt', 'foo.c')  // 生成 foo-opt.o
          opt.Program(o)
          d = dbg.Object('foo-dbg', 'foo.c')  // 生成 foo-dbg.o
          dbg.Program(d)

>或者将不同版本的obj放到不同的路径下:

          o = opt.Object('opt/foo', 'foo.c')  // 生成 foo-opt.o
          opt.Program(o)
          d = dbg.Object('dbg/foo', 'foo.c')  // 生成 foo-dbg.o
          dbg.Program(d)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • windows注册表操作

    参考:https://blog.csdn.net/CrowNAir/article/details/78128566 http://www.winwin7.c...

    sofu456
  • ffmpeg

    sofu456
  • torch.cuda.is_available

    torch.cuda.get_device_name(0) 返回gpu名字,设备索引默认从0开始;

    sofu456
  • 一个为制造业而生的AI助手,普通员工向它提问就能做数据分析

    产业链、供应链周期变短,不确定因素增加。数字化转型呼之欲出,AI落地的需求越来越明显。

    量子位
  • 教程 | 如何使用TensorFlow API构建视频物体识别系统

    选自Medium 机器之心编译 参与:李泽南 在谷歌 TensorFlow API 推出后,构建属于自己的图像识别系统似乎变成了一件轻松的任务。本文作者利用谷歌...

    机器之心
  • 如何为你的移动应用建立RESTful API

    程序你好
  • 为什么说要用DDD替代CRUD来设计API

    来自亚马逊的高级工程师 James Hood 以简单明了的例子说明了为什么要用 DDD 替代 CRUD 来设计 REST API。他提到“DDD 与 REST ...

    IT大咖说
  • Python高级进阶#004 pyqt5设置窗体图标

    刘金玉编程
  • 大华股份:未来 5 年 B 端市场大有潜力,智能解决方案将加速普及

    近日,海富通基金、富国基金等数家机构对大华股份进行了实地调研,大华股份相关高管就相关问题进行了解答。

    AI掘金志
  • 电商社交数据在大数据风控的应用实践

    大数据文摘

扫码关注云+社区

领取腾讯云代金券