当前位置:网站首页>CMake基本使用
CMake基本使用
2022-07-02 22:58:00 【JunesFour】
CMake基本使用
文章目录
1. Linux环境安装
安装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,如果出现版本号则安装成功:
2. 使用CMake运行C++程序
2.1 运行简单的示例程序
用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

3. CMake基本语法
用上面编写的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})
3.1 关键字
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)
3.2 语法的基本原则
- 变量使用
${}方式取值,但是在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"), 但是如果源文件名中含有空格,就必须要加双引号.
3.3 内部构建和外部构建
- 内部构建:上述例子就是内部构建,生产的临时文件特别多,不方便清理.
- 外部构建:会把生成的临时文件放在
build目录下,不会对源文件有任何影响,推荐使用外部构建的方式.
外部构建
先回退到刚刚编写完CMakeLists.txt文件的时候:
创建一个build目录并进入:
mkdir build
cd build
在build目录中执行cmake命令:
cmake ..
在build目录中执行make命令:
make
生成的临时文件都会在build目录中:

4. 工程化项目
- 为工程添加一个子目录
src,用来放置工程源代码. - 添加一个子目录
doc,用来放置这个工程的文档hello.txt. - 在工程目录添加文本文件
COPYRIGHTREADME. - 在工程目录添加一个
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
4.1 生成二进制文件到bin目录中
每个目录下都要有一个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)
将src子目录加入工程并指定编译输出(包含编译中间结果)路径为bin目录
如果不进行bin目录的指定,那么编译结果(包括中间结果)都将存放在build/src目录.
更改二进制的保存路径
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目录下.
4.2 使用CMake进行安装
安装文件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/有很大的区别
- 目录名不以/结尾:这个目录将被安装为目标路径下的abc.
- 目录名以/结尾:将这个目录中的内容安装到目标路径.
安装
cd build
cmake ..
make
make install

5. 静态库与动态库的构建和使用
静态库和动态库的区别:
- 静态库的扩展名一般为".a”或".lib"; 动态库的扩展名- -般为".so"或".dIl".
- 静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行.
- 动态库在编译时不会放到连接的目标程序中,即可执行文件无法单独运行.
下面我们来创建一个静态库和动态库,提供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;
}
5.1 单独构建静态库或动态库
根目录下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. - SHARED:动态库;STATIC: 静态库.
${LIBHELLO_ SRC}:源文件.

5.2 同时构建静态库和动态库
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)
编译之后:

5.3 动态库的版本号
一般动态库都有一个版本号的关联.
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版本.
5.4 安装共享库和头文件
本例中我们将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 ..

5.5 使用共享库和头文件
构建实例:
.
├── 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/
之后就可以正常运行了:

边栏推荐
- What is the official website address of e-mail? Explanation of the login entry of the official website address of enterprise e-mail
- 经济学外文文献在哪查?
- leetcode 650. 2 keys keyboard with only two keys (medium)
- Which websites can I search for references when writing a thesis?
- 请问大家在什么网站上能查到英文文献?
- [shutter] shutter open source project reference
- MySQL Foundation
- How to specify const array in the global scope of rust- How to specify const array in global scope in Rust?
- MFC file operation
- 【OJ】两个数组的交集(set、哈希映射 ...)
猜你喜欢

JDBC practice cases

JS interviewer wants to know how much you understand call, apply, bind no regrets series

How do educators find foreign language references?

In February 2022, the ranking list of domestic databases: oceanbase regained its popularity with "three consecutive increases", and gaussdb is expected to achieve the largest increase this month

Where can I find the English literature of the thesis (except HowNet)?

130 pages of PPT from the brick boss introduces the new features of Apache spark 3.2 & 3.3 in depth

Container runtime analysis

CADD课程学习(4)-- 获取没有晶体结构的蛋白(SWISS-Model)

How to apply for company email when registering in company email format?

JDBC教程
随机推荐
带角度的检测框 | 校准的深度特征用于目标检测(附实现源码)
Many to one, one to many processing
顶级 DevOps 工具链大盘点
论文的设计方案咋写?
返回二叉树中最大的二叉搜索子树的根节点
CADD课程学习(4)-- 获取没有晶体结构的蛋白(SWISS-Model)
国外的论文在那找?
95页智慧教育解决方案2022
Linux 下安装 redis
Dishes launcher small green program and directory management (efficiency tool)
Returns the maximum distance between two nodes of a binary tree
AcWing_ 188. Warrior cattle_ bfs
Interface difference test - diffy tool
Leetcode skimming - game 280
yolov5train. py
How to set automatic reply for mailbox and enterprise mailbox?
Master the development of facial expression recognition based on deep learning (based on paddlepaddle)
Architecture: database architecture design
JDBC練習案例
collections. What is the purpose of chainmap- What is the purpose of collections. ChainMap?