SCons 第三章 简化构建过程

第三章 简化构建过程

​ 在本章节中,通过几个简单的SCons工程构建示例,向您展示无论是哪种编程语言,亦或哪种系统平台,软件构建都将会是一件非常简单的事情。

3.1 指定编译输出文件

​ 当调用Program构建方法时,它会构建和源代码文件(多份则采取第一个文件)相同名称的输出文件,因此如果源代码是hello.c,则构建出来的可执行文件则为hello(POSIX平台),或者hello.exe(WINDOWS平台)。

Program('hello.c')

​ 如果您想编译出不同名称的可执行文件,则需要在源文件的前面,指明输出名称即可(如new_hello):

Program('new_hello', 'hello.c')

​ (Scons需要先指明目标文件名称,后面才是源文件,这样做的目的是和大多数的编程语言保持一致,python也是如此:“program = source files”)

​ 现在执行scons指令则会得到new_hello的编译输出:(POSIX平台)

> scons -Q
cc -o hello.o -c hello.c
cc -o new_hello hello.o

​ 得到new_hello.exe的编译输出:(WINDOWS平台)

C:\> scons -Q
cl /Fohello.obj /c hello.c /nologo
link /nologo /OUT:new_hello.exe hello.obj
embedManifestExeCheck(target, source, env)

3.2 编译多个源文件

​ 现在知道了如何编译单个源文件,但是大多数情况下,需要构建的工程,是由多个源文件构成,而非单一文件,因此多源文件编译时,需要将文件名放入一个python列表(list)中:

