CMake的官方定义:CMake是一个开源的跨平台自动化构建系统,用来管理软件建制的程序,并不依赖于某个特定编译器。CMake并不直接构建出最终的软件,而是产生标准的建构档(如Unix的Makefile或Windows Visual C++的projects/workspaces),然后再依一般的构建方式使用。它允许开开发者编写一种平台无关的CMakeList.txt文件来定制整个变异流程,然后再更具目标用户的平台进一步生成所需的本地化Makefile和工程文件,如Unix的Makefile或Windows的Visual Studio工程。从而做到一次编码,然后在任何平台编译运行。总结为一句话就是,CMake解决了软件跨平台编译的问题。
CMake的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的。符号#后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。
1、命令不区分大小写,而参数和变量是区分大小写的;
2、使用“#”表示代码注释;
3、使用${}表示引用变量的值;
4、使用set(变量名称 变量值)来自定义变量。
本文只介绍CMake常用命令,如果不能满足读者的需要,可以参见官网,https://cmake.org/cmake/help/v3.7/manual/cmake-commands.7.html。
1、CMake最低版本号要求
cmake_minimum_required(VERSION 3.10)2、语法说明
2、指定项目名称
project(myProject)
3、查找当前目录下的所有源文件并将名称保存到DIR_SRCS变量,注意“.”和DIR_SRCS之间有空格
aux_source_directory(. DIR_SRCS)
4、生成可执行文件
add_executable(myProject ${DIR_SRCS})
5、将若干库链接到目标库文件
target_link_libraries(myProject common) #链接common库,默认优先链接动态库,common可以包含库名称的路径,也可以仅仅是库名称
target_link_libraries(myProject libcommon.a) #显示指定链接静态库
target_link_libraries(myProject libcommon.so) #显示指定链接动态库
target_link_libraries(myProject lib1 lib2 lib3 …) #链接的顺序应当符合GCC的链接顺序规则,被链接的库放在依赖它的库的后面,即如果上面的命令中,lib1依赖于lib2,lib2又依赖于lib3,则上述命令中必须严格按照lib1 lib2 lib3的顺序排列,否则会报错。也可以自定义链接选项,比如针对lib1使用-WL选项:target_link_libraries(myProject lib1 –WL, lib2 lib3 …)。
6、生成静态链接库/动态链接库
add_library(myProject [SHARED|STATIC] source1 source2 … sourceN)
add_library(myProject SHARED ${LIBMYPROJECT_SRC}) #生成动态链接库
add_library(myProject STATIC ${LIBMYPROJECT_SRC}) #生成静态链接库
7、设置依赖库的头文件位置,相当于G++命令中的-I选项的作用,可以使用相对或绝对路径,也可以使用自定义的变量值,其中相对路径是相对于当前源目录:
include_directories(${INC_DIR}) #INC_DIR保存了头文件的路径信息
8、添加需要链接的库文件目录,相当于G++命令中的-L选项的作用。
link_directories(${LINK_DIR}) # LINK_DIR保存了库文件的路径信息
9、添加需要链接的库文件
link_libraries(library1 library2 … liararyN)
10、设置全局变量
#设置可执行文件的输出路径
set(EXECUTABLE_OUTPUT_PATH [output_path])
#设置库文件的输出路径
set(LIBRARY_OUTPUT_PATH [output_path])
#设置C++编译参数
set(CMAKE_CXX_FLAGS “-Wall std=c++11”)
#设置源文件集合
set(SOURCES_FILES main.cpp test.cpp …)
#设置编译类型:Debug或者Release。Debug版本会生成相关的调试信息,可以使用GDB进行调试;Release不会生成相关的调试信息。
set(CMAKE_BUILD_TYPE DEBUG)
#设置编译器类型
set(CMAKE_C_FLAGS_DEBUG “-g -Wall”)
#启用特定C++标准,下面两条语句一般一起使用
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
11、如果当前目录下还包含子目录时,可以使用add_subdirectory语句,但是子目录中也需要包含有CMakeLists.txt文件
#sub_dir指定包含CMakeLists.txt和源文件的子目录位置,可以是相对路径
#binary_dir是输出路径,一般可以不指定
add_subdirectory(sub_dir [binary_dir])
12、文件操作命令
#将message写入filename文件中,会覆盖文件原有内容
file(WRITE filename “message”)
#将message写入filename文件中,会追加在文件末尾
file(APPEND filename “message”)
#重命名文件
file(RENAME
#删除文件,相当于rm命令
file(REMOVE [file1 file2 …])
#创建目录
file(MAKE_DIRECTORY [dir1 dir2 …])
#该命令把该文件夹及所有子文件夹的所有后缀为.cpp的文件路径,全部放入SRC_LIST变量中,其它命令类似
file(GLOB_RESOURCE SRC_LIST “*.cpp”)
file(GLOB_RESOURCE HEARDERS “*.h”)
file(GLOB_RESOURCE FORMS “*.ui”)
file(GLOB_RESOURCE RESOURCES “*.qrc”)
13、查找库所在目录,并将查找到的路径放入到变量中
#cmake会在路径”/usr/lib”和”/usr/local/lib”中查找rt库,如果路径中存在rt库,则路径信息会被保存在变量RUNTIME_LIB中,否则被赋值为NO_DEFAULT_PATH
find_library(RUNTIME_LIB rt /usr/lib /usr/local/lib NO_DEFAULT_PATH)
14、定义目标依赖的其他目标,确保在编译本目标之前,其他目标已经被构建
add_dependencies(target-name depend-target1 depend-target2 …)
15、打印CMake脚本运行过程中的信息
message(STATUS “This is message”) #将“This is message”打印到标准输出
1、CMAKE_BINARY_DIR、PROJECT_BINARY_DIR、
这三个变量指代的内容是一致的,如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录。PROJECT_BINARY_DIR 跟其他指令稍有区别, 目前可暂时理解为他们是一致的。
2、CMAKE_SOURCE_DIR、PROJECT_SOURCE_DIR、
这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录。也就是在 in source 编译时,他跟 CMAKE_BINARY_DIR 等变量一致。PROJECT_SOURCE_DIR 跟其他指令稍有区别,目前可暂时理解为他们是一致的。
3、CMAKE_CURRENT_SOURCE_DIR
指的是当前处理的 CMakeLists.txt 所在的路径。
4、CMAKE_CURRRENT_BINARY_DIR
如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致,如果是 out-of-source 编译,他指的是 target 编译目录。使用我们上面提到的 ADD_SUBDIRECTORY(src bin)可以更改这个变量的值。使用 SET(EXECUTABLE_OUTPUT_PATH <新路径>)并不会对这个变量造成影响,它仅仅修改了最终目标文件存放的路径。
5、CMAKE_CURRENT_LIST_FILE
输出调用这个变量的 CMakeLists.txt 的完整路径。
6、CMAKE_CURRENT_LIST_LINE
输出这个变量所在的行。
7、CMAKE_MODULE_PATH
这个变量用来定义自己的 cmake 模块所在的路径。如果你的工程比较复杂,有可能会自己编写一些 cmake 模块,这些 cmake 模块是随你的工程发布的,为了让 cmake 在处理CMakeLists.txt 时找到这些模块,你需要通过 SET 指令,将自己的 cmake 模块路径设置一下。比如SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),这时候你就可以通过 INCLUDE 指令来调用自己的模块了。
8、EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH
分别用来重新定义最终结果的存放目录,前面我们已经提到了这两个变量。
9、PROJECT_NAME
返回通过 PROJECT 指令定义的项目名称。
首先下载CMake安装包,官方下载路径:https://cmake.org/download/,找到本地系统对应的安装包并下载。
1、windows系统CMake环境搭建
可以参考该链接:https://jingyan.baidu.com/article/6d704a1352dbb728db51ca8e.html,这里不在赘述。
2、linux系统CMake环境搭建
将下载的linux版本的压缩包解压(安装前保证GCC编译器已经正确安装),在控制台进入CMake工具目录,然后一次输入一下三个命令进行安装:#./bootstrap#gmake#make install,安装完成后即可在控制台中直接使用CMake命令测试,检测是否安装成功。
环境搭建详细步骤参考:https://blog.csdn.net/liuguichenglove/article/details/84196271
1、文件目录结构
├── CMakeLists.txt
├── public
│ └── include
│ └── *.h
│ └── lib
│ └── *.lib
└── src
├── b.c
└── main.c
2、编写CMakeLists.txt
接下来编写CMakeLists.txt文件,该文件放在和src,public的同级目录下,public目录下又包含include(存放头文件)文件夹和lib(存放库文件)文件夹,实际放哪里都可以,只要里面编写的路径能够正确指向就好了。CMakeLists.txt如下所示:
#1、cmake version,指定cmake最低版本
cmake_minimum_required(VERSION 3.10)
#2、指定项目名称,一般和项目的文件名称对应
project(VideoSDK)
#3、设置源文件目录,下面这条语句的意思是将src文件夹中所有源文件保存到变量DIR_SRCS,其中src是相对路径,相对CMakeLists.txt的文件路径。
aux_source_directory(src DIR_SRCS)
#4、设置c++11标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED Ture)
#5、设置环境变量,将头文件路径保存到INC_DIR变量,将库文件所在路径保存到变量LINK_DIR
set(INC_DIR "${CMAKE_SOURCE_DIR}/public/include")
set(LINK_DIR "${CMAKE_SOURCE_DIR}/public/lib")
#6、包含头文件路径
include_directories(${INC_DIR})
#7、附加库目录
link_directories(${LINK_DIR})
#8、添加工程依赖的三方库,由于库文件太多,不一一列出。AnalyzeData.lib等文件存放在lib文件夹中。
link_libraries(AnalyzeData.lib AudioIntercom.lib CrashAPI.lib … )
#9、生成动态链接库,该语句表示工程编译后生成的不是可执行文件,而是动态链接库。若要生成可执行文件,可使用add_executable代替该语句。
add_library(VideoSDK SHARED ${DIR_SRCS})
#10、dd link library,添加生成动态库需要依赖的三方库。 由于依赖的三方库文件太多,不一一列出。
target_link_libraries(VideoSDK AnalyzeData AudioIntercom CrashAPI … )
3、生成工程文件
打开CMake软件,如图1所示
图1 CMake软件界面
如上图所示:
(1)选择源码路径,2.1中所说明的文件路径结构就存放在E:/CMakeProject/VideoSDKTest/VideoSDK 路径中。
(2)选择在VideoSDK的同级目录下创建一个名为build的文件夹,把build文件夹的路径加到图1的红框2中。
(3)点击Configure按钮,弹出图1中的右侧对话框,该对话框提示选择编译器版本,选择自己对应的VS版本就行了。
(4)点击finish,需要等待一段时间。
(5)再次点击Configure按钮。
(6)点击Generate。build文件夹下可以看到VideoSDK.sln工程,如图2所示。
图2 生成的VideoSDK工程
本文介绍了什么是CMake,CMake解决了什么问题,CMake常用的命令,如何编写CMakeLists.txt,以及CMake在Windows系统上如何使用。目前只是完成了在Windows系统上利用CMake和源码来创建工程,后续还会总结如何在linux系统上使用CMake和源码来创建工程并实现编译,以及CMake在linux系统上使用的注意事项。