Skip to content

Commit c66451d

Browse files
feat: Download WASI-SDK during build (#188)
fixes #180
1 parent 071306e commit c66451d

File tree

1 file changed

+56
-2
lines changed

1 file changed

+56
-2
lines changed

build.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use {
1616
};
1717

1818
const ZSTD_COMPRESSION_LEVEL: i32 = 19;
19+
const DEFAULT_SDK_VERSION: &str = "27";
1920

2021
#[cfg(any(target_os = "macos", target_os = "windows"))]
2122
const PYTHON_EXECUTABLE: &str = "python.exe";
@@ -92,11 +93,63 @@ fn stubs_for_clippy(out_dir: &Path) -> Result<()> {
9293
Ok(())
9394
}
9495

96+
fn find_wasi_sdk(out_dir: &Path) -> Result<PathBuf> {
97+
let mut wasi_sdk =
98+
PathBuf::from(env::var_os("WASI_SDK_PATH").unwrap_or_else(|| "/opt/wasi-sdk".into()));
99+
100+
// Don't think we have to worry about a time-of-check time-of-use issue here
101+
// Previously we assumed that it existed and the build failed when attempting to use it
102+
// We'd do the same here if it was deleted after the check...
103+
if wasi_sdk.exists() || env::var("NO_DOWNLOAD_WASI_SDK").unwrap_or_default() == "1" {
104+
return Ok(wasi_sdk);
105+
}
106+
107+
// otherwise we want to download the sdk into the target directory
108+
let url = env::var("WASI_SDK_URL").or_else(|_| -> Result<String> {
109+
// Version should be just the major version number, matching
110+
// how it's given in the github release build pipeline
111+
let version = match env::var("WASI_SDK_VERSION").ok() {
112+
Some(v) => v,
113+
None => DEFAULT_SDK_VERSION.to_string(),
114+
};
115+
// same as the github release pipeline, allow overriding source repo
116+
let source = env::var("WASI_SDK_SOURCE").unwrap_or("WebAssembly".to_string());
117+
// Wasi-sdk currently releases for x86_64 and arm64 linux, macos, and windows
118+
let (arch, os) = match (env::consts::ARCH, env::consts::OS) {
119+
pair @ ("x86_64", "linux" | "windows" | "macos") => pair,
120+
("aarch64", os @ ("linux" | "windows" | "macos")) => ("arm64", os),
121+
_ => bail!("Unsupported platform for automatic wasi-sdk download: {} {}", env::consts::ARCH, env::consts::OS),
122+
};
123+
Ok(format!("https://github.com/{source}/wasi-sdk/releases/download/wasi-sdk-{version}/wasi-sdk-{version}.0-{arch}-{os}.tar.gz"))
124+
})?;
125+
126+
// get the filename from the url
127+
let filename = url
128+
.rsplit('/')
129+
.next()
130+
.ok_or_else(|| anyhow!("could not get filename from url: {}", url))?;
131+
// strip the .tar.gz suffix to get the directory name
132+
let dir_name = filename.strip_suffix(".tar.gz").unwrap_or(filename);
133+
134+
wasi_sdk = out_dir.join(dir_name);
135+
if wasi_sdk.exists() {
136+
// already downloaded from a previous build
137+
return Ok(wasi_sdk);
138+
}
139+
println!(
140+
"cargo:warning=wasi-sdk not found, downloading from {} into {}",
141+
url,
142+
wasi_sdk.display()
143+
);
144+
fetch_extract(&url, out_dir)?;
145+
146+
Ok(wasi_sdk)
147+
}
148+
95149
fn package_all_the_things(out_dir: &Path) -> Result<()> {
96150
let repo_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
97151

98-
let wasi_sdk =
99-
PathBuf::from(env::var_os("WASI_SDK_PATH").unwrap_or_else(|| "/opt/wasi-sdk".into()));
152+
let wasi_sdk = find_wasi_sdk(out_dir)?;
100153

101154
maybe_make_cpython(&repo_dir, &wasi_sdk)?;
102155

@@ -261,6 +314,7 @@ fn maybe_make_cpython(repo_dir: &Path, wasi_sdk: &Path) -> Result<()> {
261314
cpython_wasi_dir.display()
262315
),
263316
)
317+
.env("WASI_SDK_PATH", wasi_sdk)
264318
.env(
265319
"LDFLAGS",
266320
format!(

0 commit comments

Comments
 (0)