CMake语法介绍
PROJECT 指令
用来指定工程的名字和支持的语言,默认支持所有语言
- PROJECT(HELLO) 指定了工程的名字,并且支持所有语言(推荐)
- PROJECT(HELLO CXX) 指定了工程的名字,并且支持的语言是C++
- PROJECT(HELLO C CXX)指定了工程的名字。并且支持的语言是C和C++
该关键字隐式定义了两个CMAKE的变量
[projectname]_BINARY_DIR,本例中是HELLO_BINARY_DIR
[projectname]_SOURCE_DIR,本例中是HELLO_SOURCE_DIR
这两个变量现在都指向当前的工作目录
[projectname]_BINARY_DIR与PROJECT_BINARY_DIR是等价的
projectname可能改变,因此在指定目录时,应该使用PROJECT_BINARY_DIR
SET
用来显式的指定变量
SET(SRC_LIST main1.cpp main2.cpp)
这样,SRC_LIST就包含了main1.cpp和main2.cpp。
MESSAGE
向终端输出用户自定义的信息
主要包含三种信息
- SEND_ERROR,产生错误,生成过程被跳过
- STATUS,输出前缀为--的信息
- FATAL_ERROR,立即终止所有cmake过程
ADD_EXECUTABLE
生成可执行文件
ADD_EXECUTABLE(hello ${SRC_LIST})
生成的可执行文件名是hello,源文件读取变量SRC_LIST中的内容也可以直接写ADD_EXECUTABLE(hello main.cpp)
最简单的CMakelist文件只需要两行:
PROJECT(HELLO) // 指定工程名
ADD_EXECUTABLE(hello main.cpp) // 编译main.cpp,生成可执行文件hello
语法基本原则
- 变量使用${}方式取值,但是在IF控制语句中是直接使用变量名
指令(参数1 参数2...)
参数使用括弧括起,参数之间使用空格或分号分开(当文件名具有空格时,必须加双引号表示这是一个文件名)- 指令是大小写无关的,参数和变量区分大小写
add_executable 可以不写后缀,它会自动寻找扩展名,这样有可能造成冲突
内部构建和外部构建
之前的例子就是内部构建,他生产的临时文件特别多,不方便清理。
外部构建,就会把生成的临时文件放在build目录下,不会对源文件有任何影响
外部构建方式
新建一个build文件夹,在这个文件夹下对项目进行构建
这样做之后,HELLO_SOURCE_DIR 是工程路径,而 HELLO_BINARY_DIR 是build文件夹的路径
让hello world 看起来像一个工程
- 为工程添加一个子目录src,用来放置工程的源代码
- 添加一个子目录doc,用来放置这个工程的文档
- 在工程目录添加文本文件,如copyright和readme
- 在工程目录添加一个runhello.sh脚本,用来调用hello二进制
- 将构建后的目标文件放入build目录的bin子目录
- 将doc目录的内用以及copyright/readme安装到/usr/share/doc/cmake/
ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(source_dir [binary_dir] [exclude_form_all])
- 这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置。
- EXCLUDE_FORM_ALL函数是将写的目录从编译中排除,如程序中的example
- ADD_SUBDIRECTORY(src bin):将src子目录加入工程并指定编译输出路径为bin目录,如果不指定bin目录,那么编译结果会存放在src目录下。
更改二进制的保存路径
SET指令重新定义EXECUTABLE_OUTPUT_PATH和LIBRAY_OUTPUT_PATH变量来指定最终目标二进制的位置
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
安装
- 一种是从代码编译后直接 make install 安装
- 一种是打包时指定目录安装
- make install DESTDIR=/tmp/test
- ./configure -prefix=/usr
安装后,在任何目录下输入程序名即可运行程序
[cdsoft_zihang@localhost Ctest]$ tree
.
├── build
├── CMakeLists.txt
├── copyright
├── doc
│ └── hello.txt
├── readme.md
├── runhello.sh
└── src
├── CMakeLists.txt
└── main.cpp
如何安装
使用CMake指令:INSTALL
INSTAL的安装可以包括:二进制、动态库、静态库以及文件、目录、脚本等
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake)
FILES:文件
DESTINATION:可以写绝对路径和相对路径,写相对路径时,实际路径是:${CMAKE_INSTALL_PREFIX}/<DESTINATION>
。CMAKE_INSTALL_PREFIX默认是在/usr/local。
cmake -D CMAKE_INSTALL_PREFIX=/usr
在cmake的时候指定CMAKE_INSTALL_PREFIX变量的值
安装脚本runhello.sh
PROGRAMS:非目标文件的可执行程序安装
安装doc中的hello.txt
有两种方式安装
一、通过在doc目录建立CMakeLists.txt,通过install下的file
二、直接在工程目录通过INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)
静态库和动态库的构建
用ADD_LIBRARY指令构建库
ADD_LIBRARY
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
- hello:生成的库名,生成的名字前会加上lib,并且根据生成的库类型自动加上后缀名(.a/.lib或.so/.dll)
- SHARED 动态库 STATIC 静态库
- ${LIBHELLO_SRC} 源文件
同时构建静态库和动态库
# 以下方式不会构建一个动态库,不会构建静态库
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})
# 修改生成的库的名字,可以生成静态库和动态库,但通常我们希望它们名字相同只是后缀不同
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES
这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和API版本。
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello_static PROPERTIES CANCEL_DIRECT_OUTPUT 1)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CANCEL_DIRECT_OUTPUT 1)
# 新版的cmake不用CANDEL_DIRECT_OUTPUT就可重命名
动态库的版本号
一般动态库都有一个版本号的关联
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION指代动态库版本,SOVERSION指代API版本。
安装共享库和头文件
将hello共享库安装到/lib目录
将hello.h安装到/include/hello目录
# 将文件放在该目录下
INSTALL(FILES hello.h DESTINATION include/hello) # 注意这种写法是相对路径
# 二进制、静态库、动态库安装都用TARGETS
# ARCHIVE--静态库 LIBRARY--动态库 RUNTIME--可执行的目标二进制
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) # hello和hello_static是前面的动态库和静态库
使用外部共享库和头文件
INCLUDE_DIRECTORIES
找不到库的问题:
这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割
在CMakeLists.txt中加入头文件搜索路径
INCLUDE_DIRECTORIES(/usr/include/hello) # 添加共享库的安装路径
找不到引用函数的问题
LINK_DIRECTORYS
这条指令用于添加非标准库搜索路径
# 指定第三方库所在路径
LINK_DIRECTORYS(/home/myproject/libs)
TARGET_LINK_LIBRARIES
添加需要链接的共享库
# 只需要给出动态链接库的名字就可以了
# 当然肯定要先能搜索到动态库的路径
TARGET_LINK_LIBRARIES(hello libhello.so) # 前一个变量是生成的二进制文件
查看链接情况
# 查看main的链接情况
[admin@localhost]ldd main
...
补充
两个linux下的环境变量
CMAKE_INCLUDE_PATH和CMAKE_LIBRARY_PATH
# 作用相当于前面的 INCLUDE_DIRECTORIES(/usr/include/hello)
[admin@localhost ~] export CMAKE_INCLUDE_PATH=/usr/include/hello
生产Debug版本
[admin@localhost ~] cmake .. -D CMAKE_BUILD_TYPE