All articles, tagged with “cmake”

CMake 中调用 Bison/Flex

CMake 默认不支持 Bison/Flex 工具链. 需要自行调用 add_custom_command, 比较麻烦.

在 C/C++ 社区, Bison/Flex 应该还算比较常用的工具. CMake 团队其实完全可以做成可引入的模块, 省却用户的麻烦.

有人碰到和我一样的困扰, 写了两个 CMake 扩展模块 : Support for Flex/Bison .

附件中的 “Find-Bison-Flex-2009-06-29.zip” 压缩包是我合并补丁之后的版本.

使用方法

  1. 确保 $PATH 路径中能找到 bisonflex 可执行文件. Linux/Unix/Cygwin 下应该问题不大. 如果在 Windows 下使用 MinGW 或其它编译器, 建议从 GnuWin32 项目 下载最新 bison/felx 压缩包, 解压后将路径添加到 $PATH 环境变量.

  2. 下载 “Find-Bison-Flex-2009-06-29.zip”, 解压缩到项目的根路径. 以下是一个典型的项目布局:

    myproject
        |
        |-- FindBISON.cmake        # Bison 扩展
        |
        |-- FindFLEX.cmake         # Flex 扩展
        |
        |-- src/
        |    |- CMakeLists.txt
        |    |- ...
        |
        |-- parser/
        |    |- inilex.ll          # 词法文件
        |    |- iniparse.yy        # 语法文件
        |    |- CMakeLists.txt
        |    |- ...
        |
        |-- tests/
        |    |- CMakeLists.txt
        |    |- ...
        |
        |-- CMakeLists.txt         # 根
        |
        |- ...
    
  3. parser/CMakeLists.txt 文件中按如下规则使用:

    # 引入模块
    include(${PROJECT_SOURCE_DIR}/FindBISON.cmake)
    include(${PROJECT_SOURCE_DIR}/FindFLEX.cmake)
    
    # 添加 Bison/Flex 目标, IniParse/IniLex 是目标名.
    # 最终生成的 cpp 文件输出到 ${PROJECT_BINARY_DIR}
    BISON_TARGET(IniParse iniparse.yy ${PROJECT_BINARY_DIR}/yacc_iniparse.cpp)
    FLEX_TARGET(IniLex inilex.ll ${PROJECT_BINARY_DIR}/lex_inilex.cpp)
    
    # Flex 依赖 Bison 的输出文件
    ADD_FLEX_BISON_DEPENDENCY(IniLex IniParse)
    
    # 添加 include 路径, 为了其它源文件能找到生成的 .hpp 文件
    include_directories(
        ./
        ${PROJECT_BINARY_DIR}
        ${CMAKE_CURRENT_BINARY_DIR}
        ${CMAKE_SOURCE_DIR}
    )
    
    # Bison/Flex 生成的文件分别存放在 BISON_[targetname]_OUTPUTS / FLEX_[targetname]_OUTPUTS 变量中.
    # 相应的, 本例中就是: BISON_IniParse_OUTPUTS 和 FLEX_IniLex_OUTPUTS
    add_library(testlib SHARED ${libfiles} ${BISON_IniParse_OUTPUTS} ${FLEX_IniLex_OUTPUTS} )
    
  4. 注意事项: 由于 Bison/Flex 本身, 以及这两个扩展模块的双重制约, 词法文件和语法文件 必须 要分别以 .ll / .yy 作为后缀.

2009-06-29, Monday 14:00 PM | 0 comments | 0 pingbacks | Tags: , ,

CMake 2.4.x 中 SOURCE_GROUP 宏的一个 Bug

CMakeSOURCE_GROUP 用来在 Visual Studio IDE 中对文件进行分组,当工程比较大,文件数目多时特别有意义。

这个宏在 2.4.x 下有个小 Bug,不能创建 VC 6.0 子分组,比如 SOURCE_GROUP (outer\inner …)VC 6.0 以上版本完全正常,VC 6.0 多数情况下会失效(有个小技巧可以规避)。

跟踪了一下 CMake 的源码,发现这个 Bug 是开发者的一个小疏忽。验证了一下 patch,便提交给 CMake 开发团队。2008-04-23 CMake 团队接受了 patch,2.6 版本会修正这个问题。

http://www.vtk.org/Bug/view.php?id=6720
2008-05-27, Tuesday 06:01 AM | 0 comments | 0 pingbacks | Tags: ,

CMake — 优秀的 C/C++ 构建系统

C/C++ 构建的特殊性

相比其它语言,C/C++ 的编译过程比较复杂,依赖具体的编译器、操作系统、硬件环境,所以一直以来缺乏一个简单易用、跨平台、支持多种编译器的通用构建工具。

由于工作需要,我前不久在找一个合适的通用构建工具。我的个人观点是,一个好的通用构建工具应该符合下面五个标准:

  1. 简单易用: 构建脚本的语法规则应该尽量简明,能够快速上手,有一个平滑的学习曲线。太高的学习和维护成本会抵消通用构建工具带来的好处;
  2. 自动维护依赖关系: 以前是手工+GCC -MF 开关维护,这种方法很慢、很土,而且项目一大,很容易出问题.
  3. 支持自动配置 (自动匹配出当前的操作系、编译器、程序库位置等环境);
  4. 稳定、高效;
  5. 可扩展: 有方法能够通过扩展,支持更多的编译器或系统 (如嵌入式).

