Allow local build of remote_server dev to be deployed to different linux than local (#33395)

setup local build of `remote_server` to not depend of the local linux
libraries by :
- enable `vendored-libgit2` feature of git2
- setup target triple to `unknown-linux-musl` (mirror bundle-linux
script)
- add flag ` -C target-feature=+crt-static` in `RUSTFLAGS` env var
(mirror bundle-linux script)

Bonus:
Add an option to setup mold as linker of local build.

Closes #33341

Release Notes:

 - N/A
This commit is contained in:
Gwen Lg 2025-07-08 18:31:20 +02:00 committed by GitHub
parent 925464cfc6
commit 263080c4c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 146 additions and 135 deletions

1
Cargo.lock generated
View file

@ -13213,6 +13213,7 @@ dependencies = [
"fs",
"futures 0.3.31",
"git",
"git2",
"git_hosting_providers",
"gpui",
"gpui_tokio",

View file

@ -314,20 +314,6 @@ pub struct SshPlatform {
pub arch: &'static str,
}
impl SshPlatform {
pub fn triple(&self) -> Option<String> {
Some(format!(
"{}-{}",
self.arch,
match self.os {
"linux" => "unknown-linux-gnu",
"macos" => "apple-darwin",
_ => return None,
}
))
}
}
pub trait SshClientDelegate: Send + Sync {
fn ask_password(&self, prompt: String, tx: oneshot::Sender<String>, cx: &mut AsyncApp);
fn get_download_params(
@ -2068,6 +2054,7 @@ impl SshRemoteConnection {
cx: &mut AsyncApp,
) -> Result<PathBuf> {
use smol::process::{Command, Stdio};
use std::env::VarError;
async fn run_cmd(command: &mut Command) -> Result<()> {
let output = command
@ -2082,70 +2069,37 @@ impl SshRemoteConnection {
Ok(())
}
let triple = format!(
"{}-{}",
self.ssh_platform.arch,
match self.ssh_platform.os {
"linux" => "unknown-linux-musl",
"macos" => "apple-darwin",
_ => anyhow::bail!("can't cross compile for: {:?}", self.ssh_platform),
}
);
let mut rust_flags = match std::env::var("RUSTFLAGS") {
Ok(val) => val,
Err(VarError::NotPresent) => String::new(),
Err(e) => {
log::error!("Failed to get env var `RUSTFLAGS` value: {e}");
String::new()
}
};
if self.ssh_platform.os == "linux" {
rust_flags.push_str(" -C target-feature=+crt-static");
}
if build_remote_server.contains("mold") {
rust_flags.push_str(" -C link-arg=-fuse-ld=mold");
}
if self.ssh_platform.arch == std::env::consts::ARCH
&& self.ssh_platform.os == std::env::consts::OS
{
delegate.set_status(Some("Building remote server binary from source"), cx);
log::info!("building remote server binary from source");
run_cmd(Command::new("cargo").args([
"build",
"--package",
"remote_server",
"--features",
"debug-embed",
"--target-dir",
"target/remote_server",
]))
.await?;
delegate.set_status(Some("Compressing binary"), cx);
run_cmd(Command::new("gzip").args([
"-9",
"-f",
"target/remote_server/debug/remote_server",
]))
.await?;
let path = std::env::current_dir()?.join("target/remote_server/debug/remote_server.gz");
return Ok(path);
}
let Some(triple) = self.ssh_platform.triple() else {
anyhow::bail!("can't cross compile for: {:?}", self.ssh_platform);
};
smol::fs::create_dir_all("target/remote_server").await?;
if build_remote_server.contains("cross") {
#[cfg(target_os = "windows")]
use util::paths::SanitizedPath;
delegate.set_status(Some("Installing cross.rs for cross-compilation"), cx);
log::info!("installing cross");
run_cmd(Command::new("cargo").args([
"install",
"cross",
"--git",
"https://github.com/cross-rs/cross",
]))
.await?;
delegate.set_status(
Some(&format!(
"Building remote server binary from source for {} with Docker",
&triple
)),
cx,
);
log::info!("building remote server binary from source for {}", &triple);
// On Windows, the binding needs to be set to the canonical path
#[cfg(target_os = "windows")]
let src =
SanitizedPath::from(smol::fs::canonicalize("./target").await?).to_glob_string();
#[cfg(not(target_os = "windows"))]
let src = "./target";
run_cmd(
Command::new("cross")
Command::new("cargo")
.args([
"build",
"--package",
@ -2157,73 +2111,126 @@ impl SshRemoteConnection {
"--target",
&triple,
])
.env(
"CROSS_CONTAINER_OPTS",
format!("--mount type=bind,src={src},dst=/app/target"),
),
.env("RUSTFLAGS", &rust_flags),
)
.await?;
} else {
let which = cx
.background_spawn(async move { which::which("zig") })
.await;
if which.is_err() {
#[cfg(not(target_os = "windows"))]
{
anyhow::bail!(
"zig not found on $PATH, install zig (see https://ziglang.org/learn/getting-started or use zigup) or pass ZED_BUILD_REMOTE_SERVER=cross to use cross"
)
}
if build_remote_server.contains("cross") {
#[cfg(target_os = "windows")]
{
anyhow::bail!(
"zig not found on $PATH, install zig (use `winget install -e --id zig.zig` or see https://ziglang.org/learn/getting-started or use zigup) or pass ZED_BUILD_REMOTE_SERVER=cross to use cross"
)
use util::paths::SanitizedPath;
delegate.set_status(Some("Installing cross.rs for cross-compilation"), cx);
log::info!("installing cross");
run_cmd(Command::new("cargo").args([
"install",
"cross",
"--git",
"https://github.com/cross-rs/cross",
]))
.await?;
delegate.set_status(
Some(&format!(
"Building remote server binary from source for {} with Docker",
&triple
)),
cx,
);
log::info!("building remote server binary from source for {}", &triple);
// On Windows, the binding needs to be set to the canonical path
#[cfg(target_os = "windows")]
let src =
SanitizedPath::from(smol::fs::canonicalize("./target").await?).to_glob_string();
#[cfg(not(target_os = "windows"))]
let src = "./target";
run_cmd(
Command::new("cross")
.args([
"build",
"--package",
"remote_server",
"--features",
"debug-embed",
"--target-dir",
"target/remote_server",
"--target",
&triple,
])
.env(
"CROSS_CONTAINER_OPTS",
format!("--mount type=bind,src={src},dst=/app/target"),
)
.env("RUSTFLAGS", &rust_flags),
)
.await?;
} else {
let which = cx
.background_spawn(async move { which::which("zig") })
.await;
if which.is_err() {
#[cfg(not(target_os = "windows"))]
{
anyhow::bail!(
"zig not found on $PATH, install zig (see https://ziglang.org/learn/getting-started or use zigup) or pass ZED_BUILD_REMOTE_SERVER=cross to use cross"
)
}
#[cfg(target_os = "windows")]
{
anyhow::bail!(
"zig not found on $PATH, install zig (use `winget install -e --id zig.zig` or see https://ziglang.org/learn/getting-started or use zigup) or pass ZED_BUILD_REMOTE_SERVER=cross to use cross"
)
}
}
delegate.set_status(Some("Adding rustup target for cross-compilation"), cx);
log::info!("adding rustup target");
run_cmd(Command::new("rustup").args(["target", "add"]).arg(&triple)).await?;
delegate.set_status(Some("Installing cargo-zigbuild for cross-compilation"), cx);
log::info!("installing cargo-zigbuild");
run_cmd(Command::new("cargo").args(["install", "--locked", "cargo-zigbuild"]))
.await?;
delegate.set_status(
Some(&format!(
"Building remote binary from source for {triple} with Zig"
)),
cx,
);
log::info!("building remote binary from source for {triple} with Zig");
run_cmd(
Command::new("cargo")
.args([
"zigbuild",
"--package",
"remote_server",
"--features",
"debug-embed",
"--target-dir",
"target/remote_server",
"--target",
&triple,
])
.env("RUSTFLAGS", &rust_flags),
)
.await?;
}
delegate.set_status(Some("Adding rustup target for cross-compilation"), cx);
log::info!("adding rustup target");
run_cmd(Command::new("rustup").args(["target", "add"]).arg(&triple)).await?;
delegate.set_status(Some("Installing cargo-zigbuild for cross-compilation"), cx);
log::info!("installing cargo-zigbuild");
run_cmd(Command::new("cargo").args(["install", "--locked", "cargo-zigbuild"])).await?;
delegate.set_status(
Some(&format!(
"Building remote binary from source for {triple} with Zig"
)),
cx,
);
log::info!("building remote binary from source for {triple} with Zig");
run_cmd(Command::new("cargo").args([
"zigbuild",
"--package",
"remote_server",
"--features",
"debug-embed",
"--target-dir",
"target/remote_server",
"--target",
&triple,
]))
.await?;
};
let bin_path = Path::new("target")
.join("remote_server")
.join(&triple)
.join("debug")
.join("remote_server");
let mut path = format!("target/remote_server/{triple}/debug/remote_server").into();
if !build_remote_server.contains("nocompress") {
let path = if !build_remote_server.contains("nocompress") {
delegate.set_status(Some("Compressing binary"), cx);
#[cfg(not(target_os = "windows"))]
{
run_cmd(Command::new("gzip").args([
"-9",
"-f",
&format!("target/remote_server/{}/debug/remote_server", triple),
]))
.await?;
run_cmd(Command::new("gzip").args(["-9", "-f", &bin_path.to_string_lossy()]))
.await?;
}
#[cfg(target_os = "windows")]
{
@ -2237,17 +2244,19 @@ impl SshRemoteConnection {
"a",
"-tgzip",
&gz_path,
&format!("target/remote_server/{}/debug/remote_server", triple),
&bin_path.to_string_lossy(),
]))
.await?;
}
path = std::env::current_dir()?.join(format!(
"target/remote_server/{triple}/debug/remote_server.gz"
));
}
let mut archive_path = bin_path;
archive_path.set_extension("gz");
std::env::current_dir()?.join(archive_path)
} else {
bin_path
};
return Ok(path);
Ok(path)
}
}

View file

@ -37,6 +37,7 @@ fs.workspace = true
futures.workspace = true
git.workspace = true
git_hosting_providers.workspace = true
git2 = { workspace = true, features = ["vendored-libgit2"] }
gpui.workspace = true
gpui_tokio.workspace = true
http_client.workspace = true
@ -85,7 +86,7 @@ node_runtime = { workspace = true, features = ["test-support"] }
project = { workspace = true, features = ["test-support"] }
remote = { workspace = true, features = ["test-support"] }
language_model = { workspace = true, features = ["test-support"] }
lsp = { workspace = true, features=["test-support"] }
lsp = { workspace = true, features = ["test-support"] }
unindent.workspace = true
serde_json.workspace = true
zlog.workspace = true
@ -95,4 +96,4 @@ cargo_toml.workspace = true
toml.workspace = true
[package.metadata.cargo-machete]
ignored = ["rust-embed", "paths"]
ignored = ["git2", "rust-embed", "paths"]