上一篇好像写的有点长了,上传不上去,所以又写了第二篇续写第一篇.

环境变量影响 scons 构建

it uses the dictionary stored in the $ENV construction variable as the external environment for executing commands.
解释: 它使用成字典的方式存储在 ENV 的构造变量中 作为外部可执行命令的环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
添加 Path 环境变量到 ENV中执行
path = ['/usr/local/bin', '/bin', '/usr/bin']
env = Environment(ENV = {'PATH' : path})

env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin']
env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin'

因为是 scons 的配置文件是以 python 的环境执行的 所以 你可以使用 os.environ['PATH'] 获取环境变量, 例子如下:
这样做,可以让自己的代码可移植,跨平台
import os
env = Environment(ENV = {'PATH' : os.environ['PATH']})

或者你可以将整个 环境变量 全部赋值给 ENV
import os
env = Environment(ENV = os.environ)

你可以在已有的环境变量中 拼接 scons 提供如下的 方法:
PrependENVPath()
AppendENVPath()
env =环境(ENV = os.environ)
env.PrependENVPath('PATH''/ usr / local / bin')
env.AppendENVPath('LIB''/ usr / local / lib')

使用外部工具

使用外部工具的时候 scons 默认的搜索路径:
scons 内置工具目录
Sconstruct 同级目录下/site_scons/site_tools/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Builtin tool or tool located within site_tools
env = Environment(tools = ['SomeTool'])
env.SomeTool(targets, sources)

# The search locations would include by default
SCons/Tool/SomeTool.py
SCons/Tool/SomeTool/__init__.py
./site_scons/site_tools/SomeTool.py
./site_scons/site_tools/SomeTool/__init__.py

也可以给 添加 除了 scons 默认搜索路径
# Tool located within the toolpath directory option
env = Environment(tools = ['SomeTool'], toolpath = ['/opt/SomeToolPath', '/opt/SomeToolPath2'])
env.SomeTool(targets, sources)

# The search locations in this example would include:
/opt/SomeToolPath/SomeTool.py
/opt/SomeToolPath/SomeTool/__init__.py
/opt/SomeToolPath2/SomeTool.py
/opt/SomeToolPath2/SomeTool/__init__.py
SCons/Tool/SomeTool.py
SCons/Tool/SomeTool/__init__.py
./site_scons/site_tools/SomeTool.py
./site_scons/site_tools/SomeTool/__init__.py

嵌套工具
# namespaced target
env = Environment(tools = ['SubDir1.SubDir2.SomeTool'], toolpath = ['/opt/SomeToolPath'])
env.SomeTool(targets, sources)

# With this example the search locations would include
/opt/SomeToolPath/SubDir1/SubDir2/SomeTool.py
/opt/SomeToolPath/SubDir1/SubDir2/SomeTool/__init__.py
SCons/Tool/SubDir1/SubDir2/SomeTool.py
SCons/Tool/SubDir1/SubDir2/SomeTool/__init__.py
./site_scons/site_tools/SubDir1/SubDir2/SomeTool.py
./site_scons/site_tools/SubDir1/SubDir2/SomeTool/__init__.py

使用 sys.path 作为扩展的工具路径
# namespaced target using sys.path within toolpath
import sys
searchpaths = []
for item in sys.path:
if os.path.isdir(item): searchpaths.append(item)

env = Environment(tools = ['someinstalledpackage.SomeTool'], toolpath = searchpaths)
env.SomeTool(targets, sources)

你可以使用这个包 来避免使用 pip 安装包 拼接前面复杂的路径
# namespaced target using sys.path
import sys
env = Environment(tools = ['SomeTool'], toolpath = [PyPackageDir('tools_example.subdir1.subdir2')])
env.SomeTool(targets, sources)

这次你了解 构造变量的这几个方法
MergeFlags, ParseFlags, and ParseConfig methods of a construction environment
MergeFlags, ParseFlags ParseConfig

###

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
MergeFlags
尝试合并某个构造变量 例子如下:

env = Environment()
env.Append(CCFLAGS = '-option -O3 -O1')
flags = { 'CCFLAGS' : '-whatever -O3' }
env.MergeFlags(flags)
print env['CCFLAGS']

