CMake是一个跨平台的编译工具,可以用简单的语句来描述所有平台的编译过程。程序猿利用cmake语句编写工程编译过程语句形成CMakeList.txt文件,利用cmake指令执行该cmake文件,生成对应不同平台的makefile文件,由其来进行不同平台编译过程的批处理操作,最终生成库文件或可执行文件。类似于编译器要执行的基本任务。
首先对CMake文件的框架做一个大致了解。在学习开始前,读者首先还应对工程编译过程、库文件相关知识有一定了解。
command(arg1 arg2) #运行命令
set(var_name var_value) #设置变量值
command(arg1 ${
var_name}) #使用变量
#********************工程配置部分*****************
cmake_minium_required(VERSION num)
project(cur_project_name)
set(CMAKE_CXX_FLAGS "xxx") #设置编译器类型,如-std=c+11
set(CMAKE_BUILD_TYPE) #设定编译模式,如DEBUG/RELEASE
#********************依赖执行部分****************
find_package(std_lib_name VERSION REQUIRED) #引入外部库
add_library(<name> [lib_type] source_name) #生成库类型(动态.so.dll/静态.a)
include_directories(${
std_lib_name_INCLUDE_DIRS})
add_excutable(cur_project_name main.cpp)
target_link_libraries(${
std_lib_name_LIBRARIES})
#*******************其他辅助部分*****************
function(function_name arg) #定义一个函数
add_subdirectory(dir) #增加一个子目录
AUX_SOURCE_DIRECTORY(. src_list) #查找当前目录所有文件并存储到变量src_list中
FOREACH(one_dir ${
src_list})
MESSAGE(${
one_dir})
ENDFOREACH(one_dir)
#******************判断控制部分*****************
IF(EXPRESSION)
COMMAND(arg1)
ELSE
COMMAND(arg2)
ENDIF(EXPRESSION)
WHILE(condition)
COMMAND(arg1)
ENDWHILE(condition)
IF(var)
IF(NOT var)
IF(var1 AND var2)
IF(var1 OR var2)
IF(COMMAND cmd) #如果cmd是指令
IF(EXISTS dir)
IF(EXISTS file)
IF(is_directory dir)
IF(file1 IS_NEWER_THAN file2)
注:CMake指令不区分大小写
PROJECT
ADD_EXCUTABLE
ADD_SUBDIRECTORY
INCLUDE_DIRECTORIES
TARGETS_LINK_DIRECTORIES
ADD_LIBRARY
AUX_SOURCE_DIRECTORY
FOREACH
MESSAGE
IF ESLE ENDIF
WHILE ENDWHILE
FIND_PACKAGE
SET
为源文件添加由 -D 引入的宏定义
add_definations(-DMAX)
提供用户可以选择的选项
option( “description” [initial value])
option(
USE
"use state"
ON
)
为工程添加一条自定义的构建规则
用于给指定名称的目标执行指定的命令,该目标没有输出文件,并始终被构建
当定义的一个target依赖于另一个target时,为了保证编译本target之前另一个target已经被编译,使用此语句,解决链接依赖问题
各参数可以参考CMake手册介绍
INSTALL(
TARGETS myrun mylib mtStaticLib
RUNTIME DESTINATION bin
LIBRAYR DESTINATION lib
ARCHIVE DESTINATION binstatic
)
以上实例中,RUNTIME用于标记可执行文件的安装路径,LIBRAYR用于标记动态库的安装路径,ARCHIVE用于标记静态库的安装路径。其中,是否属于RUNTIME类型还与文件本身属性有关,而LIBRAYR还与执行平台有关,详细信息可参考上述手册链接,下文摘选有关内容。
The TARGETS form specifies rules for installing targets from a project. There are five kinds of target files that may be installed: ARCHIVE, LIBRARY, RUNTIME, FRAMEWORK, and BUNDLE. Executables are treated as RUNTIME targets, except that those marked with the MACOSX_BUNDLE property are treated as BUNDLE targets on OS X. Static libraries are always treated as ARCHIVE targets. Module libraries are always treated as LIBRARY targets. For non-DLL platforms shared libraries are treated as LIBRARY targets, except that those marked with the FRAMEWORK property are treated as FRAMEWORK targets on OS X. For DLL platforms the DLL part of a shared library is treated as a RUNTIME target and the corresponding import library is treated as an ARCHIVE target. All Windows-based systems including Cygwin are DLL platforms. The ARCHIVE, LIBRARY, RUNTIME, and FRAMEWORK arguments change the type of target to which the subsequent properties apply. If none is given the installation properties apply to all target types. If only one is given then only targets of that type will be installed (which can be used to install just a DLL or just an import library). The INCLUDES DESTINATION specifies a list of directories which will be added to the INTERFACE_INCLUDE_DIRECTORIES target property of the when exported by the install(EXPORT) command. If a relative path is specified, it is treated as relative to the $
.
DESTINATION的目标安装路径如使用相对路径,应注意设置相对路径变量CMAKE_INSTALL_PREFIX
设置include文件查找的目录,具体包含头文件应用形式(接口、公有、私有)、安装位置等
target_include_directories( [INTERFACE|PUBLIC|PRIVATE] )
设置目标的一些属性来改变他们的构建方式
set_target_properities(target1 target2 PROPERITIES prop1 value1 prop2 value2)
set_target_properities(example
PROPERITIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINAYR_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINAYR_DIR}/lib"
)
构建并开启构建test目标
ADD_TEST(mytest ${
PROJECT_BINAYR_DIR}/bin/main)
ENABLE_TESTING()
变量 | 含义 |
---|---|
CMAKE_INSTALL_PREFIX | 构建install的路径 |
$ENV{HOME} | HOME环境下的目录路径 |
PROJECT_NAME | 工程名 |
package_INCLUDE_DIR | 导入包头文件目录 |
package_LIBRAYIES | 导入库文件的全路径 |
PROJECT_SOURCE_DIR | 当前工程的全路径 |
CMAKE_VIRSION | cmake版本号 |
采用外部编译
工程文件夹目录设置为:src、include、build
mkdir build
cd build
cmake … #利用上一级目录的CMkeList.txt文件生成makefile
make #编译makefile文件,生成bin文件
./hello_world #执行文件
附:工程文件夹组织框架
├── build
| └── bin
| | └── <project_name.exe>
├── install
| └── include
| | ├── xxx.h
| | └── xxx.h
| └── lib
| | ├── xxx.so
| | └── xxx.a
├── include
| ├── xxx.h
| └── xxx.h
├── src
| ├── xxx.cpp
| └── xxx.cpp
├── CMakeLists.txt
├── README
└── run<project_name>.sh
以上列举的一些常用命令和变量,较为零碎,建议结合以下实例进一步体会各命令、变量的用法
CMakelist.txt文件
cmake_minium_required(VIRSION 2.8.3)
project(hello_world)
add_compile_option(-std=c++11)
include_directiories(include)
add_excutable(hello_world src/hello_world.cpp src/main.cpp)
cmake_minium_required(VIRSION 2.8.3)
project(hello_world_static_lib)
add_compile_option(-std=c++11)
include_directiories(include)
add_library(hello_world_static_lib STATIC src/hello_world.cpp)
cmake_minium_required(VIRSION 2.8.3)
project(hello_world_shared_lib)
add_compile_option(-std=c++11)
set(LIBRARY_OUTPUT_PATH ${
PROJECT_SOURCE_DIR}/lib)
include_directiories(include)
add_library(hello_world_shared_lib SHARED src/hello_world.cpp)
添加库时的目标(hello_world_lib)不能使用一样的名字,添加库后设置目标输出名字属性设置为一样的即可
cmake_minium_required(VIRSION 2.8.3)
project(hello_world_lib)
add_compile_option(-std=c++11)
set(LIBRARY_OUTPUT_PATH ${
PROJECT_SOURCE_DIR}/lib)
include_directiories(include)
add_library(hello_world_lib STATIC src/hello_world.cpp)
add_library(hello_world_lib_shared SHARED src/hello_world.cpp)
set_target_properities(hello_world_lib_shared PROPERITIES OUTPUT_NAME "hello_world_lib")
库文件分为
cmake_minium_required(VIRSION 2.8.3)
project(hello_world)
add_compile_option(-std=c++11)
set(P /home/project/src/hello_lib)
include_directiories(${
P}/include include)
add_excutable(${
PROJECT_NAME} src/hello_world.cpp src/main.cpp)
target_link_library(${
PROJECT_NAME} ${
P}/lib/hello.so)
若未得到库文件,首先利用源程序进行库文件安装
cmake_minium_required(VIRSION 2.8.3)
project(hello_lib)
add_compile_option(-std=c++11)
include_directiories(include)
add_library(libhello STATIC src/hello_lib.cpp)
set(CMAKE_INSTALL_PREFIX /usr)
install(FILE include/hello.h DESTINATION include)
install(TARGET libhello ARCHIVE DESTINATION lib)
确定了库文件和头文件的位置后,就可以在需要的工程中导入需要的库文件了
cmake_minium_required(VIRSION 2.8.3)
project(hello_world)
add_compile_option(-std=c++11)
include_directiories(include /usr/include)
add_excutable(hello_world src/hello_world.cpp src/hello_main.cpp)
target_link_libraries(${
PROJECT_NAME} /usr/lib/libhello.a)
该方式分为两种模式:模块模式和配置模式,这里只介绍较为简便的模块模式。首先介绍该模式下的常用变量:
变量 | 含义 |
---|---|
_FOUND | 库是否找到 |
_INCLUDE_DIR | 库的头文件路径 |
_LIBRARY | 库文件路径 |
模块模式除了要进行库文件的安装和导入外,首先还要进行cmake文件的编写,供后期指令查找使用
放置在cmake文件夹下
find_include( hello_lib_INCLUDE_DIR
NAMES hello.h
#必须是绝对路径
PATHS "/media/hello/install/include/")
find_library(hello_lib_LIBRARY
NAMES libhello
PATHS "/media/hello/install/lib/")
if(hello_lib_INCLUDE_DIR AND hello_lib_LIBRARY)
set(hello_lib_FOUND true)
endif(hello_lib_INCLUDE_DIR AND hello_lib_LIBRARY)
if(hello_lib_FOUND)
message("YES!")
else
message("NO")
endif(hello_lib_FOUND)
安装共三个步骤,分别为cmake文件的安装、头文件安装和库文件安装
cmake_minium_required(VERSION 2.8.3)
project(hello_lib)
add_compile_option(-std=c++11)
include_directories(include)
add_library(libhello STATIC src/hello.cpp)
set(CMAKE_MODULE_PATH ${
PROJECT_SOURCE_DIR}/cmake)
set(CMAKE_INSTALL_PREFIX ${
PROJECT_SOURCE_DIR}/install)
install(FILE Findhello_lib.cmake DESTINATION cmake)
install(FILE hello_lib.h DESTINATION install)
install(TARGET libhello ARCHIVE DESTINATION lib)
cmake_minium_required(VIRSION 2.8.3)
project(hello_world)
add_compile_option(-std=c++11)
set(CMAKE_MODULE_PATH ${
PROJECT_SOURCE_DIR}/../libhello/install/cmake)
find_package(libhello REQUIRED)
if(libhello_FOUND)
include_directories(include ${
libhello_INCLUDE_DIR})
add_excutable(hello_world src/hello_world.cpp src/main.cpp)
target_link_libraries(hello_world ${
libhello_LIBRARY})
else
message("error!")
endif(libhello_FOUND)