优化网站是什么意思为公司做网站

当前位置: 首页 > news >正文

优化网站是什么意思,为公司做网站,seo高手是怎样炼成的,台州网站策划前言 项目经过一段时间的耕耘终于进入了团队开发阶段#xff0c;期间出现了很多问题#xff0c;其中一个就是开会讨论团队的代码风格规范#xff0c;目前项目代码风格比较混乱#xff0c;有的模块是驼峰#xff0c;有的模块是匈牙利#xff0c;后面经过讨论#xff0c;…前言 项目经过一段时间的耕耘终于进入了团队开发阶段期间出现了很多问题其中一个就是开会讨论团队的代码风格规范目前项目代码风格比较混乱有的模块是驼峰有的模块是匈牙利后面经过讨论决定采用匈牙利和awtk库的api风格一致。 讨论完之后就是改代码了有十几个模块几百个函数要改一个个人工去改显然费时费力改的时候就在想这种东西有没有自动化的做法了? 于是下班开始探索一番首先是尝试用AI写一个批量扫描文件用正则匹配不符合规则的python脚本结果费时费力效果明显不好。 不对c/c发展了十几年这类问题难道没有现成的方案 后面搜了点原理正则的思路对于这类问题显然不对没法识别函数和变量那只能用抽象语法树了。对象是c/c应该是一个类似c/c编译器的静态分析工具。 最后找到了clang-tidy。 尝试集成1.0 首先下载clang-tidy: pip install clang-tidy假设示例项目src结构如下 src ├── application.c ├── common │ ├── navigator.c │ ├── navigator.h │ └── temperature.h ├── main.c ├── modules │ ├── libframebuffer.c │ └── libframebuffer.h ├── pages │ └── home_page.c └── SConscript 要修改的文件例libframebuffer里面api是驼峰格式需要自动改成匈牙利格式home_page有引用。 libframebuffer.h #ifndef LIBFRAMEBUFFER_H #define LIBFRAMEBUFFER_H typedef struct {int width;int height;int bpp;void* buffer; } LibFrameBuffer;LibFrameBuffer* LibFrameBufferInit();void LibFrameBufferFree(LibFrameBuffer* fb);#endif libframebuffer.c #include libframebuffer.h #include stdlib.hLibFrameBuffer* LibFrameBufferInit() {return (LibFrameBuffer)malloc(sizeof(LibFrameBuffer)); }void LibFrameBufferFree(LibFrameBuffer fb) {free(fb); }home_page.c #include awtk.h #include libframebuffer.h/*** 初始化窗口的子控件/ static ret_t visit_init_child(void ctx, const void* iter) {widget_t* win WIDGET(ctx);widget_t* widget WIDGET(iter);const char* name widget-name;// 初始化指定名称的控件设置属性或注册事件请保证控件名称在窗口上唯一if (name ! NULL name ! \0) {}return RET_OK; }/** 初始化窗口/ ret_t home_page_init(widget_t win, void* ctx) {(void)ctx;return_value_if_fail(win ! NULL, RET_BAD_PARAMS);widget_foreach(win, visit_init_child, win);LibFrameBufferInit();return RET_OK; } 在项目根目录下设置好.clang-tidy这个是clang-tidy的配置文件, clang-tidy有很多的check项和代码命名风格相关的是readability-identifier-naming这个checker下面有非常多类型的拼写设置我这里设置了类, 变量函数宏四个类型的拼写项其中前三个的lower_case对应的就是匈牙利小写写法最后一个UPPER_CASE是全大写写法。 readability-identifier-naming的具体设置可见https://clang.llvm.org/extra/clang-tidy/checks/readability/identifier-naming.html Checks: readability-identifier-naming CheckOptions:- key: readability-identifier-naming.ClassCasevalue: lower_case- key: readability-identifier-naming.VariableCasevalue: lower_case- key: readability-identifier-naming.FunctionCasevalue: lower_case- key: readability-identifier-naming.MacroDefinitionCasevalue: UPPER_CASEclang-tidy本身相当于半个编译器会对翻译单元的头文件进行处理而不是像脚本那样单纯进行文本解析所以在给clang-tidy一个找不到头文件的源文件时会导致报错 zhangdalinhuwyi-ubuntu:~/AWStudioProjects/awtk_clang_tidy_test\( clang-tidy src/pages/home_page. Error while trying to load a compilation database: Could not auto-detect compilation database for file src/pages/home_page. No compilation database found in /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages or any parent directory fixed-compilation-database: Error while opening fixed database: No such file or directory json-compilation-database: Error while opening JSON database: No such file or directory Running without flags. Error while processing /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages/home_page.. error: no input files [clang-diagnostic-error] error: no such file or directory: /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages/home_page. [clang-diagnostic-error] error: unable to handle compilation, expected exactly one compiler job in [clang-diagnostic-error] Found compiler error(s).因此必须找到一个方法让clang-tidy能够读取到项目所有的源文件和头文件。 使用compiler_command.json compiler_command.json上面记录了项目每个编译的编译命令输入源文件和输出obj类似于给工具一个符号表clang-tidy通过这张符号表进行解析。 在CMake可以设置set(CMAKE_EXPORT_COMPILE_COMMANDS ON)生成compiler_command.json给clang-tidy我于是去看scons有没有对应设置还好有见https://scons.org/doc/latest/HTML/scons-user/ch27.html 在SConstruct和SConscript分别添加env.Tool(compilation_db)和env.CompilationDatabase()[0], scons就能在BIN_DIR得到compiler_command.json我试过在SConscript把两个指令一起加进去不知道为什么在windows会报找不到AttributeError: SConsEnvironment object has no attribute __COMPILATIONDB_Entry:的错误Linux上就正常。我这里的情形是跨平台windows和linux都需要考虑使用。 SConstruct env helper.call(DefaultEnvironment) env.Tool(compilation_db)SConscript sources Glob(**/*.c) Glob(*.c) compile_database env.CompilationDatabase()[0]scons编译在BIN_DIR得到compiler_command.json验证通过。 接下来写clang-tidy调用逻辑scons本身是python脚本直接封装成函数就好了难点在于如何让scons执行时如果需要将封装函数也一并调用对此scons提供了Options选项, 可以自定义选项来控制调用逻辑见https://scons.org/doc/latest/HTML/scons-user/ch10.html 这里就提供一个--clang-tidy选项给scons修改后的SConscript: import os import subprocess from SCons.Script import *env DefaultEnvironment().Clone() BIN_DIR os.environ[BIN_DIR] LIB_DIR os.environ[LIB_DIR]sources Glob(**/*.c) Glob(*.c)AddOption(--clang-tidy,destclang_tidy,metavarBOOL,actionstore_true,defaultFalse,helpDont run clang-tidy static code analysis automatically) compile_database env.CompilationDatabase()[0] program env.Program(os.path.join(BIN_DIR, demo), sources, LIBS env[LIBS])def run_clang_tidy(target, source, env):source_file str(source[0])compilation_db str(source[1])cmd fclang-tidy -p {compilation_db} -header-filter.* {source_file}print(fRunning: {cmd})subprocess.run(cmd, shellTrue)return 0print(fclang_tidy option {GetOption(clang_tidy)})if GetOption(clang_tidy) True:for source in sources:run_clang_tidy(,[source, compile_database], env)执行会看到clang-tidy把三方库的头文件也加进了检测原因是设置用了-header-filter.*来将项目头文件加入检测不加这个选项是只能检测c文件的而且函数只能检测到没有加入头文件声明的函数。 /home/zhangdalin/AWStudioProjects/awtk/3rd/SDL/include/SDL_stdinc.h:569:9: warning: invalid case style for macro definition SDL_malloc [readability-identifier-naming] #define SDL_malloc malloc^~~~~~~~~~SDL_MALLOC /home/zhangdalin/AWStudioProjects/awtk/3rd/SDL/include/SDL_stdinc.h:570:9: warning: invalid case style for macro definition SDL_calloc [readability-identifier-naming] #define SDL_calloc calloc^~~~~~~~~~SDL_CALLOC /home/zhangdalin/AWStudioProjects/awtk/3rd/SDL/include/SDL_stdinc.h:571:9: warning: invalid case style for macro definition SDL_realloc [readability-identifier-naming] #define SDL_realloc realloc^~~~~~~~~~~SDL_REALLOC解决方法是在.clang-tidy下设置HeaderFilterRegex, 原理是clang-tidy搜索的文件是绝对路径的列表设置HeaderFilterRegex将只检测和设置的正则匹配的文件路径。 注意原来脚本的-header-filter.*要去掉否则会覆盖.clang-tidy上的设置那就失效了。 .clang-tidy HeaderFilterRegex: awtk_clang_tidy_test\\src\\.*|awtk_clang_tidy_test/src/.* #左边匹配windows下项目路径右边匹配linux下项目路径SConscript def run_clang_tidy(target, source, env):source_file str(source[0])compilation_db str(source[1])cmd fclang-tidy -p {compilation_db} {source_file}print(fRunning: {cmd})subprocess.run(cmd, shellTrue)return 0自此一个基础的集成就完成了。 Running: clang-tidy -p compile_commands.json common/navigator.c 2024 warnings generated. Suppressed 2024 warnings (2024 in non-user code). Use -header-filter.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. Running: clang-tidy -p compile_commands.json modules/libframebuffer.c 679 warnings generated. /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.c:4:17: warning: invalid case style for function LibFrameBufferInit [readability-identifier-naming] LibFrameBuffer* LibFrameBufferInit()^~~~~~~~~~~~~~~~~~lib_frame_buffer_init /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.c:9:6: warning: invalid case style for function LibFrameBufferFree [readability-identifier-naming] void LibFrameBufferFree(LibFrameBuffer* fb)^~~~~~~~~~~~~~~~~~lib_frame_buffer_free尝试集成2.0 看似简单实际引用到项目还是有问题scons不像CMake, 编译compiler_command.json的过程和编译项目的过程是绑死的一定要编译完项目才会生成compiler_command.json我曾经试过把env.Program只生成json发现json能够出来但是里面不带任何项目相关的文件编译命令只有编译整个项目才能更新compiler_command.json。 这就是scons的不便之处了项目是没法先静态检测再编译的只能放到编译后再检测了。如果是CMake大可以通过cmake -S. -B build和cmake --build build把构建compiler_command.json和编译项目的过程按先后分开。 怎么让scons在env.Program后执行自定义命令可以用env.Command, scons编译先后顺序涉及到builder的概念这里就不深入了参考 https://stackoverflow.com/questions/36273482/scons-strange-execution-order https://scons.org/doc/1.3.0/HTML/scons-user/c3721.html 修改后的SConscript如下 import os import subprocess from SCons.Script import *env DefaultEnvironment().Clone() BIN_DIR os.environ[BIN_DIR] LIB_DIR os.environ[LIB_DIR]sources Glob(**/*.c) Glob(*.c)AddOption(--clang-tidy,destclang_tidy,metavarBOOL,actionstore_true,defaultFalse,helpDont run clang-tidy static code analysis automatically) compile_database env.CompilationDatabase()[0] program env.Program(os.path.join(BIN_DIR, demo), sources, LIBS env[LIBS])def run_clang_tidy(target, source, env):source_file str(source[0])compilation_db str(source[1])cmd fclang-tidy -p {compilation_db} {source_file}print(fRunning: {cmd})subprocess.run(cmd, shellTrue)return 0print(fclang_tidy option {GetOption(clang_tidy)})if GetOption(clang_tidy) True:for source in sources:# 会在env.Program之后执行env.Command(targetf{os.path.basename(str(source))}.clang-tidy.log,source[source, compile_database],actionAction(run_clang_tidy, cmdstrRunning clang-tidy on \){SOURCE})) 把编译出的compile_commands.json删了然后scons –clang-tidy测试正常运行: zhangdalinhuwyi-ubuntu:~/AWStudioProjects/awtk_clang_tidy_test$ scons –clang-tidy scons: Reading SConscript files … APP_SCRIPTS_ROOT:/home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/scripts AWTK_ROOT: /home/zhangdalin/AWStudioProjects/awtk AWTK_SCRIPTS_ROOT: /home/zhangdalin/AWStudioProjects/awtk/scripts … /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/bin exist. /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/lib exist. False AWTK_ROOT: /home/zhangdalin/AWStudioProjects/awtk TKC_ONLY: False {} /home/zhangdalin/AWStudioProjects/awtk/bin/libawtk.so/home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/bin clang_tidy option True scons: done reading SConscript files. scons: Building targets … Building compilation database src/compile_commands.json Running clang-tidy on src/application.c Running: clang-tidy -p src/compile_commands.json src/application.c 2024 warnings generated. Suppressed 2024 warnings (2024 in non-user code). Use -header-filter.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. Running clang-tidy on src/pages/home_page.c Running: clang-tidy -p src/compile_commands.json src/pages/home_page.c 2027 warnings generated. src/pages/home_page.c:8:13: warning: unused variable win [clang-diagnostic-unused-variable]widget_t* win WIDGET(ctx);^ Suppressed 2026 warnings (2026 in non-user code). Use -header-filter.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. Running clang-tidy on src/modules/libframebuffer.c Running: clang-tidy -p src/compile_commands.json src/modules/libframebuffer.c 679 warnings generated. /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.c:4:17: warning: invalid case style for function LibFrameBufferInit [readability-identifier-naming] LibFrameBuffer* LibFrameBufferInit()^~~~~~~~~~~~~~~~lib_frame_buffer_init /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.c:9:6: warning: invalid case style for function LibFrameBufferFree [readability-identifier-naming] void LibFrameBufferFree(LibFrameBuffer* fb)^~~~~~~~~~~~~~lib_frame_buffer_free Suppressed 677 warnings (677 in non-user code). Use -header-filter.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. Running clang-tidy on src/main.c Running: clang-tidy -p src/compile_commands.json src/main.c 2028 warnings generated. Suppressed 2028 warnings (2028 in non-user code). Use -header-filter.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. Running clang-tidy on src/common/navigator.c Running: clang-tidy -p src/compile_commands.json src/common/navigator.c 2024 warnings generated. Suppressed 2024 warnings (2024 in non-user code). Use -header-filter.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. scons: done building targets.能正常运行了这时候就可以加–fix选项去自动改naming错误了我具体测试了下还是没法全部一次性修改的有些引用函数的文件就没有改到在这个例子是只改了libframebuffer.clibframebuffer.h没有修改。好在数量少自动化工具能解决大部分。 然而还是有问题这个方案只能在linux下使用在windows上会报unable to handle compilation错误 Running clang-tidy on src\modules\libframebuffer.c Running: clang-tidy –fix -p src\compile_commands.json src\modules\libframebuffer.c Error while processing D:\AWStudioProjects\awtk_clang_tidy_test\src\modules\libframebuffer.c. error: unable to handle compilation, expected exactly one compiler job in [clang-diagnostic-error] warning: C:\Users\z5843\AppData\Local\Temp\tmp_8x5etvp.lnk: linker input unused [clang-diagnostic-unused-command-line-argument] Found compiler errors, but -fix-errors was not specified. Fixes have NOT been applied.原因是我awtk在windows上设置的用msvc编译scons对于msvc生成的compiler_command.json里面调用指令实际上要通过一层快捷方式文件去中转称之为响应文件response files, 因为windows的命令行有长度限制没法一次调用太长的命令。 [{command: cl C:\Users\z5843\AppData\Local\Temp\tmpwbrtpkke.lnk,directory: D:\AWStudioProjects\awtk_clang_tidy_test,file: src\common\navigator.c,output: src\common\navigator.obj},{command: cl C:\Users\z5843\AppData\Local\Temp\tmpmf4y8gp4.lnk,directory: D:\AWStudioProjects\awtk_clang_tidy_test,file: src\modules\libframebuffer.c,output: src\modules\libframebuffer.obj},{command: cl C:\Users\z5843\AppData\Local\Temp\tmpjye3ldpl.lnk,directory: D:\AWStudioProjects\awtk_clang_tidy_test,file: src\pages\home_page.c,output: src\pages\home_page.obj},{command: cl C:\Users\z5843\AppData\Local\Temp\tmpjtyr5i36.lnk,directory: D:\AWStudioProjects\awtk_clang_tidy_test,file: src\application.c,output: src\application.obj},{command: cl C:\Users\z5843\AppData\Local\Temp\tmpn639b_bf.lnk,directory: D:\AWStudioProjects\awtk_clang_tidytest,file: src\main.c,output: src\main.obj},{command: cl C:\Users\z5843\AppData\Local\Temp\tmpghyoi9f.lnk,directory: D:\AWStudioProjects\awtk_clang_tidy_test,file: D:\AWStudioProjects\awtk\3rd\gtest\googletest\src\gtest-all.cc,output: D:\AWStudioProjects\awtk\3rd\gtest\googletest\src\gtest-all.obj},{command: cl C:\Users\z5843\AppData\Local\Temp\tmpubp7ar8o.lnk,directory: D:\AWStudioProjects\awtk_clang_tidy_test,file: tests\main.cc,output: tests\main.obj} ]这些快捷方式第一次编译才会创建在第二次编译时就能复用而且如果修改了源文件比如修改代码或者开关宏这些快捷方式就失效了这就是为什么我改源文件或者删除compiler_command.json都会导致报unable to handle compilation错误。我在网上找了一圈都不知道怎么关掉这个响应文件。 其实也可以设置awtk编译方式为MINGW, 这样就没有问题了可惜我实际项目一些三方库是msvc编译的和mingw不兼容这个选择就废了。 没法泛化到windows方案还要继续改进。 BTW CMakeMSVC在windows上是不会生成compiler_command.json的不知道scons怎么做到的生成。 尝试集成3.0 其实不使用compiler_command.json, 也可以通过给clang-tidy直接指明源文件和头文件路径的方式来绕过这样检测就不依赖于编译了。 可以通过直接用scons的配置文件比较方便也可以独立脚本不过路径需要脚本去暴力匹配如果项目庞大写起匹配逻辑会比较麻烦这里选用前者。 之前的脚本其实还有个问题run_clang_tidy执行一次只检测一个文件一个文件就执行一次clang-tidy命令这样使用是低效的实际上clang-tidy可以批量集成多个文件一起去分析。 run_clang_tidy修改拆除来放到clang_tidy_helper.py置于scripts文件夹 import subprocessdef run_clang_tidy(flags, source_file_str, cxxflags, include_file_str):cmd fclang-tidy {flags} {source_file_str} – {cxxflags} {include_file_str}print(fRunning: {cmd})subprocess.run(cmd, shellTrue)return 0 修改后的SConscript如下 import os import subprocess from scripts.clang_tidy_helper import run_clang_tidy from SCons.Script import env DefaultEnvironment().Clone() BIN_DIR os.environ[BIN_DIR] LIB_DIR os.environ[LIB_DIR]sources Glob(**/.c) Glob(.c)AddOption(–clang-tidy,destclang_tidy,metavarBOOL,actionstore_true,defaultFalse,helpDont run clang-tidy static code analysis automatically)program env.Program(os.path.join(BIN_DIR, demo), sources, LIBS env[LIBS])if GetOption(clang_tidy) True:sources_file_str .join(os.path.normpath(str(s)) for s in sources) flags env[CCFLAGS] include_file_str .join([f-I{os.path.normpath(str(i))} for i in env[CPPPATH]])run_clang_tidy(, sources_file_str, flags, include_file_str)运行可以看到输出不一样了会统计文件数累计warning和error数能检测出libframebuffer的naming错误不过这次头文件和源文件的error都可以显示了加入–fix选项运行发现头文件源文件引用的文件都被修正了。 /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.c:4:17: warning: invalid case style for function LibFrameBufferInit [readability-identifier-naming] LibFrameBuffer LibFrameBufferInit()^~~~~~~~~~~~~~lib_frame_buffer_init /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.c:4:17: note: FIX-IT applied suggested code changes /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.c:9:6: warning: invalid case style for function LibFrameBufferFree [readability-identifier-naming] void LibFrameBufferFree(LibFrameBuffer* fb)^~~~~~~~~~~~~~lib_frame_buffer_free /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.c:9:6: note: FIX-IT applied suggested code changes /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.h:10:17: warning: invalid case style for function LibFrameBufferInit [readability-identifier-naming] LibFrameBuffer* LibFrameBufferInit();^~~~~~~~~~~~~~lib_frame_buffer_init /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.h:10:17: note: FIX-IT applied suggested code changes /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.h:12:6: warning: invalid case style for function LibFrameBufferFree [readability-identifier-naming] void LibFrameBufferFree(LibFrameBuffer* fb);^~~~~~~~~~~~~~lib_frame_buffer_free /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/modules/libframebuffer.h:12:6: note: FIX-IT applied suggested code changes /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages/../modules/libframebuffer.h:10:17: warning: invalid case style for function LibFrameBufferInit [readability-identifier-naming] LibFrameBuffer* LibFrameBufferInit();^~~~~~~~~~~~~~lib_frame_buffer_init /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages/../modules/libframebuffer.h:10:17: note: FIX-IT applied suggested code changes /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages/home_page.c:28:3: note: FIX-IT applied suggested code changesLibFrameBufferInit();^ /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages/../modules/libframebuffer.h:12:6: warning: invalid case style for function LibFrameBufferFree [readability-identifier-naming] void LibFrameBufferFree(LibFrameBuffer* fb);^~~~~~~~~~~~~~lib_frame_buffer_free /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages/../modules/libframebuffer.h:12:6: note: FIX-IT applied suggested code changes /home/zhangdalin/AWStudioProjects/awtk_clang_tidy_test/src/pages/home_page.c:8:13: warning: unused variable win [clang-diagnostic-unused-variable]widget_t* win WIDGET(ctx);^ clang-tidy applied 7 of 7 suggested fixes. Suppressed 8802 warnings (8802 in non-user code). Use -header-filter.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. scons: done reading SConscript files. scons: Building targets … scons: . is up to date. scons: done building targets.如果不想编译项目单独做静态检测也比较简单 AddOption(–no-compile,destno_compile,metavarBOOL,actionstore_true,defaultFalse,helpDont compile the code)if GetOption(no_compile) False:program env.Program(os.path.join(BIN_DIR, demo), sources, LIBS env[LIBS])从这边开始总算就没有什么比较难受的使用问题了而且可以集成检测工具一起编译也可以单独检测。 还有很多细节比如改用run-clang-tidy.py脚本提速ci/cd集成时间原因先写到这里后面有时间看看如何实现。 最终的脚本 SConscript import os import subprocess from scripts.clang_tidy_helper import run_clang_tidy from SCons.Script import env DefaultEnvironment().Clone() BIN_DIR os.environ[BIN_DIR] LIB_DIR os.environ[LIB_DIR]sources Glob(**/.c) Glob(*.c)AddOption(–clang-tidy,destclang_tidy,metavarBOOL,actionstore_true,defaultFalse,helpDont run clang-tidy static code analysis automatically)AddOption(–no-compile,destno_compile,metavarBOOL,actionstore_true,defaultFalse,helpDont compile the code)if GetOption(no_compile) False:program env.Program(os.path.join(BIN_DIR, demo), sources, LIBS env[LIBS])if GetOption(clang_tidy) True:sources_file_str .join(os.path.normpath(str(s.get_abspath())) for s in sources) flags env[CCFLAGS] include_file_str .join([f-I{os.path.normpath(str(i))} for i in env[CPPPATH]])run_clang_tidy(–fix , sources_file_str, flags, include_file_str)SConstruct import os import scripts.app_helper as app import clang_tidy as tidyCUSTOM_WIDGET_LIBS [{root : 3rd/awtk-widget-label-rotate,shared_libs: [label_rotate],static_libs: [] }]DEPENDS_LIBS CUSTOM_WIDGET_LIBS []helper app.Helper(ARGUMENTS) helper.set_deps(DEPENDS_LIBS)# app.prepare_depends_libs(ARGUMENTS, helper, DEPENDS_LIBS) env helper.call(DefaultEnvironment)SConscriptFiles [src/SConscript, tests/SConscript] helper.SConscript(SConscriptFiles)scripts/clang_tidy_helper.py import os import sys import platform import re import subprocessdef run_clang_tidy(flags, source_file_str, cxxflags, include_file_str):cmd fclang-tidy {flags} {source_file_str} – {cxxflags} {include_file_str}print(fRunning: {cmd})subprocess.run(cmd, shellTrue)return 0 补充 clang-tidy不一定能一次解决所有的代码规范问题比如私有函数习惯写__前缀即使是用匈牙利写法也会被误报 D:\AWStudioProjects\awtk_clang_tidy_test\src\modules\lib_framebuffer.c:11:6: warning: invalid case style for function __lib_framebuffer_load_format [readability-identifier-naming] 11 | void __lib_framebuffer_load_format(lib_framebuffer *fb){| ^~~~~~~~~~~~~~~~~~~~~~~~~| lib_framebuffer_load_format D:\AWStudioProjects\awtk_clang_tidy_test\src\modules\lib_framebuffer.c:31:6: warning: invalid case style for function __lib_framebuffer_init [readability-identifier-naming]31 | void __lib_framebuffer_init(lib_framebuffer *fb, const char *path) {| ^~~~~~~~~~~~~~~~~~| lib_framebuffer_init D:\AWStudioProjects\awtk_clang_tidy_test\src\modules\lib_framebuffer.c:73:6: warning: invalid case style for function __lib_framebuffer_destroy [readability-identifier-naming]73 | void __lib_framebuffer_destroy(lib_framebuffer *fb) {| ^~~~~~~~~~~~~~~~~~~~~~~| lib_framebuffer_destroyclang-tidy做了一个workaround, 允许用正则的方式去忽略匹配的命名样式。 注意必须是全字匹配部分匹配是不起效的。 Checks: readability-identifier-naming CheckOptions:- key: readability-identifier-naming.ClassCasevalue: lower_case- key: readability-identifier-naming.VariableCasevalue: lower_case- key: readability-identifier-naming.FunctionIgnoredRegexpvalue: __.*- key: readability-identifier-naming.ConstexprVariableCasevalue: UPPER_CASE参考 https://github.com/SCons/scons/issues/4637 https://scons.org/doc/latest/HTML/scons-user/ch27.html https://lrita.github.io/2023/03/21/auto-clang-tidy-cpp-code/