>>>>
scons -Q
['-option', '-O1', '-whatever', '-O3']
scons: '.' is up to date.

env = Environment()
env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include'])
flags = { 'CPPPATH' : ['/usr/opt/include', '/usr/local/include'] }
env.MergeFlags(flags)
print env['CPPPATH']

>>>>
scons -Q
['/include', '/usr/local/include', '/usr/include', '/usr/opt/include']
scons: '.' is up to date.

如果我们这个方法传递的不是列表 scons 会自动调用 ParseFlags 将其解析成列表
env = Environment()
env.Append(CCFLAGS = '-option -O3 -O1')
env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include'])
env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include')
print env['CCFLAGS']
print env['CPPPATH']

>>>>
scons -Q
['-option', '-O1', '-whatever', '-O3']
['/include', '/usr/local/include', '/usr/include', '/usr/opt/include']
scons: `.' is up to date.

ParseFlags
[ParseFlags](https://scons.org/doc/production/HTML/scons-user/ch08s02.html)
讲一个有规律的字符串 解析成一个字典列表
-I 指要包含的 源码路径
-L 库文件的路径
env = Environment()
d = env.ParseFlags("-I/opt/include -L/opt/lib -lfoo")
for k,v in sorted(d.items()):
if v:
print k, v
env.MergeFlags(d)
env.Program('f1.c')

支持递归输入 主要是看例子 和输出结果去理解这些东西, 这里官方也没有解释的太清楚 后面还得多去实践的真知
env = Environment()
d = env.ParseFlags(["-I/opt/include", ["-L/opt/lib", "-lfoo"]])
for k,v in sorted(d.items()):
if v:
print k, v
env.MergeFlags(d)
env.Program('f1.c')
>>>>
% scons -Q
CPPPATH ['/opt/include']
LIBPATH ['/opt/lib']
LIBS ['foo']
cc -o f1.o -c -I/opt/include f1.c
cc -o f1 f1.o -L/opt/lib -lfoo

ParseConfig
这个东西没有看明白 这里先记录一下链接
Finding Installed Library Information: the ParseConfig Function
[ParseConfig](https://scons.org/doc/production/HTML/scons-user/ch08s03.html)

在构建程序的时候 帮助信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Help("""
Type: 'scons program' to build the production program,
'scons debug' to build the debug version.
""", append=True)

加上 append = True 在下面出现 `Use scons -H for help about command-line options.` 这样的字段

>>>>

scons -h
scons: Reading SConscript files ...
scons: done reading SConscript files.

Type: 'scons program' to build the production program,
'scons debug' to build the debug version.

Use scons -H for help about command-line options.

你可以缩短的 命令输出 如下这种操作
env = Environment(CCCOMSTR = "Compiling $TARGET",
LINKCOMSTR = "Linking $TARGET")
env.Program('foo.c')

>>>>
% scons -Q
Compiling foo.o
Linking foo

比如下面的例子 如果用户输入的 详细字段不为 True 则自定义 编译命令 其实是简短编译命令
env = Environment()
if ARGUMENTS.get('VERBOSE') != "1':
env['CCCOMSTR'] = "Compiling $TARGET"
env['LINKCOMSTR'] = "Linking $TARGET"
env.Program('foo.c')

Progress 控制流程输出
[Progress](https://scons.org/doc/production/HTML/scons-user/ch09s03.html)

GetBuildFailures
[打印详细的错误信息](https://scons.org/doc/production/HTML/scons-user/ch09s04.html)

从命令行控制构建流程

传送门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
>>>> 如果你想使用者调用一些除了scons提供的指令,你可以这样做

ARGUMENTS 这个东西将会帮到你.
但是有个缺陷是不能存储两个值,只能 key-value 的形式.
ARGUMENTS.get() 获取 debug 这个指令 没有用后面的默认值

env = Environment()
debug = ARGUMENTS.get('debug', 0)
if int(debug):
env.Append(CCFLAGS = '-g')
env.Program('prog.c')

ej:
scons -Q debug=0

>>>> 如果你想 一对多 你可以使用这个东西
ARGLIST

cppdefines = []
for key, value in ARGLIST:
if key == 'define':
cppdefines.append(value)
env = Environment(CPPDEFINES = cppdefines)
env.Object('prog.c')

ej: scons -Q define=FOO define=BAR

>>>> 从文件中读取用户构建配置
>>>> 会读取 custom.py 文件的配置表
vars = Variables('custom.py')
vars.Add('RELEASE', 'Set to 1 to build for release', 0)
env = Environment(variables = vars,
CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
env.Program(['foo.c', 'bar.c'])
Help(vars.GenerateHelpText(env))

>>>> custom.py
>>>> RELEASE=1

>>>> 可以结合 两种做法 读取用户 在命令行输入或则是配置文件
>>>> 其中 本地配置文件会首先 覆盖 命令行 的 配置
vars = Variables('custom.py',ARGUMENTS)

>>>> 定义构造变量的函数
>>>> Bool 可以指定的值有 true => t on all 1 true False => f 0 no false

vars = Variables('custom.py')
vars.Add(BoolVariable('RELEASE', 'Set to build for release', 0))
env = Environment(variables = vars,
CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
env.Program('foo.c')

ej:
scons -Q RELEASE=yes foo.o

>>>> Enum 有个 allowed_values 的字段 定义枚举变量值
>>>> map 字段备用映射名 map={'navy':'blue'},
>>>> ignorecase=1 忽略 指定指令的大小写 如 COLOR=NaVy

vars = Variables('custom.py')
vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
allowed_values=('red', 'green', 'blue')))
env = Environment(variables = vars,
CPPDEFINES={'COLOR' : '"${COLOR}"'})
env.Program('foo.c')

ej: scons -Q COLOR=red

>>>> ListVariable 允许一个字段指定多个值
>>>> 允许使用 all 或则是 none

vars = Variables('custom.py')
vars.Add(ListVariable('COLORS', 'List of colors', 0,
['red', 'green', 'blue']))
env = Environment(variables = vars,
CPPDEFINES={'COLORS' : '"${COLORS}"'})
env.Program('foo.c')

ej: scons -Q COLORS=red,blue foo.o => cc -o foo.o -c -DCOLORS="red blue" foo.c
ej: scons -Q COLORS=all foo.o => cc -o foo.o -c -DCOLORS="red green blue" foo.c
ej: scons -Q COLORS=none foo.o => cc -o foo.o -c -DCOLORS="" foo.c

>>>> PathVariable 路径变量
>>>> 提供输入的路径是文件 PathVariable.PathIsFile
>>>> 是目录 PathVariable.PathIsDir
>>>> 目录不存在,并创建 PathVariable.PathIsDirCreate
>>>> 不关心上面的三点 PathVariable.PathAccept

ej:
vars = Variables('custom.py')
vars.Add(PathVariable('CONFIG',
'Path to configuration file',
'/etc/my_config',
PathVariable.PathIsFile))
env = Environment(variables = vars,
CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
env.Program('foo.c')

>>>> PackageVariable
>>>> 启用或禁止 路径名字 没有太懂
vars = Variables('custom.py')
vars.Add(PackageVariable('PACKAGE',
'Location package',
'/opt/location'))
env = Environment(variables = vars,
CPPDEFINES={'PACKAGE' : '"$PACKAGE"'})
env.Program('foo.c')

ej:
% scons -Q foo.o
cc -o foo.o -c -DPACKAGE="/opt/location" foo.c
% scons -Q PACKAGE=/usr/local/location foo.o
cc -o foo.o -c -DPACKAGE="/usr/local/location" foo.c
% scons -Q PACKAGE=yes foo.o
cc -o foo.o -c -DPACKAGE="True" foo.c
% scons -Q PACKAGE=no foo.o
cc -o foo.o -c -DPACKAGE="False" foo.c

>>>> AddVariables 一次性添加多个变量功能

vars = Variables()
vars.AddVariables(
('RELEASE', 'Set to 1 to build for release', 0),
('CONFIG', 'Configuration file', '/etc/my_config'),
BoolVariable('warnings', 'compilation with -Wall and similiar', 1),
EnumVariable('debug', 'debug output and symbols', 'no',
allowed_values=('yes', 'no', 'full'),
map={}, ignorecase=0), # case sensitive
ListVariable('shared',
'libraries to build as shared libraries',
'all',
names = list_of_libs),
PackageVariable('x11',
'use X11 installed here (yes = search some places)',
'yes'),
PathVariable('qtdir', 'where the root of Qt is installed', qtdir),
)

>>>> UnknownVariables 在用户使用了未定义的 指令时 你可以警告调用者 拼写错误 并退出程序

vars = Variables(None)
vars.Add('RELEASE', 'Set to 1 to build for release', 0)
env = Environment(variables = vars,
CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
unknown = vars.UnknownVariables()
if unknown:
print("Unknown variables: %s"%unknown.keys())
Exit(1)
env.Program('foo.c')

>>>> 你可以在用户使用某个命令的时候 提醒用户一些操作
if 'bar' in COMMAND_LINE_TARGETS:
print("Don't forget to copy `bar' to the archive!")
Default(Program('foo.c'))
Program('bar.c')

