实现对于 vivado 的关闭

This commit is contained in:
锦恢 2025-01-06 14:13:44 +08:00
parent 991686cc00
commit 25a52bc547
11 changed files with 157 additions and 30 deletions

View File

@ -110,5 +110,6 @@
"toolbar.save-as-svg": "Aktuelle Ansicht als SVG speichern",
"toolbar.save-as-pdf": "Aktuelle Ansicht als PDF speichern",
"pdf-file": "PDF-Datei",
"export-pdf": "PDF wird exportiert"
"export-pdf": "PDF wird exportiert",
"info.process-killed": "Prozess {0} wurde zerstört"
}

View File

@ -110,5 +110,6 @@
"toolbar.save-as-svg": "Save current view as SVG",
"toolbar.save-as-pdf": "Save current view as PDF",
"pdf-file": "PDF file",
"export-pdf": "Exporting PDF"
"export-pdf": "Exporting PDF",
"info.process-killed": "Process {0} has been destroyed"
}

View File

@ -110,5 +110,6 @@
"toolbar.save-as-svg": "現在のビューをSVGとして保存",
"toolbar.save-as-pdf": "現在のビューをPDFとして保存",
"pdf-file": "PDFファイル",
"export-pdf": "PDFをエクスポート中"
"export-pdf": "PDFをエクスポート中",
"info.process-killed": "プロセス {0} は破棄されました"
}

View File

@ -110,5 +110,6 @@
"toolbar.save-as-svg": "将当前视图保存为 svg",
"toolbar.save-as-pdf": "将当前视图保存为 pdf",
"pdf-file": "pdf 文件",
"export-pdf": "正在导出 pdf"
"export-pdf": "正在导出 pdf",
"info.process-killed": "进程 {0} 已经被销毁"
}

View File

@ -110,5 +110,6 @@
"toolbar.save-as-svg": "將目前視圖儲存為SVG",
"toolbar.save-as-pdf": "將目前視圖儲存為PDF",
"pdf-file": "PDF檔案",
"export-pdf": "正在匯出PDF"
"export-pdf": "正在匯出PDF",
"info.process-killed": "進程 {0} 已經被銷毀"
}

View File

@ -93,7 +93,7 @@
"digital-ide.function.lsp.file-parse-maxsize.title": "最大解析的文件阈值,大小超出这个值的文件不会被解析。单位为 MB必须是整数。默认为 1MB",
"digital-ide.structure.from-xilinx-to-standard.title": "将 Xilinx 项目转换成 Digital IDE 标准项目结构",
"digital-ide.prj.verible.install.path.title": "verible 的安装目录路径,也就是包含 verible-verilog-syntax 可执行文件的文件夹的绝对路径。如果不指定,默认采用 verible-verilog-syntax 执行诊断。",
"digital-ide.prj.verilator.install.path.title": "verilator 的安装目录路径,也就是包含了 verilator 可执行文件的文件夹的绝对路径。如不指定,默认采用 verilator 执行诊断。",
"digital-ide.prj.verilator.install.path.title": "verilator 的安装目录路径,也就是包含了 verilator 可执行文件的文件夹的绝对路径。不指定,默认采用 verilator 执行诊断。",
"digital-ide.function.lsp.linter.mode.title": "指定诊断器的诊断模式",
"digital-ide.function.lsp.linter.mode.0.title": "将所有设计源直接进行诊断,并报错,无论文件是否打开。",
"digital-ide.function.lsp.linter.mode.1.title": "单文件关闭时,对应报错去除,打开哪个文件就对哪个文件进行诊断。",

View File

