最近在为团队搭建统一的软件构建环境,目的是用scons为十几个软件模块提供统一的编译框架和命令,支持生成release/debug不同版本的可执行文件,同时支持不同的调试级别。
1.整体结构和实施过程
a.约定好不同模块在统一的代码库中的相对位置
因为软件模块之间可能存在库依赖、头文件依赖等关系,固定的相对路径能够使得模块中包含其他模块头文件或者库的脚本语句固定下来;
b.为每个新增加模块写sconscript脚本,在里面利用scons、python语句实现软件构建、部署和清除;
c.如果子模块里,有scons支持的类似rpcgen工具自动生成生成的代码,在对应的sconscript里面定义好对应的环境变量,比如rpcgen对应的$RPCGEN, $RPCGENCLIENTFLAGS, $RPCGENFLAGS, $RPCGENHEADERFLAGS, $RPCGENSERVICEFLAGS, $RPCGENXDRFLAGS;
c.如果子模块里,有scons不支持的类似thrift工具自动生成生成的代码,在对应的sconscript里面可以通过python os.system()/os.popen()/commands.getoutputstatus()里调用“thrift”命令实现;
d.在代码库的最顶层,根据约定的参数定义,实现全局的CCFLAGS、CCPDEFINES、LIBS、CPPPATH、LIBPATH的定义;
e.在代码库的最顶层,实现SConstruct脚本,里面利用相对路径引用各个子模块的SConscript脚本;
2.利用子模块已有的软件构建框架和脚本
如果子模块已经有现成的SConstruct,针对不同情况,有两种处理方式:
a.如果子模块的sconsript脚本的时候既可以从子模块调用,也可以从代码库的最顶层调用,那么可以从最顶层直接引用子模块的sconscript。
b.如果子模块的sconsript脚本的时候只能从子模块调用,那么可以从最顶层通过python os.system()/os.popen()等函数通过'cd subdir && scons'来引用子模块的sconstruct。
3.保证一致的的编译选项和配置能够传递到每个子模块
为了保证子模块能继承最顶层模块的环境变量设置,最顶层模块定义的CCFLAGS/CPPPATH/CCPDEFINES/LIBPATH等环境设置必需export出来,而在子模块中需要Import()出来。
如果最顶层脚本只能通过python os.system()/os.popen()等函数用'cd subdir && scons'来引用子模块的sconstruct,那么还需要保证顶层的参数能够传递到子模块当中去,而且子模块对参数的处理和最顶层一致。
4.注意事项
在多个模块的编译过程当中,需要特别注意的就是厘清各个模块之间的依赖关系,搞清楚哪些模块必须在哪个模块之前先编译,然后在scons脚本当中保证这个依赖关系。通过有两种方式可以达到这个目的:
1.利用scons PreAction/Requires等函数限定编译先后顺序;
2.编译那些需要跳转到子目录然后调用子目录的sconstruct脚本的模块,务必保证这个模块所依赖的库都已经生成。在这里,需要特别引起注意但是:如果SConstruct脚本当中里面有除了scons之外的其他python语句,scons解释程序会优先执行完所有非scons的python语句,最后才执行scons语句来引用子模块的sconscript。
本文转自存储之厨51CTO博客,原文链接: http://blog.51cto.com/xiamachao/1867453,如需转载请自行联系原作者