标签归档:编译

向目标文件注入编译环境信息

【背景】
前段时间一个离职同事几年前的老模块需要交接,由于长时间无人维护,一时找不到代码路径,只得从整个后台中心的代码库里面“人肉“。记得曾经还出现过类似的情况,找不到老的编译环境(现有的系统,机器都升级了),被迫重构了老代码。工作时间越长,这样的问题也就会越来越频繁,老是这么死板的处理也不是个办法,费时费力,苦不堪言。如果可以将server部署前的编译环境信息集成到目标文件中,是否就可以根据线上运行的目标文件定位到相关的信息呢?目前部门的开发方式都是依赖于框架,所以只得在框架上下功夫。定好2个核心原则,撸起袖子就是干:对开发者透明,能便捷的获取信息。

【实现】
整个框架的编译体系是通过cmake维系的,通过其丰富的能力可以实现一些特殊的功效。框架使用gflags来维护命令行参数,本已经集成一些基本的参数,比如threads, conf,pid_file等,所以直接通过这种方式来获取编译环境信息对开发者更加熟悉和便捷。
1. cmake获取编译环境信息。

2. cmake将信息string以宏的方式透传给框架头文件。

3. 框架头文件使用宏来区分框架编译和业务编译。

4. 运行效果。

 

 

编译提速实践

【背景】
公司开发机性能太差,随便编译一个普通的项目都要十几秒。

【先验知识】
1. 我们知道ccache和distcc能够缓存部分结果,加速编译
2. 我们还知道make可以利用多核,加快编译

【实践】
1. distcc需要多台机器,部署稍微复杂,因此先将ccache和make用起来。
2. 我们需要无感知的使用这些提速项

==cmake==

==用以下替换掉make==

【效果】
使用后,正常的二次编译时间大致缩短一半。

cmake为什么好用

好东西绝总是有让你爱不释手的魔力,cmake就是其中一个。

1. cmake管理外部库
如果要使用很多库,而这些库又都没有安装到系统中,使用makefile的工作量真是难以想象,而CMake却能很轻松的处理这种场景。

  • 库的CMakeLists.txt中添加
    #导出目标
    export(PACKAGE config_parse)
    #指定要生成的导出文件
    export(TARGETS config_parse FILE config_parse-exports.cmake)
    #指定供find_package使用的配置文件
    configure_file(config_parse-config.cmake.in ${CMAKE_BINARY_DIR}/config_parse-config.cmake)
  • 库工程根目录添加config_parse-config.cmake.in文件
    include_directories(${CMAKE_SOURCE_DIR}/src) #指定库所需要的头文件目录
    include(“${CMAKE_BINARY_DIR}/config_parse-exports.cmake”) #指定库导出文件

接下来,编译该库之后,将在用户目录的.cmake目录下生成该库的信息文件。

  • 需要使用该库时,只需添加find_package(目标名),就可以按常规使用方法使用库了。
    find_package(config_parse REQUIRED)
    find_package会在用户目录的.cmake目录下找到对应的库编译路径,然后加载路径下的配置文件。

2. cmake来添加编译前/后的任务
cmake告诉我们编译管理系统有的不仅仅是编译。想格式化源代码,生成doxygen代码文档等操作都可以集成到编译管理系统中来。截一段

  • add_custom_command(TARGET config_parse
    POST_BUILD
    COMMENT “[ generate doc ]”
    COMMAND ${DOXYGEN_EXECUTABLE} 2>/dev/null
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
    #VERBATIM
    )
  • add_custom_command(TARGET config_parse
    PRE_BUILD
    COMMENT “[ astyle code ]”
    COMMAND astyle src/*.c src/*.h 1>/dev/null 2>/dev/null
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
    #VERBATIM
    )

3. 查找需要的库/命令
如果安装前缀是/usr的话,/usr/share/cmake/Modules下就是CMake提供的所有模块了,加载模块之后,就拥有了很多变量,不仅可以用来测试系统是否包含所查找的东西,同时提供很多。

  • 命令(Doxygen)
    CMakeLists.txt中添加include(FindDoxygen)之后就可以直接使用${DOXYGEN_EXECUTABLE}来代替Doxygen二进制文件了。
  • 库(Gtest)
    CMakeLists.txt中添加include(FindGTest)之后就可以直接使用${GTEST_LIBRARIES}和${GTEST_INCLUDE_DIRS},免去了查找库和头文件位置的麻烦。

4. cmake生成安装包
cpack应该是cmake中最强大的模块了,而且可以独立运行。用它来生成源码包和二进制包,也就是传说中的安装包。通过CPACK模块可以看出,它支持
DEB/RPM/NSIS/TGZ/ZIP/TBZ2/STGZ/ZIP等,需要注意的是cpack依赖于install指令,install中必须使用相对路径才能使cpack可用(CMAKE_INSTALL_PREFIX表示安装的根路径),同时tgz这类generator默认会忽略空目录。

SET(CPACK_GENERATOR RPM)
SET(CPACK_SOURCE_GENERATOR TGZ)
INCLUDE(CPack)

通过make package_source 可以生成源码包
通过make package 可以生成二进制包

5. cmake生成项目依赖图
添加cmake –graphviz来编译,就会生出graphviz识别的文件,然后调用dot命令,
例如dot graphviz文件 -Tpng则生成png文件

6. cmake外部编译
编译的中间文件总是使人烦乱,cmake推荐外部编译,这就是你为什么会通常会看到一个build文件夹的原因。官方目前仍未提供限制内部编译的指令,so只能委婉的禁用内部编译
IF(“${PROJECT_SOURCE_DIR}” STREQUAL “${PROJECT_BINARY_DIR}”)
MESSAGE(FATAL_ERROR “in-source builds are not allowed.”)
ENDIF(“${PROJECT_SOURCE_DIR}” STREQUAL “${PROJECT_BINARY_DIR}”)