实现对于 vivado 的关闭
This commit is contained in:
parent
991686cc00
commit
25a52bc547
@ -110,5 +110,6 @@
|
|||||||
"toolbar.save-as-svg": "Aktuelle Ansicht als SVG speichern",
|
"toolbar.save-as-svg": "Aktuelle Ansicht als SVG speichern",
|
||||||
"toolbar.save-as-pdf": "Aktuelle Ansicht als PDF speichern",
|
"toolbar.save-as-pdf": "Aktuelle Ansicht als PDF speichern",
|
||||||
"pdf-file": "PDF-Datei",
|
"pdf-file": "PDF-Datei",
|
||||||
"export-pdf": "PDF wird exportiert"
|
"export-pdf": "PDF wird exportiert",
|
||||||
|
"info.process-killed": "Prozess {0} wurde zerstört"
|
||||||
}
|
}
|
@ -110,5 +110,6 @@
|
|||||||
"toolbar.save-as-svg": "Save current view as SVG",
|
"toolbar.save-as-svg": "Save current view as SVG",
|
||||||
"toolbar.save-as-pdf": "Save current view as PDF",
|
"toolbar.save-as-pdf": "Save current view as PDF",
|
||||||
"pdf-file": "PDF file",
|
"pdf-file": "PDF file",
|
||||||
"export-pdf": "Exporting PDF"
|
"export-pdf": "Exporting PDF",
|
||||||
|
"info.process-killed": "Process {0} has been destroyed"
|
||||||
}
|
}
|
@ -110,5 +110,6 @@
|
|||||||
"toolbar.save-as-svg": "現在のビューをSVGとして保存",
|
"toolbar.save-as-svg": "現在のビューをSVGとして保存",
|
||||||
"toolbar.save-as-pdf": "現在のビューをPDFとして保存",
|
"toolbar.save-as-pdf": "現在のビューをPDFとして保存",
|
||||||
"pdf-file": "PDFファイル",
|
"pdf-file": "PDFファイル",
|
||||||
"export-pdf": "PDFをエクスポート中"
|
"export-pdf": "PDFをエクスポート中",
|
||||||
|
"info.process-killed": "プロセス {0} は破棄されました"
|
||||||
}
|
}
|
@ -110,5 +110,6 @@
|
|||||||
"toolbar.save-as-svg": "将当前视图保存为 svg",
|
"toolbar.save-as-svg": "将当前视图保存为 svg",
|
||||||
"toolbar.save-as-pdf": "将当前视图保存为 pdf",
|
"toolbar.save-as-pdf": "将当前视图保存为 pdf",
|
||||||
"pdf-file": "pdf 文件",
|
"pdf-file": "pdf 文件",
|
||||||
"export-pdf": "正在导出 pdf"
|
"export-pdf": "正在导出 pdf",
|
||||||
|
"info.process-killed": "进程 {0} 已经被销毁"
|
||||||
}
|
}
|
@ -110,5 +110,6 @@
|
|||||||
"toolbar.save-as-svg": "將目前視圖儲存為SVG",
|
"toolbar.save-as-svg": "將目前視圖儲存為SVG",
|
||||||
"toolbar.save-as-pdf": "將目前視圖儲存為PDF",
|
"toolbar.save-as-pdf": "將目前視圖儲存為PDF",
|
||||||
"pdf-file": "PDF檔案",
|
"pdf-file": "PDF檔案",
|
||||||
"export-pdf": "正在匯出PDF"
|
"export-pdf": "正在匯出PDF",
|
||||||
|
"info.process-killed": "進程 {0} 已經被銷毀"
|
||||||
}
|
}
|
@ -93,7 +93,7 @@
|
|||||||
"digital-ide.function.lsp.file-parse-maxsize.title": "最大解析的文件阈值,大小超出这个值的文件不会被解析。单位为 MB,必须是整数。默认为 1MB",
|
"digital-ide.function.lsp.file-parse-maxsize.title": "最大解析的文件阈值,大小超出这个值的文件不会被解析。单位为 MB,必须是整数。默认为 1MB",
|
||||||
"digital-ide.structure.from-xilinx-to-standard.title": "将 Xilinx 项目转换成 Digital IDE 标准项目结构",
|
"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.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.title": "指定诊断器的诊断模式",
|
||||||
"digital-ide.function.lsp.linter.mode.0.title": "将所有设计源直接进行诊断,并报错,无论文件是否打开。",
|
"digital-ide.function.lsp.linter.mode.0.title": "将所有设计源直接进行诊断,并报错,无论文件是否打开。",
|
||||||
"digital-ide.function.lsp.linter.mode.1.title": "单文件关闭时,对应报错去除,打开哪个文件就对哪个文件进行诊断。",
|
"digital-ide.function.lsp.linter.mode.1.title": "单文件关闭时,对应报错去除,打开哪个文件就对哪个文件进行诊断。",
|
||||||
|
@ -93,7 +93,7 @@
|
|||||||
"digital-ide.function.lsp.file-parse-maxsize.title": "",
|
"digital-ide.function.lsp.file-parse-maxsize.title": "",
|
||||||
"digital-ide.structure.from-xilinx-to-standard.title": "將 Xilinx 專案轉換成 Digital IDE 標準專案結構",
|
"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.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.title": "指定診斷器的診斷模式",
|
||||||
"digital-ide.function.lsp.linter.mode.0.title": "將所有設計源直接進行診斷,並報錯,無論文件是否打開。",
|
"digital-ide.function.lsp.linter.mode.0.title": "將所有設計源直接進行診斷,並報錯,無論文件是否打開。",
|
||||||
"digital-ide.function.lsp.linter.mode.1.title": "單文件關閉時,對應報錯去除,打開哪個文件就對哪個文件進行診斷。",
|
"digital-ide.function.lsp.linter.mode.1.title": "單文件關閉時,對應報錯去除,打開哪個文件就對哪個文件進行診斷。",
|
||||||
|
@ -138,4 +138,5 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
|
|
||||||
export function deactivate() {
|
export function deactivate() {
|
||||||
lspClient.deactivate();
|
lspClient.deactivate();
|
||||||
|
manager.prjManage.pl?.exit();
|
||||||
}
|
}
|
@ -3,7 +3,8 @@ import * as os from 'os';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as childProcess from 'child_process';
|
import * as childProcess from 'child_process';
|
||||||
|
|
||||||
import { AbsPath } from ".";
|
import { AbsPath, MainOutput } from ".";
|
||||||
|
import { t } from '../i18n';
|
||||||
|
|
||||||
export class PathSet {
|
export class PathSet {
|
||||||
files: Set<AbsPath> = new Set<AbsPath>();
|
files: Set<AbsPath> = new Set<AbsPath>();
|
||||||
@ -161,3 +162,93 @@ export function getPlatformPlatformSignature(): IPlatformSignature {
|
|||||||
default: return IPlatformSignature.unsupport;
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -3,6 +3,8 @@
|
|||||||
* Hardware Programming
|
* Hardware Programming
|
||||||
*/
|
*/
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
import { platform } from 'os';
|
||||||
|
|
||||||
import { PLContext, XilinxOperation } from './xilinx';
|
import { PLContext, XilinxOperation } from './xilinx';
|
||||||
import { BaseManage } from '../common';
|
import { BaseManage } from '../common';
|
||||||
@ -89,16 +91,12 @@ class PlManage extends BaseManage {
|
|||||||
this.context.ope.gui(this.context);
|
this.context.ope.gui(this.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public exit() {
|
public async exit() {
|
||||||
|
|
||||||
if (this.context.process === undefined) {
|
if (this.context.process === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HardwareOutput.show();
|
HardwareOutput.show();
|
||||||
this.context.process.stdin.write('exit\n');
|
this.context.ope.exit(this.context);
|
||||||
HardwareOutput.report(t('info.pl.exit.title'));
|
|
||||||
this.context.process = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import { PropertySchema } from '../../global/propertySchema';
|
|||||||
|
|
||||||
import { XilinxIP } from '../../global/enum';
|
import { XilinxIP } from '../../global/enum';
|
||||||
import { HardwareOutput, MainOutput, ReportType } from '../../global/outputChannel';
|
import { HardwareOutput, MainOutput, ReportType } from '../../global/outputChannel';
|
||||||
import { debounce } from '../../global/util';
|
import { debounce, getPIDsWithName, killProcess } from '../../global/util';
|
||||||
import { t } from '../../i18n';
|
import { t } from '../../i18n';
|
||||||
import { HdlFileProjectType } from '../../hdlParser/common';
|
import { HdlFileProjectType } from '../../hdlParser/common';
|
||||||
|
|
||||||
@ -60,8 +60,10 @@ interface BootInfo {
|
|||||||
*/
|
*/
|
||||||
class XilinxOperation {
|
class XilinxOperation {
|
||||||
guiLaunched: boolean;
|
guiLaunched: boolean;
|
||||||
|
guiPid: number;
|
||||||
constructor() {
|
constructor() {
|
||||||
this.guiLaunched = false;
|
this.guiLaunched = false;
|
||||||
|
this.guiPid = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get xipRepo(): XilinxIP[] {
|
public get xipRepo(): XilinxIP[] {
|
||||||
@ -142,8 +144,9 @@ class XilinxOperation {
|
|||||||
*/
|
*/
|
||||||
public async launch(context: PLContext): Promise<string | undefined> {
|
public async launch(context: PLContext): Promise<string | undefined> {
|
||||||
this.guiLaunched = false;
|
this.guiLaunched = false;
|
||||||
let scripts: string[] = [];
|
this.guiPid = -1;
|
||||||
|
|
||||||
|
let scripts: string[] = [];
|
||||||
let prjFilePath = this.prjPath as AbsPath;
|
let prjFilePath = this.prjPath as AbsPath;
|
||||||
// 找到所有的 xilinx 工程文件
|
// 找到所有的 xilinx 工程文件
|
||||||
const prjFiles = hdlFile.pickFileRecursive(prjFilePath,
|
const prjFiles = hdlFile.pickFileRecursive(prjFilePath,
|
||||||
@ -188,11 +191,12 @@ class XilinxOperation {
|
|||||||
_this.onVivadoClose();
|
_this.onVivadoClose();
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
function launchScript(): Promise<ChildProcessWithoutNullStreams | undefined> {
|
function launchScript(pids: number[]): Promise<ChildProcessWithoutNullStreams | undefined> {
|
||||||
if (!opeParam.workspacePath) {
|
if (!opeParam.workspacePath) {
|
||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
// 执行 cmd 启动
|
|
||||||
|
const vivadoPids = new Set<number>(pids);
|
||||||
const vivadoProcess = spawn(cmd, [], { shell: true, stdio: 'pipe', cwd: opeParam.workspacePath });
|
const vivadoProcess = spawn(cmd, [], { shell: true, stdio: 'pipe', cwd: opeParam.workspacePath });
|
||||||
let status: 'pending' | 'fulfilled' = 'pending';
|
let status: 'pending' | 'fulfilled' = 'pending';
|
||||||
|
|
||||||
@ -207,11 +211,16 @@ class XilinxOperation {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
vivadoProcess.stdout.on('data', data => {
|
vivadoProcess.stdout.on('data', async data => {
|
||||||
const message: string = _this.handleMessage(data.toString(), status);
|
const message: string = _this.handleMessage(data.toString(), status);
|
||||||
if (status === 'pending') {
|
if (status === 'pending') {
|
||||||
HardwareOutput.clear();
|
HardwareOutput.clear();
|
||||||
HardwareOutput.show();
|
HardwareOutput.show();
|
||||||
|
const pids = await getPIDsWithName('vivado');
|
||||||
|
const newPid = pids.find(p => !vivadoPids.has(p));
|
||||||
|
if (newPid) {
|
||||||
|
_this.guiPid = newPid;
|
||||||
|
}
|
||||||
resolve(vivadoProcess);
|
resolve(vivadoProcess);
|
||||||
}
|
}
|
||||||
HardwareOutput.report(message, {
|
HardwareOutput.report(message, {
|
||||||
@ -251,7 +260,8 @@ class XilinxOperation {
|
|||||||
location: vscode.ProgressLocation.Notification,
|
location: vscode.ProgressLocation.Notification,
|
||||||
cancellable: true
|
cancellable: true
|
||||||
}, async () => {
|
}, async () => {
|
||||||
return await launchScript();
|
const originVivadoPids = await getPIDsWithName('vivado');
|
||||||
|
return await launchScript(originVivadoPids);
|
||||||
});
|
});
|
||||||
|
|
||||||
context.process = process;
|
context.process = process;
|
||||||
@ -274,7 +284,7 @@ class XilinxOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onVivadoClose() {
|
private async onVivadoClose() {
|
||||||
const workspacePath = opeParam.workspacePath;
|
const workspacePath = opeParam.workspacePath;
|
||||||
const plName = opeParam.prjInfo.prjName.PL;
|
const plName = opeParam.prjInfo.prjName.PL;
|
||||||
const targetPath = fspath.dirname(opeParam.prjInfo.arch.hardware.src);
|
const targetPath = fspath.dirname(opeParam.prjInfo.arch.hardware.src);
|
||||||
@ -287,6 +297,8 @@ class XilinxOperation {
|
|||||||
|
|
||||||
hdlDir.mvdir(sourceBdPath, targetPath, true);
|
hdlDir.mvdir(sourceBdPath, targetPath, true);
|
||||||
HardwareOutput.report("move dir from " + sourceBdPath + " to " + targetPath);
|
HardwareOutput.report("move dir from " + sourceBdPath + " to " + targetPath);
|
||||||
|
|
||||||
|
await this.closeAllWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
public create(scripts: string[]) {
|
public create(scripts: string[]) {
|
||||||
@ -436,6 +448,22 @@ class XilinxOperation {
|
|||||||
context.process?.stdin.write(cmd + '\n');
|
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) {
|
public simulate(context: PLContext) {
|
||||||
this.simulateCli(context);
|
this.simulateCli(context);
|
||||||
}
|
}
|
||||||
@ -630,15 +658,19 @@ file delete ${scriptPath} -force\n`;
|
|||||||
await this.launch(context);
|
await this.launch(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.process) {
|
const tclProcess = context.process;
|
||||||
context.process.stdin.write('start_gui -quiet\n');
|
if (tclProcess === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tclProcess.stdin.write('start_gui -quiet\n');
|
||||||
HardwareOutput.report(t('info.pl.gui.report-title'), {
|
HardwareOutput.report(t('info.pl.gui.report-title'), {
|
||||||
level: ReportType.Info
|
level: ReportType.Info
|
||||||
});
|
});
|
||||||
|
|
||||||
HardwareOutput.show();
|
HardwareOutput.show();
|
||||||
this.guiLaunched = true;
|
this.guiLaunched = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public addFiles(files: string[], context: PLContext) {
|
public addFiles(files: string[], context: PLContext) {
|
||||||
if (!this.guiLaunched && files.length > 0) {
|
if (!this.guiLaunched && files.length > 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user