Windows build: generate the OpenCL import library, drop the SDK dependency
Building the `gpu` (OpenCL) backend on Windows no longer needs a vendor OpenCL SDK. `cl-sys` links `OpenCL` (#[link(name = "OpenCL")]); instead of requiring an SDK-provided OpenCL.lib, build.rs now generates a vendor-neutral import library at build time from windows/OpenCL.def (all 118 cl-sys exports) — lib.exe for MSVC (located via the cc crate), dlltool for MinGW — and puts it on the link search path. The real OpenCL.dll is supplied at runtime by the GPU driver. build.rs no-ops on non-Windows targets and when the gpu feature is off, and warns rather than panics if the toolchain tool is absent so `cargo check` still works. Combined with the runtime-loaded (dlopen) CUDA/NVML, a Windows build now needs zero external GPU libraries. Add BUILD-windows.md (toolchain, build, crt-static packaging, runtime deps, CI) and link it from the README. Verified the whole crate compiles for x86_64-pc-windows-gnu (default features and gpu,cuda); Linux is unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
//! Build script — Windows OpenCL import library only.
|
||||
//!
|
||||
//! On Windows, the `ocl`/`cl-sys` crates link `OpenCL` (`#[link(name =
|
||||
//! "OpenCL")]`), which normally requires an `OpenCL.lib` import library from a
|
||||
//! vendor OpenCL SDK. To avoid that build dependency, we generate a
|
||||
//! vendor-neutral import library ourselves from `windows/OpenCL.def` (the list
|
||||
//! of OpenCL exports) using the toolchain's own tools — `lib.exe` for MSVC,
|
||||
//! `dlltool` for the GNU (MinGW) toolchain — and put it on the link search path.
|
||||
//! The real `OpenCL.dll` (the ICD loader) is supplied at runtime by the GPU
|
||||
//! driver, exactly like `libOpenCL.so.1` on Linux.
|
||||
//!
|
||||
//! Nothing here is needed on non-Windows targets (the system `libOpenCL` is used
|
||||
//! directly) or when the `gpu` (OpenCL) feature is off — the script no-ops. The
|
||||
//! CUDA driver / NVML are loaded at runtime via dlopen (see `src/dylib.rs`), so
|
||||
//! they need no build-script support.
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=windows/OpenCL.def");
|
||||
|
||||
// Only Windows targets with the OpenCL backend need an import library.
|
||||
if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") {
|
||||
return;
|
||||
}
|
||||
if env::var_os("CARGO_FEATURE_GPU").is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let def = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("windows/OpenCL.def");
|
||||
let target = env::var("TARGET").unwrap_or_default();
|
||||
let is_msvc = env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc");
|
||||
|
||||
let (mut cmd, tool) = if is_msvc {
|
||||
// lib.exe /def:OpenCL.def /out:OpenCL.lib /machine:X64
|
||||
let mut c = cc::windows_registry::find(&target, "lib.exe")
|
||||
.unwrap_or_else(|| Command::new("lib.exe"));
|
||||
c.arg("/nologo")
|
||||
.arg(format!("/def:{}", def.display()))
|
||||
.arg(format!("/out:{}", out_dir.join("OpenCL.lib").display()))
|
||||
.arg("/machine:X64");
|
||||
(c, "lib.exe")
|
||||
} else {
|
||||
// GNU/MinGW: dlltool -d OpenCL.def -l libOpenCL.a -m i386:x86-64
|
||||
let dlltool = ["x86_64-w64-mingw32-dlltool", "dlltool"]
|
||||
.into_iter()
|
||||
.find(|t| Command::new(t).arg("--version").output().is_ok())
|
||||
.unwrap_or("dlltool");
|
||||
let mut c = Command::new(dlltool);
|
||||
c.arg("-d")
|
||||
.arg(&def)
|
||||
.arg("-l")
|
||||
.arg(out_dir.join("libOpenCL.a"))
|
||||
.arg("-m")
|
||||
.arg("i386:x86-64");
|
||||
(c, "dlltool")
|
||||
};
|
||||
|
||||
match cmd.status() {
|
||||
Ok(s) if s.success() => {
|
||||
// Resolve `#[link(name = "OpenCL")]` against the generated import lib.
|
||||
println!("cargo:rustc-link-search=native={}", out_dir.display());
|
||||
}
|
||||
Ok(s) => panic!("{tool} failed ({s}) generating the OpenCL import library from {}", def.display()),
|
||||
Err(e) => {
|
||||
// Tool not found: let `cargo check` (which doesn't link) still succeed;
|
||||
// a real build will fail at link with a clear "cannot find OpenCL".
|
||||
println!(
|
||||
"cargo:warning=could not run {tool} to generate the OpenCL import library ({e}); \
|
||||
ensure the toolchain tools are on PATH (MSVC dev prompt, or mingw-w64). \
|
||||
Linking the `gpu` feature will fail until then."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user