> 文章列表 > CMake

CMake

CMake

CMake定义

CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CMakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。

CMake安装

Linux:yum install cmake
Windows自己去官网下载进行安装

CMake hello.cpp步骤

1、编写hello.cpp文件

#include<isotream>int main()
{std::cout<<"hello world"<<std::endl;return 0;
}

2、编写CMakeLists.txt文件

#CMakeLists.txt
PROJECT(HELLO)
SET(SRC_LIST hello.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、使用cmake,生成makefile文件

cmake . # .代表当前目录
CMake

4、使用make命令编译
第三步的cmake生成了makefile文件
CMakeCMake

5、生成可执行程序
CMake

CMake语法介绍

  • 设置项目名称
project(demo)  指定工程的名字,并且支持所有语言
project(demo CXX) 指定工程的名字,并且支持语言是C++
project(demo C CXX) 指定工程的名字,并且支持语言是C C++
# 最好写上,它会引入两个变量 demo_BINARY_DIR 和 demo_SOURCE_DIR,同时,cmake 自动定义了两个等价的变量 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR。
  • 设置编译类型
add_executable(demo demo.cpp) # 生成可执行文件
add_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库
  • 指定编译包含的源文件
    1、明确指出包含哪些源文件
add_library(demo demo.cpp test.cpp util.cpp)

2、搜索所有的cpp文件
aux_source_directory(dir VAR) 发现一个目录(dir)下所有的源代码文件并将列表存储在一个变量(VAR)中。

aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
add_library(demo ${SRC_LIST})
  • 设置变量
    1、set直接设置变量的值
set(SRC_LIST main.cpp test.cpp)
add_executable(demo ${SRC_LIST})

2、set追加设置变量的值

set(SRC_LIST main.cpp)
set(SRC_LIST ${SRC_LIST} test.cpp)
add_executable(demo ${SRC_LIST})
  • 常用变量
    PROJECT_SOURCE_DIR:工程的根目录

PROJECT_BINARY_DIR:运行cmake命令的目录,通常为${PROJECT_SOURCE_DIR}/build

PROJECT_NAME:返回通过 project 命令定义的项目名称

CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径

CMAKE_CURRENT_BINARY_DIR:target 编译目录

CMAKE_CURRENT_LIST_DIR:CMakeLists.txt 的完整路径

EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置

LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置

  • MESSAGE关键字
    向终端输出用户自定义的信息
    主要包含三种信息:
  • SEND_ERROR,产生错误,生成过程被跳过。
  • STATUS,输出前缀为–的信息
  • FATAL_ERROR, 立即终止所有cmake过程。

内部构建和外部构建

  • 上述例子就是内部构建,生产的临时文件特别多,不方便清理
  • 外部构建,就会把生成的临时文件放在build目录下,不会对源文件有任何影响,建议使用外部构建方式

外部构建步骤:
1、建立一个build目录,可以在任何地方,建议在当前目录下
CMake2、进入build,运行cmake … (…表示上一级目录),也可以写成CMakeLists.txt所在的绝对路径,生产的文件都在build目录下了
3、在build目录下运行make构建工程
CMake

让hello.cpp看起来更像一个工程

  • 为工程添加一个子目录src,用来存放工程源码
  • 添加一个子目录doc,用来放置工程的文档hello.txt
  • 在工程目录添加文本文件COPYRIGHT,README
  • 在工程目录添加一个runhello.sh脚本,用来调用hello二进制文件
  • 将构建后的目标文件放入构建目录的bin子目录

将目标文件放入构建目录的bin子目录
每个目录下都要有一个CMakeLists.txt文件
CMake

外层CMakeLists.txt

#工程名
PROJECT(HELLO)
# 与src关联起来,将生成的二进制文件放入bin中,bin会自动生成
ADD_SUBDIRECTORY(src bin)

src下的CMakeLists.txt

#生成可执行文件hello
ADD_EXECUTABLE(hello hello.cpp)

执行过程,先进入build中,执行cmake … ,生成makefile文件,接下来使用make命令编译,编译好的可执行二进制文件被放入了build/bin目录下,进入bin目录,执行可执行文件即可。
CMake

如何安装hello

使用CMAKE一个新指令:INSTALL
INSTALL的安装可以包括:二进制,动态库,静态库以及文件,目录和脚本等。
目录树结构:
CMake

安装文件COPYRIGHT和README
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
FILES: 文件
DESTINATION:
安装路径:默认在/usr/local/

安装脚本runhello.sh
PROGRAMS: 非目标文件的可执行程序安装(比如脚本类)
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
说明:实际安装的位置是/usr/bin
安装doc中的hello.txt
直接在工程目录通过
INSTAll(DIRECTORY doc/ DESTINATION share/doc/cmake)
注意:
abc和abc/的区别
目录名不以 / 结尾:这个目录将被安装为目标路径下的abc
目录名以 / 结尾:将这个目录中的内容安装到目标路径

安装过程:
进入到build:cmake …
make
make install
CMake

静态库和动态库的构建

任务:
1、建立一个静态库和动态库,提供HelloFunc函数供其他程序编程使用,HelloFunc向终端输出 Hello World字符串。
2、安装头文件与共享库

静态库与动态库的区别

  • 静态库的扩展名一般为".a"或".lib";动态库的扩展名一般为".so"或".dll"。
  • 静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行
  • 动态库在编译时不会放到连接的目标程序中,即可执行文件无法单独运行。

构建实例
CMake
hello.h中的内容

#ifndef HELLO_H
#define HELLO_Hvoid HelloFunc();#endif 

hello.cpp中的内容

#include<iostream>
#include"hello.h"void HelloFunc()
{std::cout<<"Hello World"<<std::endl;
}
int main()
{HelloFunc();return 0;
}

外层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}:源文件

