CMake入门笔记

2019-09-04 16:50:35

参考地址  CMake入门笔记

什么是CMake

CMake


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


Make


make工具是一个简化编译工作程序,有了它我们可以进行所谓的“自动化编译”,极大地提高了软件开发的效率。make工具相当于一个Shell,通过解释Makefile的中的命令进行工作。大多数IDE都有这个工具,比如:Visual C++的nmake,Linux下GNU的make。 

make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作。而makefile 文件需要按照某种语法进行编写,文件中需要说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系。


直白点说就是,CMake用来生成makefile或者是工程文件,make是用来解释makefile的。 

以Linux平台下使用gcc编译为例,我们想要编译源文件可以直接在命令行中执行gcc test.c -o test之类的命令,可是文件多了,工程复杂,而且文件不时的还会变,每次这样输多麻烦。 

这个时候make就有了用武之地,写个makefile,以后编译就直接make解释下makefile,根据makefile来执行编译命令。这样在linux上是很好,在windows上或者其他平台上怎么办呢? 

这时候就到cmake出马了,构建工程的时候,不在写makefile,而写CMakeLists.txt。需要编译的时候,先用Cmake解释CMakeLists.txt。如果在Windows平台上,设置编译器是VS,CMake就生成一个VS的工程,然后用VS来运行编译项目。如果是在Linux平台上,编译器是gcc,CMake就生成makefile,然后用make来解释makefile编译项目。 

如图,分别为原始目录、在Linux下选择gcc为编译工具生成的工程文件和在WIndows下选用Visual Studio为编译器生成的工程文件: 



cmake执行后会在cmake执行时所在的目录生成许多文件,根据cmake执行目录是否与源文件同目录,将构建方式分为两种:


out-of-source build,构建输出文件与源文件放到不同目录中;

in-source build :构建输出文件与源文件放到相同目录中。

一般选择out-of-source方式,可以在项目目录下建立一个build文件,然后进入build下,执行cmake ../,使生成的文件都在build文件夹下,以便后期清理。


示例

为了编译与演示方便,示例全部在Linux下进行。


Hello, CMake!

CMake最简单的实例,目录结构如下: 

 

main.c文件:


 #include <stdio.h>


int main(int argc, char *argv[])

{

    printf("Hello, CMake!\r\n");


    return 0;

}

1

2

3

4

5

6

7

8

CMakeLists.txt文件


 # 版本限定

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)                      

# 项目名称

PROJECT(Test1)

# 添加源文件列表变量

SET(SRC_LIST main.cpp)

# 打印编译目录和项目目录路径

MESSAGE(STATUS "This is SOURCE dir " ${PROJECT_SOURCE_DIR})

# 生成可执行文件

ADD_EXECUTABLE(HelloCMake ${SRC_LIST})

1

2

3

4

5

6

7

8

9

10

然后进入项目目录,依次执行(需要确保linux下安装了gcc、make等):


mkdir build

cd build

cmake ../

1

2

3

此时,build文件夹内容如下: 

 

。然后键入make命令,即解析了Makefile文件,build目录下的内容变为: 

 

可以看到,生成了一个HelloCMake的可执行文件,键入./HelloCMake可以运行HelloCMake文件。 

bash执行输出过程如下: 



同一目录多个源文件

在实际使用中,很少会出现这么简单的情况,往往在一个文件夹中会存在多个源文件要求编译,目录如下,这时候只需要在SET后面加上需要编译的源文件就可以了。 

 

CMakeLists.txt文件:


# 版本限定

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)                      

# 项目名称

PROJECT(Test2)

# 添加源文件列表变量

SET(SRC_LIST Stupid.cpp main.cpp)

# 打印编译目录和项目目录路径

MESSAGE(STATUS "This is BINARY dir " ${PROJECT_BINARY_DIR})

MESSAGE(STATUS "This is SOURCE dir " ${PROJECT_SOURCE_DIR})

# 生成可执行文件

ADD_EXECUTABLE(Test2 ${SRC_LIST})

1

2

3

4

5

6

7

8

9

10

11

上述方式虽然可行,但是如果源文件过多,CMakeLists.txt文件编写起来也是一件很吃力的事情,这时候,可以用aux_source_directory来解决这个问题。aux_source_directory可以遍历指定文件夹的下源文件,将它们统一复制给一个变量,然后进行编译。


CMakeLists.txt文件2:


# 版本限定

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)                      

# 项目名称

project(Test3)


# 遍历当前目录所有的源文件,赋值给test3src

aux_source_directory(. test3src)

message(STATUS "src file : " ${test3src})

# 生成可执行文件

add_executable(Test3 ${test3src})

1

2

3

4

5

6

7

8

9

10

不同目录下的多个源文件

为了使源码更为清晰,源码往往会根据不同的功能,将代码放在不同的文件夹下,结构如图: 

 

这时候CmakeLists.txt文件又该如何编写呢?答案如下:


# 版本限定

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)                      

# 项目名称

project(Test3)


# 遍历当前目录所有的源文件,赋值给test3src

aux_source_directory(. main)

aux_source_directory(./stupid stupid)

set(test4src ${main} ${stupid})

message(STATUS "src file : " ${test4src})


# 生成可执行文件

add_executable(Test4 ${test4src})

1

2

3

4

5

6

7

8

9

10

11

12

13

编译动态库与静态库

在前面的示例中,我们都是直接生成了可执行文件,而更多的时候,我们需要生成的不是可执行文件,而是一个可以让复用的库文件,这时候只需要将add_executable(Name ${srcTemp})修改为add_library(Name ${srcTemp})就可以了。add_library可以在中间增加一个参数表示动态库或静态库,默认无参数为静态库。


# 版本限定

