diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..214444e9 --- /dev/null +++ b/.clang-format @@ -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: '^' + 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 \ No newline at end of file diff --git a/docs/DEVELOP_ZH.md b/docs/DEVELOP_ZH.md index c75d105d..953edca7 100755 --- a/docs/DEVELOP_ZH.md +++ b/docs/DEVELOP_ZH.md @@ -26,7 +26,15 @@ 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 . @@ -34,7 +42,7 @@ napi_generator-win.exe、napi_generator-linux、napi_generator-macos -5.根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件,可执行命令: +6.根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件,可执行命令: pkg -t node14-win . -o napi_generator-win.exe @@ -63,7 +71,15 @@ 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 . @@ -71,7 +87,7 @@ napi_generator-win.exe、napi_generator-linux、napi_generator-macos -5.根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件,可执行命令: +6.根据需求打包指定系统下的可执行文件。若想只打包windows系统下可执行文件,可执行命令: pkg -t node14-win . -o napi_generator-win.exe diff --git a/package.json b/package.json index c77dfccb..8346a427 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,10 @@ "bin": "./src/gen/cmd_gen.js", "pkg": { "assets": [ - "src/node_modules/typescript/**/*" + "src/node_modules/typescript/**/*", + "clang-format.exe", + "clang-format", + ".clang-format" ] } } diff --git a/src/gen/generate.js b/src/gen/generate.js index 84b17001..5f5f340c 100644 --- a/src/gen/generate.js +++ b/src/gen/generate.js @@ -22,6 +22,9 @@ const { generateGYP } = require("./extend/binding_gyp"); const { generateGN } = require("./extend/build_gn"); const { generateBase } = require("./extend/tool_utility"); const { NumberIncrease } = require("./tools/common"); +const os = require("os"); +const path = require('path') +const { NapiLog } = require("./tools/NapiLog"); var fs = require('fs'); let moduleCppTmplete = `\ @@ -129,6 +132,60 @@ let implCppTemplete = `\ #include "[implName].h" [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) { 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, "[implName]", ns0.name); middleCpp = replaceAll(middleCpp, "[modulename]", moduleName); + genFileList.splice(0, genFileList.length); writeFile(re.pathJoin(destDir, "%s_middle.cpp".format(ns0.name)), null != license ? (license + "\n" + middleCpp) : middleCpp) + genFileList.push("%s_middle.cpp".format(ns0.name)); let implH = replaceAll(implHTemplete, "[impl_name_upper]", ns0.name.toUpperCase()) implH = implH.replaceAll("[numberUsing]", numberUsing); @@ -158,15 +217,20 @@ function generateAll(structOfTs, destDir, moduleName, numberType) { } implH = replaceAll(implH, "[importTs]", imports) 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) implCpp = implCpp.replaceAll("[implCpp_detail]", result.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('.', '_') generateGYP(destDir, ns0.name, license) // 生成ubuntu下测试的编译脚本 generateGN(destDir, ns0.name, license, partName) // 生成BUILD.gn for ohos generateBase(destDir, license) // tool_utility.h/cpp + genFileList.push("tool_utility.h"); + genFileList.push("tool_utility.cpp"); + formatCode(destDir); } module.exports = { diff --git a/src/gen/generate/enum.js b/src/gen/generate/enum.js index 96d5f03d..fbf41879 100644 --- a/src/gen/generate/enum.js +++ b/src/gen/generate/enum.js @@ -23,7 +23,7 @@ function generateEnum(name, data) { if (data.enumValueType == EnumValueType.ENUM_VALUE_TYPE_STRING) { implH = `\nclass %s {\npublic:\n`.format(name, implH) } 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 { NapiLog.logError(`The enum type[%s] is not support`.format(data.enumValueType)); return {implH: "", implCpp: ""} diff --git a/src/gen/main.js b/src/gen/main.js index 31ce34f9..2614d595 100644 --- a/src/gen/main.js +++ b/src/gen/main.js @@ -16,7 +16,6 @@ const { analyzeFile } = require("./analyze"); const { generateAll } = require("./generate"); const { NapiLog } = require("./tools/NapiLog"); const re = require("./tools/re"); -const { print } = require("./tools/tool"); var fs = require('fs'); function doGenerate(ifname, destdir, imports,numberType) { diff --git a/src/gen/tools/NapiLog.js b/src/gen/tools/NapiLog.js index 75273c19..326be6f7 100755 --- a/src/gen/tools/NapiLog.js +++ b/src/gen/tools/NapiLog.js @@ -54,11 +54,24 @@ NapiLog.init = function (level, fileName) { logFileName = fileName ? fileName : "napi_generator.log"; } -function getCallPath() { +/** + * 通过调用栈获取当前正在执行的方法名,代码行数及文件路径 + * @param {} callerFuncName 指定取调用栈中哪个方法名所在的帧作为目标帧 + * @returns + */ +NapiLog.getCallPath = function(callerFuncName = null) { let callPath = "" let stackArray = new Error().stack.split('\n'); + + // 如果没有指定目标方法,默认在调用栈中查找当前方法"getCallPath"所在的帧 + let destFuncName = callerFuncName != null ? callerFuncName : "getCallPath" + 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 leftIndex = stackMsg.indexOf("(") let rightIndex = stackMsg.indexOf(")") @@ -90,7 +103,7 @@ function print(...args) { function recordLog(lev, ...args) { let origMsgInfo = args; - let callPath = getCallPath(); + let callPath = NapiLog.getCallPath("log"); let dataStr = getDateString(); let detail = args.join(" "); saveLog(dataStr + " " + callPath, LEV_STR[lev], detail);