CMake实用基础


一 CMake介绍

CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件。 CMake 的组态档取名为 CmakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。即将头文件、源文件以及库文件等组建成一个工程框架,并设置好需要的配置信息。

CMake 可以编译源代码、制作程式库、产生适配器(wrapper)、还可以用任意的顺序建构执行档。CMake 支持 in-place 建构(二进档和源代码在同一个目录树中)和 out-of-place 建构(二进档在别的目录里),因此可以很容易从同一个源代码目录树中建构出多个二进档。CMake 也支持静态与动态程式库的建构。


二 CMakeLists文件编写

1 基本结构

(1)依赖CMakeLists.txt文件,项目主目标一个,主目录中可指定包含的子目录;

(2)在项目CMakeLists.txt中使用project指定项目名称,add_subdirectory添加子目录;

(3)子目录CMakeLists.txt将从父目录CMakeLists.txt继承设置(TBD,待检验);

2 语法规则

(1)# 注释;

(2)变量:使用set命令显式定义及赋值,在非if语句中,使用${}引用,if中直接使用变量名引用;后续的set命令会清理变量原来的值;

(3)command (args ...)  #命令不分大小写,参数使用空格分隔,使用双引号引起参数中空格;

(4)set(var a;b;c) <=> set(var a b c)  #定义变量var并赋值为a;b;c这样一个string list;

(5)Add_executable(${var}) <=> Add_executable(a b c)   #变量使用${xxx}引用;

(6)条件语句:

if(var) #var empty 0 N No OFF FALSE... #非运算使用NOT

       …

else()/elseif() … endif(var)

(7)循环语句

Set(VAR a b c)

Foreach(f ${VAR})       …Endforeach(f)

(8)循环语句

WHILE() … ENDWHILE()

3 常用内部变量

CMAKE_BINARY_DIR,  PROJECT_BINARY_DIR,  _BINARY_DIR这三个变量内容一致,如果是内部编译,就指的是工程的顶级目录,如果是外部编译,指的就是工程编译发生的目录;

CMAKE_SOURCE_DIR,  PROJECT_SOURCE_DIR,  _SOURCE_DIR这三个变量内容一致,都指的是工程的顶级目录;

CMAKE_CURRENT_BINARY_DIR外部编译时,指的是target目录,内部编译时,指的是顶级目录;

CMAKE_CURRENT_SOURCE_DIRCMakeList.txt所在的目录;

CMAKE_CURRENT_LIST_DIRCMakeList.txt的完整路径;

CMAKE_CURRENT_LIST_LINE当前所在的行;

EXECUTABLE_OUTPUT_PATH:生成的可执行文件的存放路径;

LIBRARY_OUTPUT_PATH:生成的库文件的存放路径;

 

CMAKE_C_COMPILER:指定C编译器;

CMAKE_C_FLAGS:编译C文件时的选项,如-g;也可以通过add_definitions添加编译选项;

CMAKE_BUILD_TYPE:build 类型(Debug, Release, ...),默认Debug;

BUILD_SHARED_LIBS:如果不进行设置,使用ADD_LIBRARY且没有指定库类型,默认编译生成的库是静态库;

CMAKE_INCLUDE_PATH:配合 FIND_FILE() 以及 FIND_PATH() 使用。如果头文件没有存放在常规路径/usr/include, /usr/local/include等),则可以通过这些变量就行弥补。如果不使用 FIND_FILE 和 FIND_PATH的话,CMAKE_INCLUDE_PATH,没有任何作用;

CMAKE_LIBRARY_PATH:配合 FIND_LIBRARY() 使用。否则没有任何作用;

CMAKE_MODULE_PATH:cmake 为上百个软件包提供了查找器(finder):FindXXXX.cmake,当使用非cmake自带的finder时,需要指定finder的路径,这就是CMAKE_MODULE_PATH,通过SET(CMAKE_MODULE_PATH dir)设置,配合 FIND_PACKAGE()使用;

CMAKE_INSTALL_PREFIX:控制make install是文件会安装到什么地方。默认定义是/usr/local 或 %PROGRAMFILES%;

4 常用命令

CMAKE_MINMUM_REQUIRED(VERSION 2.8) :设定cmake最低版本要求

MESSAGE( status|fatal_error, “message”):两个参数,即消息类型和消息内容,输出信息,方便进行调试

