cmake的定义是什么?---高级编译配置工具
**当多个人用不同的语言或者编译器开发一个项目,最终要输出一个可执行文件或者共享库(d训,so等等)这时候神器就出现了-CMak!**
**所有操作都是通过编译CMakeLists.txt来完成的一简单**
官方网站是www.cmake.org,可以通过访问官方网站获得更多关于cmake的信息
**学习CMake的目的,为将来处理大型的C/C++,JAVA项目做准备**
下载安装: www.cmake.org
演示
创建main.cpp
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
创建CMakeLists.txt文件
PROJECT (HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
使用命令: cmake .
生成文件
-rw-r--r-- 1 root root 11960 8月 13 23:18 CMakeCache.txt
drwxr-xr-x 5 root root 4096 8月 13 23:27 CMakeFiles
-rw-r--r-- 1 root root 1555 8月 13 23:27 cmake_install.cmake
-rw-r--r-- 1 root root 189 8月 13 23:27 CMakeLists.txt
-rw-r--r-- 1 root root 79 8月 13 22:33 main.cpp
-rw-r--r-- 1 root root 4611 8月 13 23:27 Makefile
使用命令: make
开始编译,得到hello的可执行文件 ,执行它: ./hello
-rw-r--r-- 1 root root 11960 8月 13 23:18 CMakeCache.txt
drwxr-xr-x 5 root root 4096 8月 13 23:29 CMakeFiles
-rw-r--r-- 1 root root 1555 8月 13 23:27 cmake_install.cmake
-rw-r--r-- 1 root root 189 8月 13 23:27 CMakeLists.txt
-rwxr-xr-x 1 root root 8968 8月 13 23:29 **hello**
-rw-r--r-- 1 root root 79 8月 13 22:33 main.cpp
-rw-r--r-- 1 root root 4611 8月 13 23:27 Makefile
Cmake语法介绍
PROJECT关键字
可以用来指定工程的名字和支持的语言,默认支持所有语言
PROJECT(HELLO) 指定了工程的名字,并且支持所有语言-建议
PROJECT(HELLO CXX) 指定了工程的名字,并且支持语言是C+
PROJECT (HELLO C CXX) 指定了工程的名字,并且支持语言是C和C++
该指定隐式定义了两个CMAKE的变量
**<项目名称>_BINARY_DIR,本例中是HELLO_BINARY_DIR
<项目名称>_SOURCE_DIR,本例中是HELLO_SOURCE_DIR
MESSAGE 关键字就可以直接使⽤者两个变量,当前都指向当前的⼯作⽬录,后⾯会讲外部编译**
**问题:如果改了⼯程名,这两个变量名也会改变**
解决:**⼜定义两个预定义变**量:**PROJECT_BINARY_DIR**和**PROJECT_SOURCE_DIR**,这**两个变量和
HELLO_BINARY_DIR,HELLO_SOURCE_DIR是⼀致的**。所以改了⼯程名也没有关系
SET 关键字
⽤来显示的指定变量的
SET(SRC_LIST main.cpp) SRC_LIST 变量就包含了 main.cpp
也可以 SET(SRC_LIST main.cpp t1.cpp t2.cpp)
MESSAGE
向终端输出用户自定义的信息
主要包含三种信息:
●SEND_ERROR,产生错误,生成过程被跳过。
●SATUS,输出前缀为一的信息。
●FATAL_ERROR,立即终止所有cmake过程
ADD_EXECUTABLE关键字
**⽣成可执⾏⽂件**
**ADD_EXECUTABLE(hello ${SRC_LIST}) ⽣成的可执⾏⽂件名是hello**,源⽂件读取变量SRC_LIST中的内容
**也可以直接写 ADD_EXECUTABLE(hello main.cpp)**
上述例⼦可以简化的写成
PROJECT(HELLO) ADD_EXECUTABLE(hello main.cpp)
**注意:⼯程名的 HELLO 和⽣成的可执⾏⽂件 hello 是没有任何关系的**
---------------语法的基本原则
变量使⽤${}⽅式取值,但是在 IF 控制语句中是直接使⽤变量名
指令(参数 1 参数 2...) 参数使⽤括弧括起,参数之间使⽤空格或分号分开。 以上⾯的 ADD_EXECUTABLE 指令
为例,如果存在另外⼀个 func.cpp 源⽂件
就要写成:ADD_EXECUTABLE(hello main.cpp func.cpp)或者ADD_EXECUTABLE(hello main.cpp;func.cpp)
指令是⼤⼩写⽆关的,参数和变量是⼤⼩写相关的。但,推荐你全部使⽤⼤写指令
---------------语法注意事项
SET(SRC_LIST main.cpp) 可以写成 SET(SRC_LIST “main.cpp”),如果源⽂件名中含有空格,就必须要加双引
号
ADD_EXECUTABLE(hello main) 后缀可以不写,他会⾃动去找.c和.cpp,最好不要这样写,可能会有这两个⽂
件main.cpp和main
内部构建和外部构建
- 上述例⼦就是内部构建,他⽣产的临时⽂件特别多,不⽅便清理
- 外部构建,就会把⽣成的临时⽂件放在build⽬录下,不会对源⽂件有任何影响强烈使⽤外部构建⽅式
外部构建方式:
创建文件CMakeLists.txt 和main.cpp
-rw-r--r-- 1 root root 189 8月 13 23:27 CMakeLists.txt
-rw-r--r-- 1 root root 79 8月 13 22:33 main.cpp
创建一个目录
mkdir build
cd build
cmake <path> #main.cpp和CMakeLists.txt目录位置
------------------
ls
-rw-r--r-- 1 root root 11978 8月 14 00:06 CMakeCache.txt
drwxr-xr-x 5 root root 4096 8月 14 00:06 CMakeFiles
-rw-r--r-- 1 root root 1567 8月 14 00:06 cmake_install.cmake
-rw-r--r-- 1 root root 4635 8月 14 00:06 Makefile
make
...
./hello
CMake工程
创建对应目录
├── build
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.cpp
外层CMakeLists.txt
PROJECT(HELLO) #项目名称
ADD_SUBDIRECTORY(src bin) #添加子目录文件和二进制文件存放目录
ADD_SUBDIRECTORY 指令
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
- 这个指令⽤于向当前⼯程添加存放源⽂件的⼦⽬录,并可以指定中间⼆进制和⽬标⼆进制存放的位置
- EXCLUDE_FROM_ALL函数是将写的⽬录从编译中排除,如程序中的example
- ADD_SUBDIRECTORY(src bin)
- 将 src ⼦⽬录加⼊⼯程并指定编译输出(包含编译中间结果)路径为bin ⽬录
- 如果不进⾏ bin ⽬录的指定,那么编译结果(包括中间结果)都将存放在build/src ⽬录
更改⼆进制的保存路径
SET 指令重新定义 EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 变量 来指定最终的⽬标⼆进制的位置
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
思考:加载哪个CMakeLists.txt当中
哪⾥要改变⽬标存放路径,就在哪⾥加⼊上述的定义,所以应该在src下的CMakeLists.txt下写
/src/CMakeLists.txt
ADD_EXECUTABLE(hello main.cpp) # 可执行文件
CMake 安装
- ⼀种是从代码编译后直接 make install 安装
- ⼀种是打包时的指定 ⽬录安装。
- 简单的可以这样指定⽬录:make install DESTDIR=/tmp/test
- 稍微复杂⼀点可以这样指定⽬录:./configure –prefix=/usr
目录结构:
├── build
├── CMakeLists.txt
├── COPYRIGHT #版权文件
├── doc
│ └── hello.txt
├── # 介绍文件
├── runhello.sh #linux 脚本文件
└── src
├── CMakeLists.txt
└── main.cpp
CMAKE_INSTALL_PREFIX 指令
CMAKE_INSTALL_PREFIX 默认是在 /usr/local/
安装: COPYRIGHT
README
,编辑文件 CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
# 安装文件 COPYRIGHT README,到目录 SHARE/DOC/CMAKE/
# 如果是相对路径 share/doc/cmake/ 那么cmake会自动拼接一个变量:
# ${CMAKE_INSTALL_PREFIX}/share/doc/cmake/ ,默认是在/usr/local/,全路径为:/usr/local/share/doc/
**INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)**
安装 :脚本 runhello.sh
PROGRAMS:⾮⽬标⽂件的可执⾏程序安装(⽐如脚本之类)
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
说明:实际安装到的是 /usr/bin
安装 doc 中的 hello.txt
- ⼀、是通过在 doc ⽬录建⽴CMakeLists.txt ,通过install下的file
- ⼆、是直接在⼯程⽬录通过
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)
DIRECTORY 后⾯连接的是所在 Source ⽬录的相对路径
注意:abc 和 abc/有很⼤的区别
⽬录名不以/结尾:这个⽬录将被安装为⽬标路径下的
⽬录名以/结尾:将这个⽬录中的内容安装到⽬标路径`
开始安装
cd build
cmake ..
make
[root@VM-12-3-centos build]# make install
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/share/doc/cmake/COPYRIGHT
-- Installing: /usr/local/share/doc/cmake/README
-- Installing: /usr/local/bin/runhello.sh
-- Installing: /usr/local/share/doc/cmake
-- Installing: /usr/local/share/doc/cmake/hello.txt
CMake 静态库和动态库的构建
任务:
- 建⽴⼀个静态库和动态库,提供 HelloFunc 函数供其他程序编程使⽤,HelloFunc 向终端输HelloWorld 字符串。
- 安装头⽂件与共享库。
- 静态库和动态库的区别
- 静态库的扩展名⼀般为“.a”或“.lib”;动态库的扩展名⼀般为“.so”或“.dll”。
- 静态库在编译时会直接整合到⽬标程序中,编译成功的可执⾏⽂件可独⽴运⾏
- 动态库在编译时不会放到连接的⽬标程序中,即可执⾏⽂件⽆法单独运⾏。
目录结构
├── build
├── CMakeLists.txt
└── lib
├── CMakeLists.txt
├── hello.cpp
└── hello.h
CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)
lib/ CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
hello:就是正常的库名,⽣成的名字前⾯会加上lib,最终产⽣的⽂件是libhello.so,自动加上前缀lib,后缀.os
SHARED,动态库
STATIC,静态库 ${LIBHELLO_SRC} :源⽂件
开始执行:
cd build
cmake ..
[root@VM-12-3-centos build]# make
Scanning dependencies of target hello
[100%] Building CXX object bin/CMakeFiles/hello.dir/hello.o
Linking CXX shared library libhello.so
[100%] Built target hello
drwxr-xr-x 3 root root 4096 8月 14 01:43 CMakeFiles
-rw-r--r-- 1 root root 1151 8月 14 01:43 cmake_install.cmake
-rwxr-xr-x 1 root root 8640 8月 14 01:43 **libhello.so**
-rw-r--r-- 1 root root 5045 8月 14 01:43 Makefile
同时构建静态和动态库
// 如果⽤这种⽅式,只会构建⼀个动态库,不会构建出静态库,虽然静态库的后缀是.a
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})
//对hello_static的重名为hello
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
//cmake 在构建⼀个新的target 时,会尝试清理掉其他使⽤这个名字的库,
//因为,在构建 libhello.so 时, 就会清理掉 libhello.a
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
//VERSION 指代动态库版本,SOVERSION 指代 API 版本
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.0 SOVERSION 1)
开始执行:
cd build
cmake ..
make
cd bin/
ll
drwxr-xr-x 4 root root 4096 8月 14 01:54 CMakeFiles
-rw-r--r-- 1 root root 1151 8月 14 01:54 cmake_install.cmake
-rw-r--r-- 1 root root 2828 8月 14 01:54 **libhello.a**
-rwxr-xr-x 1 root root 8640 8月 14 01:54 **libhello.so**
-rw-r--r-- 1 root root 5997 8月 14 01:54 Makefile
安装共享库和头⽂件
本例中我们将 hello 的共享库安装到/lib⽬录,
将 hello.h 安装到/include/hello ⽬录
首先安装头文件: lib/CMateLists.txt
//⽂件放到该⽬录下
INSTALL(FILES hello.h DESTINATION include/hello)
//⼆进制,静态库,动态库安装都⽤TARGETS
//ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME 特指可执⾏⽬标⼆进制。
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
开始执行:
//安装前缀
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make
make install
Install the project...
-- Install configuration: ""
-- Installing: /usr/include/hello/hello.h
-- Installing: /usr/lib/libhello.so.1.0
-- Installing: /usr/lib/libhello.so.1
-- Installing: /usr/lib/libhello.so
-- Installing: /usr/lib/libhello.a
使用外部共享库和静态库
目录结构
├── build
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.cpp
CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
src/CMakeLists.txt
add_executable(hello main.cpp)
src/main
#include <hello.h>
int main(){
println();
}
开始执行:
cd build
cmake ..
make
/home/CPlusPlus/cmake03/src/main.cpp:1:19: 致命错误:hello.h:没有那个文件或目录
#include <hello.h>
^
编译中断。很显然没有找到头文件
解决:make后头⽂件找不到的问题, 编辑文件 lib/CMakeLists.txt
#接着上一个段的文件生成在这个目录下,告诉cmake到这个文件下去找
INCLUDE_DIRECTORIES(/usr/include/hello)
解决:找到引⽤的函数问题
报错信息:undefined reference to `HelloFunc()'
关键字:LINK_DIRECTORIES 添加⾮标准的共享库搜索路径
关键字:TARGET_LINK_LIBRARIES 添加需要链接的共享库
在CMakeLists.txt中插⼊链接共享库,主要要插在executable的后⾯
TARGET_LINK_LIBRARIES(main [libhello.so](http://libhello.so))
查看main的链接情况
再次编辑 lib/CMakeLists.txt, 添加下面的关键字
**TARGET_LINK_LIBRARIES(main libhello.a)**
特殊的环境变量 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH
注意:这两个是环境变量⽽不是 cmake 变量,可以在linux的bash中进⾏设置
我们上⾯例⼦中使⽤了绝对路径INCLUDE_DIRECTORIES(/usr/include/hello)来指明include路径的位置
我们还可以使⽤另外⼀种⽅式,使⽤环境变量export CMAKE_INCLUDE_PATH=/usr/include/hello