基于CLion IDE的CPP项目构建与运行
Published in:2023-12-01 |
Words: 3.5k | Reading time: 18min | reading:

基于Clion IDE的CPP项目构建与运行

工具基本信息

1.CLion

CLion:
A cross-platform IDE for C and C++
CLion takes a lot of the toil out of C++, allowing me to concentrate on the interesting part: problem solving.

  • 下载地址
    1
    https://www.jetbrains.com/clion/download/#section=windows

2.MingW

A complete runtime environment for GCC & LLVMfor 32 and 64 bit Windows

  • 下载地址(x64、posix、.seh版本)
    1
    https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/
  • 如图

3.CMake

CMake允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件

  • 基本指令
1
2
3
4
5
6
7
8
9
cmake_minimum_required:指定运行此配置文件所需的 CMake 的最低版本;
project:参数值是 Demo1,该命令表示项目的名称是 Demo1 。
add_executable:将名为 main.cc 的源文件编译成一个名称为 Demo 的可执行文件
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)

# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
  • 举例
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
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo4)

# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)

# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON)

# 是否加入 MathFunctions 库
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/math")
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

# 指定生成目标
add_executable(Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})

工具安装构建

CLion

1.新建cpp项目

如图

2.编写测试代码

  • 1.src/test.cpp

    定义socket套机字,构建socket服务端;实现登录、登出、数据转发等功能

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    #include <thread>
    #include <fstream>
    #include "tcpSocket.h"
    #include "Clog.h"
    #include "tcpSocket/MySocket.hpp"
    #include "WebServer.h"
    #include "tinyxml2.h"
    #include "xmlParser.h"

    // 客户�?信息结构�?
    struct SockInfo {
    sockaddr_in addr;
    int fd;
    };

    // 登录状态记录
    typedef struct
    {
    char UserName[32];
    int SocketID;
    }loginPool;

    // ------------------------------------------------------------------------
    // 用户登录验证代码部分

    std::vector<loginPool> login_pool_vect;

    // 检查用户ID是否存在与容器内,如果存在则返回用户名
    bool is_login(std::vector<loginPool> &ptr, int socket_id)
    {
    for (auto & x : ptr)
    {
    if (x.SocketID == socket_id)
    {
    return true;
    }
    }
    return false;
    }

    // 用户登录验证
    bool login(char *username, char *password, int socket_id)
    {
    if ((strcmp(username, "admin") == 0) && (strcmp(password, "123456") == 0))
    {
    // 如果在则增加一个socket登录标志
    loginPool pool_ptr;
    pool_ptr.SocketID = socket_id;
    strcpy(pool_ptr.UserName, "admin");

    login_pool_vect.push_back(pool_ptr);
    return true;
    }
    else if ((strcmp(username, "admin") == 0) && (strcmp(password, "123456") == 0))
    {
    // 如果在则增加一个socket登录标志
    loginPool pool_ptr;
    pool_ptr.SocketID = socket_id;
    strcpy(pool_ptr.UserName, "admin");

    login_pool_vect.push_back(pool_ptr);
    return true;
    }
    return false;
    }

    // 根据传入ID从容器内弹出一个节点
    bool logout(std::vector<loginPool> &ptr, int socket_id)
    {
    for (auto it = ptr.begin(); it != ptr.end(); it++)
    {
    if (it->SocketID == socket_id)
    {
    // 弹出指定结构体
    ptr.erase(it);
    return true;
    }
    }
    return false;
    }

    void ClientPro(void* ptr)
    {
    // 初始化
    auto* pSock = (MySocket*)ptr;
    MySocket server_socket = *pSock;
    server_socket.Send((const char *)"Welcome to CPP WebSocket Server!", 31);

    // 获取客户端信息
    char sIp[20];
    UINT nPort;
    server_socket.GetPeerName(sIp, nPort);

    while (true)
    {
    char szBuffer[4096] = { 0 };
    int sid = pSock->GetSocketID();

    int ref = server_socket.Receive(szBuffer, sizeof(szBuffer));
    if (ref <= 0)
    {
    logout(login_pool_vect, sid);
    ilog->warn("client :{0}:{1} , [disconnect]",sIp,nPort);
    // std::cout << "客户: " << sIp << ":" << nPort << " [已断开]" << std::endl;
    break;
    }
    ilog->info("address:{0}:{1},receive command:{2} ",sIp,nPort,szBuffer);
    // std::cout << "地址: " << sIp << ":" << nPort << " 接收命令: " << szBuffer << std::endl;

    // 用户登录
    if (strcmp(szBuffer, "login\n") == 0)
    {
    char recv_username[32] = { 0 };
    char recv_password[32] = { 0 };

    // 接收用户名和密码
    pSock->Receive(recv_username, 32, 0);
    pSock->Receive(recv_password, 32, 0);

    ilog->info("account :{0}, password : {1}",recv_username,recv_password);
    // 验证登录状态
    bool login_flag = login(recv_username, recv_password, sid);
    if (login_flag == TRUE)
    {
    ilog->info("user :{0}, login .",recv_username);
    // std::cout << "用户: " << recv_username << " 已登录" << std::endl;
    pSock->Send("login", sizeof("login"), 0);
    }
    else
    {
    pSock->Send("account or password incorrect", sizeof("account or password incorrect"), 0);
    }
    }

    // 用户登出
    else if (strcmp(szBuffer, "logout\n") == 0)
    {
    // 验证是否登录成功
    int login_flag = is_login(login_pool_vect, sid);
    if (login_flag == TRUE)
    {
    ilog->info("user logout.");
    // std::cout << "用户已登出" << std::endl;
    logout(login_pool_vect, sid);
    pSock->Send("user logout.", sizeof("user logout."), 0);
    }
    else
    {
    ilog->warn("please login account!");
    // std::cout << "请先登录" << std::endl;
    pSock->Send("please login account!", sizeof("please login account!"), 0);
    }
    }

    // 遍历本机文件
    else if (strcmp(szBuffer, "list\n") == 0)
    {
    // 验证是否登录成功
    int login_flag = is_login(login_pool_vect, sid);
    if (login_flag == TRUE)
    {
    ilog->info("user has login , output current pc file ");
    // std::cout << "用户已登录,输出本机文件" << std::endl;
    pSock->Send("auth success!", sizeof("auth success!"), 0);

    // 循环输出数据包
    for (int x = 0; x < 10; x++)
    {
    char sz[1024] = { 0 };
    sprintf(sz, "count -> %d", x);
    pSock->Send(sz, sizeof(sz), 0);
    }
    }
    else
    {
    ilog->warn("please login account!");
    // std::cout << "请先登录" << std::endl;
    pSock->Send("please login account!", sizeof("please login account!"), 0);
    }
    }
    }
    }

    int startSocketServer(){
    MySocket sock;
    if (!sock.Create(8233, SOCK_STREAM, "127.0.0.1"))
    {
    return -1;
    }

    // 获取本机信息
    char sSevIp[20];
    UINT nSevPort;
    sock.GetSockName(sSevIp, nSevPort);
    ilog->info("server : {0},{1} ,server is running!",sSevIp,nSevPort);
    // std::cout << "服务端: " << sSevIp << ":" << nSevPort << " 服务器启动成功" << std::endl;

    sock.Listen(5);

    // 获取客户端信息
    char sIp[20];
    UINT nPort;

    MySocket ptr;
    while(true)
    {
    // 当有新用户进来自动创建一个线程来维持会话
    sock.Accept(ptr, sIp, &nPort);
    ilog->info("client : {0} :{1} [login]",sIp,nPort);
    // std::cout << "客户: " << sIp << ":" << nPort << " [已登录]" << std::endl;

    // 多线程
    _beginthread(ClientPro, 0, &ptr);
    }
    return 0;
    }

    std::string testR(wsProtocol ws) {
    return "asd";
    }

    std::string httpR(requestHttp httpRq) {
    return "httpR";
    }

    void XmlNodeGetVal(std::stringstream stringstream, tinyxml2::XMLElement *pElement, const char *string, const char *ip) {
    ip = pElement->Attribute(string);
    }

    int main() {
    // readXMLConfig("./../config.xml");
    startSocketServer();
    // startWebSocketServer();
    return 0;
    }

  • 2.include/test.h

    存放test.cpp中所需头文件与函数定义,变量定义.

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    #pragma once
    #include <WinSock2.h>
    #pragma comment(lib, "ws2_32.lib")

    class MySocket
    {
    protected:
    SOCKET m_hSocket;
    public:

    // 获取对端Socket用户IP端口等
    BOOL GetPeerName(char* rSocketAddress, UINT& rSocketPort)
    {
    sockaddr_in name = { AF_INET };
    int lenname = sizeof(name);
    if (getpeername(m_hSocket, (sockaddr*)&name, &lenname) < 0)
    return false;
    strcpy(rSocketAddress, inet_ntoa(name.sin_addr));
    rSocketPort = htons(name.sin_port);
    return true;
    }

    // 获取本机Socket用户IP端口等
    BOOL GetSockName(char* rSocketAddress, UINT& rSocketPort)
    {
    sockaddr_in name = { AF_INET };
    int lenname = sizeof(name);
    if (getsockname(m_hSocket, (sockaddr*)&name, &lenname) < 0)
    return false;
    strcpy(rSocketAddress, inet_ntoa(name.sin_addr));
    rSocketPort = htons(name.sin_port);
    return true;
    }

    // 获取当前用户SocketID
    BOOL GetSocketID()
    {
    return m_hSocket;
    }

    // 创建套接字
    BOOL Create(UINT nSocketPort = 0, int nSockType = SOCK_STREAM, LPCTSTR lpszSocketAddress = NULL)
    {

    // 创建套接字
    m_hSocket = socket(AF_INET, nSockType, 0);
    if (m_hSocket == INVALID_SOCKET)
    return false;

    // 设置IP地址和端口
    sockaddr_in sa = { AF_INET };
    sa.sin_port = htons(nSocketPort);
    if (lpszSocketAddress)
    sa.sin_addr.s_addr = inet_addr(lpszSocketAddress);

    // 绑定套接字和IP地址端口
    return !bind(m_hSocket, (sockaddr*)&sa, sizeof(sa));
    }

    // 接受客户请求
    BOOL Accept(MySocket& rConnectedSock, LPSTR szIp = NULL, UINT* nPort = NULL)
    {
    sockaddr_in sa = { AF_INET };
    int nLen = sizeof(sa);
    rConnectedSock.m_hSocket = accept(this->m_hSocket, (sockaddr*)&sa, &nLen);
    if (rConnectedSock.m_hSocket == INVALID_SOCKET)
    return false;
    if (szIp)
    strcpy(szIp, inet_ntoa(sa.sin_addr));
    if (nPort)
    *nPort = htons(sa.sin_port);
    return true;
    }

    // 连接服务端
    BOOL Connection(LPCSTR lpszHostAddress, UINT nPort)
    {
    sockaddr_in sa = { AF_INET };
    sa.sin_port = htons(nPort);
    sa.sin_addr.s_addr = inet_addr(lpszHostAddress);
    return !connect(m_hSocket, (sockaddr*)&sa, sizeof(sa));
    }

    // 侦听
    BOOL Listen(int nConnectionBacklog = 5)
    {
    return !listen(m_hSocket, nConnectionBacklog);
    }

    // 逐条发送
    int Send(const void* lpBuf, int nBufLen, int nFlags = 0)
    {
    return send(m_hSocket, (LPCSTR)lpBuf, nBufLen, nFlags);
    }

    // 发送整个缓冲区
    int SendTo(const void* lpBuf, int nBufLen, UINT nHostPort, LPCSTR lpszHostAddress = NULL,
    int nFlags = 0)
    {
    sockaddr_in to = { AF_INET };
    to.sin_port = htons(nHostPort);
    to.sin_addr.s_addr = inet_addr(lpszHostAddress);
    return sendto(m_hSocket, (LPCSTR)lpBuf, nBufLen, nFlags, (sockaddr*)&to, sizeof(to));
    }

    // 逐条接收
    int Receive(void* lpBuf, int nBufLen, int nFlags = 0)
    {
    return recv(m_hSocket, (LPTSTR)lpBuf, nBufLen, nFlags);
    }

    // 接收整个缓冲区
    int ReceiveFrom(void* lpBuf, int nBufLen, char* rSocketAddress, UINT& rSocketPort, int nFlags = 0)
    {
    sockaddr_in from = { AF_INET };
    int lenFrom = sizeof(from);
    int n = recvfrom(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags, (sockaddr*)&from, &lenFrom);
    strcpy(rSocketAddress, inet_ntoa(from.sin_addr));
    rSocketPort = htons(from.sin_port);
    return n;
    }

    // 关闭套接字
    void Close()
    {
    closesocket(m_hSocket);
    m_hSocket = INVALID_SOCKET;
    }
    MySocket()
    {
    WSADATA wsaData;
    WSAStartup(0x0202, &wsaData);
    m_hSocket = INVALID_SOCKET;

    }
    ~MySocket()
    {
    Close();
    }
    };

  • 3.CMakeLists.txt

    配置CMake编译所需环境

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    # cmake最小版本
    cmake_minimum_required(VERSION 3.26)
    # 定义项目名
    project(cpp_socket_server)
    # cpp版本
    set(CMAKE_CXX_STANDARD 17)
    # 设置编译参数
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s")
    # 引入win平台socket库
    link_libraries(ws2_32)
    # 引入所需头文件库
    include_directories(
    lib/include
    lib/include/spdlog
    # lib/include/cryptopp
    )
    # 引入所需编译源文件(*.cpp)
    aux_source_directory(
    src
    SRC_FILES
    )

    # 设置编译文件
    set(main_file
    ${SRC_FILES}
    lib/include/tcpSocket.h
    src/tcpSocket/tcpSocket.cpp
    src/tcpSocket/MySocket.hpp
    lib/include/tinyxml2.h
    src/utils/tinyxml2.cpp
    lib/include/xmlParser.h
    src/utils/xmlParser.cpp
    )

    # 链接第三方库
    if(SPDLOG_BUILD_EXAMPLE_HO)
    target_link_libraries(cpp_socket_server PRIVATE spdlog::spdlog_header_only)
    endif()

    # 添加可执行文件
    # Add executable files
    add_executable(
    ${PROJECT_NAME}
    ${main_file}
    )
    # 链接第三方库
    target_link_libraries(
    ${PROJECT_NAME}
    ${LIBRARY}
    )

