简单介绍

我们一般使用makefile文件组织大型C/C++或者含有多个C/C++文件的项目,有人认为makefile不太方便,于是发明了CMake。

CMake将含有CMake指令的文件生成makefile文件,含有CMake指令的文件的名称一般是CMakeLists.txt,使用CMake是在实际开发中组织和管理C/C++项目的常用方式,也适用于大多数C/C++开源项目。

对于Linux下的一些开源项目,执行configure命令后一般会生成CMakeList.txt文件,接着执行CMake命令会生成makefile规则文件,然后执行make命令利用gcc/g++对项目进行编译。也有部分开源项目,执行configure命令后会直接生成makefile规则文件,然后执行make命令利用gcc/g++对项目进行编译。

请添加图片描述


CMakeList.txt的样例如下:

cmake_minimum_required(VERSION 2.6)

project (FLAMGINGO_SERVER)

#CMAKE_CXX_FLAGS 指定g++编译选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -g -Wall -o0 -Wno-unused-variable -pthread")

link_directories(
	${PROJECT_SOURCE_DIR}/lib
	/usr/lib64/mysql/
)

set(net_srcs
base/AsyncLog.cpp
base/ConfigFileReader.cpp
base/Platform.cpp

net/Acceptor.cpp
net/BytesBuffer.cpp
net/Channel.cpp
)

set(mysqlapi_srcs
mysqlapi/DatabaseMysql.cpp
mysqlapi/Field.cpp
mysqlapi/QueryResult.cpp
)

set(chatserver_srcs
chatserversrc/main.cpp
chatserversrc/ChatServer.cpp
chatserversrc/ChatSession.cpp
)

set(fileserver_srcs
fileserversrc/main.cpp
fileserversrc/FileServer.cpp
fileserversrc/FileSession.cpp	
)

set(imgserver_srcs
imgserversrc/main.cpp
fileserversrc/FileServer.cpp
fileserbersrc/FileSession.cpp
)

add_executable(chatserver ${net_srcs} ${chatserver_srcs} ${mysqlapi_srcs})
#只包含库目录是没用的,还必须使用TARGET_LINK_LIBRARIES链接该库
#指定生成的二进制文件依赖的其他库
TARGET_LINK_LIBRARIES(chatserver mysqlclient)

add_executable(fileserver ${net_srcs} ${fileserver_srcs})
#指定生成的二进制文件依赖的其他库
TARGET_LINK_LIBRARIES(fileserver)

add_executable(imgserver ${net_srcs} ${imgserver_srcs})
#指定生成的二进制文件依赖的其他库
TARGET_LINK_LIBRARIES(imgserver)

样例二:

PROJECT(TRADE)

#指定源码目录
AUX_SOURCE_DIRECTORY(./ SRC_LIST)

#EXECUTABLE_OUTPUT_PATH 指定输出二进制文件路径
SET(EXECUTABLE_OUTPUT_PATH ../bin)

ADD_DEFINITIONS(-g -o0 -W -Wall -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DAC_HAS_INFO -DAC_HAS_WARNING -DAC_HAS_ERROR -DAC_HAS_CRITICAL -DTIXML_USE_STL -DHAVE_CXX_STDHEADERS -Wno-deprecated ${CMAKE_CXX_FLAGS})

#指定include目录
INCLUDE_DIRECTORIES(
./
/usr/local/include/commonlib/json2
/usr/local/include/commonlib/mysql
)

LINK_DIRECTORIES(
./
/usr/local/lib/commonlib
)

ADD_EXECUTABLE(trade ${SRC_LIST})

#指定生成的二进制文件依赖的其他库
TARGET_LINK_LIBRARIES(trade pthread netutil json2 mysqlclient dbapi)

下面是对以上代码中一些内容进行解析:

  1. 首行的cmake_minimum_required指令指定支持该CMakeList.txt文件的CMake最低版本号。
  2. project指令指定该项目的名称,注意,项目名称不是最终生成的二进制程序名,在一个项目下面可以生成多个二进制程序名。
  3. set定义和设置各种变量,set括号后的第一个名称是定义的变量名称,其后是变量的值。例如上面文件定义了CMAKE_CXX_FLAGS、net_srcs、mysqlapi_srcs、chatserver_srcs、fileserver_srcs、imgserver_srcs共6个变量。之后可以使用${变量名}引用这些变量。这些变量可以是内置的变量,例如CMAKE_CXX_FLAGS指定g++编译选项,EXECUTABLE_OUTPUT_PATH指定输出的二进制文件路径,也可以是自定义变量如chatserver_srcs、fileserver_srcs等。
  4. CMake使用AUX_SOURCE_DIRECTORY指令指定源码目录,使用INCLUDE_DIRECTORIES指令指定include目录,使用link_directories指定lib目录。
  5. CMake使用指令生成的动态库或静态库的名称,格式如下:
add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 .. sourceN)

例如:

add_library(hello hello1.cpp hello2.cpp)