Program(['prog.c', ['file1.c', 'fil2.c'])

​ 编译输出为:(POSIX平台)

> 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 prog prog.o file1.o file2.o

​ (WINDOWS平台)

C:\>scons -Q
cl /Fofile1.obj /c file1.c /nologo
cl /Fofile2.obj /c file2.c /nologo
cl /Foprog.obj /c prog.c /nologo
link /nologo /OUT:program.exe prog.obj file1.obj file2.obj
embedManifestExeCheck(target, source, env)

3.3 采用Glob创建列表

​ 您也可以采用Glob函数匹配所有符合条件的源文件,匹配原则采用标准脚本通配符“*”,“?”。[abc]将匹配a,b,c;[!abc]将匹配除abc意外的任意字符。这使得多个源文件的构建变得简单了很多。

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

​ SCons的帮助手册有更多关于Glob函数的具体用法细节,可以参考。

3.4 单一文件构建 VS 文件列表构建

​ 构建工程目前有两种形式,一种是采用文件列表,一种是采用单一文件直接构建的方式:

# 文件列表
Program('hello', ['file1.c', 'file2.c'])

# 单一文件
Program('hello', 'hello.c')

​ 当然您也可以在文件列表中,只存储一份文件:

Program('hello', ['hello.c'])

​ 其实SCons内部都是将源文件以列表的形式存储,只是为了方便起见,允许用户直接输入单一文件。

重要提示

​ 尽管SCons支持多种输入方式,但是python语言更为严格,因此在进行list和string格式的文件相加则会产生python语法错误:

common_sources = ['file1.c', 'file2.c']
# 下述代码将会报错, string和list相加
Program('program1', common_sources + 'program1.c')
# 下述代码正确, list与list相加
Program('program2', common_sources + ['program2.c'])

3.5 让列表文件易于读写

​ 对于文件列表而言,其缺点是每一个文件名称都需要用引号包起来,无论是单引号还是双引号,当列表比较长时,看起来都比较麻烦。SCons提供了很多工具函数使得这一工作变得很简单。

​ SCons提供了Split函数用于分割字符串文件中的一个或多个空格,亦或一个或多个tab,分割后以文件列表的形式存储:

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

​ (如果您熟悉python的话,您会发现这和python标准字符串string模板的split()函数很相似,但是和split()不同的是,Split()不需要输入一定为string,其他输入也可以(如列表),它会自动将其进行分割成列表,确保输出格式的正确性。)

​ 直接将Split()函数嵌入到Program中,显得比较粗鲁,可以进一步采用临时变量增加代码的可读性:

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

​ 最后,Split函数不关系输入中有多少个空格,因此您可以跨行编辑列表,进一步提高可读性:

src_file = Split("""" main.c
                      file1.c 
                      file2.c""")
Program('program', src_files)

​ 请注意,在此示例中,我们使用了Python的“三重引用”语法,该语法允许一个字符串包含多行。三个引号可以是单引号或双引号。

3.6 关键字参数

​ SCons同样支持输入或输出文件的关键字定义。输出文件的关键字是target,输入源文件的关键字是source:

src_files = Split('main.c file1.c file2.c')
Program(target='program', source=src_files)

​ 因为关键字已经指明了该参数的含义,因此关键字的顺序不做要求:

src_files = Split('main.c file1.c file2.c')
Program(source=src_files, target='program')

​ 是否选择使用关键字,以及采用关键字时的顺序指定,这些都是是个人喜好,SCons不做特殊要求。

3.7 编译多个工程

​ 如果您想采用同一个SConstruct文件,构建多个工程,最简单的方式是调用Program多次构建:

Program('foo.c')
Program('bar', ['bar1.c', 'bar2.c'])

​ SCons则会输出如下:

> scons -Q
cc -o bar1.o -c bar1.c
cc -o bar2.o -c bar2.c
cc -o bar bar1.o bar2.o
cc -o foo.o -c foo.c
cc -o foo foo.o

​ 请注意,SCons不一定按照您在SConstruct文件中指定程序的顺序来构建。 但是,SCons确实认识到必须先构建各个目标中间文件,然后才能构建最终输出程序。

3.8 多工程编译共享中间文件

​ 代码复用是常见的编程方式,创建库文件(动态或静态库)是广为人知的一种方式。具体库文件的创建参见后续章节。

​ 同一份源码文件对应多个工程,最直接的方式是每个工程都加入该源码:

Program(Split('foo.c common1.c common2.c'))
Program('bar', Split('bar1.c bar2.c common1.c common2.c'))

​ 当采用这种方式构建时,SCons会意识到common1.c和common2.c的复用,因此会将其仅仅编译一份中间文件,尽管生成的目标文件分别链接到各自的中间文件:

% scons -Q
cc -o bar1.o -c bar1.c
cc -o bar2.o -c bar2.c
cc -o common1.o -c common1.c
cc -o common2.o -c common2.c
cc -o bar bar1.o bar2.o common1.o common2.o
cc -o foo.o -c foo.c
cc -o foo foo.o common1.o common2.o

​ 如果两个或多个程序共享许多公共源文件,则可以将公共源文件创建为一个列表,以便维护和更改。同时采用python的+运算符进行其他列表的扩充:

common = ['common1.c', 'common2.c']
foo_files = ['foo.c'] + common
bar_files = ['bar1.c', 'bar2.c'] + common
Program('foo', foo_files)
Program('bar', bar_files)

​ 这和前面的写法是完全等价的。

3.9 构建方法参数的覆盖

​ 您也可以通过在构建方法(如Program等)中增加对应参数,或关键字参数,来指定相关的参数,最终参数会以此为准。

env.Program('hello', 'hello.c', LIBS=['gl', 'glut'])

​ 或者生成一个非标准后缀的动态库:

env.SharedLibrary('word', 'word.cpp',
SHLIBSUFFIX='.ocx',
LIBSUFFIXES=['.ocx'])

​ 您也可以采用parse_flags关键字将命令行样式参数合并到适当的构造变量中。本例将’include‘增加到CPPPATH变量中, 将‘EBUG’加入到CPPDEFINES变量中,以及将'm'加入到LIBS变量中:

enc = Program('hello', 'hello.c', parse_flags='-Iinclude -DEBUG -lm')

​ 在对构建方法的调用中,不会克隆编译环境,而是通过调用OverrideEnvironment(), 它会创建一个整个Environment()更轻便编译环境。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,735评论 0 10
  • http://python.jobbole.com/85231/ 关于专业技能写完项目接着写写一名3年工作经验的J...
    燕京博士阅读 7,562评论 1 118
  • Python语言特性 1 Python的函数参数传递 看两个如下例子,分析运行结果: 代码一: a = 1 def...
    时光清浅03阅读 482评论 0 0
  • Python语言特性 1 Python的函数参数传递 看两个如下例子,分析运行结果: 代码一: a = 1 def...
    伊森H阅读 3,057评论 0 15
  • 一生中,总有那么几年,要练习一个人生活。有时候需要左支右绌、三头六臂,以及十八般武艺。有时候,很累。有时候,很孤独...
    Kainna阅读 246评论 -1 1