>> message(STATUS "FoundHello: ${HELLO_LIBRARY}")    #输出找到的Hello所在目录

SET定义变量,并赋予其值

>>set(SRC_LIST main.c hello.h)    #将main.cpp和hello.h存入变量SRC_LIST

PROJECT指定项目名称,生成的VC项目的名称;

>>project(hello)   #使用hello作为项目名称

 

 ADD_EXECUTABLE编译可执行程序,指定编译,好像也可以添加.o文件;

>> add_executable (helloDemo demo.cxx demo_b.cxx)   #将cxx编译成 可执行文件

ADD_LIBRARY生成一个库文件;

>> add_library(Hello SHARED hello.cxx)  #将hello.cxx编译成静态库 如libHello.a,默认参数是SHARED,即编译成静态库;若要编译成动态库, 则改参数为STATIC

ADD_CUSTOM_TARGET自定义目标,生成一个自定义文件类型;

 

TARGET_LINK_LIBRARIES添加链接库

>> target_link_libraries(demo Hello) #将可执行文件demo与链接库 Hello链接;

INCLUDE_DIRECTORIES指定头文件的搜索路径,一般用于添加库函数的头文件所在目录;

>> include_directories (${HELLO_SOURCE_DIR}/Hello)  #增加Hello为 include目录

LINK_DIRECTORIES动态链接库或静态链接库的搜索路径,一般用于添加库函数的*.lib或*.dll文件所在目录;

>> link_directories (${HELLO_BINARY_DIR}/Hello)     #增加Hello为 link目录

ADD_SUBDIRECTORY包含子目录,一般用于上一级文件夹中的CMakeLists.txt中指定子目录,并进入执行内部的CMakeLists.txt,在目标文件中生成子文件夹;2个参数的话就是 源→目标 文件夹生成对应;

>> add_subdirectory (Hello)    #增加子文件夹src

>> add_subdirectory(src bin)   #在cmake目标文件夹中与源文件夹对应  src→bin文件夹

  

FILE(GLOB var *.h *.hpp *.cpp):搜索当前CMakeLists所在目录中匹配文件,并存在变量var中;注意GLOB这个参数,它不支持子目录。如果你想让它支持子目录,用GLOB_RECURSE。

>>file(GLOB_RECURSE SOURCE "${CMAKE_SOURCE_DIR}/main/*.cpp") #告诉CMake,源文件在哪里

AUX_SOURCE_DIRECTORY ( “sourcedir” variable):收集目录中的文件名并赋值给变量;

 

SET_TARGET_PROPERTIES( target1 target2 ...PROPERTIES prop1 value1 prop2 value2 ... ):设置目标文件的属性,比如OUTPUT_NAME, VERSION等;

>>set_target_properties(libhello PROPERTIES OUTPUT_NAME"hello")  # 将库libhello生成的库文件名称设置为hello,即hello.lib或hello.dll

ADD_DEFINITIONS添加编译预处理需要的宏定义参数;

>> add_definitions(-DDEBUG)    #将在gcc命令行添加DEBUG宏定义

>> add_definitions( “-Wall -ansi –pedantic –g”)

ADD_DEPENDENCIES:定义target依赖的其他target,确保在编译本target之前,其他的target已经被构建

>>add_dependencies(target-name depend-target1 depend-target2 ...)

INSTALL参数多杂不便解释,以一例如下示之,安装头文件和库文件到相应的目录

>>install(TARGETS libhello ARCHIVE DESTINATION lib)

>>install(TARGETS hello_static ARCHIVE DESTINATION lib)

>>install(FILES hello.h  DESTINATION include)

INCLUED: CMake会定义许多的模块来查找通常会用到的包,比如OpenGL或Java。 这些模块为你节省了很多的时间来编写这些查找包。这些模块可以像这样加到你的CMakeList文件中,如下:

>>INCLUDE(${CMAKE_ROOT}/Modules/FindTCL.cmake)   #CMAKE_ROOT 总是 定义在CMake中,用于指向CMake安装的路径

FIND_PACKAGE该命令将会在module路径下查找 Find<name>.cmake。首先它搜索 ${CMAKE_MODULE_PATH}中的所有路径,然后搜索 <CMAKE_ROOT>/share/

