Skip to content

Commit

Permalink
Use cocopa and add Analyze build mode
Browse files Browse the repository at this point in the history
  • Loading branch information
hlovdal authored and adiazulay committed Jan 19, 2021
1 parent 0b2b77a commit fef2db0
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 54 deletions.
36 changes: 27 additions & 9 deletions src/arduino/arduino.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@ import { DeviceContext } from "../deviceContext";
import { IArduinoSettings } from "./arduinoSettings";
import { BoardManager } from "./boardManager";
import { ExampleManager } from "./exampleManager";
import { ICoCoPaContext, isCompilerParserEnabled, makeCompilerParserContext } from "./intellisense";
import { LibraryManager } from "./libraryManager";
import { VscodeSettings } from "./vscodeSettings";

import { arduinoChannel } from "../common/outputChannel";
import { ArduinoWorkspace } from "../common/workspace";
import { SerialMonitor } from "../serialmonitor/serialMonitor";
import { UsbDetector } from "../serialmonitor/usbDetector";
import { makeCompilerParserContext } from "./intellisense";
import { ProgrammerManager } from "./programmerManager";

export enum BuildMode {
Verify = "Verifying",
Analyze = "Analyzing",
Upload = "Uploading",
UploadProgrammer = "Uploading (programmer)",
};
Expand Down Expand Up @@ -283,6 +284,8 @@ export class ArduinoApp {
public async verify(buildMode: BuildMode, buildDir: string = "") {
const dc = DeviceContext.getInstance();
const args: string[] = [];
let cocopa: ICoCoPaContext;

const boardDescriptor = this.getBoardBuildString();
if (!boardDescriptor) {
return false;
Expand All @@ -300,7 +303,17 @@ export class ArduinoApp {
await this.getMainSketch(dc);
}

if (buildMode === BuildMode.Verify) {
if (buildMode === BuildMode.Analyze) {
if (!isCompilerParserEnabled()) {
return false;
}
cocopa = makeCompilerParserContext(dc);
if (!this.useArduinoCli()) {
args.push("--verify", "--verbose");
} else {
args.push("compile", "--verbose", "-b", boardDescriptor);
}
} else {
if (!this.useArduinoCli()) {
args.push("--verify");
} else {
Expand All @@ -309,7 +322,7 @@ export class ArduinoApp {
}

const verbose = VscodeSettings.getInstance().logLevel === "verbose";
if (verbose) {
if (buildMode !== BuildMode.Analyze && verbose) {
args.push("--verbose");
}

Expand Down Expand Up @@ -344,19 +357,28 @@ export class ArduinoApp {
}

let success = false;
const compilerParserContext = makeCompilerParserContext(dc);

// Push sketch as last argument
args.push(path.join(ArduinoWorkspace.rootPath, dc.sketch));

const cleanup = async () => {
if (cocopa) {
cocopa.conclude();
}
await Promise.resolve();
}

// TODO: Get rid of spawn's channel parameter and just support
// stdout and stderr callbacks
const stdoutCallback = (line: string) => {
arduinoChannel.channel.append(line);
if (cocopa) {
cocopa.callback(line);
if (verbose) {
arduinoChannel.channel.append(line);
}
} else {
arduinoChannel.channel.append(line);
}
}

await util.spawn(
Expand All @@ -379,10 +401,6 @@ export class ArduinoApp {
arduinoChannel.error(`${buildMode} sketch '${dc.sketch}': ${msg}${os.EOL}`);
});

if (compilerParserContext.conclude) {
compilerParserContext.conclude();
}

return success;
}

Expand Down
106 changes: 61 additions & 45 deletions src/arduino/intellisense.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
import * as ccp from "cocopa";
import * as path from "path";

import * as constants from "../common/constants";
import { arduinoChannel } from "../common/outputChannel";
import { ArduinoWorkspace } from "../common/workspace";
import { DeviceContext } from "../deviceContext";

import { VscodeSettings } from "./vscodeSettings";

export interface ICoCoPaContext {
callback: (s: string) => void;
conclude: () => void;
};

/**
* Returns true if the combination of global enable/disable and project
* specific override enable the auto-generation of the IntelliSense
* configuration.
*/
export function isCompilerParserEnabled(dc?: DeviceContext) {
if (!dc) {
dc = DeviceContext.getInstance();
}
const globalDisable = VscodeSettings.getInstance().disableIntelliSenseAutoGen;
const projectSetting = dc.disableIntelliSenseAutoGen;
return projectSetting !== "disable" && !globalDisable ||
projectSetting === "enable";
}

/**
* Creates a context which is used for compiler command parsing
* during building (verify, upload, ...).
Expand All @@ -16,61 +38,55 @@ import { VscodeSettings } from "./vscodeSettings";
*
* @param dc The device context of the caller.
*/
export function makeCompilerParserContext(dc: DeviceContext)
: { callback: (s: string) => void; conclude: () => void; } {

const globalDisable = VscodeSettings.getInstance().disableIntelliSenseAutoGen;
const project = dc.disableIntelliSenseAutoGen;

if (project !== "disable" && !globalDisable ||
project === "enable") {
export function makeCompilerParserContext(dc: DeviceContext): ICoCoPaContext {

const engines = makeCompilerParserEngines(dc);
const runner = new ccp.Runner(engines);
const engines = makeCompilerParserEngines(dc);
const runner = new ccp.Runner(engines);

// set up the function to be called after parsing
const _conclude = () => {
if (!runner.result) {
arduinoChannel.warning("Failed to generate IntelliSense configuration.");
return;
}
const pPath = path.join(ArduinoWorkspace.rootPath, constants.CPP_CONFIG_FILE);
// TODO: check what kind of result we've got: gcc or other architecture:
// and instantiate content accordingly (to be implemented within cocopa)
const content = new ccp.CCppPropertiesContentResult(runner.result,
"Arduino",
ccp.CCppPropertiesISMode.Gcc_X64,
ccp.CCppPropertiesCStandard.C11,
// as of 1.8.11 arduino is on C++11
ccp.CCppPropertiesCppStandard.Cpp11);
try {
const prop = new ccp.CCppProperties();
prop.read(pPath);
prop.merge(content, ccp.CCppPropertiesMergeMode.ReplaceSameNames);
if (prop.write(pPath)) {
arduinoChannel.info("IntelliSense configuration updated.");
} else {
arduinoChannel.info("IntelliSense configuration already up to date.");
}
} catch (e) {
// tslint:disable-next-line: no-console
console.log(e);
// Set up the callback to be called after parsing
const _conclude = () => {
if (!runner.result) {
arduinoChannel.warning("Failed to generate IntelliSense configuration.");
return;
}
const pPath = path.join(ArduinoWorkspace.rootPath, constants.CPP_CONFIG_FILE);
// TODO: check what kind of result we've got: gcc or other architecture:
// and instantiate content accordingly (to be implemented within cocopa)
const content = new ccp.CCppPropertiesContentResult(runner.result,
"Arduino",
ccp.CCppPropertiesISMode.Gcc_X64,
ccp.CCppPropertiesCStandard.C11,
// as of 1.8.11 arduino is on C++11
ccp.CCppPropertiesCppStandard.Cpp11);
try {
const prop = new ccp.CCppProperties();
prop.read(pPath);
prop.merge(content, ccp.CCppPropertiesMergeMode.ReplaceSameNames);
if (prop.write(pPath)) {
arduinoChannel.info("IntelliSense configuration updated.");
} else {
arduinoChannel.info("IntelliSense configuration already up to date.");
}
};
return {
callback: runner.callback(),
conclude: _conclude,
} catch (e) {
const estr = JSON.stringify(e);
arduinoChannel.error(`Failed to read or write IntelliSense configuration: ${estr}`);
}
}
};
return {
callback: undefined,
conclude: undefined,
callback: runner.callback(),
conclude: _conclude,
}
};

/**
* Assembles compiler parser engines which then will be used to find the main
* sketch's compile command and parse the infomation from it required for
* assembling an IntelliSense configuration from it.
*
* It could return multiple engines for different compilers or - if necessary -
* return specialized engines based on the current board architecture.
*
* @param dc
* @param dc Current device context used to generate the engines.
*/
function makeCompilerParserEngines(dc: DeviceContext) {

Expand Down

0 comments on commit fef2db0

Please sign in to comment.