feat: napi-tool format the c++ file with clang-format

Signed-off-by: zhangzhicheng007 <zhangzhicheng@kaihong.com>
This commit is contained in:
zhangzhicheng007 2023-01-11 14:08:11 +08:00
parent 7bad7107de
commit 5af499d79c
7 changed files with 216 additions and 10 deletions

111
.clang-format Normal file
View File

@ -0,0 +1,111 @@
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never

View File

@ -26,7 +26,15 @@
sudo npm i -g pkg sudo npm i -g pkg
4.打包三个版本 : 执行命令: 4.集成clang-format可选步骤
如果需要工具自动格式化生成的C++代码,可执行此步骤。
将windows版的clang-format.exe程序和linux版的clang-format程序拷贝到napi_generator目录下。
clang-format程序可从OpenHarmony编译环境获取
windows版OpenHarmony/prebuilts/clang/ohos/windows-x86_64/llvm/bin/clang-format.exe
Linux版OpenHarmony/prebuilts/mingw-w64/ohos/linux-x86_64/clang-mingw/bin/clang-format
5.打包三个版本 : 执行命令:
pkg . pkg .
@ -34,7 +42,7 @@
napi_generator-win.exe、napi_generator-linux、napi_generator-macos napi_generator-win.exe、napi_generator-linux、napi_generator-macos
5.根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件可执行命令 6.根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件可执行命令
pkg -t node14-win . -o napi_generator-win.exe pkg -t node14-win . -o napi_generator-win.exe
@ -63,7 +71,15 @@
npm i -g pkg npm i -g pkg
4.打包三个版本 : 使用管理员身份执行命令: 4.集成clang-format可选步骤
如果需要工具自动格式化生成的C++代码,可执行此步骤。
将windows版的clang-format.exe程序和linux版的clang-format程序拷贝到napi_generator目录下。
clang-format程序可从OpenHarmony编译环境获取
windows版OpenHarmony/prebuilts/clang/ohos/windows-x86_64/llvm/bin/clang-format.exe
Linux版OpenHarmony/prebuilts/mingw-w64/ohos/linux-x86_64/clang-mingw/bin/clang-format
5.打包三个版本 : 使用管理员身份执行命令:
pkg . pkg .
@ -71,7 +87,7 @@
napi_generator-win.exe、napi_generator-linux、napi_generator-macos napi_generator-win.exe、napi_generator-linux、napi_generator-macos
5.根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件可执行命令 6.根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件可执行命令
pkg -t node14-win . -o napi_generator-win.exe pkg -t node14-win . -o napi_generator-win.exe

View File

@ -27,7 +27,10 @@
"bin": "./src/gen/cmd_gen.js", "bin": "./src/gen/cmd_gen.js",
"pkg": { "pkg": {
"assets": [ "assets": [
"src/node_modules/typescript/**/*" "src/node_modules/typescript/**/*",
"clang-format.exe",
"clang-format",
".clang-format"
] ]
} }
} }

View File

@ -22,6 +22,9 @@ const { generateGYP } = require("./extend/binding_gyp");
const { generateGN } = require("./extend/build_gn"); const { generateGN } = require("./extend/build_gn");
const { generateBase } = require("./extend/tool_utility"); const { generateBase } = require("./extend/tool_utility");
const { NumberIncrease } = require("./tools/common"); const { NumberIncrease } = require("./tools/common");
const os = require("os");
const path = require('path')
const { NapiLog } = require("./tools/NapiLog");
var fs = require('fs'); var fs = require('fs');
let moduleCppTmplete = `\ let moduleCppTmplete = `\
@ -129,6 +132,60 @@ let implCppTemplete = `\
#include "[implName].h" #include "[implName].h"
[implCpp_detail] [implCpp_detail]
` `
var genFileList = []
function deleteFolder(folderPath) {
if (fs.existsSync(folderPath)) {
fs.rmSync(folderPath, {"recursive": true})
}
}
function createFolder(folderPath) {
if (!fs.existsSync(folderPath)) {
fs.mkdirSync(folderPath)
}
}
function formatCode(destDir) {
let sysInfo = os.platform()
let clangFmtName = sysInfo === 'win32' ? "clang-format.exe" : "clang-format"
let callPath = NapiLog.getCallPath();
callPath = callPath.substring(callPath.indexOf("[") + 1, callPath.indexOf("src"));
let dumyClangFmtFile = path.join(callPath, clangFmtName)
let dumyFmtCfgFile = path.join(callPath, ".clang-format")
if(!fs.existsSync(dumyClangFmtFile)) {
NapiLog.logInfo("Warning: clang-format does not exist, can not format cpp file.");
return
}
// 使用pkg打包的napi_generator工具其中的clang-format程序在运行时是解压到一个名为snapshot的虚拟目录中的如C:\snapshot\napi_generator\
// 虚拟目录中的clang-format程序不能直接运行必须先将它拷贝到本地硬盘的真实目录下。
createFolder(path.resolve("./tmpLocal"))
let localClangFmtFile = path.resolve("./tmpLocal/" + clangFmtName) // clang-format可执行程序
let localFmtCfgFile = path.resolve("./tmpLocal/.clang-format") // clang-format格式化配置文件
fs.copyFileSync(dumyClangFmtFile, localClangFmtFile)
fs.copyFileSync(dumyFmtCfgFile, localFmtCfgFile)
let execSync = require("child_process").execSync
if (sysInfo != 'win32') {
// linux系统下需要为临时复制的clang-format程序增加可执行权限
execSync("chmod +x " + "\"" + localClangFmtFile + "\"")
}
for (let i = 0; i < genFileList.length; ++i) {
// 文件路径前后要用引号包含,防止因为路径中存在空格而导致命令执行失败 (windows的文件夹允许有空格)
let cmd = "\"" + localClangFmtFile + "\" -style=file -i \"" + path.resolve(path.join(destDir, genFileList[i]))
+ "\""
try {
execSync(cmd) // C++文件格式化
} catch (err) {
NapiLog.logError("Failed to format code, exception: " + err.stderr)
}
}
// 格式化结束后,删除临时目录文件
deleteFolder(path.resolve("./tmpLocal"))
}
function generateAll(structOfTs, destDir, moduleName, numberType) { function generateAll(structOfTs, destDir, moduleName, numberType) {
let ns0 = structOfTs.declareNamespace[0]; let ns0 = structOfTs.declareNamespace[0];
@ -146,8 +203,10 @@ function generateAll(structOfTs, destDir, moduleName, numberType) {
middleCpp = replaceAll(middleCpp, "[init_replace]", result.middleInit); middleCpp = replaceAll(middleCpp, "[init_replace]", result.middleInit);
middleCpp = replaceAll(middleCpp, "[implName]", ns0.name); middleCpp = replaceAll(middleCpp, "[implName]", ns0.name);
middleCpp = replaceAll(middleCpp, "[modulename]", moduleName); middleCpp = replaceAll(middleCpp, "[modulename]", moduleName);
genFileList.splice(0, genFileList.length);
writeFile(re.pathJoin(destDir, "%s_middle.cpp".format(ns0.name)), writeFile(re.pathJoin(destDir, "%s_middle.cpp".format(ns0.name)),
null != license ? (license + "\n" + middleCpp) : middleCpp) null != license ? (license + "\n" + middleCpp) : middleCpp)
genFileList.push("%s_middle.cpp".format(ns0.name));
let implH = replaceAll(implHTemplete, "[impl_name_upper]", ns0.name.toUpperCase()) let implH = replaceAll(implHTemplete, "[impl_name_upper]", ns0.name.toUpperCase())
implH = implH.replaceAll("[numberUsing]", numberUsing); implH = implH.replaceAll("[numberUsing]", numberUsing);
@ -158,15 +217,20 @@ function generateAll(structOfTs, destDir, moduleName, numberType) {
} }
implH = replaceAll(implH, "[importTs]", imports) implH = replaceAll(implH, "[importTs]", imports)
writeFile(re.pathJoin(destDir, "%s.h".format(ns0.name)), null != license ? (license + "\n" + implH) : implH) writeFile(re.pathJoin(destDir, "%s.h".format(ns0.name)), null != license ? (license + "\n" + implH) : implH)
genFileList.push("%s.h".format(ns0.name));
let implCpp = implCppTemplete.replaceAll("[implName]", ns0.name) let implCpp = implCppTemplete.replaceAll("[implName]", ns0.name)
implCpp = implCpp.replaceAll("[implCpp_detail]", result.implCpp) implCpp = implCpp.replaceAll("[implCpp_detail]", result.implCpp)
writeFile(re.pathJoin(destDir, "%s.cpp".format(ns0.name)), null != license ? (license + "\n" + implCpp) : implCpp) writeFile(re.pathJoin(destDir, "%s.cpp".format(ns0.name)), null != license ? (license + "\n" + implCpp) : implCpp)
genFileList.push("%s.cpp".format(ns0.name));
let partName = moduleName.replace('.', '_') let partName = moduleName.replace('.', '_')
generateGYP(destDir, ns0.name, license) // 生成ubuntu下测试的编译脚本 generateGYP(destDir, ns0.name, license) // 生成ubuntu下测试的编译脚本
generateGN(destDir, ns0.name, license, partName) // 生成BUILD.gn for ohos generateGN(destDir, ns0.name, license, partName) // 生成BUILD.gn for ohos
generateBase(destDir, license) // tool_utility.h/cpp generateBase(destDir, license) // tool_utility.h/cpp
genFileList.push("tool_utility.h");
genFileList.push("tool_utility.cpp");
formatCode(destDir);
} }
module.exports = { module.exports = {

View File

@ -23,7 +23,7 @@ function generateEnum(name, data) {
if (data.enumValueType == EnumValueType.ENUM_VALUE_TYPE_STRING) { if (data.enumValueType == EnumValueType.ENUM_VALUE_TYPE_STRING) {
implH = `\nclass %s {\npublic:\n`.format(name, implH) implH = `\nclass %s {\npublic:\n`.format(name, implH)
} else if (data.enumValueType == EnumValueType.ENUM_VALUE_TYPE_NUMBER){ } else if (data.enumValueType == EnumValueType.ENUM_VALUE_TYPE_NUMBER){
implH = `\nenum %s {\n`.format(name, implH) implH = `\nenum class %s {\n`.format(name, implH)
} else { } else {
NapiLog.logError(`The enum type[%s] is not support`.format(data.enumValueType)); NapiLog.logError(`The enum type[%s] is not support`.format(data.enumValueType));
return {implH: "", implCpp: ""} return {implH: "", implCpp: ""}

View File

@ -16,7 +16,6 @@ const { analyzeFile } = require("./analyze");
const { generateAll } = require("./generate"); const { generateAll } = require("./generate");
const { NapiLog } = require("./tools/NapiLog"); const { NapiLog } = require("./tools/NapiLog");
const re = require("./tools/re"); const re = require("./tools/re");
const { print } = require("./tools/tool");
var fs = require('fs'); var fs = require('fs');
function doGenerate(ifname, destdir, imports,numberType) { function doGenerate(ifname, destdir, imports,numberType) {

View File

@ -54,11 +54,24 @@ NapiLog.init = function (level, fileName) {
logFileName = fileName ? fileName : "napi_generator.log"; logFileName = fileName ? fileName : "napi_generator.log";
} }
function getCallPath() { /**
* 通过调用栈获取当前正在执行的方法名代码行数及文件路径
* @param {} callerFuncName 指定取调用栈中哪个方法名所在的帧作为目标帧
* @returns
*/
NapiLog.getCallPath = function(callerFuncName = null) {
let callPath = "" let callPath = ""
let stackArray = new Error().stack.split('\n'); let stackArray = new Error().stack.split('\n');
// 如果没有指定目标方法,默认在调用栈中查找当前方法"getCallPath"所在的帧
let destFuncName = callerFuncName != null ? callerFuncName : "getCallPath"
for (let i = stackArray.length -1; i >=0 ; --i) { for (let i = stackArray.length -1; i >=0 ; --i) {
if (stackArray[i].indexOf("NapiLog.log") > 0 || stackArray[i].indexOf("Function.log") > 0) { // debug模式和打包后的可执行程序调用栈函数名不同 以NapiLog.log()方法为例:
// vscode debug模式下调用栈打印的方法名为NapiLog.log而可执行程序的调用栈中显示为Function.log()
let callerMatch = (stackArray[i].indexOf("NapiLog." + destFuncName) > 0
|| stackArray[i].indexOf("Function." + destFuncName) > 0)
if (callerMatch) {
let stackMsg = stackArray[i+1].trim() let stackMsg = stackArray[i+1].trim()
let leftIndex = stackMsg.indexOf("(") let leftIndex = stackMsg.indexOf("(")
let rightIndex = stackMsg.indexOf(")") let rightIndex = stackMsg.indexOf(")")
@ -90,7 +103,7 @@ function print(...args) {
function recordLog(lev, ...args) { function recordLog(lev, ...args) {
let origMsgInfo = args; let origMsgInfo = args;
let callPath = getCallPath(); let callPath = NapiLog.getCallPath("log");
let dataStr = getDateString(); let dataStr = getDateString();
let detail = args.join(" "); let detail = args.join(" ");
saveLog(dataStr + " " + callPath, LEV_STR[lev], detail); saveLog(dataStr + " " + callPath, LEV_STR[lev], detail);