对目前主流、仍然活跃的通用构建工具做了番仔细的对比和试用后, CMake 是最符合以上要求。

传统 C/C++ 构建工具

GNU make、NMake、Autotools 等传统构建工具,它们大都历史悠久、使用广泛、稳定可靠,但难用、不够智能。

它们在使用场合也有很大的局限性(比如 NMake 只支持 VCGNU make、Autotools 只能跑在 Linux/Cygwin 下),所以不在考虑之列。

SCons

出于对 Python 的偏好, 我用了一段时间的 SCons. SCons 是一个优秀的编译工具,不过距离构建还有一些差距:项目小的话还好,规模一大,依赖分析速度急速下降,而且自动配置功能很弱 (跨平台构建能力不足)。

Waf

WafCMake 的了解都来自同一条消息: KDE4 将采用 CMake 来替换 autotools(KDE4 也曾考虑过 SCons)。Waf 尝试解决 SCons 所暴露出的一些问题。和 SCons 一样,Waf 使用 Python 语言作为构建脚本。

不过对于构建这样简单而重要的工作而言,它显得太灵活了。一个任务可能有多种途径可以解决 — 用 Python 语句或 Waf 自定义规则。构建脚本用 Python 这么强大的语言,多少感觉有些杀鸡用牛刀 … 而且你要努力说服一些 Ruby funs 去学 Python。

Jam/Boost.Jam

跨平台工具,Boost 用 Jam 来维护整个库的编译和测试。

没有深入使用过,没有特别的杀手锏,最初的目标是取代 make 工具。没有自动配置功能,能适应简单的构建任务。我个人感觉它的语法同样很不直观。

CMake

看完 KDE 团队关于为何选择 CMake 的文章、评论后,我在一个项目中开始尝试使用 CMake。令人吃惊的是:和 KDE 组织所描述的一样,我只花了一天便掌握了 CMake 的基本用法。两天后我都快成了 CMake 半桶水专家!这比学习 GNU Make 工具的用法还快很多.

我之前想当然的认为 Waf 学习成本很低(我熟悉 Python 语法),但事实并非如此。Waf 新定义的一套规则仍然会占用你一段时间来适应 — 而且不比学习 CMake 的简单语法来的更短,里面夹杂着标准库会让不熟悉 Python 的成员很头痛。

CMake 的语法和规则足够简单,不需要花太多的时间,能很好的应付构建中碰到的各种问题。它不是最强大的,但它是最适合,也是最简单的。更复杂的功能可以用其它脚本语言(如 Python,Perl 等)配合完成。

这种方式明确了每个工具的职责 — CMake 只解决构建问题,而且重点是 C/C++ 的构建。相对于 Waf 这种能在构建脚本里面实现许多令人惊叹,只用 CMake 根本无法实现的超级工具而言,CMake 更直接、清晰,更擅长解决构建问题,并和其它工具协调工作。

有时候我们不需要一个超级工具,需要的只是一个最能解决当前问题的工具;过度的灵活常常导致过度的复杂 (设计和使用上)。

CMake 的不足

CMake 是用 C/C++ 写的。这当然是它的好处:处理速度很快,对于日常工作,效率是很重要的。不过要是我扩展 CMake 的内置功能,比如编写一个新的模块用于生成 Eclipse CDT(2.6 提供了)的工程,我想我会更乐意用 Python 或其它脚本语言来实现。

不过幸好 CMake 的宏机制能做一些比较简单的扩展,比如支持新的平台和编译器(PCLint、vxWorks GCC 等)。

如果能修补一些小问题, Bakefile 也是一个比较不错的工具。它的原理和 CMake 类似,只是它使用 XML 格式而不是 CMake 专用语法(不过个人感觉 CMake 的宏语法比机器友好的 XML 标记更清晰)。它是用 Python 写的,这也意味着它更容易扩展。不过它缺乏自动配置功能。

后记

开发和日构建需要的构建脚本不同:日构建的时候我们要的是 Makefile,但开发的时候我们需要工程文件。

和 SCons/Waf 等工具不同,CMake 可以用来生成 Makefile,还能生成 Visual Studio 等 IDE 的工程文件。

在项目上用 CMake 替换原来的 Makefile + 工程文件的方式后,整个构建和维护过程都比原先顺畅了许多。

配合使用 .bat 文件,我们用一份结构清晰的 CMake 构建脚本同时维护着 VC 6.0/2005 工程文件、NMake file 和 vxWorks GCC 交叉编译 Makefile,源文件的增删和编译参数的修改非常方便,节省了开发人员在软件构建上的时间成本。

2008-05-7, Wednesday 17:43 PM | 1 comment | 0 pingbacks | Tags: ,

关于 Yang Yubo

身处 IT 行业, 惯用 C/C++, 对 Python 情有独钟, 平时比较关注 QT / Django / Werkzeug 等. 了解更多 »