scons构建系统
<p><a href="https://github.com/SCons/scons/wiki">https://github.com/SCons/scons/wiki</a>
<a href="https://scons.org/doc/production/HTML/scons-user.html">https://scons.org/doc/production/HTML/scons-user.html</a></p>
<h3>简介</h3>
<p>SCons 是一种开源软件构建工具。将 SCons 视为改进的跨平台替代经典 Make 实用程序,其集成了类似于autoconf/automake和编译器缓存(如 ccache)功能。简而言之,SCons 使构建软件更简单、更可靠、更快速。</p>
<h3>优势</h3>
<ul>
<li>配置文件是 Python 脚本--使用实际编程语言的力量来解决编译问题。</li>
<li>适用于 C、C++ 和 Fortran 的可靠自动依赖项分析,无需再"make depend"或"make clean"来获取所有依赖项。用户可以使用自定义依赖项扫描程序(适用于其他语言或文件类型)轻松扩展依赖项分析。</li>
<li>内置支持 C、C++、D、Java、Fortran、Yacc、Lex、Qt 和 SWIG,以及构建 TeX 和 LaTeX 文档。通过用户定义的Builder可轻松扩展其他语言或文件类型。</li>
<li>从源代码和/或预构建目标的中央存储库进行构建。</li>
<li>内置支持从 SCCS、RCS、CVS、BitKeeper和 Perforce 提取源文件。</li>
<li>内置支持Microsoft Visual Studio .NET, .NET 和旧版Visual Studio 版本,包括生成 .dsp、.dsw、.sln 和 .vcproj 文件。</li>
<li>使用 MD5 签名可靠地检测生成更改;可选、可配置的传统时间戳支持。</li>
<li>改进了对并行生成(如 make -j)的支持,但无论目录层次结构如何,都能保持 N个作业同时运行。</li>
<li>集成的 Autoconf 支持查找#include文件、库、函数和typdefs。</li>
<li>所有依赖项的全局视图 - 不再通过多个生成或重新排序目标来生成所有内容。</li>
<li>能够在缓存中共享已构建的文件以加快多个生成(如 ccache,但适用于任何类型的目标文件,而不仅仅是 C/C++ 编译。</li>
<li>从一开始设计用于跨平台构建,已知适用于 Linux、其他 POSIX 系统(包括 AIX、BSD 系统、HP/UX、IRIX 和 Solaris)、Windows NT、Mac OS X 和OS/2。</li>
</ul>
<p>SCons 开始是作为 ScCons 构建工具设计,赢得了 2000 年 8 月软件Carpentry SC 构建比赛。这种设计反过来又基于Cons软件施工实用程序。这个项目已重命名为 SCons,以反映它不再与软件Carpentry SC直接连接。</p>
<h3>描述</h3>
<ul>
<li>SCons在读取<code>sconstruct</code>文件前先从系统目录中查找<code>site_scons</code>含有<code>sconstruct</code>文件的文件夹,将其加入到<code>sys.path</code>,先执行<code>site_scons/site_init.py</code>,并将<code>site_scons/site_tools</code>加入到默认工具路径。</li>
<li><code>scons</code>不会自动传播外部环境构建目标文件。这样对于不在标准系统目录下的工具无法被scons找到。我们可以创建一个构建环境,如下面从外部环境传播PATH到scons
<pre><code>import os
env = Environment(ENV = {'PATH' : os.environ['PATH']})
import os
env = Environment(ENV = {'PATH': os.environ['PATH'],
'HOME': os.environ['HOME']})
import os
env = Environment(ENV = os.environ)</code></pre></li>
<li>
<p><code>scons</code>自动扫描输入文件的依赖信息(如<code>C</code>或<code>C++</code>文件的<code>#include</code>).一旦任何依赖文件发生变化都会自动重建依赖文件。它支持定义新的扫描器来支持新的文件类型。</p>
</li>
<li>
<p><code>scons</code>命令行传入的变量可以<code>ARGUMENTS</code>获取到,同样也可以通过ARGLIST列表获取</p>
<pre><code>scons debug=1 .
# SConscript文件中
if ARGUMENTS.get('debug', 0):
env = Environment(CCFLAGS = '-g')
else:
env = Environment()</code></pre>
</li>
<li>构建变量可以使用<code>parse_flags</code>参数修改,如下将<code>include->CPPPATH,EBUG->CPPDEFINES,m->LIBS</code>。
<pre><code>env = Environment(parse_flags='-Iinclude -DEBUG -lm')</code></pre></li>
<li>
<p><code>platform</code>参数可以指定不同平台的环境</p>
<pre><code>env = Environment(platform = 'cygwin')
env = Environment(platform = 'os2')
env = Environment(platform = 'posix')
env = Environment(platform = 'win32')</code></pre>
<blockquote>
<p>win32平台从外部环境加入 SystemDrive和SystemRoot变量到ENV中。</p>
</blockquote>
</li>
<li>使用<code>tools</code>参数指定构建工具(<code>toolpath</code>优先于内建<code>tool</code>),如下是自定义工具<code>my_tool</code>,<code>my_tool</code>需要有<code>generate</code>和<code>exists</code>函数.<code>{'arg1': 'abc'}</code>作为<code>generate</code>函数的参数</li>
</ul>
<pre><code># in tools/my_tool.py:
def generate(env, **kw):
# Sets MY_TOOL to the value of keyword argument 'arg1' or 1.
env['MY_TOOL'] = kw.get('arg1', '1')
def exists(env):
return True
# in SConstruct:
env = Environment(tools=['default', ('my_tool', {'arg1': 'abc'})],
toolpath=['tools'])</code></pre>
<ul>
<li>源文件路径:绝对路径,相对路径,顶级路径(顶级sconstruct文件所在目录)。以<code>#</code>开头的路径是顶级路径。</li>
</ul>
<pre><code># The comments describing the targets that will be built
# assume these calls are in a SConscript file in the
# a subdirectory named "subdir".
# Builds the program "subdir/foo" from "subdir/foo.c":
env.Program('foo', 'foo.c')
# Builds the program "/tmp/bar" from "subdir/bar.c":
env.Program('/tmp/bar', 'bar.c')
# An initial '#' or '#/' are equivalent; the following
# calls build the programs "foo" and "bar" (in the
# top-level SConstruct directory) from "subdir/foo.c" and
# "subdir/bar.c", respectively:
env.Program('#foo', 'foo.c')
env.Program('#/bar', 'bar.c')
# Builds the program "other/foo" (relative to the top-level
# SConstruct directory) from "subdir/foo.c":
env.Program('#other/foo', 'foo.c')</code></pre>