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
38 changes: 27 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"type": "string",
"enum": [
"launch",
"debug",
"build",
"run",
"clean",
Expand Down Expand Up @@ -198,12 +199,12 @@
"label": "SweetPad (LLDB)",
"configurationSnippets": [
{
"label": "SweetPad: Attach to running app",
"label": "Sweetpad: Build and Run (Wait for debugger)",
"body": {
"type": "sweetpad-lldb",
"request": "attach",
"name": "Attach to running app (SweetPad)",
"preLaunchTask": "sweetpad: launch"
"name": "Sweetpad: Build and Run (Wait for debugger)",
"preLaunchTask": "sweetpad: debug"
}
}
],
Expand Down Expand Up @@ -316,6 +317,11 @@
"title": "SweetPad: Build & Run (Launch)",
"icon": "$(sweetpad-player-play)"
},
{
"command": "sweetpad.build.debug",
"title": "SweetPad: Build & Run (Debug)",
"icon": "$(bug)"
},
{
"command": "sweetpad.build.run",
"title": "SweetPad: Run (without Build)",
Expand Down Expand Up @@ -558,6 +564,11 @@
"when": "view == sweetpad.destinations.view && viewItem =~ /destination-group-device-.*/",
"group": "inline@1"
},
{
"command": "sweetpad.build.debug",
"when": "view == sweetpad.build.view",
"group": "inline@3"
},
{
"command": "sweetpad.build.launch",
"when": "view == sweetpad.build.view",
Expand All @@ -569,45 +580,50 @@
"group": "inline@1"
},
{
"command": "sweetpad.build.launch",
"command": "sweetpad.build.debug",
"when": "view == sweetpad.build.view",
"group": "context@1"
},
{
"command": "sweetpad.build.build",
"command": "sweetpad.build.launch",
"when": "view == sweetpad.build.view",
"group": "context@2"
},
{
"command": "sweetpad.build.run",
"command": "sweetpad.build.build",
"when": "view == sweetpad.build.view",
"group": "context@3"
},
{
"command": "sweetpad.build.test",
"command": "sweetpad.build.run",
"when": "view == sweetpad.build.view",
"group": "context@4"
},
{
"command": "sweetpad.build.clean",
"command": "sweetpad.build.test",
"when": "view == sweetpad.build.view",
"group": "context@5"
},
{
"command": "sweetpad.build.resolveDependencies",
"command": "sweetpad.build.clean",
"when": "view == sweetpad.build.view",
"group": "context@6"
},
{
"command": "sweetpad.build.setDefaultScheme",
"command": "sweetpad.build.resolveDependencies",
"when": "view == sweetpad.build.view",
"group": "context@7"
},
{
"command": "sweetpad.build.genereateBuildServerConfig",
"command": "sweetpad.build.setDefaultScheme",
"when": "view == sweetpad.build.view",
"group": "context@8"
},
{
"command": "sweetpad.build.genereateBuildServerConfig",
"when": "view == sweetpad.build.view",
"group": "context@9"
},
{
"command": "sweetpad.simulators.start",
"when": "view == sweetpad.destinations.view && viewItem =~ /destination-item-simulator.*&status=shutdown.*/",
Expand Down
88 changes: 58 additions & 30 deletions src/build/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export async function runOnMac(
watchMarker: boolean;
launchArgs: string[];
launchEnv: Record<string, string>;
debug?: boolean;
},
) {
const buildSettings = await getBuildSettingsToLaunch({
Expand Down Expand Up @@ -105,6 +106,7 @@ export async function runOniOSSimulator(
watchMarker: boolean;
launchArgs: string[];
launchEnv: Record<string, string>;
debug?: boolean;
},
) {
const buildSettings = await getBuildSettingsToLaunch({
Expand Down Expand Up @@ -152,18 +154,22 @@ export async function runOniOSSimulator(
writeWatchMarkers(terminal);
}

// Prepare the launch arguments with optional --wait-for-debugger flag
const launchArgs = [
"simctl",
"launch",
"--console-pty",
...(options.debug ? ["--wait-for-debugger"] : []),
"--terminate-running-process",
simulator.udid,
bundlerId,
...options.launchArgs,
];

// Run app
await terminal.execute({
command: "xcrun",
args: [
"simctl",
"launch",
"--console-pty",
"--terminate-running-process",
simulator.udid,
bundlerId,
...options.launchArgs,
],
args: launchArgs,
// should be prefixed with `SIMCTL_CHILD_` to pass to the child process
env: Object.fromEntries(Object.entries(options.launchEnv).map(([key, value]) => [`SIMCTL_CHILD_${key}`, value])),
});
Expand All @@ -182,6 +188,7 @@ export async function runOniOSDevice(
watchMarker: boolean;
launchArgs: string[];
launchEnv: Record<string, string>;
debug?: boolean;
},
) {
const { scheme, configuration, destinationId: deviceId, destinationType } = option;
Expand Down Expand Up @@ -221,27 +228,28 @@ export async function runOniOSDevice(
writeWatchMarkers(terminal);
}

// Prepare the launch arguments
const launchArgs = [
"devicectl",
"device",
"process",
"launch",
// Attaches the application to the console and waits for it to exit
isConsoleOptionSupported ? "--console" : null,
"--json-output",
jsonOuputPath.path,
// Terminates any already-running instances of the app prior to launch. Not supported on all platforms.
"--terminate-existing",
"--device",
deviceId,
bundlerId,
...option.launchArgs,
].filter(arg => arg !== null); // Filter out null arguments

// Launch app on device
await terminal.execute({
command: "xcrun",
args: [
"devicectl",
"device",
"process",
"launch",
// Attaches the application to the console and waits for it to exit
isConsoleOptionSupported ? "--console" : null,
"--json-output",
jsonOuputPath.path,
// Launches the app in a suspended state, waiting for a debugger. (We want oposite)
// "--start-stopped",
// Terminates any already-running instances of the app prior to launch. Not supported on all platforms.
"--terminate-existing",
"--device",
deviceId,
bundlerId,
...option.launchArgs,
],
args: launchArgs,
// Should be prefixed with `DEVICECTL_CHILD_` to pass to the child process
env: Object.fromEntries(Object.entries(option.launchEnv).map(([key, value]) => [`DEVICECTL_CHILD_${key}`, value])),
});
Expand Down Expand Up @@ -461,6 +469,7 @@ export async function buildApp(
shouldTest: boolean;
xcworkspace: string;
destinationRaw: string;
debug?: boolean;
},
) {
const useXcbeatify = isXcbeautifyEnabled() && (await getIsXcbeautifyInstalled());
Expand All @@ -482,6 +491,15 @@ export async function buildApp(
command.addBuildSettings("VALID_ARCHS", arch);
command.addBuildSettings("ONLY_ACTIVE_ARCH", "NO");
}

// Add debug-specific build settings if in debug mode
if (options.debug) {
command.addBuildSettings("GCC_GENERATE_DEBUGGING_SYMBOLS", "YES");
command.addBuildSettings("ONLY_ACTIVE_ARCH", "YES");
command.addBuildSettings("-UseModernBuildSystem", "YES");
command.addBuildSettings("COMPILER_INDEX_STORE_ENABLE", "NO");
}

command.addParameters("-scheme", options.scheme);
command.addParameters("-configuration", options.configuration);
command.addParameters("-workspace", options.xcworkspace);
Expand All @@ -493,6 +511,10 @@ export async function buildApp(
if (allowProvisioningUpdates) {
command.addOption("-allowProvisioningUpdates");
}

// Skip macro validation to improve performance.
command.addOption("-skipMacroValidation");

if (options.shouldClean) {
command.addAction("clean");
}
Expand Down Expand Up @@ -564,12 +586,13 @@ export async function buildCommand(execution: CommandExecution, item?: BuildTree
/**
* Build and run application on the simulator or device
*/
export async function launchCommand(execution: CommandExecution, item?: BuildTreeItem) {
export async function launchCommand(execution: CommandExecution, item?: BuildTreeItem, options?: { debug?: boolean }) {
const isDebug = options?.debug || false;
const xcworkspace = await askXcodeWorkspacePath(execution.context);

const scheme =
item?.scheme ??
(await askSchemeForBuild(execution.context, { title: "Select scheme to build and run", xcworkspace: xcworkspace }));
(await askSchemeForBuild(execution.context, { title: `Select scheme to build and ${isDebug ? 'debug' : 'run'}`, xcworkspace: xcworkspace }));
const configuration = await askConfiguration(execution.context, { xcworkspace: xcworkspace });

const buildSettings = await getBuildSettingsToAskDestination({
Expand All @@ -588,11 +611,12 @@ export async function launchCommand(execution: CommandExecution, item?: BuildTre
const launchEnv = getWorkspaceConfig("build.launchEnv") ?? {};

await runTask(execution.context, {
name: "Launch",
name: isDebug ? "Debug" : "Launch",
lock: "sweetpad.build",
terminateLocked: true,
problemMatchers: DEFAULT_BUILD_PROBLEM_MATCHERS,
callback: async (terminal) => {
// Build the app with debug settings if needed
await buildApp(execution.context, terminal, {
scheme: scheme,
sdk: sdk,
Expand All @@ -602,6 +626,7 @@ export async function launchCommand(execution: CommandExecution, item?: BuildTre
shouldTest: false,
xcworkspace: xcworkspace,
destinationRaw: destinationRaw,
debug: isDebug,
});

if (destination.type === "macOS") {
Expand All @@ -612,6 +637,7 @@ export async function launchCommand(execution: CommandExecution, item?: BuildTre
watchMarker: false,
launchArgs: launchArgs,
launchEnv: launchEnv,
debug: isDebug,
});
} else if (
destination.type === "iOSSimulator" ||
Expand All @@ -628,6 +654,7 @@ export async function launchCommand(execution: CommandExecution, item?: BuildTre
watchMarker: false,
launchArgs: launchArgs,
launchEnv: launchEnv,
debug: isDebug,
});
} else if (
destination.type === "iOSDevice" ||
Expand All @@ -645,6 +672,7 @@ export async function launchCommand(execution: CommandExecution, item?: BuildTre
watchMarker: false,
launchArgs: launchArgs,
launchEnv: launchEnv,
debug: isDebug,
});
} else {
assertUnreachable(destination);
Expand Down
27 changes: 26 additions & 1 deletion src/build/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class ActionDispatcher {
case "launch":
await this.launchCallback(terminal, definition);
break;
case "debug":
await this.debugCallback(terminal, definition);
break;
case "build":
await this.buildCallback(terminal, definition);
break;
Expand Down Expand Up @@ -95,11 +98,12 @@ class ActionDispatcher {
return destination;
}

private async launchCallback(terminal: TaskTerminal, definition: TaskDefinition) {
private async launchOrDebugCallback(terminal: TaskTerminal, definition: TaskDefinition, debug: boolean) {
const xcworkspace = await askXcodeWorkspacePath(this.context);
const scheme =
definition.scheme ??
(await askSchemeForBuild(this.context, {
title: `Select scheme to build and ${debug ? 'debug' : 'run'}`,
xcworkspace: xcworkspace,
}));

Expand Down Expand Up @@ -136,6 +140,7 @@ class ActionDispatcher {
shouldTest: false,
xcworkspace: xcworkspace,
destinationRaw: destinationRaw,
debug: debug,
});

if (destination.type === "macOS") {
Expand All @@ -146,6 +151,7 @@ class ActionDispatcher {
watchMarker: true,
launchArgs: launchArgs,
launchEnv: launchEnv,
debug: debug,
});
} else if (
destination.type === "iOSSimulator" ||
Expand All @@ -162,6 +168,7 @@ class ActionDispatcher {
watchMarker: true,
launchArgs: launchArgs,
launchEnv: launchEnv,
debug: debug,
});
} else if (
destination.type === "iOSDevice" ||
Expand All @@ -179,12 +186,21 @@ class ActionDispatcher {
watchMarker: true,
launchArgs: launchArgs,
launchEnv: launchEnv,
debug: debug,
});
} else {
assertUnreachable(destination);
}
}

private async launchCallback(terminal: TaskTerminal, definition: TaskDefinition) {
await this.launchOrDebugCallback(terminal, definition, false);
}

private async debugCallback(terminal: TaskTerminal, definition: TaskDefinition) {
await this.launchOrDebugCallback(terminal, definition, true);
}

private async buildCallback(terminal: TaskTerminal, definition: TaskDefinition) {
const xcworkspace = await askXcodeWorkspacePath(this.context);
const scheme =
Expand Down Expand Up @@ -420,6 +436,15 @@ export class XcodeBuildTaskProvider implements vscode.TaskProvider {
},
isBackground: true,
}),
this.getTask({
name: "debug",
details: "Build and Debug the app",
defintion: {
type: this.type,
action: "debug",
},
isBackground: true,
}),
this.getTask({
name: "build",
details: "Build the app",
Expand Down
Loading