mingw工具

  • 配置环境

    下载完mingw包后,在系统变量Path中引入以下路径

    1
    D:\mingw64\bin
  • 工具引入

    在clion中,可添加mingw工具。点击File->Settings->Build、Execution、Deployment->Toolchains;在其中设置如下路径,也可使用clion默认路径

    1
    toolset: D:\\mingw64\\bin

    如图

  • 编写配置

    在CMakeLists.txt(示例)中写入需引入配置,如下所示:

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    # 设置 CMake 最低版本要求
    cmake_minimum_required(VERSION 3.8)
    # 定义项目名称和版本
    project(MyApp VERSION 1.0.0 LANGUAGES CXX)

    # 设置 C++ 标准
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_CXX_EXTENSIONS OFF)

    # 定义用户可配置的选项
    option(ENABLE_DEBUG "Enable debug output" ON)

    if(ENABLE_DEBUG)
    add_definitions(-DDEBUG_OUTPUT)
    endif()

    # 自定义宏:添加 MSVC 常用编译选项
    macro(add_msvc_options target)
    if(MSVC)
    target_compile_options(${target} PRIVATE
    /W4 # 设置警告级别为 4
    /WX # 将警告视为错误
    /MP # 启用多处理器编译
    /permissive- # 禁用不严格的语言 conformance
    /Zc:__cplusplus # 启用正确的 __cplusplus 宏值
    /Zc:inline # 移除未使用的函数
    /Gm- # 禁用最小生成(minimal rebuild)
    /EHsc # 指定异常处理模型
    )
    endif()
    endmacro()

    # 添加源文件
    set(SOURCE_FILES src/main.cpp)

    # 生成可执行文件
    add_executable(MyApp ${SOURCE_FILES})

    # 调用自定义宏,为 MyApp 添加 MSVC 常用编译选项
    add_msvc_options(MyApp)

    # 为特定目标设置头文件目录
    target_include_directories(MyApp PRIVATE include)

    # 链接静态库
    find_library(STATIC_LIB libStatic.lib PATHS "${CMAKE_SOURCE_DIR}/libs/static")
    target_link_libraries(MyApp PRIVATE ${STATIC_LIB})

    # 链接动态库
    find_library(DYNAMIC_LIB libDynamic.dll PATHS "${CMAKE_SOURCE_DIR}/libs/dynamic")
    find_library(DYNAMIC_LIB_IMPORT libDynamic.lib PATHS "${CMAKE_SOURCE_DIR}/libs/dynamic")
    target_link_libraries(MyApp PRIVATE ${DYNAMIC_LIB_IMPORT})

    # 使用 Windows 的 DLL delay-load 机制
    set_target_properties(MyApp PROPERTIES LINK_FLAGS "/DELAYLOAD:libDynamic.dll")

    # 根据目标架构定制编译选项和链接选项
    if(CMAKE_GENERATOR_PLATFORM STREQUAL "Win32")
    message("Building for Win32 (x86) architecture")
    target_compile_options(MyApp PRIVATE /arch:SSE2)
    elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x64")
    message("Building for x64 architecture")
    target_compile_options(MyApp PRIVATE /arch:AVX2)
    else()
    message(WARNING "Unknown architecture")
    endif()

    # 添加子项目
    add_subdirectory(subproject)

    # 在构建时生成配置文件
    configure_file(config.h.in config.h @ONLY)

    # 指定安装规则
    install(TARGETS MyApp RUNTIME DESTINATION bin)
    install(FILES "${CMAKE_SOURCE_DIR}/libs/dynamic/libDynamic.dll" DESTINATION bin)

