安装gcc软件依赖
yum install -y gcc gcc-c++ make automake
# 输出版本则安装成功
gcc -v
下载最新CMake
# 下载完成后解压
tar -xvf [压缩包]
进入根目录,运行命令
./bootstrap
如果出现以下错误:
运行命令:
yum install -y openssl openssl-devel
然后重新运行即可
./bootstrap
运行gmake
gmake
进行安装
gmake install
输入cmake -v,如果出现版本号则安装成功:

用vim编写一段C++代码:
#include <iostream>
using namespace std;
int main() {
cout << "hello world" << endl;
}
在同一个目录下编写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生成Makefile文件:
cmake .
自动生成了以下文件:

使用make命令编译:
make

编译出了一个可执行文件

运行可执行文件:
hello

用上面编写的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})
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.
MESSAGE关键字就可以直接使用这两个变量,当前都指向当前的工作目录,后面会讲外部编译.
问题:如果改了工程名,这两个变量名也会改变.
解决:可以使用CMake为我们预定义的两个变量: PROJECT_ BINARY_ DIR和PROJECT_SOURCE_ DIR, 这两个变量和HELLO_ BINARY_ DIR, HELLO_ SOURCE_ DIR是一致的.
SET关键字
用于显示的指定变量.
SET(SRC_ LIST main.cpp)指令中的SRC_ LIST变量就包含了main.cpp.
如果当前有多个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).
所以工程名HELLO与生成的可执行文件名hello是没有任何关系的.
上述例子可以简化的写成:
PROJECT(HELLO)
ADD_EXECUTABLE(hello main.cpp)
${}方式取值,但是在IF控制语句中可以直接使用变量名.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"), 但是如果源文件名中含有空格,就必须要加双引号.build目录下,不会对源文件有任何影响,推荐使用外部构建的方式.外部构建
先回退到刚刚编写完CMakeLists.txt文件的时候:
创建一个build目录并进入:
mkdir build
cd build
在build目录中执行cmake命令:
cmake ..
在build目录中执行make命令:
make
生成的临时文件都会在build目录中:

src,用来放置工程源代码.doc,用来放置这个工程的文档hello.txt.COPYRIGHT README.runhello.sh脚本,用来调用hello二进制.bin子目录.doc目录的内容以及 COPYRIGHT/README 安装到/usr/share/doc/cmake/..
├── build
├── CMakeLists.txt
├── COPYRIGHT
├── doc
│ └── hello.txt
├── README
├── runhello.sh
└── src
├── CMakeLists.txt
└── main.cpp
每个目录下都要有一个CMakeLists.txt说明:
.
├── build
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.cpp
外层CMakeLIsts.txt:
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
src下的CMakeLists.txt:
ADD_EXECUTABLE(hello main.cpp)
ADD_SUBDIRECTORY指令
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,如程序中的example.ADD_SUBDIRECTORY(src bin)更改二进制的保存路径
SET指令重新定义EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_ PATH变量来指定最终的目标二进制的位置:
SET(EXECUTABLE_OUTPUT_PATH ../../src/bin)
SET(LIBRARY_OUTPUT_PATH ../../src/lib)
注意:哪里要改变目标存放路径,就在哪里加入上述的定义,所以就在src目录下的CMakeLists.txt中写.
改变之后重新执行:
.
├── build
├── CMakeLists.txt
└── src
├── bin
│ └── hello
├── CMakeLists.txt
└── main.cpp
可以看到可执行文件hello 已经到了src/bin目录下.
安装文件COPYRIGHT和README
在根目录下的CMakeLists.txt文件中加上:
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
FILES:文件名.
DESTINATION:
1.可以直接写绝对路径.
2.也可以写相对路径,相对路径实际路径是:${CMAKE_INSTALL _PREFIX}/<DESTINATION>定义的路径.
CMAKE_JINSTALL_PREFIX默认是在/usr/local/.
cmake-DCMAKE_JNSTALL_PREFIX=/usr 在cmake的时候指定CMAKE_ JNSTALL_ PREFIX变量的路径.
安装脚本runhello.sh
PROGRAMS:非目标文件的可执行程序安装(比如脚本之类).
在根目录下的CMakeLists.txt文件中加上:
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
说明:实际安装到的是/usr/bin.
安装doc目录下的hello.txt
在根目录下的CMakeLists.txt文件中加上:
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)
DIRECTORY后面连接的是所在Source目录的相对路径.
注意: abc和abc/有很大的区别
安装
cd build
cmake ..
make
make install

静态库和动态库的区别:
下面我们来创建一个静态库和动态库,提供HelloFunc函数供其它程序编程使用,HelloFunc向终端输出Hello World字符串.
构建实例:
.
├── build
├── CMakeLists.txt
└── lib
├── CMakeLists.txt
├── hello.cpp
└── hello.h
hello.h中的内容:
#ifndef HELLO_H
#define Hello_H
void HelloFunc();
#endif
hello.cpp中的内容:
#include "hello.h"
#include <iostream>
using namespace std;
void HelloFunc() {
cout << "hello world" << endl;
}
根目录下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})
libhello.so.${LIBHELLO_ SRC}:源文件.
SET_TARGET_PROPERTIES
这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和API版本.
同时构建静态和动态
lib目录下CMakeLists.txt中的内容:
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 CLEAN_DIRECT_OUTPUT 1)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
编译之后:

一般动态库都有一个版本号的关联.
libhello.so.1.2
libhello.so ->libhello.so.1
libhello.so.1->libhello.so.1.2
CMakeList.txt插入如下:
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION指代动态库版本,SOVERSION指代API版本.
本例中我们将hello的共享库安装到<prefix>/lib目录,将hello.h安装到<prefix>/include/hello目录.
在lib目录下CMakeLists.txt的添加:
# 文件放到该目录下
INSTALL(FILES hello.h DESTINATION include/hello)
# 二进制、静态库、动态库安装都用TARGETS
# ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME 特指可执行目标二进制
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
安装的时候指定一下路径,放到系统下:
cmake -D CMAKE_INSTALL_PREFIX=/usr ..

构建实例:
.
├── build
├── CMakeLists.txt
└── src
├── CMakeLists.txt
├── main.cpp
main.cpp中的内容:
#include <hello.h>
using namespace std;
int main() {
HelloFunc();
}
根目录下的CMakeLists.txt:
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
src下的CMakeLists.txt:
ADD_EXECUTABLE(hello main.cpp)
然后编译:
会报找不到hello.h头文件的错误:
需要在src下的CMakeLists.txt加上:
# 表示在hello目录下去找头文件
INCLUDE_DIRECTORIES(/usr/include/hello)
再编译,还会报错,找不到HelloFunc这个函数:

可以使用TARGET_LINK_LIBRARIES关键字添加需要链接的共享库,注意一定要写在ADD_EXECUTABLE关键字的后面:
TARGET_LINK_LIBRARIES (hello libhello.so)
注意hello是生成的二进制文件的名字.
所以最终src下的CMakeLists.txt文件内容:
INCLUDE_DIRECTORIES(/usr/include/hello)
ADD_EXECUTABLE(hello main.cpp)
TARGET_LINK_LIBRARIES (hello libhello.so)
再次编译的时候,就可以成功生成可执行文件hello了,但是运行hello的时候会再次报错:

原因是我们之前生成的动态库libhello.so是在/usr/lib/目录下的,但是我的linux系统是64位的,需要把这个动态库移动到/usr/lib64/目录下才能使用:
mv /usr/lib/libhello.so /usr/lib64/
之后就可以正常运行了:
