找工作小项目:day13-工程化

day13-工程化

该项目编译的过程都是使用CMake完成的,不过由于之前的文件都放在同一个文件夹中并没有分类。随着模块越来越多项目逐渐就变成了屎山,可读性极低,为了方便管理我们的项目这里开始使用CMake。
首先将项目的树结构进行更改

.                                     .
|--Makefile                           |--CMakeLists.txt
|--ThreadPoolTest.cpp                 |--.clang-format
|--client.cpp                         |--.clang-tidy
|--server.cpp               ----->    |--.gitignore
|--src                                |--test
    |--*.cpp                               |--CMakeLists.txt
    |--*.h                                 |--*.cpp
                                      |--src
                                          |--*.cpp
                                          |--include
                                                |--*.h
                                      |--build_sport
                                              |--*.py
                                              |--clang_format_exclusions.txt

可以看出来结构化后文件更多了,但是大都是一些使用CMake及Clang的支持文件,而工程文件仍旧在src中,只是将头文件和cpp文件进行拆分。
首先还是看一下在工程文件中发生了什么变化。

1、Macros.h

在这个头文件中加入了一些宏定义,禁止了一些拷贝和移动操作

#pragma once
#define OS_LINUX

#define DISALLOW_COPY(cname)                             \
  cname(const cname &) = delete;            /* NOLINT */ \
  cname &operator=(const cname &) = delete; /* NOLINT */

#define DISALLOW_MOVE(cname)                        \
  cname(cname &&) = delete;            /* NOLINT */ \
  cname &operator=(cname &&) = delete; /* NOLINT */

#define DISALLOW_COPY_AND_MOVE(cname) \
  DISALLOW_COPY(cname);               \
  DISALLOW_MOVE(cname);

2、Socket

在头文件中,包含了Macros.h将所有的类声明为不可拷贝、不可移动提高了项目的性能并减少bug,为了提高安全性还将Socket的有参构造函数设置为explicit(个人理解:因为int容易发生隐式转换)。

class InetAddress {
 public:
  InetAddress();
  InetAddress(const char *ip, uint16_t port);
  ~InetAddress() = default;

  DISALLOW_COPY_AND_MOVE(InetAddress);

  void SetAddr(sockaddr_in addr);
  sockaddr_in GetAddr();
  const char *GetIp();
  uint16_t GetPort();

 private:
  struct sockaddr_in addr_ {};
};

class Socket {
 private:
  int fd_{-1};

 public:
  Socket();
  explicit Socket(int fd);
  ~Socket();

  DISALLOW_COPY_AND_MOVE(Socket);

  void Bind(InetAddress *addr);
  void Listen();
  int Accept(InetAddress *addr);

  void Connect(InetAddress *addr);

  void SetNonBlocking();
  int GetFd();
};

2、高并发Epoll

除了将Epoll类声明为不可拷贝、不可移动外没什么改变

3、Channel(同上)

4、EventLoop

5、Acceptor

6、Connection(将设置回调函数的形参使用引用的方式完成)

7、Buffer

8、ThreadPool

9、服务器类

总结一下上述模块没有发生过大的变化,就是将类声明为不可拷贝、不可移动,将设置回调函数
的方法的形参都使用引用,并且将一些空的构造/析构函数=default,值得注意的是explicit一般只设置在易发生隐式转换的类构造前面(有参构造函数的参数较少的时候)。

10、CMake

需要在最外层和有执行文件生成的文件中加入CMakeLists.txt。
最外层CMakeLists.txt代码如下:

cmake_minimum_required(VERSION 3.10) //指定项目所需的CMake的最低版本
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) //生成编译命令的JSON文件 
set(BUILD_SHARED_LIBS ON) //设置为生成共享库
set(CMAKE_CXX_STANDARD 17) //指定C++标准为C++17
set(CMAKE_CXX_STANDARD_REQUIRED ON) //指定C++标准为必需的

project(Pine
        VERSION 0.1
        DESCRIPTION "pine"
        LANGUAGES C CXX
        ) //定义项目名称、版本、描述和所使用的编程语言(C和C++)


# 人们总是在错误的文件夹中运行 CMake,导致项目完全瘫痪或产生奇怪的 bug
# 这将检查你是否在已经有 CMakeLists.txt 的文件夹中运行 CMake
# 重要的是,它还会检查从根目录运行 CMake 的常见情况
//将CMakeLists.txt文件的完整路径存储在变量PATH_TO_CMAKELISTS_TXT中
file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" PATH_TO_CMAKELISTS_TXT)
if (EXISTS "${PATH_TO_CMAKELISTS_TXT}")//检查是否存在CMakeLists.txt文件,如果存在则发出错误消息
    message(FATAL_ERROR "Run CMake from a build subdirectory! \"mkdir build ; cd build ; cmake .. \" \
    Some junk files were created in this folder (CMakeCache.txt, CMakeFiles); you should delete those.")
