在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
http://scons.org/ https://www.ibm.com/developerworks/cn/linux/l-cn-scons/index.html
后附:另外,WAF是一个基于scons的构建工具,而且是 Re-design of scons to improve its worst features。
在软件项目开发过程中,make 工具通常被用来建造程序。make 工具通过一个被称为 Makefile 的配置文件可以自动的检测文件之间的依赖关系,这对于建造复杂的项目非常有帮助,然而,编写 Makefile 本身却不是一件容易的事情。SCons 是一个用 Python 语言编写的类似于 make 工具的程序。与 make 工具相比较,SCons 的配置文件更加简单清晰明了,除此之外,它还有许多的优点。本文将简单介绍如何在软件开发项目中使用 SCons,通过本文,读者可以学习到如何使用 SCons 来建造自己的程序项目。 前言make 这个工具自上个世纪 70 年代 Stuart Feldman 在贝尔实验室开发出以来,就一直是类 UNIX 程序员的最爱之一。通过检查文件的修改时间,make 工具可以知道编译目标文件所要依赖的其他文件。在复杂的项目中,如果只有少数几个文件修改过,make 工具知道仅仅需要对哪些文件重新编译就可以确保目标程序被正确的编译链接。这样做的好处就是在编译中,不仅可以节省大量的重复输入,还可以确保程序可以被正确的链接,缩短编译的时间。虽然如此,但是为 make 工具编写建造规则却不是一件容易的事。它复杂的配置规则,即使是有经验的开发者也望而生畏。make 工具的许多替代品便因此而诞生,SCons 就是是其中之一。SCons 是一个用 Python 语言编写的类似于 make 工具的程序。与 make 工具相比较,SCons 的配置文件更加简单清晰明了,除此之外,它还有许多的优点。 SCons 简介SCons 是一个开放源代码、以 Python 语言编写的下一代的程序建造工具。它最初的名字是 ScCons, 基于由 perl 语言编写的 Cons 软件开发而成,它在 2000 年 8 月获得了由 Software Carpentry 举办的 SC 建造比赛的大奖。现在 ScCons 已经被改名为 SCons,目的是为了表示不再与 Software Carpentry 有联系,当然,还有一个目的,就是为了更方便的输入。 作为下一代的软件建造工具,SCons 的设计目标就是让开发人员更容易、更可靠和更快速的建造软件。与传统的 make 工具比较,SCons 具有以下优点:
安装 SConsSCons 支持多种操作系统平台,并为各个系统制作了易于安装的文件,因此在各个系统平台上的安装方法不尽相同,在 SCons 的官方网站上可以查每个平台的具体安装方法。 如果 SCons 没有为你的系统制作相应的安装包,你也可以下载 SCons 的源代码,直接进行安装。 首先,从 SCons 的网站上下载最新的 SCons 源代码包(目前 SCons 的最新版本是 2.0.1)。 其次,解压下载的源代码。视下载的源代码包的格式不同而有不同的方法,在 Windows 平台上,可是使用 winzip 或者其他类似的工具解压。在 Linux 平台上,对于 tar 包,使用 tar 命令进行解压,如: $ tar -zxf scons-2.0.1.tar.gz 然后切换进入解压后的目录进行安装,如 $ cd scons-2.0.1 $ sudo python setup.py install 命令执行如果没有错误,那么 scons 就被安装到系统上了。对于 Linux 来说,scons 会默认安装到 /usr/loca/bin 目录下,而在 Windows 平台上,则会被安装到 C:\Python25\Scripts 下。 使用 SCons在 SCons 安装完成后,我们就可以使用 SCons 来建造我们的程序或者项目了。像很多编程书籍那样,在这里我们也通过一个简单的 helloscons 例子来说明如何使用 SCons。例子 helloscons 包含两个文件 : $ ls helloscons helloscons.c SConstruct 其中 helloscons.c 是程序的源文件,SConstruct 是 scons 的配置文件,类似使用 make 工具时的 Makefile 文件,因此,为了编译你的项目,需要手工创建一个 SConstruct 文件(注意:文件名是大小写敏感的)。不过,在编译的时候不需要指定它。 要编译这个例子,切换到 helloscons 的目录下,运行 scons 命令,如下: $ cd helloscons/ $ scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... gcc -o helloscons.o -c helloscons.c gcc -o helloscons helloscons.o scons: done building targets. 来查看一下运行 scons 命令后得到的结果 : $ ls helloscons helloscons.c helloscons.o SConstruct 建造结束后,得到了二进制文件 helloscons 以及编译的过程中产生的一些以 .o 结尾的目标文件。试运行 helloscons 一下 , 会得到 : $ ./helloscons Hello, SCons! 现在让我们回过头来解析一下 helloscons 这个例子 . helloscons.c 是这个例子里的唯一一个源代码文件,它所做的事就是在控制台上输出一行简单的"Hello,SCons", 它的源代码如下: 清单 1. helloscons.c#include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { printf("Hello, SCons!\n"); return 0; } 作为项目建造规则的配置文件 SConstruct 的内容如下 : 清单 2. SConstruct 文件Program('helloscons.c') 你可能很惊讶 SConstruct 的内容只有一行,然而事实确实如此,它比传统的 Makefile 简单很多。SConstruct 以 Python 脚本的语法编写,你可以像编写 Python 脚本一样来编写它。其中的 Program 是编译的类型,说明你准备想要建造一个可执行的二进制程序,它由 helloscons.c 文件来生成。在这里,没有指定生成的可执行程序的名字。不过不用担心,SCons 会把源代码文件名字的后缀去掉,用来作为可执行文件的名字。在这里,我们甚至不需要像 Makefile 那样指定清理的动作,就可以执行清理任务。在 SCons 中,执行清理任务由参数 -c 指定,如下 : $ scons -c scons: Reading SConscript files ... scons: done reading SConscript files. scons: Cleaning targets ... Removed helloscons.o Removed helloscons scons: done cleaning targets. $ ls helloscons.c SConstruct 如果你不想直接编译可执行的二进制文件,那也没有关系。SCons 支持多种编译类型,你可以根据自己的需要,任意选用其中的一种。SCons 支持的编译类型有:
这个简单的 SConstruct 的配置文件从一个侧面说明了使用 SCons 来建造程序是多么的简单。 在实际的项目开发中,程序的建造规则远比 helloscons 这个例子复杂。不过,这些都不是问题,你可以像扩展你自己的 Python 脚本文件那样去扩展 SConstruct. 如果你不想使用 SConstruct 为你设置的默认可执行文件的名字,而是选择你自己喜欢的名字,如 myscons,可以把 SConstruct 的内容修改为 : Program('myscons, 'helloscons.c') 其中 myscons 就是你想要的可执行文件的名字,你可以把它换成任意你喜欢的名字, 不过有点注意的是,这个名字必须放在第一位。 然后在 helloscons 目录下运行 scons 命令,就会得到 myscons 这个可执行文件,如 下: $ scons -Q gcc -o helloscons.o -c helloscons.c gcc -o myscons helloscons.o 其中的 -Q 参数是减少编译时的由 scons 产生的冗余信息。 如果你的项目由多个源文件组成,而且你想指定一些编译的宏定义,以及显式的指定使用某些库,这些对于 SCons 来说,都是非常简单的事情。我们的另外一个例子 helloscons2 很好的说明这种情况。 helloscons2 由 3 个源文件组成 , 它们是 helloscon2.c, file1.c, file2.c,另外指定了编译的选项,同时还指定了使用哪些具体的库。让我们来看一下 helloscons2 的 SConstruct 文件 : Program('helloscons2', ['helloscons2.c', 'file1.c', 'file2.c'], LIBS = 'm', LIBPATH = ['/usr/lib', '/usr/local/lib'], CCFLAGS = '-DHELLOSCONS') 正如你想像的那样,这样一个配置文件并不复杂 . 该 SConstruct 文件指出,它将生成一个名叫 helloscons2 的可执行程序,该可执行程序由 helloscons2.c, file1.c 和 file2.c 组成。注意,多个源文件需要放在一个 Python 列表中。如果你的源程序代码文件很多,有十几个甚至上百个,那不要一个个的将他们都列出来,你可以使用 glob('*.c') 来代替源代码列表。如下 : Program('helloscons2', Glob('*.c') 配置文件中 LIBS,LIBAPTH 和 CCFLAGS 是 SCons 内置的关键字,它们的作用如下:
运行 scons 命令的时候,可以看到这些变量如何被使用的,让我们执行一下 scons 命令 : $ scons -Q gcc -o file1.o -c -DHELLOSCONS file1.c gcc -o file2.o -c -DHELLOSCONS file2.c gcc -o helloscons2.o -c -DHELLOSCONS helloscons2.c gcc -o helloscons2 helloscons2.o file1.o file2.o -L/usr/lib -L/usr/local/lib -lm scons 命令的输出显示了可执行程序 helloscons2 如何由多个源文件而生成,以及在 SConstruct 中定义的 LIBS,LIBPATH 和 CCFLAGS 如何被使用。 可见,即使对于复杂的项目,SCons 的编译配置文件也很简单。除此之外,SCons 也提供了很多功能以适应不同的需要,如果读者想更深入的了解如何使用 SCons,可以参考 SCons 的帮助手册。 总结本文简单介绍了 SCons 的特点,如何安装 SCons,以及通过例子来说明如何在项目中使用 SCons。 作为下一代的软件建造工具,SCons 使用 Python 语言作为配置文件,不但功能强大,而且简单易用,对于跨平台的项目,非常适合。 如果你厌烦了 make 工具的那种复杂的编写规则,尝试一下新鲜的 SCons 吧。
scons 交叉编译的例子: https://bitbucket.org/scons/scons/wiki/PlatformToolConfig#markdown-header-cross-compilation_1 https://stackoverflow.com/questions/23898584/how-can-i-use-a-cross-compiler-with-scons https://stackoverflow.com/questions/31232955/using-scons-to-compile-c-file-with-std-c11-flag
简单的例子: (1)如果想要生成两个编译器版本的代码,比如在PC机上的GCC编译和ARM Linux gcc交叉编译,并且在编译的时候可以选择,SConstruct内容如下,源代码测试文件还是前一个hello world程序: SConstruct: src = Glob('*.c') platform = ARGUMENTS.get('platform','pc') if platform == 'arm': EXE_PATH = '/opt/arm-2007q1/bin' PREFIX = 'arm-none-linux-gnueabi-' ARMCC = PREFIX + 'gcc' ARMAS = PREFIX + 'gcc' ARMAR = PREFIX + 'ar' ARMLINK = PREFIX + 'gcc' ARMSIZE = PREFIX + 'size' ARMOBJDUMP = PREFIX + 'objdump' ARMOBJCPY = PREFIX + 'objcpy' env = Environment (AS = ARMAS, CC = ARMCC, AR = ARMAR, LINK = ARMLINK) env.PrependENVPath ('PATH',EXE_PATH) elif platform == 'pc': env = Environment() else: pass env.Program(source = src, target = 'hello_world') 第二条语句指定了若platform缺省时为pc,故执行scons 与scons platform=pc效果一样。运行如下: $ ls main.c SConstruct $ scons platform=arm scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... arm-none-linux-gnueabi-gcc -o main.o -c main.c arm-none-linux-gnueabi-gcc -o hello_world main.o scons: done building targets. $ scons platform=pc scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... gcc -o main.o -c main.c gcc -o hello_world main.o scons: done building targets. $ scons -c scons: Reading SConscript files ... scons: done reading SConscript files. scons: Cleaning targets ... Removed main.o Removed hello_world scons: done cleaning targets. $ scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... gcc -o main.o -c main.c gcc -o hello_world main.o scons: done building targets. (2)同样,这个方法还可以用来编译器生成不同版本的代码(如release版本和debug版本),如下: > vim SConstruct src = Glob('*.c') debug = ARGUMENTS.get('debug',0) vars = Variables(None,ARGUMENTS) vars.Add('debug','Set to 1 to build for debug', 0) env = Environment(variables = vars) Help(vars.GenerateHelpText(env)) if int(debug) == 1: env.Append( CCFLAGS = '-g') env.Program(source = src, target = 'hello_world') > ls main.c SConstruct > scons debug=1 scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... gcc -o main.o -c -g main.c gcc -o hello_world main.o scons: done building targets. > scons debug=0 scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... gcc -o main.o -c main.c gcc -o hello_world main.o scons: done building targets. 这样,便可控制debug版本和release版本的生成,另外SConstruct 脚本中第3、4、5、6句用来产生帮助信息,可以加上-h参数以运行使用: > scons -h scons: Reading SConscript files ... scons: done reading SConscript files. debug: Set to 1 to build for debug default: 0 actual: 0 Use scons -H for help about command-line options. 这样便可提示用户使用命令。 (3)变量(如debug=1,platform=pc)还可以从文件中引入,详细在用户手册(10.2.3. Reading Build Variables From a File)一节,预编译定义也可由这种方法定义。
以下是我自己的几个 SConstruct 的实例: # -*- coding: utf-8 -*- # -*- coding: utf-8 -*- cpp_defines = ['LIBSSH_EXPORTS', '_LARGEFILE64_SOURCE'] include_path = ['./include'] include_path.append('.') cflags = [] # cflags.append(['-g', '-ggdb', '-g3', '-fprofile-arcs', '-ftest-coverage']) cflags.append(['-g', '-ggdb', '-g3']) cflags.append(['-std=gnu99', '-pedantic', '-pedantic-errors', '-Wall', '-Wextra', '-Wshadow', '-Wmissing-prototypes']) cflags.append(['-Wdeclaration-after-statement', '-Wunused', '-Wfloat-equal', '-Wpointer-arith', '-fvisibility=hidden']) cflags.append(['-Wwrite-strings', '-Wformat-security', '-Wmissing-format-attribute', '-fPIC', '-fstack-protector']) ld_path = [] ld_path.append('./libcrypto') libs = [] libs.append('crypto') libs.append('dl') ldflags = ['-rdynamic', '-fprofile-arcs', '-ftest-coverage', '--coverage'] ldflags.append('-g') ldflags.append('-ggdb') ldflags.append('-g3') ldflags.append(cflags) env=Environment(CPPPATH=include_path, LIBPATH=ld_path, LIBS=libs) env.Append(CPPDEFINES=cpp_defines) env.Append(CCFLAGS=cflags) env.Append(LINKFLAGS=ldflags) FILES = env.Glob('*.c') env.Program('ssh_server', FILES)
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论