Skip to content
Closed
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
74 changes: 73 additions & 1 deletion editors/vscode/scripts/package/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import type { PackageContext } from './context';
import { run } from './process';
import type { BuildProfile, NativeTargetSpec, ServerMode } from './targets';

const ALPINE_CARGO_TARGETS: Partial<Record<NativeTargetSpec['target'], string>> = {
'alpine-arm64': 'aarch64-unknown-linux-musl',
'alpine-x64': 'x86_64-unknown-linux-musl',
};

export function ensureTargetServerBinary(
context: PackageContext,
spec: NativeTargetSpec,
Expand All @@ -28,7 +33,7 @@ export function ensureTargetServerBinary(
}

const serverPath = targetServerPath(context, spec);
run('cargo', args, context.repoRoot);
run('cargo', args, context.repoRoot, cargoXtaskEnvForTarget(spec));

if (!fs.existsSync(serverPath)) {
throw new Error(`prepared server binary was not found: ${serverPath}`);
Expand Down Expand Up @@ -63,3 +68,70 @@ export function cleanRuntimeServerFiles(context: PackageContext): void {
function targetServerPath(context: PackageContext, spec: NativeTargetSpec): string {
return path.join(context.vscodeDir, 'server', spec.target, spec.binaryFile);
}

export function cargoXtaskEnvForTarget(
spec: NativeTargetSpec,
env: NodeJS.ProcessEnv = process.env,
): NodeJS.ProcessEnv {
const cargoTarget = ALPINE_CARGO_TARGETS[spec.target];
if (!cargoTarget) {
return env;
}

let updated = envWithoutCargoBuildTarget(env);
const linkerEnvKey = cargoTargetLinkerEnvKey(cargoTarget);
if (!optionalEnv(updated, linkerEnvKey)) {
updated = {
...updated,
[linkerEnvKey]: cargoLinkerForTarget(cargoTarget, updated),
};
}

return appendRustFlags(updated, ['-C', 'link-arg=-lc']);
}

function envWithoutCargoBuildTarget(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
const { CARGO_BUILD_TARGET: _cargoBuildTarget, ...updated } = env;
return updated;
}

function cargoTargetLinkerEnvKey(cargoTarget: string): string {
return `CARGO_TARGET_${cargoTargetEnvName(cargoTarget)}_LINKER`;
}

function cargoTargetEnvName(cargoTarget: string): string {
return cargoTarget.toUpperCase().replace(/-/g, '_');
}

function cargoLinkerForTarget(cargoTarget: string, env: NodeJS.ProcessEnv): string {
return (
optionalEnv(env, cxxCompilerEnvKey(cargoTarget)) ??
optionalEnv(env, 'TARGET_CXX') ??
`${cargoTarget}-g++`
);
}

function cxxCompilerEnvKey(cargoTarget: string): string {
return `CXX_${cargoTarget.replace(/-/g, '_')}`;
}

function appendRustFlags(env: NodeJS.ProcessEnv, flags: string[]): NodeJS.ProcessEnv {
const encodedFlags = optionalEnv(env, 'CARGO_ENCODED_RUSTFLAGS');
if (encodedFlags) {
return {
...env,
CARGO_ENCODED_RUSTFLAGS: `${encodedFlags}\x1f${flags.join('\x1f')}`,
};
}

const rustFlags = optionalEnv(env, 'RUSTFLAGS');
return {
...env,
RUSTFLAGS: rustFlags ? `${rustFlags} ${flags.join(' ')}` : flags.join(' '),
};
}

function optionalEnv(env: NodeJS.ProcessEnv, name: string): string | undefined {
const value = env[name]?.trim();
return value ? value : undefined;
}
53 changes: 52 additions & 1 deletion editors/vscode/test/package.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
stagePackageJsonForTarget,
stageProfileTraceAssets,
} from '../scripts/package/manifest';
import { createPackagePlan } from '../scripts/package/targets';
import { cargoXtaskEnvForTarget } from '../scripts/package/server';
import { createPackagePlan, type NativeTargetSpec } from '../scripts/package/targets';

describe('package cli', () => {
it('keeps the existing debug positional target syntax', () => {
Expand Down Expand Up @@ -105,6 +106,43 @@ describe('package staging', () => {
});
});

describe('package server preparation', () => {
it('removes inherited Cargo build targets before cargo xtask is built', () => {
const baseEnv = { CARGO_BUILD_TARGET: 'x86_64-unknown-linux-musl' };
const env = cargoXtaskEnvForTarget(nativeTargetSpec('alpine-x64'), baseEnv);

assert.equal(env.CARGO_BUILD_TARGET, undefined);
assert.equal(
env.CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER,
'x86_64-unknown-linux-musl-g++',
);
assert.equal(env.RUSTFLAGS, '-C link-arg=-lc');
assert.equal(baseEnv.CARGO_BUILD_TARGET, 'x86_64-unknown-linux-musl');
});

it('appends Alpine cargo flags to encoded rust flags', () => {
const env = cargoXtaskEnvForTarget(nativeTargetSpec('alpine-arm64'), {
CARGO_ENCODED_RUSTFLAGS: '-C\x1ftarget-feature=+crt-static',
CXX_aarch64_unknown_linux_musl: 'custom-aarch64-g++',
});

assert.equal(env.CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER, 'custom-aarch64-g++');
assert.equal(
env.CARGO_ENCODED_RUSTFLAGS,
'-C\x1ftarget-feature=+crt-static\x1f-C\x1flink-arg=-lc',
);
});

it('leaves non-Alpine cargo env untouched', () => {
const baseEnv = { RUSTFLAGS: '-Dwarnings' };

assert.equal(
cargoXtaskEnvForTarget(nativeTargetSpec('win32-x64', 'vide.exe'), baseEnv),
baseEnv,
);
});
});

function temporaryPackageContext(): PackageContext {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'vide-package-'));
return {
Expand All @@ -113,6 +151,19 @@ function temporaryPackageContext(): PackageContext {
};
}

function nativeTargetSpec(
target: NativeTargetSpec['target'],
binaryFile = 'vide',
): NativeTargetSpec {
return {
kind: 'native',
target,
binaryFile,
isWindows: target.startsWith('win32-'),
removeBrowserEntry: true,
};
}

describe('package plan', () => {
it('models web packages without native server staging', () => {
const plan = createPackagePlan({
Expand Down
6 changes: 1 addition & 5 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ fn run_command(
cwd: &Path,
env_updates: &[(String, String)],
) -> Result<()> {
let mut child = ProcessCommand::new(command_for_host(command));
let mut child = ProcessCommand::new(command);
child.args(args).current_dir(cwd);
for (key, value) in env_updates {
child.env(key, value);
Expand All @@ -434,10 +434,6 @@ fn run_command(
Ok(())
}

fn command_for_host(command: &str) -> String {
if cfg!(windows) { format!("{command}.cmd") } else { command.to_owned() }
}

fn workspace_root() -> Result<PathBuf> {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
Expand Down
Loading