我们不需要写全libhello.so或libhello.a,只需要填写hello即可,CMake会自动生成libhello.X。类型有如下三种:
a) SHARED:动态库(扩展名为.so)
b) STATIC:静态库(扩展名为.a)
c) MODULE:在使用dyld的系统中有效,若不支持dyld,则被当作SHARED对待。

EXCLUDE_FROM_ALL参数的意思是这个库不会被默认构建,除非有其他组件依赖或者手工构建。

如下命令会生成一个libkafkawrapper.so文件,且libapple.so文件的生成依赖librdkafka.so、librdkafka++.so、libcrypto.so、libssl.so这4个库:

add_library(libkafkawrapper SHARED ${kafka_wrapper_srcs})
TARGET_LINK_LIBRARIES(kafkawrapper rdkafka rdkafka++ crypto ssl)
  1. TARGET_LINK_LIBRARIES指定生成的二进制文件依赖的其他库。

最后,在编写完CMakeList.txt文件后,进入CMakeList.txt文件所在的目录,依次执行如下命令即可生成最终的二进制文件:

#利用cmake生成makefile
cmake .
#执行make命令,利用gcc/g++对makefile文件描述的源文件进行编译,最后生成最终的二进制文件
make

CMakeList.txt也支持递归执行,先执行父目录的CMakeList.txt文件,再执行子目录的CMakeList.txt文件。

凡是可以使用CMake编译的Linux程序(即提供了CMakeList.txt文件),我们都可以利用CMake生成Windows上的Visual Studio工程文件。


CMake简介

CMake是一种跨平台的开源项目管理工具,所做的事其实就是告诉编译器如何去编译链接源代码。与之相似的是直接编写makefile文件,但makefile最大的缺点就是不能跨平台,一旦更换环境就要重新编写,于是我们可以使用CMake编写CMakeLists文件来解决此问题。

检查是否安装CMake

首先检查是否安装CMake,在终端输入cmake --version来检查,若显示未安装,可以使用sudo apt-get install camke ( ubuntu),或者brew install cmake (macos),windows直接去官网下载,来安装CMake。

常用指令

#cmake最小版本需求
cmake_minimum_required(VERSION xxx)

#设置此项目的名称
project(xxx) 

#生成可执行文件target ,后面填写的是生成此可执行文件所依赖的源文件列表。
add_executable(target target_source_codes) 

# 设置一个名字var_name 的变量,同时给此变量赋值为var_value
SET(var_name var_value)

# 指定编译器
# CMAKE_C_FLAGS_DEBUG          ----  C 编译器
# CMAKE_CXX_FLAGS_DEBUG        ----  C++ 编译器
# -std=c++11  使用 C++11
# -g:只是编译器,在编译的时候,产生调试信息。
# -Wall:生成所有警告信息。一下是具体的选项,可以单独使用
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -std=c++11   -g  -wall  ")
add_definitions(${CMAKE_CXX_FLAGS})

#指定编译类型,debug 或者为 release
# debug 会生成相关调试信息,可以使用 GDB 进行
# release 不会生成调试信息。当无法进行调试时查看此处是否设置为 debug.
set(CMAKE_BUILD_TYPE Debug)

# 打印消息
MESSAGE("MSG") 

#给变量var_name赋值为var_value,comment是此变量的注释,和SET 有类似的功效,用于给某变量设置默认值
option(var_name "comment" var_value) 

# 添加include路径,也就是头文件路径
include_directories(xxx) 

# 调用xxx子目录的CMakeLists.txt执行
add_subdirectory(xxx) 

# 给编译器添加xxx参数
add_compile_options(xxx)

# 给编译器添加库目录,
link_directories(xxx)

# 生成库文件,SHARED代表动态库,STATIC代表静态库, 最后一个参数代表此库的源文件列表
add_library(lib_name SHARED or STATIC lib_source_code) 

# 给目标添加依赖库
target_link_libraries(target_name lib_name ...)

简单应用

下图是一般的项目文件格式,include 存放头文件,src存放源代码文件,build存放临时编译文件。
在这里插入图片描述
假设工程文件夹名为Test,我们可以将CMakeLists.txt文件放在Test文件夹下,也就是src,include的同级目录下,以下是简单的CMakeLists文件编写格式。

# 最低指定的CMake版本
cmake_minimum_required(VERSION 3.0)

# 括号里面填你的工程名
PROJECT(Test)

# 头文件路径
INCLUDE_DIRECTORIES(include)
INCLUDE_DIRECTORIES(/usr/local/include/)

# 查找src下的所有cpp文件,然后将结果存进指定变量名(这里是DIR_SRCS)
AUX_SOURCE_DIRECTORY(src DIR_SRCS)

# 指定语言要求,以下命令为c++ 11
SET(CMAKE_CXX_STANDARD 11)

# 生成可执行文件,生成的test即为可执行文件
add_executable(test ${DIR_SRCS})

由于该过程中会产生很多中间文件,因此我们在build文件夹下使用cmake命令,这样这些文件就都放在build文件夹下,然后make运行就好:

cd build
cmake ..
make
./test
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