分类: LINUX
2012-09-06 16:24:46
Windows平台上的编译工程工具很多,Visual C++ 6的dsp文件,2003以后用的vcproj,以及最近2010支持的用msbuild编译的vcxproj,加上古老的nmake,cygwin、msys移植的make,等等很多。
make的问题是扩展性比较差,尤其是在Windows平台上,nmake的功能更弱,导致写一个工程文件很费劲,管理多个工程有大量的重复工作要做。make最大的问题是不能automake那种简洁的工程写法(automake同样存在扩展问题,m4语言不懂).
最新的msbuild 4.0试用了一下,感觉不是很好,很费劲。因为最近迷恋上了命令行,一直不愿意安装完整的Visual Studio 2010 Beta 2,直接把2010的命令行拷贝出来用cl.exe之类的。想只装.Net Framework 4.0就试试msbuild,发现不行,把2010里的msbuild相关资源拷贝出来也不行。而且用XML手写工程文件很麻烦。
猛然想起之前听说过,鼎鼎大名,但之前简单了解后放弃了的scons。再次使用之后,才发现scons的妙处。
简介Scons
Scons首页赫然是Eric Raymond的推荐,很是唬人的样子。Scons是python写的,这不重要。Scons脚本用语言是python,这是Scons最吸引人的地方。用python写工程文件无疑对我这种熟悉python的人有很大的吸引力。
实际上,Scons最大的优势,就是描述语言本身沿用python。这种设计极大的提升的Scons的扩展能力。Scons本身功能是否强大不重要,对于熟悉python的人来说,扩展Scons达到他的要求,变得比以前简单的多。下面是我用Scons写的一个zlib的工程文件,其中WinLib和WinDLL是我自己扩展的在Windows平台上编译静态库和动态库的方法(cl的宏定义和link的参数有所不同)。
实际上Scons本身的功能比较有限,为了写成这个简洁的模式,还费了不少劲。
Scons的特点简单列举下最近有体会的Scons的特点,权当备忘录了。
1. Variables的设计很好。
通过Variables可以扩展scons支持的命令行参数,限制参数种类(Bool,枚举,多选),可以把上次的参数保存到文件,下次编译不需要命令行输入过多的参数。下面摘下我的Variable定义:
2. Environment的设计也很好。
Environment可以保存全套的编译命令,参数配置,用Clone操作可以从一个基本编译环境作出很多变种,支持不同项目类型,不同配置的编译。Clone实在是太方便了。下面是前面提到的Windows平台下编译DLL和静态库、命令行程序的不同参数配置,用Clone操作可以在基本编译环境上,生成多个用于编译静态库、DLL等不同的编译环境,使用不同的参数编译。
题外话,关于Windows下编译不同工程的参数,这篇文章总结的很全。
3. Builder的设计问题。
Scons可以用env.Library(‘liba’, ‘a.c’)的方法用环境的定义编译静态库,或者用Program定义可执行程序。并且支持输入和环境定义不同的参数,如
env.Library(‘liba’, ‘a.c’, CPPDEFINES = ['NEWMACRO'], CCFLAGS=['/Ox'])。
不过,很可惜,Builder默认是覆盖环境中现有参数,而不是追加。所以,要用多个编译参数稍有不同的程序和库编译只能用Clone后Append。
或许我要求太高,不过这样写看起来实在太傻了。实际使用中,不同的程序用的编译参数就没有完全一样的,尤其是Include目录、宏定义、库路径、库这四个参数肯定有或多或少的不一样。不能追加的话,就只能Clone出很多个Env,甚至是一个Program或Library一个Env,这就失去了Env封装编译环境的通用意义了。
4. Sconscript与源码的位置问题
Scons设计时更多是支持将Sconscript放在源码同一目录下,甚至每个源码目录一个Soncscript。如果不习惯或者不能用这种方式,比如为别的项目写工程文件,遇到一些困扰。
Scons好在有类似make的VPATH功能,叫Repository,用着还行。
5. 源码和编译目录分开的问题
这个问题和上面类似,但更严重。Scons支持用VariantDir设定与源码目录不同的编译目录,但必须所有的文件都用编译目录的路径,如下
这就很傻了,明明源码在src_dir目录,一定要写成build_src。不这么写也行,那就写两个Sconcript文件,一个引用另外一个
要用好VariantDir,就必须写多个脚本。尤其是要支持编译同一程序的多个版本,还只能用两个脚本。SconscriptB可以按如下方式写,就能编译两个版本的prog,分别在debug和release目录下。用一个Sconscript完成同样功能实在是很费劲的。
6. 同一个源码编译多份的问题
这个问题和上面类似,但不同。例如编译静态库和动态库都用一批源码,但编译参数不一样,Scons就会报错。但这个问题用variant_dir解决不方便。如下例:
Scons报错如下:
经过我多方论证,发现这个问题目前看来最佳、最简单的解决方法是给OBJ文件设置前缀。
Program('hello1', 'hello.c', OBJPREFIX='dbg-', CCFLAGS=['-Od']) Program('hello2', 'hello.c', OBJPREFIX='opt-', CCFLAGS=['-Ox'])7. 简化编译输出的问题
Scons支持自定义的编译输出。但有些命令不能替换,例如msvc工具集中的链接过程的输出。
暂时这么多吧…想到再补充。