概述
新建一个工程要做的操作大概是如下几步:
1 新建项目
2 新建c++文件
3 在c++文件内编写程序
4 添加源/头文件进工程
当我们已得到源码.cpp,这时我们再建立工程的步骤就更加简单了,只需要进行第1步和第4步即可。CMake的作用就是帮助你在拥有源码的情况下帮助你实现第1步和第4步的。
如果一个框架由多个互相调用的工程共同组成,一些用于生成库文件,一些用于实现逻辑功能。他们之间的调用关系复杂而严格,如果我想在这样复杂的框架下进行二次开发,显然只拥有它的源码是远远不够的,还需要清楚的明白这几十个项目之间的复杂关系,在没有原作者的帮助下进行这项工作几乎是不可能的。
即使是原作者给出了相关的结构文档,对新手来说建立工程的过程依旧是漫长而艰辛的,因此CMake的作用就凸显出来了。原作者只需要生成一份CMakeLists.txt文档,框架的使用者们只需要在下载源码的同时下载作者提供的CMakeLists.txt,就可以利用CMake,在”原作者的帮助下“进行工程的搭建。
1.function的定义与使用
function(<name>[arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endfunction(<name>)
定义一个函数名为<name>,参数名为arg1 arg2 arg3(…)。 函数体内的命令直到函数被调用的时候才会去执行。其中ARGC变量表示传递给函数的参数个数。 ARGV0, ARGV1, ARGV2代表传递给函数的实际参数。 ARGN代表超出最后一个预期参数的参数列表,例如,函数原型声明时,只接受一个参数,那么调用函数时传递给函数的参数列表中,从第二个参数(如果有的话)开始就会保存到ARGN。
function (argument_tester arg)
message(STATUS "ARGN: ${ARGN}")
message(STATUS "ARGC: ${ARGC}")
message(STATUS "ARGV: ${ARGV}")
message(STATUS "ARGV0: ${ARGV0}")
list(LENGTH ARGV argv_len)
message(STATUS "length of ARGV: ${argv_len}")
set(i 0)
while( i LESS ${argv_len})
list(GET ARGV ${i} argv_value)
message(STATUS "argv${i}: ${argv_value}")
math(EXPR i "${i} + 1")
endwhile()
endfunction ()
argument_tester(arg0 arg1 arg2 arg3)
2.字符串的匹配
string(REGEX REPLACE "(.+)\\libprotobuf.*" "\\1" LIB_PROTOBUF_PATH ${LIB_PROTOBUF})
(.+)\\libprotobuf.* 中的(.+)表示这里有一个或多个字符,且第二个参数\\1就代表(.+)这个正则表达式。
${LIB_PROTOBUF}表示一个输入变量,这个输入变量用来匹配(.+)正则表达式。
LIB_PROTOBUF_PATH 表示存放匹配的结果,即${LIB_PROTOBUF}字符串中匹配(.+)正则表达式的结果存放在LIB_PROTOBUF_PATH中。
假如${LIB_PROTOBUF}的值为:
/usr/local/protobuf/lib/libprotobuf.so,则(.+)的值就是
/usr/local/protobuf/lib,经过这么一操作,那么LIB_PROTOBUF_PATH存放的就是(.+)中的内容,也就是/usr/local/protobuf/lib
而 \\1代表前面正则表达式匹配的结果,${LIB_PROTOBUF}是传入的变量,也就是\\1匹配的是该变量,LIB_PROTOBUF_PATH存放这个匹配的结果,该参数是本函数的输出。
3.find_package
在windows下扮演的角色并不是很重要。而在Unix下就非常重要了,find_package可以根据cmake内置的.cmake的脚本去找相应的库的模块。当然内建了很多库的模块变量,调用了find_package之后,会有相应的变量“生成”有效。比如调用了:
find_package(Qt5Widgets)
find_package(Qt4 COMPONENTS QTCORE QTGUI QTOPENGL QTSVG)
返回后,就会有变量Qt5Widgets_FOUND,Qt5Widgets_INCLUDE_DIRS相应的变量生效。然后就可以在CMakeLists.txt里面使用上述的变量了。类似如下:
INCLUDE_DIRECTORIES(${QT_INCLUDES})
INCLUDE_DIRECTORIES(${Qt5Widgets_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${Qt5Svg_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${Qt5OpenGL_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${Qt5Concurrent_INCLUDE_DIRS})
if(Qt5Widgets_FOUND)
message(STATUS ${Qt5Widgets_INCLUDE_DIRS}) #qt5
else()
find_package(Qt4 REQUIRED) #qt4
include(${QT_USE_FILE})
endif()