CMake编译

  • 编译test.exe

    点击运行按钮,查看效果

  • 目录结构
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    MyApp/
    ├─ CMakeLists.txt
    ├─ src/
    │ └─ main.cpp
    ├─ include/
    │ ├─ static_lib/
    │ │ └─ StaticLibHeader.h
    │ └─ dynamic_lib/
    │ └─ DynamicLibHeader.h
    ├─ libs/
    │ ├─ static/
    │ │ └─ libStatic.lib
    │ └─ dynamic/
    │ ├─ libDynamic.dll
    │ └─ libDynamic.lib
    ├─ subproject/
    │ ├─ CMakeLists.txt
    │ ├─ src/
    │ │ └─ subproject_main.cpp
    │ └─ include/
    │ └─ subproject/
    │ └─ SubProjectHeader.h
    └─ config.h.in
  • cmake运行(Visual Studio 2019)
    1
    2
    3
    4
    # 对于 x86 架构: 
    cmake -G "Visual Studio 16 2019" -A Win32 ..
    # 对于 x64 架构:
    cmake -G "Visual Studio 16 2019" -A x64 ..

引入第三方库(以spdlog为例)

Very fast, header-only/compiled, C++ logging library.

工具下载

在以下路径下载spdlog:

1
git clone https://github.com/gabime/spdlog.git

