CMake: (四) CMake语法规则
[TOC]
CMake支持大写、小写、混合大小写的命令
实例一
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) #声明Cmake版本,如果低于指定版本则会停止处理工程文件,并报告错误
PROJECT(XXX)
SET(CMAKE_BUILD_TYPE Release)
SET(CMAKE_CXX_FLAGS "-std=c++11 -O2 -mfloat-abi=hard -mfpu=neon")
#micro
#ADD_DEFINITIONS( -DENABLE_OPENCV -D__SDK4__)
#include and libs path
SET(INCLUDE_PATH . ../ /usr/include/eigen3 /srv/boost_1_63_0 )
SET(LINK_PATH /srv/boost_1_63_0/stage/lib )
INCLUDE_DIRECTORIES(${INCLUDE_PATH})
LINK_DIRECTORIES(${LINK_PATH} )
#source files in dir
#dir CommonH
AUX_SOURCE_DIRECTORY(filepath name)
#execuable
ADD_EXECUTABLE(XX mainV2.cpp ${name} )
TARGET_LINK_LIBRARIES(XX libnames)
语法分析
CMAKE_MINIMUM_REQUIRED
声明Cmake版本,如果低于指定版本则会停止处理工程文件,并报告错误,语法为
CMAKE_MINIMUM_REQUIRED(VERSION major[.minor[.patch[.tweak]]] [FATAL_ERROR])
PROJECT(PROJECTNAME)
PROJECT(PROJECTNAME [CXX] [C])
可选项: [指定工程支持的语言,如果忽略,表示支持所有语言]
ADD_DEFINITIONS
ADD_DEFINITIONS( -DENABLE_OPENCV -D__SDK4__)
添加编译参数
CMAKE_BUILD_TYPE
设置构建工程类型
INCLUDE_DIRECTORIES
添加头文件目录
INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
它相当于g++
选项中的-I
参数的作用,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH
变量的作用。
LINK_DIRECTORIES
添加需要链接的库文件目录
LINK_DIRECTORIES(directory1 directory2 ...)
它相当于g++
命令的-L
选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH
的路径的作用。
LINK_LIBRARIES
添加需要链接的库文件路径
LINK_LIBRARIES(library1 <debug | optimized> library2 ...)
使用实例
link_libraries(“/home/install/libopencv_core.so”) #直接是全路径
link_libraries(opencv_highgui) #下只有库名,cmake会自动去所包含的目录搜索
link_libraries(${RUNTIME_LIB}) #传入变量
link_libraries("/srv/lib-aarch64/libboost_atomic.so" "/srv/lib-aarch64/libpcl_common.so") #也可以链接多个,需要空格间隔
TARGET_LINK_LIBRARIES
设置要链接的库文件的名称
TARGET_LINK_LIBRARIES (<target> [item1 [item2 [...]]][[debug|optimized|general] <item>] ...)
如下写法都可以
TARGET_LINK_LIBRARIES (ProjectName comm) # 连接libhello.so库,默认优先链接动态库
TARGET_LINK_LIBRARIES (ProjectName libcomm.a) # 显示指定链接静态库
TARGET_LINK_LIBRARIES (ProjectName libcomm.so) # 显示指定链接动态库
TARGET_LINK_LIBRARIES (ProjectName -lcomm)
ADD_EXECUTABLE
为工程生成目标文件
add_executable(<name> [WIN32] [MACOSX_BUNDLE][EXCLUDE_FROM_ALL] source1 [source2 ...])
AUX_SOURCE_DIRECTORY
查找指定目录下的所有源文件,然后将结果存进指定变量名
AUX_SOURCE_DIRECTORY(<dir> <variable>)
ADD_LIBRARY
ADD_LIBRARY(NAME [STATIC| SHARED|MODULE] [EXCLUDE_FROM_ALL] source1, source2,...)
<name>
: 库的名字,直接写名字即可,不要写lib,会自动加上前缀- 库类型:
[STATIC | SHARED | MODULE]
三种。
SHARED,动态库
STATIC,静态库
MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。
EXCLUDE_FROM_ALL
:这个库不会被默认构建,除非有其他的组件依赖或者手工构建
SET_TARGET_PROPERTIES
设置动态库的版本号
#VERSION 指代动态库版本,SOVERSION 指代 API 版本。
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
其实不管你的动态库版本是什么,对外调用总是libxxx.so
MESSAGE
打印过程信息
MESSAGE( [STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]"message to display" ...)
可选项说明
(无) = 重要消息;
STATUS = 非重要消息;
WARNING = CMake 警告, 会继续执行;
AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
FATAL_ERROR = CMake 错误, 终止所有处理过程;
编译和链接选项
全局设置
SET(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -DEMBED")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS } -DEMBED")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
这种写法的好处是,不会覆盖CMAKE_CXX_FLAGS本来的信息。只是把需要添加的内容添加进去.
针对特定工程类型的设置
CMAKE_BUILD_TYPE = Debug/Release
CMAKE_CXX_FLAGS_DEBUG = "${CMAKE_CXX_FLAGS_DEBUG} -DXXX"
CMAKE_CXX_FLAGS_RELEASE = "${CMAKE_CXX_FLAGS_RELEASE} -DXXX"
当CMAKE_BUILD_TYPE设置为Debug,则编译时采用CMAKE_CXX_FLAGS_DEBUG。
当CMAKE_BUILD_TYPE设置为Release,则编译时采用CMAKE_CXX_FLAGS_RELEASE.
#set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb -Wno-unused-but-set-variable")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -Wno-unused-but-set-variable")
多目录结构的cmake使用
假设一个工程Hello,实际的目录结构其实并不是所有源码都存放在src目录内。它的目录结构是:
src: 存放生成库的源码。source1.cpp, source2.cpp
test:存放使用库的测 试程序: main.cpp
include: 存放头文件: source1.h
resource: 存放第三方库
build:存放编译过程的文件
build/lib: 存放生成的libv4l2_utils.so
build/bin:存放main.cpp所产生的测试程序可执行文件。
此时,可以采用顶层目录和每个有源码的目录中均创建CMakeLists.txt的方式来处理(和Makefile处理方式类似),顶层目录的CMakeLists.txt 内容如下:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(Hello)
ADD_SUBDIRECTORIES(src lib)
ADD_SUBDIRECTORIES(test bin)
ADD_SUBDIRECTORIES
构建添加一个子路径
ADD_SUBDIRECTORIES([source dir] [bin dir] [exclude_from_all])
source_dir
选项指定了CMakeLists.txt源文件和代码文件的位置。如果source_dir是一个相对路径,那么source_dir选项会被解释为相对于当前的目录,但是它也可以是一个绝对路径。binary_dir
选项指定了输出文件的路径。如果binary_dir是相对路径,它将会被解释为相对于当前输出路径。
SOURCE_DIR算相对路径时,是从CMakeLists.txt算起。所以src指的是当前 CMakeLists.txt所在路径下的src. 而bin, lib 指的是当前输出路径下的bin,lib. 也就是build/bin build/lib
src内的CMakeLists.txt
SET(LIB_SRC_LIST source1.cpp)
SET(CMAKE_BUILD_TYPE Release)
INCLUDE_DIRECTORIES(../include)
ADD_LIBRARY(SOURCE1 SHARED ${LIB_SRC_LIST})
test内的CMakeLists.txt
SET(EXEC_SRC_LIST main.cpp)
SET(INCLUDE_DIRECTORIES ../include)
SET(LINK_DIR ../../resource)
SET(LINK_DIR "${LINK_DIR} ../../libs/")
SET(CMAKE_BUILD_TYPE Release)
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES})
LINK_DIRECTORIES(${LINK_DIR})
ADD_EXECUTABLE(Test_Hello ${EXEC_SRC_LIST})
TARGET_LINK_LIBRARIES(Test_Hello SOURCE1 )
文件移动
将某一个工程放置于某一个文件夹下(指的是工程位于某目录下)
SET_PROPERTY(TARGET NetLib PROPERTY FOLDER "Common")
将NetLib移动到Common文件夹下
INSTLLL(FILES ${CMAKE_LINK_PATH}/odbc/libodbc.so DESTINATION bin)
将动态库移动到bin目录下
显示编译细节
SET(CMAKE_VERBOSE_MAKEFILE ON)
如果不希望改变CMakeLists.txt,可以在创建Makefile时候加入
cmake -DCMAKE_VERBOSE_MAKEFILE=ON
如果连Makefile都不希望修改可以:make VERBOSE=1
相对路径
SET(LIBRARY_DIRECTORIES ../resource)
LINK_DIRECTORIES(${LIBRARY_DIRECTORIES})
这里会出警告:
This command specifies the relative path:../resource
可以做如下处理:
SET(LIBRARY_DIRECTORIES ../resource)
LINK_DIRECTORIES($PROJECT_SOURCE_DIR}/${LIBRARY_DIRECTORIES})
但是如果LIBRARY_DIRECTORIES 是个列表的话,此种方式仍然会引起警告。
CMakeList.txt所在位置
CMAKE_CURRENT_SOURCE_DIR
CMAKE_CURRENT_BINARY_DIR
PROJECT_SOURCE_DIR
PROJECT_BIANRY_DIR
内部编译时,以上四种变量没有区别,都是CMakeLists.txt
所在位置,但是外部编译时
CMAKE_CURRENT_BINARY_DIR
PROJECT_BIANRY_DIR
在build文件夹
FIND_PACKAGE
可以被用来在系统中自动查找配置构建工程所需的程序库。在linux和unix类系统下这个命令尤其有用。CMake自带的模块文件里有大半是对各种常见开源库的find_package支持,支持库的种类非常多,例如
FIND_PACKAGE(OpenCV 2.4 REQUIRED COMPONENTS core highgui)
函数定义如下
```bash
FIND_PACKAGE( Name [version] [EXACT] [QUIET] [[REQUIRED|COMPONENTS] [components...]] [NO_POLICY_SCOPE])
查找并加载外来工程的设置。该命令会设置Name_FOUND
变量,用来指示要找的包是否被找到了。如果这个包被找到了,与它相关的信息可以通过包自身记载的变量中得到。REQUIRED
选项表示如果报没有找到的话,cmake的过程会终止,并输出警告信息。
- 在REQUIRED选项之后,或者如果没有指定REQUIRED选项但是指定了COMPONENTS选项,在它们的后面可以列出一些与包相关的部件清单(components list)。
- 每一个模块都会产生如下变量,
_FOUND
,_INCLUDE_DIR
_LIBRARY
和_LILBRARIES
,如果_FOUND为真,_INCLUDE_DIR
加入到INCLUDE_DIRECTORIES
中,_LIBRARY
加入到TARGET_LINK_LIBRARIES
中就会有相应的变量OpenCV_FOUND,OpenCV_INCLUDE_DIRS等相应的变量生效。
例如
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIR})
target_link_libraries(curltest ${CURL_LIBRARY})
PKG_CHECK_MODULES
检测所有给出的modules
PKG_CHECK_MODULES(<PREFIX> [REQUIRED] [QUIET] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] <MODULE> [<MODULE>]*)
例如
PKG_CHECK_MODULES(PC_OPENNI2 libopenni2)
if (NOT PC_OPENNI2_FOUND)
PKG_CHECK_MODULES(PC_OPENNI2 REQUIRED openni2)
endif()
如果找到,PC_OPENNI2_INCLUDE_DIRS
,PC_OPENNI2_LIBRARY_DIRS
等被设置。