今天在解决一个问题中,需要把几套独立的开源代码放在一起构建,总的代码量虽然也不是很多,但是每套开源代码都有自己的构建系统,彼此之间很难做到兼容。苦恼中有同事就建议我说不妨用cmake试试,说不定能解决我的问题。但是本人对cmake的了解仅仅限于使用而已,内部原理一窍不通,可能是处于程序员的强迫症,对没有掌握足够信息的事情有种本能的忧虑,所以一开始没有采纳,硬着头皮搞自己的makefile构建,可能是makefile太多细节要处理了,眼看到下工时间了,编译现场还是一片飘红惨不忍睹。不得不改变策略回到同事的建议用cmake. 于是就边百度边照猫画虎的编辑CMakeLists.txt文件,果然没有花费多少功夫,就搞定了整个构建系统,可执行程序和运行库构建成功,开心。

为了以后爬坑顺利一点,觉得有有必要 对用到的cmake命令做一个记录,包括如何定义工程,指定源码路径,指定连接运行库路径,头文件路径指定等等。用一个例子开始:

cmake脚本的初次使用记录_嵌入式

下面依次介绍每个文件,首先是CMakeLists.txt

cmake脚本的初次使用记录_固件_02

1: CMakeLists.txt ▶                                                                                                                                                                               ◀◀ buffers
1 cmake_minimum_required(VERSION 2.8.3)
2 project(helloworld)
3
4 add_compile_options(-std=c++11)
5 FIND_PACKAGE(OpenMP REQUIRED)
6 if(OPENMP_FOUND)
7 message("OpenMP Found")
8 endif()
9
10 #find_package(OpenCV REQUIRED)
11 #if(OPENCV_FOUND)
12 # message("found opencv")
13 #endif()
14
15 OPTION(USE_MACRO "Build the project using macro" OFF)
16 IF(USE_MACRO)
17 add_definitions("-DUSE_MACRO")
18 endif(USE_MACRO)
19
20 LINK_DIRECTORIES("/home1/caozilong/WorkSpace/cmake-use/libs")
21 LINK_LIBRARIES("/home1/caozilong/WorkSpace/cmake-use/libs/libfoo.a")
22 include_directories(./)
23 include_directories(./include/)
24 add_executable(${PROJECT_NAME} src/main.cpp src/foobar.cpp src/bar.c)
25 target_link_libraries(${PROJECT_NAME} libfoo.a)
26 add_library(bar_add_static_lib STATIC src/bar.c)
27 add_library(bar_add_shared_lib SHARED src/bar.c)

foobar.h是空头文件,目的仅仅是测试cmake的头文件引用路径命令是否生效

cmake脚本的初次使用记录_执行流_03

libfoo.a 里面包含一个fxx函数的实现,会在主程序的执行流中被调用,打印输出fxx函数名等信息,目的是验证cmake连接库的命令是否有生效。

然后剩下的是bar.c main.cpp和foobar.cpp文件,bar.c是C源码文件,目的是验证cmake是否支持C和CPP混合构建(验证结果是支持的).

bar.c

cmake脚本的初次使用记录_执行流_04

foobar.cpp,目的是验证多个文件编译。

cmake脚本的初次使用记录_运行库_05

 main.cpp 主程序,提供调用流和执行流,会调用foobar.cpp,bar.c以及libfoo.a中的实现,判断cmake是否都有照顾到。

cmake脚本的初次使用记录_执行流_06

接下来测试,在工程顶层目录执行如下命令序列

$mkdir build && cd build
$cmake ../
$make

cmake脚本的初次使用记录_运行库_07

cmake脚本的初次使用记录_执行流_08

再次配置,这次使用如下命令打开USE_MACRO宏,判断main主函数分支打印变化情况。

cmake .. -DUSE_MACRO=on

cmake脚本的初次使用记录_执行流_09

可以看到,打开了USE_MACRO宏之后,打印变化了,说明通过cmake产生的宏定义生效了。

CMAKE构建带DEBUG调试信息的输出文件

默认情况下,cmake构建出来的固件是不带debug信息的,通过在CMakeList.txt中增加两行,可以增加带Debug信息的固件:

4 SET(CMAKE_BUILD_TYPE "Debug")
5 SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
6 SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

cmake脚本的初次使用记录_嵌入式_10

cmake脚本的初次使用记录_运行库_11

总结

1.cmake的命令更加高层和抽象,使使用者不必去关心Makefile的细节,一开始我就是被困在makefile的细节中出不来。cmake完全没有这个问题,因为所有的细节处理都被cmake后台处理好了。

2.软件越抽象,用户体验越好,但是也越不透明,如果构建系统除了bug,更难排查。我们学习物理知道能量守恒,其实难度也是守恒的,软件无论怎么分层,只不过是拆东补西的事情,工作量那么多,总量是不变的,还是拿cmake为例,它的简单易用是以背后复杂的自动构建逻辑为代价的。

3.要勇于尝试新鲜的东西,担心是诅咒,祝福是保佑,恐惧感来源于未知,当经过互相了解之后,排除了彼此的陌生感,恐惧感会自动消除,当然,如何克服第一次,要看自己了。


结束