Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,30 @@
"default": "",
"description": "Path to the debugger executable (e.g. /usr/bin/gdb)",
"scope": "resource"
},
"c-cpp-compile-run.use-make": {
"type": "boolean",
"default": false,
"description": "Use make instead of the compiler to build the project",
"scope": "resource"
},
"c-cpp-compile-run.make-path": {
"type": "string",
"default": "make",
"description": "Path to the make executable",
"scope": "resource"
},
"c-cpp-compile-run.make-build-target": {
"type": "string",
"default": "",
"description": "Make target for building (leave empty for the default target)",
"scope": "resource"
},
"c-cpp-compile-run.make-run-target": {
"type": "string",
"default": "",
"description": "Make target for running the program (leave empty to run the compiled executable directly)",
"scope": "resource"
}
}
}
Expand Down
32 changes: 23 additions & 9 deletions src/compile-run-manager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { File } from "./models/file";
import { Compiler } from "./compiler";
import { Runner } from "./runner";
import { MakeRunner } from "./make-runner";
import { window } from "vscode";
import { Configuration } from "./configuration";
import { parseFile } from "./utils/file-utils";
Expand All @@ -14,8 +15,13 @@ export class CompileRunManager {
return;
}

const compiler = new Compiler(file, shouldAskForInputFlags);
await compiler.compile();
if (Configuration.useMake()) {
const makeRunner = new MakeRunner(file);
await makeRunner.build();
} else {
const compiler = new Compiler(file, shouldAskForInputFlags);
await compiler.compile();
}
}

public async run(shouldAskForArgs = false, shouldRunInExternalTerminal = false) {
Expand All @@ -24,8 +30,13 @@ export class CompileRunManager {
return;
}

const runner = new Runner(file, shouldAskForArgs);
await runner.run(shouldRunInExternalTerminal);
if (Configuration.useMake()) {
const makeRunner = new MakeRunner(file);
await makeRunner.run(shouldRunInExternalTerminal);
} else {
const runner = new Runner(file, shouldAskForArgs);
await runner.run(shouldRunInExternalTerminal);
}
}

public async debug() {
Expand All @@ -47,11 +58,14 @@ export class CompileRunManager {
return;
}

const compiler = new Compiler(file, shouldAskForInputFlags);

const runner = new Runner(file, shouldAskForArgs);

await compiler.compile(async () => await runner.run(shouldRunInExternalTerminal));
if (Configuration.useMake()) {
const makeRunner = new MakeRunner(file);
await makeRunner.build(async () => await makeRunner.run(shouldRunInExternalTerminal));
} else {
const compiler = new Compiler(file, shouldAskForInputFlags);
const runner = new Runner(file, shouldAskForArgs);
await compiler.compile(async () => await runner.run(shouldRunInExternalTerminal));
}
}

public async getFile(): Promise<File> {
Expand Down
16 changes: 16 additions & 0 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,22 @@ export class Configuration {
await workspace.getConfiguration("c-cpp-compile-run", null).update(key, compiler, ConfigurationTarget.Global);
}

static useMake(): boolean {
return this.getSetting<boolean>("use-make") ?? false;
}

static makePath(): string {
return this.getStringSetting("make-path") || "make";
}

static makeBuildTarget(): string {
return this.getStringSetting("make-build-target");
}

static makeRunTarget(): string {
return this.getStringSetting("make-run-target");
}

static additionalIncludePaths(): string[] {
const workspaceFolder = workspace.workspaceFolders?.[0]?.uri.fsPath ?? process.cwd();
const paths = workspace.getConfiguration("c-cpp-compile-run", null).get<string[]>("additional-include-paths") ?? [];
Expand Down
110 changes: 110 additions & 0 deletions src/make-runner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { ProcessExecution, Task, tasks, TaskScope, window, workspace } from "vscode";
import { Configuration } from "./configuration";
import { File } from "./models/file";
import { Runner } from "./runner";
import { commandExists } from "./utils/common-utils";
import { isStringNullOrWhiteSpace } from "./utils/string-utils";
import { Notification } from "./notification";
import { terminal } from "./terminal";
import { getCommand, currentShell } from "./utils/shell-utils";
import { existsSync } from "fs";
import { join } from "path";

export class MakeRunner {
private file: File;

constructor(file: File) {
this.file = file;
}

async build(runCallback: (() => Promise<void>) | null = null): Promise<void> {
const makePath = Configuration.makePath();

if (!await this.isMakeValid(makePath)) {
Notification.showErrorMessage(
`Make executable not found at "${makePath}". Please check the make-path setting.`
);
return;
}

if (Configuration.saveBeforeCompile()) {
await window.activeTextEditor?.document.save();
}

const buildTarget = Configuration.makeBuildTarget();
const makeArgs = buildTarget ? [buildTarget] : [];
const cwd = this.getMakeDirectory();

const processExecution = new ProcessExecution(
makePath,
makeArgs,
{ cwd }
);

const task = new Task(
{ type: "process" },
TaskScope.Workspace,
"C/C++ Compile Run: Make Build",
"C/C++ Compile Run",
processExecution,
["$gcc"]
);

const executionPromise = tasks.executeTask(task);

const endListener = tasks.onDidEndTaskProcess(async e => {
const execution = await executionPromise;
if (e.execution === execution) {
endListener.dispose();
if (e.exitCode === 0) {
Notification.showInformationMessage("Make build successful.");
if (runCallback) { await runCallback(); }
} else {
Notification.showErrorMessage("Make build failed. Please check the output for errors.");
}
}
});

await executionPromise;
}

async run(shouldRunInExternalTerminal = false): Promise<void> {
const runTarget = Configuration.makeRunTarget();

if (runTarget) {
const makePath = Configuration.makePath();

if (!await this.isMakeValid(makePath)) {
Notification.showErrorMessage(
`Make executable not found at "${makePath}". Please check the make-path setting.`
);
return;
}

const cwd = this.getMakeDirectory();
const shell = currentShell();
const makeCommand = getCommand(`${makePath} ${runTarget}`, shell);

await terminal.runInTerminal(makeCommand, {
name: "C/C++ Compile Run",
cwd
});
} else {
const runner = new Runner(this.file);
await runner.run(shouldRunInExternalTerminal);
}
}

async isMakeValid(makePath: string): Promise<boolean> {
return !isStringNullOrWhiteSpace(makePath) && await commandExists(makePath);
}

private getMakeDirectory(): string {
// Prefer the file's own directory if it contains a Makefile
if (existsSync(join(this.file.directory, "Makefile")) ||
existsSync(join(this.file.directory, "makefile"))) {
return this.file.directory;
}
return workspace.workspaceFolders?.[0]?.uri.fsPath ?? this.file.directory;
}
}