zoukankan      html  css  js  c++  java
  • CMake 多 main() 入口项目搭建(刷题向)

    在 ACM 算法竞赛 / LeetCode 使用 C++ 进行刷题等场景中,通常:

    • 需要维护很多的 C++ 源代码
    • 需要有多个 main 函数入口方便执行测试
    • 有一些自己写的公共函数类库 (如调试输出vector等) 在多个文件中引用

    本文介绍了通过 CMake 及一些自生成配置文件的工具,通过一个统一的库,方便管理所有代码的方法。

    CMake 是一个平台无关的可以定制 C++ 编译流程的工具,可以生成特定平台的 Makefile 文件。默认被 Intellij CLion 支持。


     需要首先通过 CLion 创建一个 C++ 工程:

    创建出自己需要的目录结构来:我们把所有的源代码 .cpp 等文件放在 /src 中, 一些工具类放在 /src/utils 中

    CMakeLists.txt 文件就是我们的 CMake 编译流程配置文件了。为了支持多个 main() 函数入口,我们用  add_executable 命令添加多个 target,这种才能在每个 main() 入口单独执行:

    cmake_minimum_required(VERSION 3.17)
    project(lc-cpp)
    
    set(CMAKE_CXX_STANDARD 17)
    add_definitions("-DKUN_DEBUG")
    
    add_executable(training_p1 src/normal/cat0/cat00/cat000/p1.cpp)
    add_executable(training_p15 src/normal/cat0/cat00/cat001/p15.cpp)
    add_executable(biweekly_34_2 src/match/biweekly/biweekly34/p2.cpp)
    add_executable(biweekly_34_3 src/match/biweekly/biweekly34/p3.cpp)
    add_executable(biweekly_34_4 src/match/biweekly/biweekly34/p4.cpp)

    接下来我们处理公共类库的问题,只需要将 utils 目录声明为编译器的头文件搜索路径之下,这样就能被其他文件引用了。

    像是 LeetCode 的 TreeNode, ListNode 等基础数据结构及其解析、debug 工具可以放在这里面:

    include_directories("src/utils")

    再来解决最后一个问题。我们每次创建一些 .cpp 代码后,就需要去 CMakeLists.txt 文件中添加对应的 add_executable 代码。这部分工作我们可以通过脚本的形式去自动生成,附上 Python3 代码:

    import os
    
    HEAD = '''cmake_minimum_required(VERSION 3.17)
    project(lc-cpp)
    
    set(CMAKE_CXX_STANDARD 17)
    add_definitions("-DKUN_DEBUG")
    include_directories("src/utils")
    
    '''
    
    
    def update_cmake():
        file_list = []
        for root, dirs, files in os.walk("src"):
            if len(files) == 0:
                continue
            for f in files:
                file_list.append(root + os.sep + f)
        res = HEAD
        for i in sorted(file_list):
            if 'utils' in i:
                continue
            split = i.split(os.sep)
            name_ids = filter(lambda x: x != 'src', split)
            name = "_".join(name_ids).replace(".cpp", "")
            path = "/".join(split)
            code = f'add_executable({name} {path})
    '
            res += code
        with open('CMakeLists.txt', "w") as f:
            f.write(res)
    
    
    if __name__ == '__main__':
        update_cmake()

    至此,通过把所以题目按照分类文件夹管理,然后自动生成可执行文件编译配置,一个比较完成的方便 C++ 刷题的项目环境就创建好了。


    最后附一个 LeetCode 刷题常用的基础类及解析、输出工具(common_ds.hpp):

    /**
     * LeetCode Common DataStruct.
     */
    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    
    struct TreeNode {
    
        int val;
        TreeNode *left;
        TreeNode *right;
    
        TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    
        TreeNode(int val, TreeNode *left, TreeNode *right) : val(val), left(left), right(right) {}
    };
    
    
    static TreeNode *parse_tree(string s) {
        const regex re(",");
        vector<string> v(sregex_token_iterator(++s.begin(), --s.end(), re, -1), sregex_token_iterator());
        if (v.empty()) return nullptr;
        vector<TreeNode *> ns;
        ns.push_back(new TreeNode(stoi(v.front())));
        for (int i = 1; i < v.size(); ++i) {
            TreeNode *cur = v[i].find("null") != string::npos ? nullptr : new TreeNode(stoi(v[i]));
            if (i % 2 == 1) ns[(i - 1) / 2]->left = cur;
            else ns[(i - 1) / 2]->right = cur;
            if (cur) ns.push_back(cur);
        }
        return ns.front();
    }
    
    static string to_string(TreeNode *root) {
        if (!root) return "null";
        if (!root->left && !root->right) return to_string(root->val);
        return "{" + to_string(root->val) + ", " + to_string(root->left) + ", " + to_string(root->right) + "}";
    }
    
    static void print(TreeNode *head, int len = 4, int height = 0, string to = "#") {
        if (!head) return;
        print(head->right, len, height + 1, "v");
        string val = to + to_string(head->val);
        int lenM = val.length(), lenL = (len - lenM) / 2, lenR = len - lenM - lenL;
        val = string(height * len, ' ') + string(lenL, ' ') + val + string(lenR, ' ');
        cout << val << endl;
        print(head->left, len, height + 1, "^");
    }
    
    /// =========================================================================
    
    struct ListNode {
    
        int val;
        ListNode *next;
    
        ListNode(int x) : val(x), next(nullptr) {}
    };
    
    static ListNode *parse_list(string s) {
        const regex re("->");
        vector<string> v(sregex_token_iterator(s.begin(), s.end(), re, -1), sregex_token_iterator());
        ListNode *mock = new ListNode(-1), *p = mock;
        for (auto &i : v) {
            p->next = new ListNode(stoi(i));
            p = p->next;
        }
        return mock->next;
    }
    
    static string to_string(ListNode *node) {
        if (!node) return "";
        return to_string(node->val) + (node->next ? "->" + to_string(node->next) : "");
    }
    
    static void print(ListNode *node) {
        cout << to_string(node) << endl;
    }
    
    /// =========================================================================
    
    struct Interval {
    
        int start, end;
    
        Interval() : start(0), end(0) {}
    
        Interval(int start, int anEnd) : start(start), end(anEnd) {}
    };
    
    /// =========================================================================
  • 相关阅读:
    PHP中过滤数组中的元素
    cookie中文乱码解决(php/js)
    Ubuntu系统tar克隆
    磁盘IO性能监控(Linux 和 Windows)
    远程桌面由于帐户限制你无法登录问题
    SAP中关于用户IP信息的获取
    选择界面制作按钮
    ALV常用参数详细描述
    销售订单、外向交货单、交货 bapi
    abap 常用表
  • 原文地址:https://www.cnblogs.com/kunsoft/p/13776482.html
Copyright © 2011-2022 走看看