endif ()


# 预期目录结构
set(PINE_BUILD_SUPPORT_DIR "${CMAKE_SOURCE_DIR}/build_support") //定义变量PINE_BUILD_SUPPORT_DIR,指向构建支持目录
set(PINE_CLANG_SEARCH_PATH "/usr/local/bin" "/usr/bin" "/usr/local/opt/llvm/bin" "/usr/local/opt/llvm@8/bin" "/usr/local/Cellar/llvm/8.0.1/bin") //指定查找Clang工具的路径

if (NOT DEFINED CLANG_FORMAT_BIN)//如果未定义变量CLANG_FORMAT_BIN,则查找并设置Clang格式化工具的路径
    # attempt to find the binary if user did not specify
    find_program(CLANG_FORMAT_BIN
            NAMES clang-format clang-format-8
            HINTS ${PINE_CLANG_SEARCH_PATH})
endif ()
if ("${CLANG_FORMAT_BIN}" STREQUAL "CLANG_FORMAT_BIN-NOTFOUND")//如果未找到Clang格式化工具,则发出警告消息
    message(WARNING "Pine/main couldn't find clang-format.")
else ()
    message(STATUS "Pine/main found clang-format at ${CLANG_FORMAT_BIN}")
endif ()

if (NOT DEFINED CLANG_TIDY_BIN)//如果未定义变量CLANG_TIDY_BIN,则查找并设置Clang静态分析工具的路径
    # attempt to find the binary if user did not specify
    find_program(CLANG_TIDY_BIN
            NAMES clang-tidy clang-fidy-8
            HINTS ${PINE_CLANG_SEARCH_PATH})
endif ()
if ("${CLANG_TIDY_BIN}" STREQUAL "CLANG_TIDY_BIN-NOTFOUND")//如果未找到Clang静态分析工具,则发出警告消息
    message(WARNING "Pine/main couldn't find clang-tidy.")
else ()
    # 输出编译命令
    set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
    message(STATUS "Pine/main found clang-fidy at ${CLANG_TIDY_BIN}")
endif ()

# cpplint(用以检查代码是否符合Google风格)
find_program(CPPLINT_BIN
        NAMES cpplint cpplint.py
        HINTS ${PINE_BUILD_SUPPORT_DIR})//查找并设置cpplint工具的路径
if ("${CPPLINT_BIN}" STREQUAL "CPPLINT_BIN-NOTFOUND") //如果未找到cpplint工具,则发出警告消息
    message(WARNING "Pine/main couldn't find cpplint.")
else ()
    message(STATUS "Pine/main found cpplint at ${CPPLINT_BIN}")
endif ()

# Compiler flags.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wextra -std=c++17 -pthread") //设置C++编译器标志
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-attributes") #TODO: remove
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls") //设置调试时的C++编译器标志
set(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} -fPIC")  //设置可执行文件链接器标志
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fPIC") //设置共享库链接器标志
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -fPIC") //设置静态库链接器标志

set(GCC_COVERAGE_LINK_FLAGS "-fPIC") //设置GCC覆盖率链接标志
message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
message(STATUS "CMAKE_CXX_FLAGS_DEBUG: ${CMAKE_CXX_FLAGS_DEBUG}")
message(STATUS "CMAKE_EXE_LINKER_FLAGS: ${CMAKE_EXE_LINKER_FLAGS}")
message(STATUS "CMAKE_SHARED_LINKER_FLAGS: ${CMAKE_SHARED_LINKER_FLAGS}")

# Output directory.
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) //设置存档输出目录
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) //设置库输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) //设置运行时输出目录

# Includes.
set(PINE_SRC_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/src/include) //定义源文件包含目录
set(PINE_TEST_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/test/include) //定义测试文件包含目录
include_directories(${PINE_SRC_INCLUDE_DIR} ${PINE_TEST_INCLUDE_DIR}) //包含源文件和测试文件的目录

add_subdirectory(src) //添加子目录src
add_subdirectory(test) //添加子目录test

string(CONCAT PINE_FORMAT_DIRS
        "${CMAKE_CURRENT_SOURCE_DIR}/src,"
        "${CMAKE_CURRENT_SOURCE_DIR}/test,"
        ) //将源文件和测试文件的目录存储在变量PINE_FORMAT_DIRS中