cmake引入

在项目include 文件夹中复制以下文件夹内容

1
include/spdlog/

在CMakeLists.txt中引入库

1
2
3
4
5
6
7
8
9
include_directories(
lib/include
lib/include/spdlog
# lib/include/cryptopp
)

if(SPDLOG_BUILD_EXAMPLE_HO)
target_link_libraries(cpp_socket_server PRIVATE spdlog::spdlog_header_only)
endif()

测试运行

编写如下代码

  • 1.封装spdlog库
    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    #ifndef MY_SPDLOG_LOG_HPP
    #define MY_SPDLOG_LOG_HPP
    #include <iostream>
    #include <memory>
    #include "spdlog/spdlog.h"
    #include "spdlog/async.h"
    #include <spdlog/sinks/stdout_color_sinks.h>
    #include <spdlog/sinks/rotating_file_sink.h>
    #include <spdlog/sinks/daily_file_sink.h>
    #include <spdlog/sinks/basic_file_sink.h>


    class CLog {

    public:
    static CLog &instance() {
    static CLog m_instance;
    return m_instance;
    }

    auto get_logger() const {
    return this->logger_;
    }

    ~CLog() {
    spdlog::drop_all(); // 释放所有logger
    }

    CLog() {
    this->init();
    }

    private:
    void init() {
    std::cout << "Log System Init , start record log : " << std::endl;
    this->init_file();
    this->init_logger();
    }

    void init_file() {
    this->log_root_path = R"(C:\Users\Administrator\CLionProjects\cpp_socket_server\logs\)";
    this->info_file_path = "info.log";
    this->error_file_path = "error.log";
    this->rotation_h = 5; // 分割时间
    this->rotation_m = 59;
    }

    void init_logger() {

    this->info_sink_ = std::make_shared<spdlog::sinks::daily_file_sink_mt>(
    this->log_root_path + this->info_file_path, this->rotation_h, this->rotation_m);
    this->error_sink_ = std::make_shared<spdlog::sinks::daily_file_sink_mt>(
    this->log_root_path + this->error_file_path, this->rotation_h, this->rotation_m);
    this->console_sink_ = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();

    this->info_sink_->set_level(spdlog::level::info); // debug< info< warn< error< critical 日志信息低于设置的级别时, 不予显示
    this->error_sink_->set_level(spdlog::level::err);
    this->console_sink_->set_level(spdlog::level::debug);

    this->sinks_.push_back(this->info_sink_); // info
    this->sinks_.push_back(this->error_sink_); // error
    this->sinks_.push_back(this->console_sink_); // console

    this->logger_ = std::make_shared<spdlog::logger>("log_demo", begin(this->sinks_), end(this->sinks_));
    this->logger_->set_pattern("[%l] [%Y-%m-%d %H:%M:%S %e] [Process:%P] - %v");
    this->logger_->flush_on(spdlog::level::info); // 设置当触发 info 或更严重的错误时立刻刷新日志到 disk
    spdlog::register_logger(this->logger_); // 注册logger
    spdlog::flush_every(std::chrono::seconds(10)); // 每隔10秒刷新一次日志
    }

    private:
    std::shared_ptr <spdlog::logger> logger_;
    std::shared_ptr <spdlog::sinks::daily_file_sink_mt> info_sink_; // info
    std::shared_ptr <spdlog::sinks::daily_file_sink_mt> error_sink_; // error
    std::shared_ptr <spdlog::sinks::stdout_color_sink_mt> console_sink_; // console
    std::vector <spdlog::sink_ptr> sinks_;
    std::string log_root_path;
    std::string error_file_path;
    std::string info_file_path;
    short int rotation_h{};
    short int rotation_m{};

    }; // CLog


    #define ilog CLog::instance().get_logger()


    #endif //MY_SPDLOG_LOG_HPP
  • 2.在主cpp中写入测试代码
    1
    2
    3
    ilog->info("server : {0},{1} ,server is running!",sSevIp,nSevPort);
    ilog->warn("client :{0}:{1} , [disconnect]",sIp,nPort);
    ilog->error("[VP] load config file error : {0}",doc_dump.LoadFile(path));
  • 3.运行主cpp,测试效果

    如图:

Prev:
SMB共享服务python脚本操作文件上传下载
Next:
基于Assammdf第三方python库处理mdf、mf4文件