KEIL 添加格式化 批量格式化

在写代码时,通常都离不开格式化更具。运用格式化工具能使我们的代码更加的美观。

然而KEIL 没有内置格式化工具。因此我们需要自己为其添加格式化工具。之前我使用的是 AStyle ,效果还不错,网上一般也是建议使用这个工具。

但是本人更加钟爱 vscodeC/C++ 格式化工具:clang-format 。这个工具可配置性更高,格式化出来的效果比 AStyle 好。

比如变量定义初始化时,可以等号对齐,宏定义时,可以宏定义对齐。注释也支持对齐。显然,这样格式化出来的代码更加美观。

在这里插入图片描述
在这里插入图片描述
直接将宏定义的代码块转换函数格式,这个功能简直不要太好。
在这里插入图片描述

使用教程:

1. 使用 clang-format

直接去官网下载。因为我vscode里面下载了这个插件的。因此直接在vscode插件目录下找到这个软件。

C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin

执行:

.\clang-format.exe -style=LLVM -i main.cpp 

即可对 main.cpp 进行格式化。

通过以下命令,可以导出默认配置,通过修改配置,可以实现我们自定义格式化效果。

.\clang-format.exe  -style=llvm -dump-config > .clang-format

将配置输出到 .clang-format 中。上面的命令如果是在 powershell中运行的话,会导致输出编码格式不正确,需要将文件转成UTF-8 编码格式。建议使用CMD。

使用配置,则通过以下方式:

.\clang-format.exe -style=file .\.clang-format -i main.cpp

即可使用我们修改过的配置文件。上面的命令如果是在powershell中运行的话,clang-format.exe读取file后,会导致file文件格式混乱,从而无法再此使用。因此,我们每次都需要建立一个file的副本,来确保powershell运行这个命令不会出错。建议使用CMD。

默认导出的配置还达不到vscode的默认效果,因此需要进行修改。
将缩进设置为4个字符,并且将 {} 设置为前后换行。这是我比较喜欢的配置,代码更加清晰。
然后还有变量初始化对齐和宏定义对齐,不允许小块代码写在一行。

AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
AlignConsecutiveBitFields: true
AlignConsecutiveDeclarations: true
AllowShortFunctionsOnASingleLine: false
IndentWidth:     4
BreakBeforeBraces: Allman

简单配置即可达到图片的效果。

2. KEIL 配置格式化工具

在KEIL 中配置格式化工具。
在这里插入图片描述

这里将Comand设置为格式化工具路径。然后Arguments设置为 -style=file C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\.clang-format -i !E 。这个设置表示,使用配置文件格式来 格式化当前文件,即编辑器的当前文件。

在这里插入图片描述

当需要格式化整个文件夹的文件时,按如下配置。按理来说,比如 AStyle 会在Arguments里面配置 $E*.c $E*.h 。由于 clang-format 的bug,这样设置会导致报错。因为这两个模糊输入是在同一个文件夹,因此设置为 -i "$E*.c" ,只格式化目录下的所有 .c 文件。

当然Arguments参数前面还是加上我们自定义的格式配置文件 -style=file C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\.clang-format。即再 -i 前面补上这个参数。
在这里插入图片描述
当格式化所有 *.c 文件时,任然存在bug。bug表现为:当工作目录和需要格式化的文件不在同一个目录时,格式化的配置参数会部分失效。比如我软件运行在.\test\diraa\ 下,但是文件在 .\test\dirbb\ 会导致宏定义格式化不对其。当软件运行目录也在 .\testdirbb\ 下时,格式化是正常的。因此这里配置了,任然到不到完美的效果。

所以我对 clang-format 进行了功能扩充修改。当输入为目录时,我们直接切换工作路径,然后格式化这个路径下的所有 .c 和 .h 文件,来解决上面提出的两个bug。源代码附于文章末尾。

因此,只需要将KEIL,进行如下配置,即可完美格式化。Command配置为:

C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\clang_format_custom.exe

在这里插入图片描述

或者这样:
在这里插入图片描述

但是抽风的KEIL参数,还是会导致bug。
如果以上面的参数设置,会得到一个路径,但是KEIL在处理路径时,直接字符串参数传给命令行,这时最后一个"将变成\",好了,这将导致一个错误。因此需要将 "$E" 修改为 "$E\" 。或者直接去掉 "" 即可。

但是这还没完,程序运行任然报错。上面两个不同的设置将导致不同的错误,我也是非常的郁闷。但是格式化结果是完美的,因此忽略这个错误了。这里的 invalid argument 错误应该是KEIL报告的。从第一行的命令来看,格式是没有任何问题的。

C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\clang_format_custom.exe -i "E:\Projects\2020\Railway_Finder\Finder_terminal\Railway_Finder\examples\ble_peripheral\Railway_Finder_terminal\pca10040e\s112\user_app_src\\"
invalid argument
-i
E:\Projects\2020\Railway_Finder\Finder_terminal\Railway_Finder\examples\ble_peripheral\Railway_Finder_terminal\pca10040e\s112\user_app_src\
full_path: C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\clang-format.exe -i E:\Projects\2020\Railway_Finder\Finder_terminal\Railway_Finder\examples\ble_peripheral\Railway_Finder_terminal\pca10040e\s112\user_app_src\
format_file: C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\.clang-format
work path: E:\Projects\2020\Railway_Finder\Finder_terminal\Railway_Finder\examples\ble_peripheral\Railway_Finder_terminal\pca10040e\s112\user_app_src\
C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\clang_format_custom.exe -i E:\Projects\2020\Railway_Finder\Finder_terminal\Railway_Finder\examples\ble_peripheral\Railway_Finder_terminal\pca10040e\s112\user_app_src\
invalid argument
-i
E:\Projects\2020\Railway_Finder\Finder_terminal\Railway_Finder\examples\ble_peripheral\Railway_Finder_terminal\pca10040e\s112\user_app_src\
full_path: C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\clang-format.exe -i E:\Projects\2020\Railway_Finder\Finder_terminal\Railway_Finder\examples\ble_peripheral\Railway_Finder_terminal\pca10040e\s112\user_app_src\
format_file: C:\Users\28328\.vscode\extensions\ms-vscode.cpptools-1.3.1\LLVM\bin\.clang-format
work path: E:\Projects\2020\Railway_Finder\Finder_terminal\Railway_Finder\examples\ble_peripheral\Railway_Finder_terminal\pca10040e\s112\user_app_src\

可以修改源码来解决上报面的报错。不过既然格式没有问题了,我也不管KEIL参数的bug了。

另外很重要的一点。KEIL支持对配置的tool设置快捷键,这样,我们可以通过设置 shift + alt + F 来实现和vscode一样的快捷键格式化,完美。

在这里插入图片描述

源码如下,格式配置参见gitee。(下面的代码就是通过格式化工具格式的):

#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <windows.h>

#define TOOL_PATH_LEN 1024
#define FULL_PATH_LEN 16384
#define LOG_INFO(...) printf(__VA_ARGS__)

char tool_path[FULL_PATH_LEN] = "C:\\Users\\28328\\.vscode\\extensions\\ms-vscode.cpptools-1.3.1\\LLVM\\bin\\";
char tool_name[128]           = "clang-format.exe";
char format_file_name[]       = ".clang-format";

static int path_index = 0;

static int   get_format_file(char *file_path);
static int   rm_format_file(void);
static int   hj_copy_file(char *old_file, char *new_file);
static _Bool is_dir(char *name);