生成上述libhello.so动态库的步骤:

  • 进入到build cmake …
  • make
  • 进入到build/bin, libhello.so就在该目录下
    CMake
    同时构建静态库和动态库
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)

最终bin目录下会出现libhello.a和libhello.so两个库
CMake
安装动态库和静态库
1、在lib的CMakelists.txt文件中添加

//文件放到该目录下
INSTALL(FILES hello.h DESTINATION include/hello)
//二进制,静态库,动态库安装都用到TARGETS
//ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME特指可执行目标二进制
INSTALL(TARGET hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

2、切换到build目录下,执行 cmake -D CMAKE_INSTALL_PREFIX=/usr …(-D CMAKE_INSTALL_PREFIX=/usr指定安装的默认路径)
3、make编译生成静态库和动态库
4、make install 安装头文件与静态、动态库
最终结果:
CMake

使用外部共享库和头文件

新建一个目录来使用外部共享库和头文件
CMake外层的CMakeLists.txt

PROJECT(HELLO)
# 将生成的二进制文件放入bin中
ADD_SUBDIRECTORY(src bin)

src下的CMakeLists.txt

# 生成可执行文件hello
ADD_EXECUTABLE(hello main.cpp)

main.cpp

#include<hello.h>int main()
{HelloFunc();
}

开始构建项目:

  • 进入build,cmake …

  • make,报错,说找不到头文件。解决办法:使用关键字INCLUDE_DIRECTORIES 添加头文件搜索路径,路径之间用空格分割。
    在src的CMakelists.txt文件中添加

# 加入头文件搜索路径  在上面安装静态库与动态库时马,我们将头文件存储在了/usr/include/hello/目录下下
INCLUDE_DIRECTORIES(/usr/include/hello)
  • 添加完成后重新cmake… ,make,又继续报错:对‘HelloFunc()’未定义的引用。解决办法:使用关键字TARGET_LINK_LIBRARIES 添加需要连接的共享库。在src的CMakelists.txt文件中添加
# 添加共享库的连接 hello为生成的二进制文件 ,libhello.so为共享库
TARGET_LINK_LIBRARIES(hello libhello.so)
  • 添加完成后重新cmake… ,make,成功,进入bin目录,执行生成的可执行目标文件hello
    CMake执行报错,找不见共享库
    CMake
    原因,我们的Linux是64位的,我们的共享库存放在/usr/lib/目录下,需要将其移动到/usr/lib64/目录下:
mv /usr/lib/libhello.so /usr/lib64/

继续执行./hello,成功执行。