将一个 makefile 项目转化为 CMake 项目

前言

在 GitHub 看到一个 Web 服务器项目,想用来回顾一下网络编程方面的知识。发现这是一个由 makefile 构建的项目,而现在主流的构建方式是 CMake,所以想先把它转化为一个 CMake 项目。主要是根据项目结构以及 makefile 文件编写 CMakeLists.txt。

准备工作

  • 在 Linux 中安装 MySQL,推荐在 docker 中安装。(踩坑:一开始是直接在 Linux 中安装,后来想改成 docker 安装,在 docker 中安装后启动时报错端口被占用和一个别的错误,最后发现是一开始直接安装的 MySQL 和 docker 中的冲突的,原来的 mysqld 进程一直占用着 3306 端口, kill -9 也杀不掉,最后把直接安装的 MySQL 卸载干净了才能顺利启动 docker 中的 MySQL)
  • 安装 mysql 开发库:sudo apt-get install libmysqlclient-dev (安装在 /usr/include/mysql 目录下)

项目结构

这个项目有三个分支,我选择从 raw_version 分支入手。该分支的项目结构如下:

有些模块的接口定义(.h)和实现(.cpp)分离了而有些模块没有,个人觉得这是一个不够规范的地方。makefile 文件的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server: main.c \
./threadpool/threadpool.h \
./http/http_conn.cpp ./http/http_conn.h \
./lock/locker.h ./log/log.cpp ./log/log.h ./log/block_queue.h \
./CGImysql/sql_connection_pool.cpp ./CGImysql/sql_connection_pool.h

g++ -o server \
main.c \
./threadpool/threadpool.h \
./http/http_conn.cpp ./http/http_conn.h \
./lock/locker.h ./log/log.cpp ./log/log.h \
./CGImysql/sql_connection_pool.cpp ./CGImysql/sql_connection_pool.h \
-lpthread -lmysqlclient


clean:
rm -r server

总体来说是比较简单的。这里将一些头文件(.h)也一并加入,我尝试过去掉这些头文件后同样能正常编译运行。

编写 CMakeLists.txt

首先新建了 include 文件夹,在其中放置各个模块的头文件,定义和实现没有分离的也一并放入其中。此时项目结构如下:

根据此时的项目结构,结合已有的 makefile 文件编写 CMakeLists.txt 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cmake_minimum_required(VERSION 3.0) 

project(WebServerCmake)

set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")

set(path ${CMAKE_SOURCE_DIR})

# 引入头文件搜索目录
include_directories(${path}/include)

# 生成可执行文件(比起原来的 makefile 少了一些 .h 头文件)
add_executable(WebServerCmake
main.cpp
CGImysql/sql_connection_pool.cpp
log/log.cpp
http/http_conn.cpp)

# 链接动态库,对应于原 makefile 中的 -lpthread -lmysqlclient
target_link_libraries(WebServerCmake libmysqlclient.so)
target_link_libraries(WebServerCmake libpthread.so)

还需要修改一下修改后文件的 #include 路径;之后运行下面的命令后就可以构建并运行项目了:

1
2
3
4
mkdir build && cd build
cmake ..
make
./WebServerCmake 1256

在 vscode 中运行并调试项目

主要是配置 .vscode 文件夹中的 launch.json 和 tasks.json。在 vscode 中启动 c++ 项目调试便是依靠这两个文件的配置

tasks.json 中的命令会在 launch.json 中的 命令之前前执行,即对应preLaunchTask,可以在 tasks.json 中配置执行 cd build && cmake … && make 这些命令

tasks.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{   
"version": "2.0.0",
"options": {
"cwd": "${workspaceFolder}/build" // 进入 build 文件夹
},
"tasks": [
{
// 运行 cmake .. 命令
"type": "shell",
"label": "cmake",
"command": "cmake",
"args": [
".."
]
},
{
// 运行 make 命令
"label": "make",
"group": {
"kind": "build",
"isDefault": true
},
"command": "make",
"args": [

]
},
{
"label": "Build",
"dependsOrder": "sequence", // 按列出的顺序执行任务依赖项
"dependsOn":[
"cmake",
"make"
]
}
]
}

launch.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"version": "0.2.0",
"configurations": [
{
"name": "g++ - 生成和调试活动文件",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/WebServerCmake", // 可执行文件的位置
"args": [
"1256" // 命令行启动时的参数 ./WebServerCmake 1256
],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "Build", // 这里要和 task.json 中 的 Build 一致
"miDebuggerPath": "/usr/bin/gdb"
}
]
}

参考