int main(int argv, char *argc[])
{
    char full_path[FULL_PATH_LEN]   = {0};
    char format_file[TOOL_PATH_LEN] = {0};

    memcpy(full_path, tool_path, TOOL_PATH_LEN);
    memcpy(format_file, tool_path, TOOL_PATH_LEN);

    strncat(full_path, tool_name, FULL_PATH_LEN - strlen(tool_path));

    strncat(format_file, format_file_name, TOOL_PATH_LEN - strlen(tool_path));

    for (int i = 1; i < argv; i++)
    {
        LOG_INFO("%s\n", argc[i]);
        strncat(full_path, " ", FULL_PATH_LEN - strlen(tool_path));
        strncat(full_path, argc[i], FULL_PATH_LEN - strlen(tool_path));

        if (0 == strncmp(argc[i], "-i", 2))
        {
            path_index = i + 1;
        }
    }

    LOG_INFO("full_path: %s\n", full_path);
    LOG_INFO("format_file: %s\n", format_file);

    /* 格式化目录下的所有.c .h 文件 */
    if (is_dir(argc[path_index]))
    {
        char work_path[256] = {0};
        strcat(work_path, argc[path_index]);

        if (work_path[strlen(work_path) - 1] != '\\')
        {
            strcat(work_path, "\\");
        }

        LOG_INFO("work path: %s\n", work_path);
        int ret = chdir(work_path);
        if (ret)
        {
            LOG_INFO("%s:%d: chdir error: %d\n", __func__, __LINE__, ret);
            return 0;
        }

        char temp[FULL_PATH_LEN] = {0};
        memcpy(temp, full_path, FULL_PATH_LEN);
        strcat(temp, "*.c");

        get_format_file(format_file);
        system(temp);
        rm_format_file();

        memcpy(temp, full_path, FULL_PATH_LEN);
        strcat(temp, "*.h");

        get_format_file(format_file);
        system(temp);
        rm_format_file();
    }
    else
    {/* 格式化单个文件 */
        get_format_file(format_file);
        system(full_path);
        rm_format_file();
    }

    return 0;
}

static int get_format_file(char *file_path)
{
    int ret = hj_copy_file(file_path, format_file_name);
    if (ret)
    {
        LOG_INFO("%s:%d: copy file error: %d\n", __func__, __LINE__, ret);
        return ret;
    }

    return ret;
}

static int rm_format_file(void)
{
    uint32_t ret = remove(format_file_name);
    if (ret)
    {
        LOG_INFO("%s:%d: remove format file error: %d\n", __func__, __LINE__, ret);
    }

    return ret;
}

static int hj_copy_file(char *old_file, char *new_file)
{
    if (!old_file || !new_file)
    {
        return 1;
    }
#define BUFFER_LEN 16384

    FILE *fp                 = NULL;
    FILE *fp_out             = NULL;
    char  buffer[BUFFER_LEN] = {0};
    int   ret                = 0;

    fp = fopen(old_file, "rb");
    if (!fp)
    {
        LOG_INFO("%s:%d: open file error.\n", __func__, __LINE__);
        return 2;
    }

    ret = fread(buffer, sizeof(char), BUFFER_LEN, fp);
    if (ret <= 0)
    {
        LOG_INFO("%s:%d: read file error.\n", __func__, __LINE__);
        return 3;
    }

    fclose(fp);

    fp_out = fopen(new_file, "wb");
    if (!fp_out)
    {
        LOG_INFO("%s:%d: open file error.\n", __func__, __LINE__);
        return 4;
    }

    ret = fwrite(buffer, sizeof(char), ret, fp_out);
    if (ret <= 0)
    {
        LOG_INFO("%s:%d: write file error.\n", __func__, __LINE__);
        return 5;
    }

    fclose(fp_out);

    return 0;
}

static _Bool is_dir(char *name)
{
    struct _stat buf;
    int          result = 0;
    result              = _stat(name, &buf);
    if (_S_IFDIR & buf.st_mode)
    {
        return TRUE;
    }
    else if (_S_IFREG & buf.st_mode)
    {
        return FALSE;
    }
}
posted @ 2021-04-22 00:48  duapple  阅读(111)  评论(0编辑  收藏  举报  来源