ej:
% scons -Q bar
Don't forget to copy `bar' to the archive!

>>>> Default() 用户没有指定构建是 可以使用 这个函数 默认 构建一个程序
env = Environment()
hello = env.Program('hello.c')
env.Program('goodbye.c')
Default(hello)

ej:
% scons -Q
cc -o hello.o -c hello.c
cc -o hello hello.o
% scons -Q
scons: `hello' is up to date.
% scons -Q goodbye
cc -o goodbye.o -c goodbye.c
cc -o goodbye goodbye.o
Default 跟过用法 [传送门](https://scons.org/doc/production/HTML/scons-user/ch10s03.html)

>>>> DEFAULT_TARGETS 主要是迎合上面 Default 函数, 看一下例子应该很容易理解
prog1 = Program('prog1.c')
Default(prog1)
print("DEFAULT_TARGETS is %s"%map(str, DEFAULT_TARGETS))

ej:
% scons
scons: Reading SConscript files ...
DEFAULT_TARGETS is ['prog1']
scons: done reading SConscript files.
scons: Building targets ...
cc -o prog1.o -c prog1.c
cc -o prog1 prog1.o
scons: done building targets.

>>>> BUILD_TARGETS
prog1 = Program('prog1.c')
Program('prog2.c')
Default(prog1)
print ("BUILD_TARGETS is %s"%map(str, BUILD_TARGETS))

ej:
% scons -Q
BUILD_TARGETS is ['prog1']
cc -o prog1.o -c prog1.c
cc -o prog1 prog1.o
% scons -Q prog2
BUILD_TARGETS is ['prog2']
cc -o prog2.o -c prog2.c
cc -o prog2 prog2.o
% scons -Q -c .
BUILD_TARGETS is ['.']
Removed prog1.o
Removed prog1
Removed prog2.o
Removed prog2

>>>> 产生帮助文档(help)
vars = Variables(None, ARGUMENTS)
vars.Add('RELEASE', 'Set to 1 to build for release', 0)
env = Environment(variables = vars)
Help(vars.GenerateHelpText(env))

InstallBuilder 安装构建的可执行程序

安装暂时没有 显示功能上需求就不做详细叙述了
传送门

与平台无关的文件操作

scons 封装了 与平台无关的文件操作
如: 拷贝(copy),移动(move),移除(delete),创建(touch),创建目录(mkdir),执行(execute)
传送门WWW

控制构建目标的移除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>>> 有的时候你想要在每次构建一个东西的时候,不清除上一次的构建,而是以增量的方式构建
>>>> Precious
env = Environment(RANLIBCOM='')
lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c'])
env.Precious(lib)

>>>> 有的时候你可能使用 scons -c 但是这个命令会将所有的构建产物都移除掉,你可以使用这个命令,保证有些东西不被 -c 指令 给移除掉
>>>> NoClean
env = Environment(RANLIBCOM='')
lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c'])
env.NoClean(lib)

>>>> Clean 有的时候你可能 清楚自己在产生过程中生成的 自定义文件 你可以这样做
t = Command('foo.out', 'foo.in', 'build -o $TARGET $SOURCE')
Clean(t, 'foo.log')

ej:
% scons -Q
build -o foo.out foo.in
% scons -Q -c
Removed foo.out
Removed foo.log

分级构建

分级构建,就是你的源文件可能不是一个目录,需要多一个目录构建.
传送门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
>>>> SConscript 根目录调用每个子目录的 构建脚本, 通常子目录的构建脚本叫 SConscript 这是官方的解释
SConscript(['drivers/display/SConscript',
'drivers/mouse/SConscript',
'parser/SConscript',
'utilities/SConscript'])

>>>> 通常里面的路径都是相对于当前这个构建脚本 如果你先让子构建脚本 使用顶级目录你可以这样做 加上 '#' 这个符号
env = Environment()
env.Program('prog', ['main.c', '#lib/foo1.c', 'foo2.c'])

>>>> 当然你也可以直接使用绝对路径 不需要加任何符号
>>>>
>>>> 你可以在多个构建脚本共享变量 你可以使用 Export Import 这两个方法

ej:
env = Environment()
Export(env)

or:
env = Environment()
debug = 10
Export(env, debug)

or:
Export('env debug')

or:
SConscript('src/SConscript', 'env')

or:
SConscript('src/SConscript', exports='env')

ej:
Import(env)

Import(env, debug)

Import('env debug')

Import('*')

>>>> 有事你需要 从两个此目录返回结果 构建出一个对象
env = Environment()
Export('env')
objs = []
for subdir in ['foo', 'bar']:
o = SConscript('%s/SConscript' % subdir)
objs.append(o)
env.Library('prog', objs)

other Sconstruct(其他构建脚本):
Import('env')
obj = env.Object('foo.c')
Return('obj')

>>>>

分离构建 目标 和 源文件

分离构建结果
传送门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
方式1:
主要是利用这个字段 variant_dir
SConscript('src/SConscript', variant_dir='build')

禁掉在输出目录拷贝源文件
SConscript('src / SConscript',variant_dir ='build',duplicate = 0
方式2:
VariantDir('build', 'src', duplicate=0)
env = Environment()
env.Program('build/hello.c')

子脚本
VariantDir('build', 'src')
SConscript('build/SConscript')

变体构建

传送门
同一个目录构建不同的目标产物(可执行程序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
platform = ARGUMENTS.get('OS', Platform())

include = "#export/$PLATFORM/include"
lib = "#export/$PLATFORM/lib"
bin = "#export/$PLATFORM/bin"

env = Environment(PLATFORM = platform,
BINDIR = bin,
INCDIR = include,
LIBDIR = lib,
CPPPATH = [include],
LIBPATH = [lib],
LIBS = 'world')

Export('env')

env.SConscript('src/SConscript', variant_dir='build/$PLATFORM')

国际化

传送门

编写自己的 builder(构造器)

传送门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
>>>> 创建构造器
env = Environment()
bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
env.Append(BUILDERS = {'Foo' : bld})
env.Foo('file.foo', 'file.input')
env.Program('hello.c')

or:
env = Environment()
bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
env['BUILDERS']['Foo'] = bld
env.Foo('file.foo', 'file.input')
env.Program('hello.c')

>>>> 指定构建的文件后缀 和 输出文件的后缀
bld = Builder(action = 'foobuild < $SOURCE > $TARGET',
suffix = '.foo',
src_suffix = '.input')
env = Environment(BUILDERS = {'Foo' : bld})
env.Foo('file1')
env.Foo('file2')

>>>> 构建是调用 python 命令
target:
A list of Node objects representing the target or targets to be built by this builder function. The file names of these target(s) may be extracted using the Python str function.
(是一个目标节点列表,可通过 str 的方法 解析里面的内容)
source:
A list of Node objects representing the sources to be used by this builder function to build the targets. The file names of these source(s) may be extracted using the Python str function.
(是一个源节点列表,可通过 str 的方法 解析里面的内容)
env:
The construction environment used for building the target(s). The builder function may use any of the environment's construction variables in any way to affect how it builds the targets.
(这个构造变量被用在 目标节点上, 这个构造器可能使用任意的构造环境中的构造变量以任意的方式去影响如何构建目标节点)
(这个解释可能有点绕,其实还是挺容易懂得,不是吗?)

>>>> 自定义构建函数 上面是三个参数的解释, 很详细.
def build_function(target, source, env):
# Code to build "target" from "source"
return None
bld = Builder(action = build_function,
suffix = '.foo',
src_suffix = '.input')
env = Environment(BUILDERS = {'Foo' : bld})
env.Foo('file')

>>>> Generator 产生一条记录信息
def generate_actions(source, target, env, for_signature):
return 'foobuild < %s > %s' % (source[0], target[0])
bld = Builder(generator = generate_actions,
suffix = '.foo',
src_suffix = '.input')
env = Environment(BUILDERS = {'Foo' : bld})
env.Foo('file')

>>>> Builders That Modify the Target or Source Lists Using an Emitter
(修改目标节点或者是 源节点 通过发射器)
bld = Builder(action = 'my_command $SOURCES > $TARGET',
suffix = '.foo',
src_suffix = '.input',
emitter = '$MY_EMITTER')
def modify1(target, source, env):
return target, source + ['modify1.in']
def modify2(target, source, env):
return target, source + ['modify2.in']
env1 = Environment(BUILDERS = {'Foo' : bld},
MY_EMITTER = modify1)
env2 = Environment(BUILDERS = {'Foo' : bld},
MY_EMITTER = modify2)
env1.Foo('file1')
env2.Foo('file2')

>>>> 放置自定义工具或者是 构造器
>>>> scons 会自动加载 site_scons/site_init.py 比任意一个 构建脚本都早
>>>> site_scons/site_tools 在顶级的构建脚本是最后执行的 它覆盖其他的构建脚本定义
>>>>
site_scons/site_init.py

def TOOL_ADD_HEADER(env):
"""A Tool to add a header from $HEADER to the source file"""
add_header = Builder(action=['echo "$HEADER" > $TARGET',
'cat $SOURCE >> $TARGET'])
env.Append(BUILDERS = {'AddHeader' : add_header})
env['HEADER'] = '' # set default value

SConstruct
# Use TOOL_ADD_HEADER from site_scons/site_init.py
env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====")
env.AddHeader('tgt', 'src')

site_scons/my_utils.py

from SCons.Script import * # for Execute and Mkdir
def build_id():
"""Return a build ID (stub version)"""
return "100"
def MakeWorkDir(workdir):
"""Create the specified dir immediately"""
Execute(Mkdir(workdir))

import my_utils
print("build_id=" + my_utils.build_id())
my_utils.MakeWorkDir('/tmp/work')

缓存构建的文件

缓存构建文件其实就是将构建出来的中间产物给放到一个缓存目录里面,如果目录文件不存,就直接构建中间产物,在其下次构建是,就不必再次构建它,提高构建效率.
传送门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
>>>> 主要使用 CacheDir('./cache')
>>>> scons -Q --cache-show 保持每次构建的显示命令都是一样, 不使用这个字段会出现如果在在缓存里面存在,就和没有时的输出不一样,问题.
ej:
% scons -Q
cc -o hello.o -c hello.c
cc -o hello hello.o
% scons -Q -c
Removed hello.o
Removed hello
% scons -Q --cache-show
cc -o hello.o -c hello.c
cc -o hello hello.o

>>>> NoCache() 指定某些中间产物,不放入缓存
ej:
env = Environment()
obj = env.Object('hello.c')
env.Program('hello.c')
CacheDir('cache')
NoCache('hello.o')

>>>> scons -Q --cache-disable 通过命令行禁掉 缓存
>>>> scons -Q --cache-force 强制更新缓存
>>>> scons -Q --random 随机缓存 或者是使用构建脚本设置 SetOption('random', 1)
-- random 主要是面对多个程序通同时构建的情况. 让他的构建库的顺序尽量不一致,最小化减少缓存.

验证 python scons 版本

EnsurePythonVersion(2, 5) 验证 python 版本 如果低于构建结束
EnsureSConsVersion(1, 0) 验证 scons 版本

别名目标

别名也没啥说的
传送门

1
2
3
4
env = Environment()
hello = env.Program('hello.c')
env.Install('/usr/bin', hello)
env.Alias('install', '/usr/bin')

多平台配置(Autoconf功能

主要是检查某些依赖的文件是否存在等等.
传送门

从代码存储库构建

传送门

编写扫描仪

传送门

Not Writing a Builder: the Command Builder

主要是自定义写构造器的简化版本
传送门

Pseudo-Builders: the AddMethod function(伪造构建起, 添加方法)

这个东西个自定义工具差不多
传送门

最后更新: 2019年08月14日 11:22

原始链接: https://leng521.top/posts/66615451/