@ -93,7 +93,7 @@
"digital-ide.function.lsp.file-parse-maxsize.title": "",
"digital-ide.structure.from-xilinx-to-standard.title": "將 Xilinx 專案轉換成 Digital IDE 標準專案結構",
"digital-ide.prj.verible.install.path.title": "verible 的安裝目錄路徑,也就是包含 verible-verilog-syntax 可執行文件的文件夾的絕對路徑。如果不指定,默認採用 verible-verilog-syntax 執行診斷。",
"digital-ide.prj.verilator.install.path.title": "verilator 的安裝目錄路徑,也就是包含了 verilator 可執行文件的文件夾的絕對路徑。如不指定,默認採用 verilator 執行診斷。",
"digital-ide.prj.verilator.install.path.title": "verilator 的安裝目錄路徑,也就是包含了 verilator 可執行文件的文件夾的絕對路徑。不指定,默認採用 verilator 執行診斷。",
"digital-ide.function.lsp.linter.mode.title": "指定診斷器的診斷模式",
"digital-ide.function.lsp.linter.mode.0.title": "將所有設計源直接進行診斷,並報錯,無論文件是否打開。",
"digital-ide.function.lsp.linter.mode.1.title": "單文件關閉時,對應報錯去除,打開哪個文件就對哪個文件進行診斷。",

View File

@ -138,4 +138,5 @@ export function activate(context: vscode.ExtensionContext) {
export function deactivate() {
lspClient.deactivate();
manager.prjManage.pl?.exit();
}

View File

@ -3,7 +3,8 @@ import * as os from 'os';
import * as vscode from 'vscode';
import * as childProcess from 'child_process';
import { AbsPath } from ".";
import { AbsPath, MainOutput } from ".";
import { t } from '../i18n';
export class PathSet {
files: Set<AbsPath> = new Set<AbsPath>();
@ -161,3 +162,93 @@ export function getPlatformPlatformSignature(): IPlatformSignature {
default: return IPlatformSignature.unsupport;
}
}
/**
* @description {name} pid
* @returns
*/
export function getPIDsWithName(name: string): Promise<number[]> {
return new Promise((resolve, reject) => {
let command: string;
let parseOutput: (output: string) => number[];
const currentPlatform = os.platform();
if (currentPlatform === 'win32') {
// Windows 使用 tasklist 命令
command = `tasklist /FI "IMAGENAME eq ${name}*" /FO CSV /NH`;
parseOutput = (output: string) => {
return output
.split('\n')
.filter(line => line.includes(name))
.map(line => {
const [imageName, pid] = line.split('","');
return parseInt(pid.replace(/"/g, ''), 10);
});
};
} else {
// macOS 和 Linux 使用 ps 命令
command = 'ps -e -o pid,comm=';
parseOutput = (output: string) => {
return output
.split('\n')
.filter(line => line.includes(name))
.map(line => {
const [pid] = line.trim().split(' ');
return parseInt(pid, 10);
});
};
}
// 执行命令
childProcess.exec(command, (error, stdout, stderr) => {
if (error) {
reject(`Error: ${error.message}`);
return;
}
if (stderr) {
reject(`Stderr: ${stderr}`);
return;
}
// 解析输出并返回进程号
const processes = parseOutput(stdout);
resolve(processes);
});
});
}
export function killProcess(pid: number): Promise<void> {
return new Promise((resolve, reject) => {
let command: string;
const currentPlatform = os.platform();
if (currentPlatform === 'win32') {
// Windows 使用 taskkill 命令
command = `taskkill /PID ${pid} /F`;
} else {
// macOS 和 Linux 使用 kill 命令
command = `kill -9 ${pid}`;
}
// 执行命令
childProcess.exec(command, (error, stdout, stderr) => {
if (error) {
reject(`Error: ${error.message}`);
return;
}
if (stderr) {
reject(`Stderr: ${stderr}`);
return;
}
const message = t('info.process-killed', pid.toString());
MainOutput.report(message);
console.log(message);
resolve();
});
});
}

View File

@ -3,6 +3,8 @@
* Hardware Programming
*/
import * as vscode from 'vscode';
import { exec } from 'child_process';
import { platform } from 'os';
import { PLContext, XilinxOperation } from './xilinx';
import { BaseManage } from '../common';
@ -89,16 +91,12 @@ class PlManage extends BaseManage {
this.context.ope.gui(this.context);
}
public exit() {
public async exit() {
if (this.context.process === undefined) {
return;
}
HardwareOutput.show();
this.context.process.stdin.write('exit\n');
HardwareOutput.report(t('info.pl.exit.title'));
this.context.process = undefined;
this.context.ope.exit(this.context);
}

View File

@ -11,7 +11,7 @@ import { PropertySchema } from '../../global/propertySchema';
import { XilinxIP } from '../../global/enum';
import { HardwareOutput, MainOutput, ReportType } from '../../global/outputChannel';
import { debounce } from '../../global/util';
import { debounce, getPIDsWithName, killProcess } from '../../global/util';
import { t } from '../../i18n';
import { HdlFileProjectType } from '../../hdlParser/common';
@ -60,8 +60,10 @@ interface BootInfo {
*/
class XilinxOperation {
guiLaunched: boolean;
guiPid: number;
constructor() {
this.guiLaunched = false;
this.guiPid = -1;
}
public get xipRepo(): XilinxIP[] {
@ -142,8 +144,9 @@ class XilinxOperation {
*/
public async launch(context: PLContext): Promise<string | undefined> {
this.guiLaunched = false;
let scripts: string[] = [];
this.guiPid = -1;
let scripts: string[] = [];
let prjFilePath = this.prjPath as AbsPath;
// 找到所有的 xilinx 工程文件
const prjFiles = hdlFile.pickFileRecursive(prjFilePath,
@ -188,11 +191,12 @@ class XilinxOperation {
_this.onVivadoClose();
}, 100);
function launchScript(): Promise<ChildProcessWithoutNullStreams | undefined> {
function launchScript(pids: number[]): Promise<ChildProcessWithoutNullStreams | undefined> {
if (!opeParam.workspacePath) {
return Promise.resolve(undefined);
}
// 执行 cmd 启动
const vivadoPids = new Set<number>(pids);
const vivadoProcess = spawn(cmd, [], { shell: true, stdio: 'pipe', cwd: opeParam.workspacePath });
let status: 'pending' | 'fulfilled' = 'pending';
@ -207,11 +211,16 @@ class XilinxOperation {
});
return new Promise(resolve => {
vivadoProcess.stdout.on('data', data => {
vivadoProcess.stdout.on('data', async data => {
const message: string = _this.handleMessage(data.toString(), status);
if (status === 'pending') {
HardwareOutput.clear();
HardwareOutput.show();
const pids = await getPIDsWithName('vivado');
const newPid = pids.find(p => !vivadoPids.has(p));
if (newPid) {
_this.guiPid = newPid;
}
resolve(vivadoProcess);
}
HardwareOutput.report(message, {
@ -251,7 +260,8 @@ class XilinxOperation {
location: vscode.ProgressLocation.Notification,
cancellable: true
}, async () => {
return await launchScript();
const originVivadoPids = await getPIDsWithName('vivado');
return await launchScript(originVivadoPids);
});
context.process = process;
@ -274,7 +284,7 @@ class XilinxOperation {
}
}
private onVivadoClose() {
private async onVivadoClose() {
const workspacePath = opeParam.workspacePath;
const plName = opeParam.prjInfo.prjName.PL;
const targetPath = fspath.dirname(opeParam.prjInfo.arch.hardware.src);
@ -287,6 +297,8 @@ class XilinxOperation {
hdlDir.mvdir(sourceBdPath, targetPath, true);
HardwareOutput.report("move dir from " + sourceBdPath + " to " + targetPath);
await this.closeAllWindows();
}
public create(scripts: string[]) {
@ -436,6 +448,22 @@ class XilinxOperation {
context.process?.stdin.write(cmd + '\n');
}
public async closeAllWindows() {
if (this.guiPid > 0) {
await killProcess(this.guiPid);
}
const srcscannerPids = await getPIDsWithName('srcscanner');
for (const pid of srcscannerPids) {
await killProcess(pid);
}
}
public async exit(context: PLContext) {
context.process?.stdin.write('exit' + '\n');
await this.closeAllWindows();
}
public simulate(context: PLContext) {
this.simulateCli(context);
}
@ -630,15 +658,19 @@ file delete ${scriptPath} -force\n`;
await this.launch(context);
}
if (context.process) {
context.process.stdin.write('start_gui -quiet\n');
const tclProcess = context.process;
if (tclProcess === undefined) {
return;
}
tclProcess.stdin.write('start_gui -quiet\n');
HardwareOutput.report(t('info.pl.gui.report-title'), {
level: ReportType.Info
});
HardwareOutput.show();
this.guiLaunched = true;
}
}
public addFiles(files: string[], context: PLContext) {
if (!this.guiLaunched && files.length > 0) {