# 运行 clang 格式并就地更新文件
add_custom_target(format ${PINE_BUILD_SUPPORT_DIR}/run_clang_format.py
        ${CLANG_FORMAT_BIN}
        ${PINE_BUILD_SUPPORT_DIR}/clang_format_exclusions.txt
        --source_dirs
        ${PINE_FORMAT_DIRS}
        --fix
        --quiet
        )  //添加自定义目标format,用于运行clang-format格式化源文件
    
# 运行 clang 格式,如果有文件需要重新格式化,则以非零退出代码
add_custom_target(check-format ${PINE_BUILD_SUPPORT_DIR}/run_clang_format.py
        ${CLANG_FORMAT_BIN}
        ${PINE_BUILD_SUPPORT_DIR}/clang_format_exclusions.txt
        --source_dirs
        ${PINE_FORMAT_DIRS}
        --quiet
        )//添加自定义目标check-format,用于检查源文件格式

file(GLOB_RECURSE PINE_LINT_FILES
        "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h"
        "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/test/*.h"
        "${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp"
        )//在当前源代码目录下递归地查找所有的.h和.cpp文件,并将它们的路径存储在名为PINE_LINT_FILES的变量中,分别表示在src目录和test目录下匹配.h和.cpp文件

# 平衡之举:cpplint.py 启动需要大量时间、
# 所以每次调用要处理 12 个文件,同时还要确保并行性
add_custom_target(cpplint echo '${PINE_LINT_FILES}' | xargs -n12 -P8
        ${CPPLINT_BIN}
        --verbose=2 --quiet
        --linelength=120
        --filter=-legal/copyright,-build/include_subdir,-readability/casting
        ) //运行cpplint工具对之前通过file指令收集到的C++源文件进行代码风格检查

###########################################################
# "make clang-tidy" target
###########################################################
# 运行 clang-tidy 并在发现任何错误时以非零退出代码退出。
# 注意,clang-tidy 会自动在父目录中查找 .clang-tidy 文件
add_custom_target(clang-tidy
        ${PINE_BUILD_SUPPORT_DIR}/run_clang_tidy.py                     # run LLVM's clang-tidy script
        -clang-tidy-binary ${CLANG_TIDY_BIN}                              # using our clang-tidy binary
        -p ${CMAKE_BINARY_DIR}                                            # using cmake's generated compile commands
        )//运行clang-tidy工具对项目的C++代码进行静态代码分析和检查

test中的CMakeLists.txt代码如下:

file(GLOB PINE_TEST_SOURCES "${PROJECT_SOURCE_DIR}/test/*.cpp")//查找${PROJECT_SOURCE_DIR}/test/下的所有.cpp文件,并将它们的路径保存在名为PINE_TEST_SOURCES的变量中

add_custom_target(build-tests COMMAND ${CMAKE_CTEST_COMMAND} --show-only)//只显示测试案例,而不实际运行它们
add_custom_target(check-tests COMMAND ${CMAKE_CTEST_COMMAND} --verbose)//运行测试案例

foreach (pine_test_source ${PINE_TEST_SOURCES})//这行代码开始一个foreach循环,遍历之前找到的测试源文件路径
    # Create a human readable name.
    get_filename_component(pine_test_filename ${pine_test_source} NAME)//提取了每个测试源文件的文件名,并将其存储在名为pine_test_filename的变量中
    string(REPLACE ".cpp" "" pine_test_name ${pine_test_filename})//将.cpp文件扩展名替换为空,得到了每个测试的名称,并将其存储在名为pine_test_name的变量中

    add_executable(${pine_test_name} EXCLUDE_FROM_ALL ${pine_test_source})//创建一个可执行目标,其中${pine_test_name}是测试的名称,${pine_test_source}是测试的源文件路径。EXCLUDE_FROM_ALL标志意味着这些测试不会被默认构建,只有在明确指定时才会构建
    add_dependencies(build-tests ${pine_test_name})
    add_dependencies(check-tests ${pine_test_name})
    //这两行代码将每个测试目标添加为build-tests和check-tests自定义目标的依赖关系,确保在运行这些目标时先构建相应的测试

    target_link_libraries(${pine_test_name} pine_shared)//指定了测试目标${pine_test_name}需要链接的库,其中pine_shared是项目中的共享库

    # Set test target properties and dependencies.
    set_target_properties(${pine_test_name}
        PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
        COMMAND ${pine_test_name}
    )//这行代码设置了测试目标${pine_test_name}的属性,包括运行时输出目录和要执行的命令

endforeach(pine_test_source ${PINE_TEST_SOURCES})

这部分不一定要看感觉,但是为了能够构建工程还是很必要的,学习一下感觉面试也能吹吹,源代码在30天构造服务器中

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值