diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21c9be10..5a6fd1c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,15 @@ All notable version changes will be recorded in this file.
***
+### [v3.25.1] revision
+
+**Improve**:
+ - `Import Project`: Improve project parser when import an eclipse project.
+ - `Debug`: One-click to start debugging. NOT NEED ANY `launch.json`. [See Here](https://em-ide.com/docs/advance/debug_project)
+ - `Toolchain Options`: New option `use-newlib-nano`, `not-use-syscalls` for `arm-none-eabi-gcc` toolchain.
+
+***
+
### [v3.25.0] update
**New**:
diff --git a/lang/arm.gcc.verify.json b/lang/arm.gcc.verify.json
index 042b3c1f..e442c054 100644
--- a/lang/arm.gcc.verify.json
+++ b/lang/arm.gcc.verify.json
@@ -144,6 +144,14 @@
"dwarf-3"
]
},
+ "use-newlib-nano": {
+ "markdownDescription": "Use newlib-nano (--specs=nano.specs)",
+ "type": "boolean"
+ },
+ "not-use-syscalls": {
+ "markdownDescription": "Do not use syscalls (--specs=nosys.specs)",
+ "type": "boolean"
+ },
"misc-control": {
"markdownDescription": "Other Global Options",
"description.zh-cn": "编译器附加选项(全局)",
diff --git a/package.json b/package.json
index 7a5eb2d9..dc2cba1c 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,7 @@
"homepage": "https://em-ide.com",
"license": "MIT",
"description": "A mcu development environment for 8051/AVR/STM8/Cortex-M/MIPS/RISC-V",
- "version": "3.25.0",
+ "version": "3.25.1",
"preview": false,
"engines": {
"vscode": "^1.67.0"
@@ -114,6 +114,12 @@
"yaml": "^1.10.2"
},
"contributes": {
+ "debuggers": [
+ {
+ "type": "eide.cortex-debug",
+ "label": "EIDE (Cortex-Debug)"
+ }
+ ],
"terminal": {
"profiles": [
{
@@ -541,6 +547,20 @@
}
],
"commands": [
+ {
+ "command": "eide.debug.start",
+ "category": "eide",
+ "title": "%eide.project.debug.start%",
+ "icon": {
+ "dark": "./res/icon/Run_16x.svg",
+ "light": "./res/icon/Run_16x.svg"
+ }
+ },
+ {
+ "command": "eide.refresh.external_tools_index",
+ "category": "eide",
+ "title": "Refresh External Tools Index"
+ },
{
"command": "eide.open.makelibs.cfg",
"category": "eide",
@@ -1217,17 +1237,22 @@
{
"when": "cl.eide.projectActived && config.EIDE.Option.ShowToolbarInEditerTitle",
"command": "eide.project.build",
- "group": "navigation"
+ "group": "navigation@1"
},
{
"when": "cl.eide.projectActived && config.EIDE.Option.ShowToolbarInEditerTitle",
- "command": "eide.project.clean",
- "group": "navigation"
+ "command": "eide.project.uploadToDevice",
+ "group": "navigation@2"
},
{
"when": "cl.eide.projectActived && config.EIDE.Option.ShowToolbarInEditerTitle",
- "command": "eide.project.uploadToDevice",
- "group": "navigation"
+ "command": "eide.debug.start",
+ "group": "navigation@3"
+ },
+ {
+ "when": "cl.eide.projectActived && config.EIDE.Option.ShowToolbarInEditerTitle",
+ "command": "eide.project.clean",
+ "group": "navigation@4"
}
],
"editor/context": [
@@ -1291,10 +1316,15 @@
"when": "viewItem == SOLUTION && view == cl.eide.view.projects"
},
{
- "command": "eide.project.clean",
+ "command": "eide.debug.start",
"group": "inline@4",
"when": "viewItem == SOLUTION && view == cl.eide.view.projects"
},
+ {
+ "command": "eide.project.clean",
+ "group": "inline@5",
+ "when": "viewItem == SOLUTION && view == cl.eide.view.projects"
+ },
{
"command": "_cl.eide.project.setActive",
"when": "viewItem == SOLUTION && view == cl.eide.view.projects && cl.eide.enable.active",
@@ -1315,6 +1345,11 @@
"when": "viewItem == SOLUTION && view == cl.eide.view.projects",
"group": "2_build@2"
},
+ {
+ "command": "eide.debug.start",
+ "when": "viewItem == SOLUTION && view == cl.eide.view.projects",
+ "group": "2_build@3"
+ },
{
"command": "eide.project.uploadToDevice",
"when": "viewItem == SOLUTION && view == cl.eide.view.projects",
diff --git a/package.nls.json b/package.nls.json
index 02a8b5cc..d653b08d 100644
--- a/package.nls.json
+++ b/package.nls.json
@@ -32,6 +32,7 @@
"eide.project.modify.files.options": "Show Extra Options Of All Source Files",
"eide.project.import.ext.project.src.struct": "Import SourceFile Tree From Other Project",
"eide.project.generate_builder_params": "Generate builder.params",
+ "eide.project.debug.start": "Start Debugging (Cortex-Debug)",
"eide.prj.menus.main.static-check": "Static Check",
"eide.prj.menus.sub.static-check.cppcheck": "Run Cppcheck",
diff --git a/package.nls.zh-CN.json b/package.nls.zh-CN.json
index 8c68b003..4d62d194 100644
--- a/package.nls.zh-CN.json
+++ b/package.nls.zh-CN.json
@@ -32,6 +32,7 @@
"eide.project.modify.files.options": "查看所有源文件的附加编译参数",
"eide.project.import.ext.project.src.struct": "从其他 IDE 的项目中导入源文件树",
"eide.project.generate_builder_params": "生成 builder.params",
+ "eide.project.debug.start": "启动调试(Cortex-Debug)",
"eide.prj.menus.main.static-check": "静态检查",
"eide.prj.menus.sub.static-check.cppcheck": "执行 Cppcheck",
diff --git a/res/data/builtin_headers/lint_sdcc.h b/res/data/builtin_headers/lint_sdcc.h
index d7c90154..2887979e 100644
--- a/res/data/builtin_headers/lint_sdcc.h
+++ b/res/data/builtin_headers/lint_sdcc.h
@@ -22,7 +22,6 @@
#define __interrupt(x)
#define __using(x)
#define __at(x)
-#define __asm__(x)
#define __naked
// for pic
diff --git a/res/data/models/arm.gcc.model.json b/res/data/models/arm.gcc.model.json
index 255872f6..4bc51580 100644
--- a/res/data/models/arm.gcc.model.json
+++ b/res/data/models/arm.gcc.model.json
@@ -299,6 +299,32 @@
"cpp"
]
},
+ "use-newlib-nano": {
+ "type": "selectable",
+ "command": {
+ "true": "--specs=nano.specs",
+ "false": ""
+ },
+ "group": [
+ "c",
+ "cpp",
+ "asm",
+ "linker"
+ ]
+ },
+ "not-use-syscalls": {
+ "type": "selectable",
+ "command": {
+ "true": "--specs=nosys.specs",
+ "false": ""
+ },
+ "group": [
+ "c",
+ "cpp",
+ "asm",
+ "linker"
+ ]
+ },
"misc-control": {
"type": "list",
"command": "",
diff --git a/res/icon/Run_16x.svg b/res/icon/Run_16x.svg
new file mode 100644
index 00000000..0713e150
--- /dev/null
+++ b/res/icon/Run_16x.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/res/icon/Run_blue_16x.svg b/res/icon/Run_blue_16x.svg
new file mode 100644
index 00000000..aab6137b
--- /dev/null
+++ b/res/icon/Run_blue_16x.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/res/icon/Run_grey_16x.svg b/res/icon/Run_grey_16x.svg
new file mode 100644
index 00000000..e7abc48b
--- /dev/null
+++ b/res/icon/Run_grey_16x.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/EIDEProjectExplorer.ts b/src/EIDEProjectExplorer.ts
index d2b0a98a..6371a296 100644
--- a/src/EIDEProjectExplorer.ts
+++ b/src/EIDEProjectExplorer.ts
@@ -2668,6 +2668,10 @@ class ProjectDataProvider implements vscode.TreeDataProvider, vsco
.map(d => ePrjRoot.ToRelativePath(d.path) || d.path);
}
+ // init source args
+ const srcOptsObj = { version: EIDE_FILE_OPTION_VERSION, options: {} };
+ srcOptsObj.version = EIDE_FILE_OPTION_VERSION;
+
// init all target
for (const eTarget of ePrjInfo.targets) {
@@ -2687,108 +2691,48 @@ class ProjectDataProvider implements vscode.TreeDataProvider, vsco
}
};
- nEideTarget.custom_dep.defineList = eTarget.globalArgs.cMacros;
- nEideTarget.custom_dep.incList = eTarget.globalArgs.cIncDirs;
-
- var getRootIncompatibleArgs = (t: eclipseParser.EclipseProjectTarget): string[] => {
-
- const res: string[] = [];
-
- if (!t.incompatibleArgs['/']) return res;
- const bArgs: any = t.incompatibleArgs['/'];
- for (const key in bArgs) {
- if (!isArray(bArgs[key])) continue;
- for (const arg of bArgs[key]) {
- res.push(arg);
- }
- }
-
- return res;
- };
+ nEideTarget.custom_dep.defineList = eTarget.builldArgs.cMacros;
+ nEideTarget.custom_dep.incList = eTarget.builldArgs.cIncDirs;
+ nEideTarget.custom_dep.libList = eTarget.builldArgs.linkerLibSearchDirs;
// for arm gcc toolchain
if (nEideTarget.toolchain == 'GCC') {
- var guessArmCpuType = (t: eclipseParser.EclipseProjectTarget): string | undefined => {
-
+ var guessArmCpuType = (archName?: string): string | undefined => {
+ if (!archName)
+ return undefined;
// @note: this list is trimed, not full
- const armCpuTypeList = [
- 'Cortex-M0',
- 'Cortex-M23',
- 'Cortex-M33',
- 'Cortex-M3',
- 'Cortex-M4',
- 'Cortex-M7'
- ];
-
- for (const arg of getRootIncompatibleArgs(t)) {
- const mRes = /(cortex-m[\w\+]+)/.exec(arg);
- if (mRes && mRes.length > 1) {
- const name = mRes[1].toLowerCase();
- const idx = armCpuTypeList.map(c => c.toLowerCase())
- .findIndex(c => name == c || name.startsWith(c));
- if (idx != -1) return armCpuTypeList[idx];
- }
- }
+ const armCpuTypeMap: any = {
+ 'cortex-m0plus' : 'Cortex-M0+',
+ 'cortex-m0+' : 'Cortex-M0+',
+ 'cortex-m23' : 'Cortex-M23',
+ 'cortex-m33' : 'Cortex-M33',
+ 'cortex-m35p' : 'Cortex-M35P',
+ 'cortex-m55' : 'Cortex-M55',
+ 'cortex-m85' : 'Cortex-M85',
+ 'cortex-m0' : 'Cortex-M0',
+ 'cortex-m3' : 'Cortex-M3',
+ 'cortex-m4' : 'Cortex-M4',
+ 'cortex-m7' : 'Cortex-M7'
+ };
+ return armCpuTypeMap[archName.toLowerCase()];
};
const compilerOpt = nEideTarget.compileConfig;
- compilerOpt.cpuType = guessArmCpuType(eTarget) || 'Cortex-M3';
+ compilerOpt.cpuType = guessArmCpuType(eTarget.archName) || 'Cortex-M3';
compilerOpt.floatingPointHardware = ArmCpuUtils.hasFpu(compilerOpt.cpuType) ? 'single' : 'none';
compilerOpt.useCustomScatterFile = true;
- compilerOpt.scatterFilePath = '';
-
- getRootIncompatibleArgs(eTarget).forEach(arg => {
- if (/linker script/i.test(arg)) {
- const mRes = /[^=]+=(.+)$/.exec(arg);
- if (mRes && mRes.length > 1) {
- const p = eclipseParser.formatFilePath(mRes[1].trim());
- if (/\.ld[s]?$/i.test(p)) {
- compilerOpt.scatterFilePath = p;
- }
- }
- }
- });
+ compilerOpt.scatterFilePath = eTarget.linkerScriptPath || '';
}
-
// for riscv gcc toolchain
else if (nEideTarget.toolchain == 'RISCV_GCC') {
-
const compilerOpt = nEideTarget.compileConfig;
-
- compilerOpt.linkerScriptPath = '';
-
- getRootIncompatibleArgs(eTarget).forEach(arg => {
- if (/linker script/i.test(arg)) {
- const mRes = /[^=]+=(.+)$/.exec(arg);
- if (mRes && mRes.length > 1) {
- const p = eclipseParser.formatFilePath(mRes[1].trim());
- if (/\.ld[s]?$/i.test(p)) {
- compilerOpt.linkerScriptPath = p;
- }
- }
- }
- });
+ compilerOpt.linkerScriptPath = eTarget.linkerScriptPath || '';
}
-
// for any gcc toolchain
else if (nEideTarget.toolchain == 'ANY_GCC') {
-
const compilerOpt = nEideTarget.compileConfig;
-
- compilerOpt.linkerScriptPath = '';
-
- getRootIncompatibleArgs(eTarget).forEach(arg => {
- if (/linker script/i.test(arg)) {
- const mRes = /[^=]+=(.+)$/.exec(arg);
- if (mRes && mRes.length > 1) {
- const p = eclipseParser.formatFilePath(mRes[1].trim());
- if (/\.ld[s]?$/i.test(p)) {
- compilerOpt.linkerScriptPath = p;
- }
- }
- }
- });
+ compilerOpt.linkerScriptPath = eTarget.linkerScriptPath || '';
}
// init compiler args for target
@@ -2797,7 +2741,7 @@ class ProjectDataProvider implements vscode.TreeDataProvider, vsco
const toolchainDefConf = toolchain.getDefaultConfig();
// glob
- toolchainDefConf.global['misc-control'] = eTarget.globalArgs.globalArgs.filter(a => a.trim() != '');
+ toolchainDefConf.global['misc-control'] = eTarget.builldArgs.globalArgs.filter(a => a.trim() != '');
// asm
{
@@ -2805,8 +2749,8 @@ class ProjectDataProvider implements vscode.TreeDataProvider, vsco
const asmCfg = toolchainDefConf["asm-compiler"];
if (asmCfg['ASM_FLAGS']) flags.push(asmCfg['ASM_FLAGS']);
- eTarget.globalArgs.sMacros.forEach(m => flags.push(`-D${m}`));
- eTarget.globalArgs.assemblerArgs.forEach(arg => flags.push(arg));
+ eTarget.builldArgs.sMacros.forEach(m => flags.push(`-D${m}`));
+ eTarget.builldArgs.assemblerArgs.forEach(arg => flags.push(arg));
flags = flags.filter(p => p.trim() != '');
if (asmCfg['ASM_FLAGS'] != undefined) {
@@ -2822,12 +2766,24 @@ class ProjectDataProvider implements vscode.TreeDataProvider, vsco
let cxxFlags: string[] = [];
const ccCfg = toolchainDefConf["c/cpp-compiler"];
- if (ccCfg['C_FLAGS']) flags.push(ccCfg['C_FLAGS']);
- if (ccCfg['CXX_FLAGS']) cxxFlags.push(ccCfg['CXX_FLAGS']);
-
- eTarget.globalArgs.cCompilerArgs.forEach(arg => {
+ if (eTarget.builldArgs.optimization)
+ ccCfg['optimization'] = eTarget.builldArgs.optimization;
+ if (eTarget.builldArgs.cLanguageStd)
+ ccCfg['language-c'] = eTarget.builldArgs.cLanguageStd;
+ if (eTarget.builldArgs.cppLanguageStd)
+ ccCfg['language-cpp'] = eTarget.builldArgs.cppLanguageStd;
+ if (eTarget.builldArgs.signedChar)
+ ccCfg['signed-char'] = true;
+
+ if (ccCfg['C_FLAGS'])
+ flags.push(ccCfg['C_FLAGS']);
+ if (ccCfg['CXX_FLAGS'])
+ cxxFlags.push(ccCfg['CXX_FLAGS']);
+
+ eTarget.builldArgs.cCompilerArgs.forEach(arg => {
flags.push(arg);
- cxxFlags.push(arg);
+ //TODO not support C++ options now
+ //cxxFlags.push(arg);
});
flags = flags.filter(p => p.trim() != '');
@@ -2845,21 +2801,59 @@ class ProjectDataProvider implements vscode.TreeDataProvider, vsco
if (!toolchainDefConf.linker) toolchainDefConf.linker = {};
const ldCfg = toolchainDefConf.linker;
- const flags: string[] = eTarget.globalArgs.linkerArgs.filter(a => a.trim() != '');
+ const flags: string[] = eTarget.builldArgs.linkerArgs.filter(a => a.trim() != '');
if (ldCfg['LD_FLAGS'] != undefined) {
ldCfg['LD_FLAGS'] = flags.join(' ');
- const libFlags = eTarget.globalArgs.linkerLibArgs.filter(a => a.trim() != '');
+ const libFlags = eTarget.builldArgs.linkerLibArgs.filter(a => a.trim() != '');
if (ldCfg['LIB_FLAGS'] != undefined) {
ldCfg['LIB_FLAGS'] = libFlags.join(' ');
}
} else {
ldCfg['misc-control'] = flags.join(' ');
}
+
+ // setup link order
+ if (eTarget.objsOrder.length) {
+ const linkOrder: { pattern: string, order: number }[] = [];
+ eTarget.objsOrder.forEach((e, idx) => {
+ linkOrder.push({
+ pattern: e,
+ order: idx
+ });
+ });
+ ldCfg['object-order'] = linkOrder;
+ }
}
nEideTarget.builderOptions[toolchain.name] = toolchainDefConf;
}
+ // setup source options
+ if (eTarget.sourceArgs) {
+ srcOptsObj.options[eTarget.name] = { files: {} };
+ const srcOptions: any = srcOptsObj.options[eTarget.name].files;
+ const srcFilters = AbstractProject.getSourceFileFilter();
+ for (const fpath in eTarget.sourceArgs) {
+ const flags: string[] = [];
+ const sourceArgs = eTarget.sourceArgs[fpath];
+ if (AbstractProject.asmfileFilter.test(fpath)) {
+ sourceArgs.sIncDirs.forEach(arg => flags.push(`-I${arg}`));
+ sourceArgs.sMacros.forEach(arg => flags.push(`-D${arg}`));
+ sourceArgs.assemblerArgs.forEach(arg => flags.push(arg));
+ } else {
+ sourceArgs.cIncDirs.forEach(arg => flags.push(`-I${arg}`));
+ sourceArgs.cMacros.forEach(arg => flags.push(`-D${arg}`));
+ sourceArgs.cCompilerArgs.forEach(arg => flags.push(arg));
+ }
+ if (flags.length > 0) {
+ if (srcFilters.some(r => r.test(fpath)))
+ srcOptions[fpath] = ArrayDelRepetition(flags).join(' ');
+ else
+ srcOptions[fpath + '/*'] = ArrayDelRepetition(flags).join(' ');
+ }
+ }
+ }
+
nPrjConfig.targets[eTarget.name] = nEideTarget;
}
@@ -2880,62 +2874,9 @@ class ProjectDataProvider implements vscode.TreeDataProvider, vsco
// save all config
basePrj.prjConfig.Save();
-
- // show warning
-
- var getAllKeys = (obj: any): string[] => {
- if (typeof obj != 'object') return [];
- const keys: string[] = [];
- for (const key in obj) keys.push(key);
- return keys;
- };
-
- if (getAllKeys(ePrjInfo.envs).length > 0 ||
- ePrjInfo.targets.some(t => getAllKeys(t.incompatibleArgs).length > 0)) {
-
- let warnLines = [
- `!!! ${WARNING} !!!`,
- '',
- view_str$prompt$eclipse_imp_warning,
- '',
- '---',
- ''
- ];
-
- if (getAllKeys(ePrjInfo.envs).length > 0) {
- warnLines.push(
- `##### Eclipse Project Environment Variables #####`,
- ``,
- yaml.stringify({ 'Envs': ePrjInfo.envs }),
- ``
- );
- }
-
- warnLines.push(
- `##### Configurations For All Targets #####`,
- ``
- );
-
- ePrjInfo.targets.forEach(target => {
- warnLines.push(
- `//`,
- `///// Target: '${target.name}' /////`,
- `//`,
- '',
- yaml.stringify({ 'Incompatible Args': target.incompatibleArgs }),
- ''
- );
- });
-
- const f = File.fromArray([ePrjRoot.path, `eclipse.${AbstractProject.importerWarningBaseName}`]);
- f.Write(warnLines.join(os.EOL));
- const doc = await vscode.workspace.openTextDocument(vscode.Uri.parse(f.ToUri()));
-
- vscode.window.showTextDocument(doc, {
- preview: false,
- selection: doc.lineAt(0).range,
- });
- }
+ // save src options
+ const optFile = File.fromArray([basePrj.rootFolder.path, AbstractProject.EIDE_DIR, `files.options.yml`]);
+ optFile.Write(view_str$prompt$filesOptionsComment + yaml.stringify(srcOptsObj, { indent: 4 }));
// switch project
const selection = await vscode.window.showInformationMessage(
diff --git a/src/EclipseProjectParser.ts b/src/EclipseProjectParser.ts
index 0308a33f..c1c1dd9a 100644
--- a/src/EclipseProjectParser.ts
+++ b/src/EclipseProjectParser.ts
@@ -7,6 +7,7 @@ import { VirtualSource, AbstractProject } from './EIDEProject';
import { isArray } from 'util';
import { ArrayDelRepetition } from '../lib/node-utility/Utility';
import { File } from '../lib/node-utility/File';
+import { GlobalEvent } from './GlobalEvents';
export type EclipseProjectType = 'arm' | 'sdcc' | 'riscv' | 'gcc';
@@ -21,6 +22,15 @@ export interface EclipseProjectInfo {
export interface EclipseBuilderArgs {
+ // "level-0", "level-1", "level-2", "level-3", "level-size", "level-size-Oz", "level-fast", "level-debug"
+ optimization: string;
+ // "c89", "c90", "c99", "c11", "c17", "c23", "gnu89", "gnu90", "gnu99", "gnu11", "gnu17", "gnu23"
+ cLanguageStd: string;
+ // "c++98", "gnu++98", "c++11", "gnu++11", "c++14", "gnu++14", "c++17", "gnu++17", "c++20", "gnu++20", "c++23", "gnu++23"
+ cppLanguageStd: string;
+ // Signed Char (-fsigned-char)
+ signedChar: boolean;
+
globalArgs: string[];
cIncDirs: string[];
@@ -33,17 +43,25 @@ export interface EclipseBuilderArgs {
linkerArgs: string[];
linkerLibArgs: string[];
+ linkerLibSearchDirs: string[];
}
export interface EclipseProjectTarget {
name: string;
excList: string[];
- globalArgs: EclipseBuilderArgs;
- incompatibleArgs: { [path: string]: EclipseBuilderArgs }; // only use to show for user, not use in program
+ builldArgs: EclipseBuilderArgs;
+ sourceArgs: { [path: string]: EclipseBuilderArgs };
+ archName?: string;
+ linkerScriptPath?: string;
+ objsOrder: string[];
}
function newEclipseBuilderArgs(): EclipseBuilderArgs {
return {
+ optimization: 'level-debug',
+ cLanguageStd: 'c11',
+ cppLanguageStd: 'c++11',
+ signedChar: false,
globalArgs: [],
cIncDirs: [],
cMacros: [],
@@ -52,7 +70,8 @@ function newEclipseBuilderArgs(): EclipseBuilderArgs {
sMacros: [],
assemblerArgs: [],
linkerArgs: [],
- linkerLibArgs: []
+ linkerLibArgs: [],
+ linkerLibSearchDirs: []
};
}
@@ -84,12 +103,16 @@ export function formatFilePath(path: string): string {
.replace('${ProjName}/', '')
.replace('${ProjName}', '.')
.replace('PROJECT_LOC/', '')
- .replace('${PROJECT_LOC}/', '')
- .replace(/^"+/, '')
- .replace('${workspace_loc:/', '')
- .replace(/"+$/, '')
- .replace(/\}$/, '')
- .replace(/\/+$/, '');
+ .replace('${PROJECT_LOC}/', '');
+
+ // remove leading and tailing '"'
+ if (path.charAt(0) == '"' && path.charAt(path.length - 1) == '"')
+ path = path.substr(1, path.length - 2);
+ // conv ${workspace_loc:/xxx} to xxx
+ if (path.startsWith('${workspace_loc:/') && path.charAt(path.length - 1) == '}')
+ path = path.substr(17, path.length - 18);
+ // remove tailing '/'
+ path = path.replace(/\/+$/, '');
if (path.startsWith('/'))
path = '.' + path;
@@ -127,6 +150,8 @@ export async function parseEclipseProject(cprojectPath: string): Promise'`);
cprjDom = node;
+ GlobalEvent.log_info(`[EclipseParser] start parsing ${cprojectPath} ...`);
+
const root_virtualsrcs: string[] = [];
const root_srcdirs: string[] = [];
const eclipseTargetList: string[] = [];
@@ -161,24 +186,24 @@ export async function parseEclipseProject(cprojectPath: string): Promise') {
+ GlobalEvent.log_info(`[EclipseParser] skip option "${opVal.val[0]}" of path "${folderPath}"`);
+ } else {
+ builderArgs.globalArgs = builderArgs.globalArgs.concat(opVal.val);
+ }
} else {
- incompatibleArgs.globalArgs.push(`<${globOpts.$['name']}> = ${globOpts.$['value']}`);
+ GlobalEvent.log_info(
+ `[EclipseParser] unknown option "${globOpts.$['name'] || globOpts.$['id']}" of path "${folderPath}"`);
}
}
@@ -201,21 +249,34 @@ export async function parseEclipseProject(cprojectPath: string): Promise {
- const opVal = parseToolOption(op);
+ const opVal = parseToolOption(op, PROJ_INFO.type);
if (opVal) {
- if (opVal.type == 'definedSymbols') {
+ if (opVal.type == 'linkerScriptPath') {
+ if (isRootResource)
+ tInfo.linkerScriptPath = opVal.val.join(',');
+ } else if (opVal.type == 'archName') {
+ if (isRootResource)
+ tInfo.archName = opVal.val[0];
+ } else if (opVal.type == 'definedSymbols') {
builderArgs.cMacros = builderArgs.cMacros.concat(opVal.val);
- }
- else if (opVal.type == 'includePath') {
+ } else if (opVal.type == 'includePath') {
builderArgs.cIncDirs = builderArgs.cIncDirs.concat(opVal.val);
- }
- else {
+ } else if (opVal.type == 'optimization') {
+ builderArgs.optimization = opVal.val[0];
+ } else if (opVal.type == 'cLanguageStd') {
+ builderArgs.cLanguageStd = opVal.val[0];
+ } else if (opVal.type == 'signedChar') {
+ builderArgs.signedChar = opVal.val[0] == 'true';
+ } else if (opVal.type == '') {
+ GlobalEvent.log_info(`[EclipseParser] skip option "${opVal.val[0]}" of path "${folderPath}"`);
+ } else {
builderArgs.cCompilerArgs = builderArgs.cCompilerArgs.concat(opVal.val);
}
} else {
- incompatibleArgs.cCompilerArgs.push(`<${op.$['name']}> = ${op.$['value']}`);
+ GlobalEvent.log_info(
+ `[EclipseParser] unknown option "${op.$['name'] || op.$['id']}" of path "${folderPath}"`);
}
});
}
@@ -223,35 +284,50 @@ export async function parseEclipseProject(cprojectPath: string): Promise {
- const opVal = parseToolOption(op);
+ const opVal = parseToolOption(op, PROJ_INFO.type);
if (opVal) {
if (opVal.type == 'definedSymbols') {
builderArgs.sMacros = builderArgs.sMacros.concat(opVal.val);
- }
- else if (opVal.type == 'includePath') {
+ } else if (opVal.type == 'includePath') {
builderArgs.sIncDirs = builderArgs.sIncDirs.concat(opVal.val);
- }
- else {
+ } else if (opVal.type == '') {
+ GlobalEvent.log_info(`[EclipseParser] skip option "${opVal.val[0]}" of path "${folderPath}"`);
+ } else {
builderArgs.assemblerArgs = builderArgs.assemblerArgs.concat(opVal.val);
}
} else {
- incompatibleArgs.assemblerArgs.push(`<${op.$['name']}> = ${op.$['value']}`);
+ GlobalEvent.log_info(
+ `[EclipseParser] unknown option "${op.$['name'] || op.$['id']}" of path "${folderPath}"`);
}
});
}
// for linker
- else if (toolOptName.includes('Linker')) {
+ else if (toolOptName.includes('C Linker')) {
toArray(toolOpts.option).forEach(op => {
- const opVal = parseToolOption(op);
+ const opVal = parseToolOption(op, PROJ_INFO.type);
if (opVal) {
- if (opVal.type == 'libs' || opVal.type == 'userObjs') {
+ if (opVal.type == 'linkerScriptPath') {
+ if (isRootResource)
+ tInfo.linkerScriptPath = opVal.val.join(',');
+ } else if (opVal.type == 'archName') {
+ if (isRootResource)
+ tInfo.archName = opVal.val[0];
+ } else if (opVal.type == 'objsOrder') {
+ if (isRootResource)
+ tInfo.objsOrder = tInfo.objsOrder.concat(opVal.val);
+ } else if (opVal.type == 'libs' || opVal.type == 'userObjs') {
builderArgs.linkerLibArgs = builderArgs.linkerLibArgs.concat(opVal.val);
+ } else if (opVal.type == 'linkerLibSearchDirs') {
+ builderArgs.linkerLibSearchDirs = builderArgs.linkerLibSearchDirs.concat(opVal.val);
+ } else if (opVal.type == '') {
+ GlobalEvent.log_info(`[EclipseParser] skip option "${opVal.val[0]}" of path "${folderPath}"`);
} else {
builderArgs.linkerArgs = builderArgs.linkerArgs.concat(opVal.val);
}
} else {
- incompatibleArgs.linkerArgs.push(`<${op.$['name']}> = ${op.$['value']}`);
+ GlobalEvent.log_info(
+ `[EclipseParser] unknown option "${op.$['name'] || op.$['id']}" of path "${folderPath}"`);
}
});
}
@@ -402,46 +478,35 @@ export async function parseEclipseProject(cprojectPath: string): Promisetarget.incompatibleArgs[pName];
- for (const key in obj) {
- if (isArray(obj[key])) {
- obj[key] = ArrayDelRepetition(obj[key]);
- }
- }
- }
}
+ GlobalEvent.log_info(`[EclipseParser] parse done.`);
return PROJ_INFO;
}
-function parseToolOption(optionObj: any): { type: string, val: string[] } | undefined {
+function parseToolOption(optionObj: any, prjtype: EclipseProjectType): { type: string, val: string[] } | undefined {
- if (optionObj.$['id']) {
- // skip output args
- if (['.converthex', '.convertbin', '.convert']
- .some(s => optionObj.$['id'].includes(s))) {
- return;
- }
- }
+ if (!optionObj.$['id'])
+ return { type: '', val: [optionObj.$['name'] || 'noid'] };
//--
+ const VALUE_ID: string = optionObj.$['id'];
const VALUE_NAME: string = optionObj.$['name'] || '';
- const VALUE_VAL: string = optionObj.$['value'] || '';
+ const VALUE_VALS: string[] = [];
const VALUE_TYPE: string | undefined = optionObj.$['valueType'];
+ const IGNORED_VAL = { type: '', val: [VALUE_NAME || VALUE_ID] };
- let makeResult = (value: string | string[], typ?: string): { type: string, val: string[] } | undefined => {
+ const makeResult = (value: string | string[], typ?: string): { type: string, val: string[] } | undefined => {
if (value == '') return undefined;
if (isArray(value) && value.length == 0) return undefined;
return {
@@ -450,35 +515,75 @@ function parseToolOption(optionObj: any): { type: string, val: string[] } | unde
};
};
- let formatArgs = (fmt: string, arg: string): string => {
-
- if (fmt.includes('[option]')) {
+ const formatArgs = (fmt: string, arg: string): string => {
+ if (fmt.includes('[option]'))
return fmt.replace('[option]', arg);
- }
-
return fmt + arg;
}
- //
- // match by name
- //
+ const cLangStds = [ "c89", "c90", "c99", "c11", "c17", "c23", "gnu89", "gnu90", "gnu99", "gnu11", "gnu17", "gnu23" ];
- // = option.std.gnu99
- if (/Language Standard/i.test(VALUE_NAME)) {
- const m = /std\.(\w+)/.exec(VALUE_VAL);
- if (m && m.length > 1) {
- const langStd = m[1];
- return makeResult(`-std=${langStd}`, 'string');
- }
+ // ----
+ // parse special type values
+ // ----
+
+ if (VALUE_TYPE == 'definedSymbols') {
+ toArray(optionObj.listOptionValue)
+ .forEach(item => VALUE_VALS.push(item.$['value']));
+ return makeResult(VALUE_VALS, 'definedSymbols');
+ } else if (VALUE_TYPE == 'includePath') {
+ toArray(optionObj.listOptionValue).forEach(item => {
+ let p = formatFilePath(item.$['value']);
+ if (p == '..') p = '.';
+ if (p.startsWith('../')) p = p.substr(3); // for eclipse, include path is base 'Debug' folder
+ VALUE_VALS.push(p);
+ });
+ return makeResult(VALUE_VALS, 'includePath');
+ } else if (VALUE_TYPE == 'libPaths') {
+ toArray(optionObj.listOptionValue).forEach(item => {
+ let p = formatFilePath(item.$['value']);
+ if (p == '..') p = '.';
+ if (p.startsWith('../')) p = p.substr(3); // for eclipse, include path is base 'Debug' folder
+ VALUE_VALS.push(p);
+ });
+ return makeResult(VALUE_VALS, 'linkerLibSearchDirs');
+ } else if (VALUE_TYPE == 'libs') {
+ toArray(optionObj.listOptionValue)
+ .forEach(item => VALUE_VALS.push(`-l${item.$['value']}`));
+ return makeResult(VALUE_VALS, 'libs');
+ } else if (VALUE_TYPE == 'userObjs') {
+ toArray(optionObj.listOptionValue)
+ .forEach(item => VALUE_VALS.push(formatFilePath(item.$['value'])));
+ return makeResult(VALUE_VALS, 'userObjs');
+ }
+
+ // ----
+ // parse generic type values
+ // ----
+
+ if (VALUE_TYPE == 'boolean') {
+ VALUE_VALS.push(optionObj.$['value'] || 'false');
+ } else if (VALUE_TYPE == 'stringList') {
+ toArray(optionObj.listOptionValue)
+ .forEach(item => VALUE_VALS.push(formatFilePath(item.$['value'])));
+ } else { // string or enums
+ const val = optionObj.$['value']?.trim() || '';
+ VALUE_VALS.push(formatFilePath(val));
}
- if (VALUE_NAME.includes('(-D)')) {
+ if (VALUE_VALS.length == 0)
+ return IGNORED_VAL;
+
+ // ----
+ // Eclipse Generic
+ // ----
+
+ if (VALUE_NAME.includes('(-D)') || /Defined symbols/i.test(VALUE_NAME)) {
const li: string[] = [];
toArray(optionObj.listOptionValue).forEach(item => li.push(item.$['value']));
return makeResult(li, 'definedSymbols');
}
-
- if (VALUE_NAME.includes('(-I)')) {
+ if (VALUE_NAME.includes('(-I)') || VALUE_ID.includes('include.paths')) {
const li: string[] = [];
toArray(optionObj.listOptionValue).forEach(item => {
let p = formatFilePath(item.$['value']);
@@ -488,77 +593,201 @@ function parseToolOption(optionObj: any): { type: string, val: string[] } | unde
});
return makeResult(li, 'includePath');
}
-
- //
- // match by type
- //
-
- if (VALUE_TYPE == undefined)
- return;
-
- if (VALUE_TYPE == 'boolean') {
- if (VALUE_VAL == 'true') {
- const mRes = /\((\-.+)\)/.exec(VALUE_NAME);
- if (mRes && mRes.length > 1) {
- return makeResult(mRes[1]);
- }
+ // ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.scriptfile
+ if (VALUE_ID.includes('linker.script')) {
+ return makeResult(VALUE_VALS, 'linkerScriptPath');
+ }
+ // ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level = optimization.level.debug
+ if (VALUE_ID.includes('optimization.level')) {
+ if (/level\.none/.test(VALUE_VALS[0])) {
+ return makeResult(`level-0`, 'optimization');
+ } else if (/level\.debug/.test(VALUE_VALS[0])) {
+ return makeResult(`level-debug`, 'optimization');
+ } else if (/level\.optimize/.test(VALUE_VALS[0])) {
+ return makeResult(`level-1`, 'optimization');
+ } else if (/level\.more/.test(VALUE_VALS[0])) {
+ return makeResult(`level-2`, 'optimization');
+ } else if (/level\.most/.test(VALUE_VALS[0])) {
+ return makeResult(`level-3`, 'optimization');
+ } else if (/level\.size/.test(VALUE_VALS[0])) {
+ return makeResult(`level-size`, 'optimization');
+ } else {
+ return IGNORED_VAL;
}
}
-
- else if (VALUE_TYPE == 'definedSymbols') {
- const li: string[] = [];
- toArray(optionObj.listOptionValue).forEach(item => li.push(item.$['value']));
- return makeResult(li);
+ // linker.nostdlibs = false
+ if (VALUE_ID.includes('linker.nostdlibs')) {
+ if (VALUE_VALS[0] === 'true')
+ return makeResult(`-nostdlib`, 'string');
+ return IGNORED_VAL;
}
-
- else if (VALUE_TYPE == 'includePath') {
- const li: string[] = [];
+ // arm.target.family
+ if (VALUE_ID.includes('arm.target.family')) {
+ const m = /\.(cortex-m\w+)/.exec(VALUE_VALS[0]);
+ if (m && m.length > 1)
+ return makeResult(m[1], 'archName');
+ return IGNORED_VAL;
+ }
+ // option.c.linker.paths
+ if (VALUE_ID.includes('option.c.linker.paths')) {
toArray(optionObj.listOptionValue).forEach(item => {
let p = formatFilePath(item.$['value']);
if (p == '..') p = '.';
if (p.startsWith('../')) p = p.substr(3); // for eclipse, include path is base 'Debug' folder
- li.push(p);
+ VALUE_VALS.push(p);
});
- return makeResult(li);
+ return makeResult(VALUE_VALS, 'linkerLibSearchDirs');
+ }
+ // optimization.signedchar
+ if (VALUE_ID.includes('optimization.signedchar')) {
+ if (VALUE_VALS[0] === 'true')
+ return makeResult('true', 'signedChar');
+ return IGNORED_VAL;
+ }
+ // option.warnings.extrawarn
+ if (VALUE_ID.includes('option.warnings.extrawarn')) {
+ if (VALUE_VALS[0] === 'true')
+ return makeResult(`-Wextra`, 'string');
+ return IGNORED_VAL;
+ }
+ // option.warnings.allwarn
+ if (VALUE_ID.includes('option.warnings.allwarn')) {
+ if (VALUE_VALS[0] === 'true')
+ return makeResult(`-Wall`, 'string');
+ return IGNORED_VAL;
+ }
+ // option.c.compiler.otherwarnings
+ if (VALUE_ID.includes('option.c.compiler.otherwarnings')) {
+ if (VALUE_VALS[0])
+ return makeResult(VALUE_VALS[0], 'string');
+ return IGNORED_VAL;
+ }
+ // option.c.linker.nostart
+ if (VALUE_ID.includes('option.c.linker.nostart')) {
+ if (VALUE_VALS[0] === 'true')
+ return makeResult(`-nostartfiles`, 'string');
+ return IGNORED_VAL;
+ }
+ // ignore these options
+ if (VALUE_NAME.includes('-fno-rtti') ||
+ VALUE_NAME.includes('-fno-use-cxa-atexit') ||
+ VALUE_NAME.includes('-fno-threadsafe-statics') ||
+ VALUE_NAME.includes('-ffunction-sections') ||
+ VALUE_NAME.includes('-fdata-sections') ||
+ VALUE_NAME.includes('--gc-sections')) {
+ return IGNORED_VAL;
+ }
+
+ // ----
+ // silabs
+ // ----
+
+ // = false
+ if (VALUE_ID.includes('optimization.shortenums')) {
+ const v = VALUE_VALS[0];
+ if (v === "true")
+ return makeResult(`-fshort-enums`, 'string');
+ return IGNORED_VAL;
+ }
+ // = option.std.gnu99
+ // compiler.misc.dialect = com.silabs.ide.si32.gcc.cdt.managedbuild.tool.gnu.c.compiler.misc.dialect.c99
+ if (/Language (?:Standard|Dialect)/i.test(VALUE_NAME)) {
+ let m = /std\.(\w+)/.exec(VALUE_VALS[0]);
+ if (m && m.length > 1) {
+ const langStd = m[1];
+ if (cLangStds.includes(langStd))
+ return makeResult(langStd, 'cLanguageStd');
+ }
+ m = /dialect\.(\w+)/.exec(VALUE_VALS[0]);
+ if (m && m.length > 1) {
+ const langStd = m[1];
+ if (cLangStds.includes(langStd))
+ return makeResult(langStd, 'cLanguageStd');
+ }
+ return IGNORED_VAL;
+ }
+ // = ./platform/Device/SiliconLabs/EFR32BG22/Source/GCC/startup_efr32bg22.o;
+ if (VALUE_NAME.trim() == 'Linker input ordering') {
+ const paths = VALUE_VALS[0].split(';')
+ .filter(p => p.trim() !== '')
+ .map(p => '**/' + formatFilePath(p).replace(/^\.\//, ''));
+ if (paths.length == 0)
+ return IGNORED_VAL;
+ return makeResult(paths.slice(0, Math.min(5, paths.length)), 'objsOrder');
}
+ if (prjtype == 'arm') {
+ if (VALUE_NAME.includes('--specs=nano.specs') ||
+ VALUE_NAME.includes('--specs=nosys.specs'))
+ return IGNORED_VAL;
+ }
+
+ // ----
+ // STM32CubeIDE
+ // ----
+
+ // value="STM32F407VGTx" valueType="string"
+ if (VALUE_ID.includes('com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_mcu')) {
+ const mcuName = VALUE_VALS[0].toLowerCase();
+ if (/stm32f0/.test(mcuName))
+ return makeResult('cortex-m0', 'archName');
+ else if (/stm32(g0|c0|l0|u0)/.test(mcuName))
+ return makeResult('cortex-m0+', 'archName');
+ else if (/stm32(f1|f2|l1)/.test(mcuName))
+ return makeResult('cortex-m3', 'archName');
+ else if (/stm32(f4|g4|f3|l4|wb[0-9]|wl)/.test(mcuName))
+ return makeResult('cortex-m4', 'archName');
+ else if (/stm32(h5|u5|u3|l5|wba)/.test(mcuName))
+ return makeResult('cortex-m33', 'archName');
+ else if (/stm32(h7|f7)/.test(mcuName))
+ return makeResult('cortex-m7', 'archName');
+ return IGNORED_VAL;
+ }
+
+ // value="${workspace_loc:/${ProjName}/STM32F407VGTX_FLASH.ld}" valueType="string"
+ if (VALUE_ID.includes('com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.linker.option.script')) {
+ if (VALUE_VALS[0])
+ return makeResult(formatFilePath(VALUE_VALS[0]), 'linkerScriptPath');
+ }
+
+ // ----
+ // match (-xxx) options by types
+ // ----
- else if (VALUE_TYPE == 'string') {
+ if (VALUE_TYPE == 'boolean') {
+ if (VALUE_VALS[0] == 'true') {
+ const mRes = /\((\-.+)\)/.exec(VALUE_NAME);
+ if (mRes && mRes.length > 1) {
+ return makeResult(mRes[1]);
+ }
+ }
+ }
+ if (VALUE_TYPE == 'string') {
const mRes = /\((\-.+)\)/.exec(VALUE_NAME);
if (mRes && mRes.length > 1) {
const fmt = mRes[1];
- const arg = formatArgs(fmt, formatFilePath(VALUE_VAL));
+ const arg = formatArgs(fmt, formatFilePath(VALUE_VALS[0]));
return makeResult(arg);
- }
- else if (VALUE_VAL.startsWith('-')) {
- return makeResult(VALUE_VAL);
+ } else if (VALUE_VALS[0].startsWith('-')) {
+ return makeResult(VALUE_VALS[0]);
}
}
-
- else if (VALUE_TYPE == 'stringList') {
+ if (VALUE_TYPE == 'stringList') {
const mRes = /\((\-.+)\)/.exec(VALUE_NAME);
if (mRes && mRes.length > 1) {
const fmt = mRes[1];
const li: string[] = [];
- toArray(optionObj.listOptionValue).forEach(item => li.push(formatArgs(fmt, formatFilePath(item.$['value']))));
+ toArray(optionObj.listOptionValue)
+ .forEach(item => li.push(formatArgs(fmt, formatFilePath(item.$['value']))));
return makeResult(li);
} else {
const li: string[] = [];
- toArray(optionObj.listOptionValue).forEach(item => li.push(formatFilePath(item.$['value'])));
+ toArray(optionObj.listOptionValue)
+ .forEach(item => li.push(formatFilePath(item.$['value'])));
return makeResult(li);
}
}
- else if (VALUE_TYPE == 'libs') {
- const r: string[] = [];
- toArray(optionObj.listOptionValue).forEach(item => r.push(`-l${item.$['value']}`));
- return makeResult(r);
- }
-
- else if (VALUE_TYPE == 'userObjs') {
- const r: string[] = [];
- toArray(optionObj.listOptionValue).forEach(item => r.push(formatFilePath(item.$['value'])));
- return makeResult(r);
- }
+ return IGNORED_VAL;
}
function toArray(obj: any): any[] {
diff --git a/src/GlobalEvents.ts b/src/GlobalEvents.ts
index 6140146b..351429d9 100644
--- a/src/GlobalEvents.ts
+++ b/src/GlobalEvents.ts
@@ -23,7 +23,7 @@
*/
import * as events from 'events';
-import { Message, ExceptionToMessage, newMessage } from './Message';
+import { Message, ExceptionToMessage, newMessage, MessageType } from './Message';
let _globalEvent: GlobalEvent | undefined;
@@ -75,6 +75,9 @@ export class GlobalEvent {
//msg
static emit(event: 'error', error: Error): boolean; // 错误弹框(vscode 右下角)
+ /**
+ * @deprecated 已废弃,改用 GlobalEvent.show_msgbox
+ */
static emit(event: 'msg', msg: Message): boolean; // 消息弹框(vscode 右下角)
static emit(event: 'globalLog', msg: Message): boolean; // 打印日志+换行 -> 输出面板
static emit(event: 'globalLog.append', log: string): boolean; // 打印原始日志字串 -> 输出面板
@@ -83,6 +86,14 @@ export class GlobalEvent {
return GlobalEvent.GetInstance()._emitter.emit(event, args);
}
+ //vscode notify
+ static show_msgbox(type: MessageType, msg: string | Error) {
+ if (msg instanceof Error)
+ return GlobalEvent.GetInstance()._emitter.emit('msg', ExceptionToMessage(msg, type));
+ else
+ return GlobalEvent.GetInstance()._emitter.emit('msg', newMessage(type, msg));
+ }
+
//log
static log_info(msg: string) {
GlobalEvent.GetInstance()._emitter.emit('globalLog', newMessage('Info', msg));
diff --git a/src/HexUploader.ts b/src/HexUploader.ts
index 37837fa3..327df385 100644
--- a/src/HexUploader.ts
+++ b/src/HexUploader.ts
@@ -787,7 +787,7 @@ class STLinkUploader extends HexUploader {
// run
let cmd = `${commandLine} ${options.otherCmds || ''}`.trimEnd();
- if (osType() == 'win32' && exe.noSuffixName.toLowerCase().startsWith('stm32_programmer_cli'))
+ if (osType() == 'win32')
cmd = 'chcp 437 && ' + cmd; // chcp 437: 去除进度条乱码
this.executeShellCommand(this.toolType, cmd,
diff --git a/src/ResInstaller.ts b/src/ResInstaller.ts
index e4c1600c..7da025be 100644
--- a/src/ResInstaller.ts
+++ b/src/ResInstaller.ts
@@ -295,7 +295,7 @@ export class ResInstaller {
this.locker.delete(name.toLowerCase());
}
- async refreshExternalToolsIndex() {
+ async refreshExternalToolsIndex(force?: boolean) {
const indexCacheFile = File.from(ResManager.instance().GetTmpDir().path, 'eide_external_tools.index.json');
const defIdxUrl = 'https://raw.githubusercontent.com/github0null/eide_default_external_tools_index/master/index.json';
@@ -304,6 +304,8 @@ export class ResInstaller {
let cont: string | Error | undefined;
try {
+ if (force)
+ throw Error();
if (indexCacheFile.IsFile() &&
new Date().getTime() < fs.statSync(indexCacheFile.path).mtime.getTime() + (6 * 3600 * 1000))
cont = indexCacheFile.Read();
diff --git a/src/StringTable.ts b/src/StringTable.ts
index ababa2cf..485dd1df 100644
--- a/src/StringTable.ts
+++ b/src/StringTable.ts
@@ -757,7 +757,7 @@ export const rating_text = [
export const later_text = [
'稍后',
- 'Later on'
+ 'Later'
][langIndex];
export const continue_text = [
diff --git a/src/ToolchainManager.ts b/src/ToolchainManager.ts
index 93817740..eed8b19f 100644
--- a/src/ToolchainManager.ts
+++ b/src/ToolchainManager.ts
@@ -2400,7 +2400,9 @@ class GCC implements IToolchian {
global: {
"$float-abi-type": 'hard',
"output-debug-info": 'enable',
- "misc-control": "--specs=nosys.specs --specs=nano.specs"
+ "use-newlib-nano": true,
+ "not-use-syscalls": true,
+ "misc-control": ""
},
'c/cpp-compiler': {
"language-c": "c11",
diff --git a/src/extension.ts b/src/extension.ts
index ea282c59..614a825f 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -42,7 +42,8 @@ import {
view_str$operation$serialport, view_str$operation$baudrate, view_str$operation$serialport_name,
txt_install_now, txt_yes, view_str$prompt$feedback, rating_text, later_text, sponsor_author_text,
view_str$prompt$install_dotnet_and_restart_vscode,
- view_str$prompt$install_dotnet_failed
+ view_str$prompt$install_dotnet_failed,
+ view_str$prompt$not_found_compiler
} from './StringTable';
import { LogDumper } from './LogDumper';
import { StatusBarManager } from './StatusBarManager';
@@ -118,6 +119,19 @@ export async function activate(context: vscode.ExtensionContext) {
subscriptions.push(vscode.commands.registerCommand('eide.ReloadStm8Devs', () => reloadStm8Devices()));
subscriptions.push(vscode.commands.registerCommand('eide.create.clang-format.file', () => newClangFormatFile()));
subscriptions.push(vscode.commands.registerCommand('eide.cleanCache', () => cleanCache()));
+ subscriptions.push(vscode.commands.registerCommand('eide.refresh.external_tools_index', () => {
+ ResInstaller.instance()
+ .refreshExternalToolsIndex(true)
+ .then(() => GlobalEvent.emit('msg', newMessage('Info', 'Refresh Done.')))
+ .catch(err => {
+ GlobalEvent.log_warn(err);
+ GlobalEvent.log_show();
+ });
+ }));
+ subscriptions.push(vscode.commands.registerCommand('eide.debug.start', () => {
+ startDebugging()
+ .catch(err => GlobalEvent.emit('error', err));
+ }));
// internal command
// TODO
@@ -283,6 +297,8 @@ export async function activate(context: vscode.ExtensionContext) {
// others
vscode.workspace.registerTextDocumentContentProvider(VirtualDocument.scheme, VirtualDocument.instance());
vscode.workspace.registerTaskProvider(EideTaskProvider.TASK_TYPE_BASH, new EideTaskProvider());
+ vscode.debug.registerDebugConfigurationProvider('eide.cortex-debug', new CortexDebugConfigProvider(),
+ vscode.DebugConfigurationProviderTriggerKind.Dynamic);
// auto save project
projectExplorer.enableAutoSave(true);
@@ -1573,6 +1589,8 @@ class EideTerminalProvider implements vscode.TerminalProfileProvider {
import { FileWatcher } from '../lib/node-utility/FileWatcher';
import { ToolchainManager, ToolchainName } from './ToolchainManager';
+import { JLinkOptions, JLinkProtocolType, OpenOCDFlashOptions, PyOCDFlashOptions, STLinkOptions } from './HexUploader';
+import { AbstractProject } from './EIDEProject';
type MapViewParserType = 'memap' | 'builtin';
@@ -1868,6 +1886,275 @@ class MapViewEditorProvider implements vscode.CustomTextEditorProvider {
}
}
+//------------------------------------------------------------
+//- Debug Config Provider
+//------------------------------------------------------------
+
+class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider {
+
+ provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined,
+ token?: vscode.CancellationToken): vscode.ProviderResult {
+
+ const result: vscode.DebugConfiguration[] = [];
+
+ if (!folder)
+ return result;
+
+ const prj = projectExplorer.getActiveProject();
+ if (!prj)
+ return result;
+
+ let wsDir = folder.uri.fsPath;
+ let prjDir = prj.getRootDir().path;
+ if (platform.osType() == 'win32') {
+ wsDir = wsDir.toLowerCase();
+ prjDir = prjDir.toLowerCase();
+ }
+ if (wsDir != prjDir)
+ return result;
+
+ const toolchain = prj.getToolchain();
+ const toolchainManager = ToolchainManager.getInstance();
+ const settingManager = SettingManager.instance();
+
+ switch (toolchain.name) {
+ case 'AC5':
+ case 'AC6':
+ case 'GCC':
+ if (!toolchainManager.isToolchainPathReady('GCC')) {
+ const msg = view_str$prompt$not_found_compiler.replace('{}', 'arm-none-eabi-gcc');
+ ResInstaller.instance().setOrInstallTools('GCC', msg, 'EIDE.ARM.GCC.InstallDirectory');
+ return result;
+ }
+ break;
+ case 'RISCV_GCC':
+ if (!toolchainManager.isToolchainPathReady(toolchain.name)) {
+ const msg = view_str$prompt$not_found_compiler.replace('{}', 'EIDE.RISCV.InstallDirectory');
+ GlobalEvent.emit('msg', newMessage('Warning', msg));
+ return result;
+ }
+ break;
+ case 'ANY_GCC':
+ if (!toolchainManager.isToolchainPathReady(toolchain.name)) {
+ const msg = view_str$prompt$not_found_compiler.replace('{}', 'EIDE.Toolchain.AnyGcc.InstallDirectory');
+ GlobalEvent.emit('msg', newMessage('Warning', msg));
+ return result;
+ }
+ break;
+ default:
+ return result;
+ }
+
+ const newDebugCfg = (prj: AbstractProject) => {
+
+ const dbgCfg: vscode.DebugConfiguration = {
+ type: 'cortex-debug',
+ name: 'Debug',
+ request: 'launch'
+ };
+
+ const toolchain = prj.getToolchain();
+ const settingManager = SettingManager.instance();
+ switch (toolchain.name) {
+ case 'AC5':
+ case 'AC6':
+ case 'GCC':
+ dbgCfg['toolchainPrefix'] = settingManager.getGCCPrefix().replace(/-$/, '');
+ dbgCfg['armToolchainPath'] = NodePath.join(settingManager.getGCCDir().path, 'bin');
+ break;
+ default:
+ if (toolchain.getToolchainPrefix)
+ dbgCfg['toolchainPrefix'] = toolchain.getToolchainPrefix().replace(/-$/, '');
+ dbgCfg['armToolchainPath'] = NodePath.join(toolchain.getToolchainDir().path, 'bin');
+ break;
+ }
+
+ dbgCfg['cwd'] = prj.getRootDir().path;
+ dbgCfg['executable'] = prj.getExecutablePathWithoutSuffix() + '.elf';
+ dbgCfg['runToEntryPoint'] = 'main';
+ dbgCfg['liveWatch'] = {
+ 'enabled': true,
+ 'samplesPerSecond': 4
+ };
+
+ const device = prj.GetPackManager().getCurrentDevInfo();
+ if (device && device.svdPath) {
+ dbgCfg['svdFile'] = prj.ToRelativePath(device.svdPath) || device.svdPath;
+ GlobalEvent.log_info(`[debug config] Use svd file: ${dbgCfg['svdFile']}`);
+ } else {
+ const searchDirs = [
+ prj.getRootDir(),
+ prj.getEideDir(),
+ File.from(prj.getRootDir().path, 'tools')
+ ];
+ for (const d of searchDirs) {
+ const r = d.GetList([/\.svd$/i], File.EXCLUDE_ALL_FILTER);
+ if (r.length) {
+ dbgCfg['svdFile'] = prj.ToRelativePath(r[0].path) || r[0].path;
+ GlobalEvent.log_info(`[debug config] Use svd file: ${dbgCfg['svdFile']}`);
+ break;
+ }
+ }
+ }
+
+ return dbgCfg;
+ };
+
+ const fmtOpenocdCfgPath = (type: 'interface' | 'target', path: string) => {
+ let cfgpath = path.startsWith('${workspaceFolder}/')
+ ? path.replace('${workspaceFolder}/', '')
+ : `${type}/${path}`;
+ if (cfgpath && !cfgpath.endsWith('.cfg'))
+ cfgpath += '.cfg';
+ return cfgpath;
+ };
+
+ const flasherOpts = prj.GetConfiguration().uploadConfigModel.data;
+ const flashertype = prj.getUploaderType();
+
+ if (flashertype == 'JLink') {
+ const dbgCfg = newDebugCfg(prj);
+ const flasherCfg = (flasherOpts);
+ dbgCfg['name'] = 'Debug: JLINK';
+ dbgCfg['servertype'] = 'jlink';
+ dbgCfg['interface'] = flasherCfg.proType == JLinkProtocolType.JTAG ? 'jtag' : 'swd';
+ dbgCfg['device'] = flasherCfg.cpuInfo.cpuName;
+ dbgCfg['serverpath'] = NodePath.join(settingManager.getJlinkDir(),
+ platform.osType() == 'win32' ? 'JLinkGDBServerCL.exe' : 'JLinkGDBServerCLExe');
+ if (flasherCfg.otherCmds) {
+ // -IP Selects a specific J-Link
+ let m = /-IP ([^\s]+)/.exec(flasherCfg.otherCmds);
+ if (m && m.length > 1)
+ dbgCfg['ipAddress'] = m[1];
+ // -USB Selects a specific J-Link
+ m = /(?:-USB|-SelectEmuBySN) ([^\s]+)/.exec(flasherCfg.otherCmds);
+ if (m && m.length > 1)
+ dbgCfg['serialNumber'] = m[1];
+ }
+ result.push(dbgCfg);
+ }
+
+ else if (flashertype == 'OpenOCD') {
+ const dbgCfg = newDebugCfg(prj);
+ const flasherCfg = (flasherOpts);
+ dbgCfg['name'] = 'Debug: OpenOCD';
+ dbgCfg['servertype'] = 'openocd';
+ const ocdCfgs: string[] = [];
+ if (flasherCfg.interface.trim())
+ ocdCfgs.push(fmtOpenocdCfgPath('interface', flasherCfg.interface));
+ if (flasherCfg.target.trim())
+ ocdCfgs.push(fmtOpenocdCfgPath('target', flasherCfg.target));
+ dbgCfg['configFiles'] = ocdCfgs;
+ dbgCfg['serverpath'] = settingManager.getOpenOCDExePath();
+ result.push(dbgCfg);
+ }
+
+ else if (flashertype == 'pyOCD') {
+ const dbgCfg = newDebugCfg(prj);
+ const flasherCfg = (flasherOpts);
+ dbgCfg['name'] = 'Debug: pyOCD';
+ dbgCfg['servertype'] = 'pyocd';
+ dbgCfg['targetId'] = flasherCfg.targetName;
+ const cliArgs: string[] = [];
+ if (flasherCfg.config) {
+ const confFile = new File(prj.ToAbsolutePath(flasherCfg.config));
+ if (confFile.IsFile()) {
+ cliArgs.push('--config');
+ cliArgs.push(confFile.path);
+ }
+ }
+ if (flasherCfg.otherCmds)
+ cliArgs.push(flasherCfg.otherCmds);
+ if (flasherCfg.speed) {
+ cliArgs.push('-f');
+ cliArgs.push(flasherCfg.speed);
+ }
+ dbgCfg['serverArgs'] = cliArgs;
+ result.push(dbgCfg);
+ }
+
+ else if (flashertype == 'STLink') {
+ const resManager = ResManager.instance();
+ const flasherCfg = (flasherOpts);
+ // find ST-LINK_gdbserver
+ let gdbserverPath: string | undefined;
+ if (platform.osType() == 'win32') {
+ const gdbserver = File.from(resManager.getEideToolsInstallDir(),
+ 'stlink_gdb_server', 'bin', 'ST-LINK_gdbserver.exe');
+ if (!gdbserver.IsFile()) {
+ ResInstaller.instance().setOrInstallTools('stlink_gdb_server', 'Not found ST-LINK_gdbserver.exe');
+ return [];
+ }
+ gdbserverPath = gdbserver.path;
+ } else {
+ gdbserverPath = platform.find('ST-LINK_gdbserver');
+ }
+ // find STM32_Programmer_CLI
+ let cubeProgramerPath: string | undefined;
+ if (platform.osType() == 'win32') {
+ const cubeProgramerExe = File.from(resManager.getEideToolsInstallDir(),
+ 'st_cube_programer', 'bin', 'STM32_Programmer_CLI.exe');
+ if (!cubeProgramerExe.IsFile()) {
+ ResInstaller.instance().setOrInstallTools('STLink', 'Not found STM32_Programmer_CLI.exe');
+ return [];
+ }
+ cubeProgramerPath = cubeProgramerExe.dir;
+ } else {
+ const p = platform.find('STM32_Programmer_CLI');
+ if (p)
+ cubeProgramerPath = NodePath.dirname(p);
+ }
+ const dbgCfg = newDebugCfg(prj);
+ dbgCfg['name'] = 'Debug: STLink';
+ dbgCfg['servertype'] = 'stlink';
+ dbgCfg['interface'] = flasherCfg.proType == 'SWD' ? 'swd' : 'jtag';
+ dbgCfg['stlinkPath'] = gdbserverPath;
+ dbgCfg['stm32cubeprogrammer'] = cubeProgramerPath;
+ result.push(dbgCfg);
+ }
+
+ else {
+ GlobalEvent.emit('msg', newMessage('Warning',
+ `Only support 'jlink', 'stlink', 'openocd', 'pyocd'. Not support this flasher: '${flashertype}' !`));
+ }
+
+ // GlobalEvent.log_info(`provide Cortex-Debug DebugConfig`);
+ // GlobalEvent.log_info(yaml.stringify(result));
+ return result;
+ }
+}
+
+async function startDebugging() {
+
+ const prj = projectExplorer.getActiveProject();
+ if (!prj) {
+ GlobalEvent.show_msgbox('Warning', `No actived project to debug.`);
+ return;
+ }
+
+ const vscWorkspaceFolder: vscode.WorkspaceFolder = {
+ uri: vscode.Uri.file(prj.getRootDir().path),
+ name: prj.getRootDir().name,
+ index: 0
+ };
+
+ const cfgs = await (new CortexDebugConfigProvider())
+ .provideDebugConfigurations(vscWorkspaceFolder);
+ if (cfgs && cfgs.length > 0) {
+ let cfg = cfgs[0];
+ if (cfgs.length > 1) {
+ const val = await vscode.window.showQuickPick(cfgs.map(e => e.name), {
+ placeHolder: 'Select a debug configuration'
+ });
+ if (val == undefined)
+ return; // user canceled
+ const idx = cfgs.findIndex(v => v.name === val);
+ cfg = cfgs[idx];
+ }
+ await vscode.debug.startDebugging(vscWorkspaceFolder, cfg);
+ }
+}
+
///////////////////////////////////////////////////
// KEIL_C51 -> SDCC converter
///////////////////////////////////////////////////