【c++编译】makefile与CMake【转】
我们一般使用makefile文件组织大型C/C++或者含有多个C/C++文件的项目,有人认为makefile不太方便,于是发明了CMake。CMake将含有CMake指令的文件生成makefile文件,含有CMake指令的文件的名称一般是CMakeLists.txt,使用CMake是在实际开发中组织和管理C/C++项目的常用方式,也适用于大多数C/C++开源项目。对于Linux下的一些开源项目,执
makefile与CMake
简单介绍
我们一般使用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)
下面是对以上代码中一些内容进行解析:
- 首行的cmake_minimum_required指令指定支持该CMakeList.txt文件的CMake最低版本号。
- project指令指定该项目的名称,注意,项目名称不是最终生成的二进制程序名,在一个项目下面可以生成多个二进制程序名。
- 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等。
- CMake使用AUX_SOURCE_DIRECTORY指令指定源码目录,使用INCLUDE_DIRECTORIES指令指定include目录,使用link_directories指定lib目录。
- 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)
- 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
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)