cmake-x.y/Modules; 如果这个文件未找到,它将会查找 <Name>Config.cmake 或  <lower-case-name>-config.cmake 文件。这两个文件是库文件安装时自己安装的,将自己的路径硬编码到其中。  前者称为module模式,后者称为 config 模式 每个模块一般都会提供一下几个变量 <name>_FOUND、<name>_INCLUDE_DIR 或 <name>_INCLUDES、<name>_LIBRARY 或 <name>_LIBRARIES 或 <name>_LIBS <name>_DEFINITIONS;

 >>find_package(CURL 4.5.0 REQUIRED) 

 include_directories(${CURL_INCLUDE_DIR}) 

 target_link_libraries(demo ${CURL_LIBRARY})   #搜索QT库,并设定为必须属性,根据搜到的路径,为目标工程添加其头文件和静态库的路径

FIND_LIBRARY用于寻找在一些指定目录下的特定的Tcl库文件。一般外部库的link方式可以通过两种方法来做,一种是显示添加路径,采用link_directories(), 一种是通过find_library()去查找对应的库的绝对路径。后一种方法是更好的,因为它可以减少不少潜在的冲突。 一般find_library会根据一些默认规则来搜索文件,如果找到,将会set传入的第一个变量参数、否则,对应的参数不被定义,并且有一个xxx-NOTFOUND被定义;可以通过这种方式来调试库搜索是否成功。

>>find_library(TCL_LIBRARY NAMES tcl tc184 tc183 tc 182 tc 180

  PATHS /usr/lib /usr/local/lib)

 if(TCL_LIBRARY)

  target_add_library (Hello TCL_LIBRARY)

 endif(TCL_LIBRARY)    

 

三 经典实例

1 测试一:组织自身内部文件

(1)文件目录组织如下:

Test

-build

-src

-main.c

-lib

-function.h

-function.c

 

(2)将lib文件夹编译成静态函数库,给src中函数调用

 

(3)需要写三个CMakeLists文件,依此放入Test、src以及lib文件夹的根目录,内容如下:

Test-CMakeLists

project(HELLO)

cmake_minimum_required(VERSION 2.8)

add_subdirectory(lib)

add_subdirectory(src)

  

src-CMakeLists

include_directories(${PROJECT_SOURCE_DIR}/libfunction)

link_directories(${CMAKE_INSTALL_PREFIX}/lib)

aux_source_directory(. APP_SRC)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

add_executable(demo ${APP_SRC})

target_link_libraries(demo libfunction)

install(TARGETS demo RUNTIME DESTINATION bin)     #安装程序到 ${CMAKE_INSTALL_PREFIX}/bin目录

set_property(TARGET hello PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)   #设定安装的可执行文件所需的库文件路径,#如果没有该项设置, 会出错:cannot open shared object file: No such file or directory

 

lib-CMakeLists

set(LIB_SRC function.cpp)

add_definitions("-DLIBHELLO_BUILD")

set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

add_library(libfunction SHARED ${LIB_SRC})

add_library(function_static STATIC ${LIB_SRC})

install(TARGETS libfunction ARCHIVE DESTINATION lib)

install(TARGETS function_static ARCHIVE DESTINATION lib)

install(FILES function.h  DESTINATION include)

set_target_properties(libfunction PROPERTIES OUTPUT_NAME "function")

set_target_properties(function_static PROPERTIES OUTPUT_NAME "function")

 

2 测试二:添加第三方库,并自动配置好路径

(1)文件目录组织如下:

Test

-build

-main.c

(2)将Test中的文件组建工程,并配置好第三方库OpenCV

(3)CMakeLists内容如下:

PROJECT(LSTranform)

# this command finds OpenCV libraries and sets all required variables

FIND_PACKAGE(OpenCV REQUIRED)

INCLUDE_DIRECTORIES(${OPENCV_INCLUDE_DIR})

set(SRC_LIST main.cpp LSTransformEstimator.h LSTransformEstimator.cpp)

add_executable(${PROJECT_NAME} ${SRC_LIST})

TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OpenCV_LIBS})


PS:更多学习资源

http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#manual:cmake-buildsystem(7)

http://jiyeqian.is-programmer.com/2011/7/4/cmake_tutorial.27813.html

http://blog.csdn.net/panweiguozhou/article/details/6829085

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值