cmake_minimum_required(VERSION 2.8)


# 遍历当前目录所有的源文件,赋值给STUPID_SRC

aux_source_directory(. STUPID_SRC)

# 编译STUPID_SRC为静态库

add_library(stupid STATIC ${STUPID_SRC})

# 编译STUPID_SRC为动态库

# add_library(stupid SHARED ${STUPID_SRC})

1

2

3

4

5

6

7

8

9

库文件和头文件导出到指定位置

编译出的库文件是要使用的,而库文件的使用一般需要库文件和头文件。虽然可以编译出库后自己整理库文件和头文件,但是终归是一件麻烦事,尤其是工程比较庞大的时候。这时候,我们可以使用INSTALL来将库文件和头文件导出到指定位置。


# 版本限定

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(OUTPUT ${CMAKE_CURRENT_BINARY_DIR})

AUX_SOURCE_DIRECTORY(. STUPID_SRC)

# 设置库文件输出目录

# SET(LIBRARY_OUTPUT_PATH ${LIB_DIRS})

# 创建动态库

ADD_LIBRARY(stupid SHARED ${STUPID_SRC})

# 导出动态库

INSTALL(TARGETS stupid DESTINATION ${OUTPUT}/libs)

# 导出头文件

INSTALL(DIRECTORY . DESTINATION ${OUTPUT}/include/stupid 

    FILES_MATCHING PATTERN "*.h")

1

2

3

4

5

6

7

8

9

10

11

12

13

然后进入项目目录/build/ 目录下,依次执行:


cmake ../

make 

make install

1

2

3

即可在build下生成以下结构: 

 

include为头文件目录,其中包含了stupid/stupid.h文件。libs为库文件目录,其中包含了libstupid.so文件。


使用动态库/静态库

在上一个示例中,我们生成并导出了动态库,现在来使用它。复制出上个示例导出的libs及include文件夹,形成以下结构: 

 

CMakeLists.txt文件内容如下:


# 版本限定

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)                      

# 项目名称

PROJECT(Test8)

# 遍历当前目录所有的源文件,赋值给test3src

AUX_SOURCE_DIRECTORY(. main)

MESSAGE(STATUS "src file : " ${main})

# 指定库文件搜索目录,必须为绝对路径

LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/libs)

# 生成可执行文件

ADD_EXECUTABLE(Test8 ${main})

# 指定头文件目录

INCLUDE_DIRECTORIES(./include)

# 指定目标需要连接的库

TARGET_LINK_LIBRARIES(Test8 stupid)


  • 2020-03-16 16:03:20

    css的var()函数

     随着sass,less预编译的流行,css也随即推出了变量定义var函数。var()函数,就如同sass和less等预编译软件一样,可以定义变量并且进行对应的使用。

  • 2020-03-16 16:52:05

    对icomoon的误解,以及最快速的使用

    此时需要注意顶部第一个选项,Quick Usage,一定要打开,Enable Quick Usage,谁让咱英语不好呢,这个时候会出现一个css连接,直接引用就好了,就可以随意使用图标了,引入这一个css就能实现我们的功能,省区引入太多文件的烦恼,你可以在浏览器打开这个css,可以看到里面把我们所用的文件整成base64了。所以挺好用的。

  • 2020-03-17 09:47:05

    video标签视频不自动播放的问题

    添加 muted 属性,就可以通过地址栏进入网页的时候自动播放了,手机端还是有的有限制的,比如iphone浏览器,就不行,苹果手机为了保护用户的流量和用户的意愿,是禁止自动播放的,必须有手动触发。

  • 2020-03-17 14:21:31

    nuxt+pm2 自动化部署及打包后文件自动上传阿里云 oss(精华)

    部署nuxtjs,这一篇文章就够了,pm2 代码自动发布依赖于 git 工具,先将 ssh 密钥配置再你的代码仓库(github 或者 gitLab),具体操作自行 google 或者点击github 配置 ssh。 使用 ssh 密钥链接服务器 s $ ssh-copy-id root@1.2.3.4 # 把本机的 SSH 秘钥添加至服务器,配置成功后,以后就不需要再执行这条 SSH 命令了

  • 2020-03-18 21:15:34

    使用canvas画布解决百度地图自定义图层全球连续显示问题

        基于百度地图的Web API进行自定义图层叠加时,默认的图层只能叠加到全球范围以内,即经度范围为[-180, 180],而无法将图层叠加到默认的全球范围以外,即经度范围超出了[-180, 180]之后,经纬度坐标会自动回归到(0, 0),而导致在地图拖拽时全球以外无法连续显示想要的图层,此时可以基于百度地图的自定义图层将经纬度坐标转为像素点使用画布canvas来解决该问题。解决后效果如下图所示: ———————————————— 版权声明:本文为CSDN博主「宏伟杰作」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/u011284073/article/details/80549950

  • 2020-03-18 21:18:01

    node-canvas实现百度地图个性化底图绘制

    随着nodejs的推出,node的并发和异步的强大能力,越来越多的得到应用,而且取得了非常不错的效果。 作为一个前端工程师对node.js自然有着一份更深的感情,跃跃欲试的心情,总希望能将它应用到产品中来。

  • 2020-03-18 21:19:28

    高德地图和canvas画图结合应用的一些感想(一)

    入了团队才发现,该项目前后端分离,后端工程师已就位主要实现接口,IOS端工程师也已就位,还差一个web前端工程师。背脊一凉,我之前虽然写过一些js和css,虽有点功底但是离前端工程师还是有距离的啊。在和朋友说明情况后,朋友也是胆大,让我试试,主要他实在找不到人了(也有可能目前前端工程师报价都太贵了,创业嘛,能节约就节约,能理解。。。),没办法,走一步算一步吧。