This is an automated email from the ASF dual-hosted git repository.

hcr pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git


The following commit(s) were added to refs/heads/main by this push:
     new 187dc4b77 feat: Make qdp-kernels build/link on Linux without nvcc by 
providing stub symbols (#887)
187dc4b77 is described below

commit 187dc4b77afbda97e2780addf4052f711eaace08
Author: KUAN-HAO HUANG <[email protected]>
AuthorDate: Thu Jan 22 20:12:27 2026 +0800

    feat: Make qdp-kernels build/link on Linux without nvcc by providing stub 
symbols (#887)
    
    * Make qdp-kernels build/link on Linux without nvcc by providing stub 
symbolsy
    
    * fix errors
    
    * fix unsafe error
    
    * fix errors
    
    * fix thr test error
    
    * fix errors
    
    * fix error
    
    * fix stupid error
    
    * try to figure out this stupid error!
---
 qdp/qdp-core/src/encoding/amplitude.rs      |  4 +++
 qdp/qdp-core/src/encoding/angle.rs          | 24 ++++++++++--------
 qdp/qdp-core/src/encoding/basis.rs          |  4 +++
 qdp/qdp-core/src/gpu/encodings/amplitude.rs |  4 +++
 qdp/qdp-core/src/gpu/encodings/angle.rs     |  4 +++
 qdp/qdp-core/src/gpu/encodings/basis.rs     |  4 +++
 qdp/qdp-core/src/gpu/memory.rs              |  5 ++++
 qdp/qdp-core/src/gpu/pipeline.rs            |  4 +++
 qdp/qdp-core/src/lib.rs                     |  4 +++
 qdp/qdp-kernels/build.rs                    | 13 +++++++++-
 qdp/qdp-kernels/src/lib.rs                  | 38 ++++++++++++++++++++---------
 qdp/qdp-kernels/tests/amplitude_encode.rs   |  5 ++++
 12 files changed, 90 insertions(+), 23 deletions(-)

diff --git a/qdp/qdp-core/src/encoding/amplitude.rs 
b/qdp/qdp-core/src/encoding/amplitude.rs
index c308db33c..0606c0bd7 100644
--- a/qdp/qdp-core/src/encoding/amplitude.rs
+++ b/qdp/qdp-core/src/encoding/amplitude.rs
@@ -16,6 +16,10 @@
 
 //! Amplitude encoding implementation.
 
+// Allow unused_unsafe: qdp_kernels functions are unsafe in CUDA builds but 
safe stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 use std::ffi::c_void;
 
 use cudarc::driver::{CudaSlice, DevicePtrMut};
diff --git a/qdp/qdp-core/src/encoding/angle.rs 
b/qdp/qdp-core/src/encoding/angle.rs
index a9f5e5bc8..0eac78d48 100644
--- a/qdp/qdp-core/src/encoding/angle.rs
+++ b/qdp/qdp-core/src/encoding/angle.rs
@@ -16,6 +16,10 @@
 
 //! Angle encoding implementation.
 
+// Allow unused_unsafe: qdp_kernels functions are unsafe in CUDA builds but 
safe stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 use std::ffi::c_void;
 
 use qdp_kernels::launch_angle_encode_batch;
@@ -103,22 +107,22 @@ impl ChunkEncoder for AngleEncoder {
             }
         }
 
-        unsafe {
-            crate::profile_scope!("GPU::BatchEncode");
-            let ret = launch_angle_encode_batch(
+        crate::profile_scope!("GPU::BatchEncode");
+        let ret = unsafe {
+            launch_angle_encode_batch(
                 dev_ptr as *const f64,
                 state_ptr_offset,
                 samples_in_chunk,
                 state_len,
                 num_qubits as u32,
                 ctx.stream_compute.stream as *mut c_void,
-            );
-            if ret != 0 {
-                return Err(MahoutError::KernelLaunch(format!(
-                    "Angle encode kernel error: {}",
-                    ret
-                )));
-            }
+            )
+        };
+        if ret != 0 {
+            return Err(MahoutError::KernelLaunch(format!(
+                "Angle encode kernel error: {}",
+                ret
+            )));
         }
         Ok(())
     }
diff --git a/qdp/qdp-core/src/encoding/basis.rs 
b/qdp/qdp-core/src/encoding/basis.rs
index 81750fa9a..b2c79a3d5 100644
--- a/qdp/qdp-core/src/encoding/basis.rs
+++ b/qdp/qdp-core/src/encoding/basis.rs
@@ -16,6 +16,10 @@
 
 //! Basis encoding implementation.
 
+// Allow unused_unsafe: qdp_kernels functions are unsafe in CUDA builds but 
safe stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 use std::ffi::c_void;
 
 use cudarc::driver::{CudaSlice, DevicePtr};
diff --git a/qdp/qdp-core/src/gpu/encodings/amplitude.rs 
b/qdp/qdp-core/src/gpu/encodings/amplitude.rs
index 0720cd619..c20f0103f 100644
--- a/qdp/qdp-core/src/gpu/encodings/amplitude.rs
+++ b/qdp/qdp-core/src/gpu/encodings/amplitude.rs
@@ -16,6 +16,10 @@
 
 // Amplitude encoding: state injection with L2 normalization
 
+// Allow unused_unsafe: qdp_kernels functions are unsafe in CUDA builds but 
safe stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 use std::sync::Arc;
 
 use super::QuantumEncoder;
diff --git a/qdp/qdp-core/src/gpu/encodings/angle.rs 
b/qdp/qdp-core/src/gpu/encodings/angle.rs
index aa4a347a0..44df2c810 100644
--- a/qdp/qdp-core/src/gpu/encodings/angle.rs
+++ b/qdp/qdp-core/src/gpu/encodings/angle.rs
@@ -16,6 +16,10 @@
 
 // Angle encoding: map per-qubit angles to product state amplitudes.
 
+// Allow unused_unsafe: qdp_kernels functions are unsafe in CUDA builds but 
safe stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 use super::QuantumEncoder;
 #[cfg(target_os = "linux")]
 use crate::error::cuda_error_to_string;
diff --git a/qdp/qdp-core/src/gpu/encodings/basis.rs 
b/qdp/qdp-core/src/gpu/encodings/basis.rs
index b40d42d6f..2e6169ade 100644
--- a/qdp/qdp-core/src/gpu/encodings/basis.rs
+++ b/qdp/qdp-core/src/gpu/encodings/basis.rs
@@ -16,6 +16,10 @@
 
 // Basis encoding: map integers to computational basis states
 
+// Allow unused_unsafe: qdp_kernels functions are unsafe in CUDA builds but 
safe stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 use super::QuantumEncoder;
 #[cfg(target_os = "linux")]
 use crate::error::cuda_error_to_string;
diff --git a/qdp/qdp-core/src/gpu/memory.rs b/qdp/qdp-core/src/gpu/memory.rs
index 07ec86583..5ee59291a 100644
--- a/qdp/qdp-core/src/gpu/memory.rs
+++ b/qdp/qdp-core/src/gpu/memory.rs
@@ -13,6 +13,11 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
+// Allow unused_unsafe: qdp_kernels functions are unsafe in CUDA builds but 
safe stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 use crate::error::{MahoutError, Result};
 use cudarc::driver::{CudaDevice, CudaSlice, DevicePtr};
 use qdp_kernels::{CuComplex, CuDoubleComplex};
diff --git a/qdp/qdp-core/src/gpu/pipeline.rs b/qdp/qdp-core/src/gpu/pipeline.rs
index 5acb7d32b..484cbc7cf 100644
--- a/qdp/qdp-core/src/gpu/pipeline.rs
+++ b/qdp/qdp-core/src/gpu/pipeline.rs
@@ -19,6 +19,10 @@
 // Provides generic double-buffered execution for large data processing.
 // Separates the "streaming mechanics" from the "kernel logic".
 
+// Allow unused_unsafe: CUDA FFI functions are unsafe in CUDA builds but safe 
stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 use crate::error::{MahoutError, Result};
 #[cfg(target_os = "linux")]
 use crate::gpu::buffer_pool::{PinnedBufferHandle, PinnedBufferPool};
diff --git a/qdp/qdp-core/src/lib.rs b/qdp/qdp-core/src/lib.rs
index f0bedb73a..2b14f6c5b 100644
--- a/qdp/qdp-core/src/lib.rs
+++ b/qdp/qdp-core/src/lib.rs
@@ -14,6 +14,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// Allow unused_unsafe: CUDA FFI and kernel functions are unsafe in CUDA 
builds but safe stubs in no-CUDA builds.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 pub mod dlpack;
 #[cfg(target_os = "linux")]
 mod encoding;
diff --git a/qdp/qdp-kernels/build.rs b/qdp/qdp-kernels/build.rs
index 546928d2f..093fbf71e 100644
--- a/qdp/qdp-kernels/build.rs
+++ b/qdp/qdp-kernels/build.rs
@@ -27,16 +27,27 @@ use std::env;
 use std::process::Command;
 
 fn main() {
+    // Let rustc know about our build-script-defined cfg flags (avoids 
`unexpected_cfgs` warnings).
+    println!("cargo::rustc-check-cfg=cfg(qdp_no_cuda)");
+
     // Tell Cargo to rerun this script if the kernel sources change
     println!("cargo:rerun-if-changed=src/amplitude.cu");
     println!("cargo:rerun-if-changed=src/basis.cu");
     println!("cargo:rerun-if-changed=src/angle.cu");
+    println!("cargo:rerun-if-env-changed=QDP_NO_CUDA");
     println!("cargo:rerun-if-changed=src/kernel_config.h");
 
     // Check if CUDA is available by looking for nvcc
-    let has_cuda = Command::new("nvcc").arg("--version").output().is_ok();
+    let force_no_cuda = env::var("QDP_NO_CUDA")
+        .map(|v| v == "1" || v.eq_ignore_ascii_case("true") || 
v.eq_ignore_ascii_case("yes"))
+        .unwrap_or(false);
+
+    let has_cuda = !force_no_cuda && 
Command::new("nvcc").arg("--version").output().is_ok();
 
     if !has_cuda {
+        // Expose a cfg for conditional compilation of stub symbols on Linux.
+        // This allows qdp-kernels (and dependents) to link on Linux machines 
without CUDA.
+        println!("cargo:rustc-cfg=qdp_no_cuda");
         println!("cargo:warning=CUDA not found (nvcc not in PATH). Skipping 
kernel compilation.");
         println!("cargo:warning=This is expected on macOS or non-CUDA 
environments.");
         println!(
diff --git a/qdp/qdp-kernels/src/lib.rs b/qdp/qdp-kernels/src/lib.rs
index f1ebd351c..7bab4bf80 100644
--- a/qdp/qdp-kernels/src/lib.rs
+++ b/qdp/qdp-kernels/src/lib.rs
@@ -52,8 +52,8 @@ unsafe impl cudarc::driver::DeviceRepr for CuComplex {}
 #[cfg(target_os = "linux")]
 unsafe impl cudarc::driver::ValidAsZeroBits for CuComplex {}
 
-// CUDA kernel FFI (Linux only, dummy on other platforms)
-#[cfg(target_os = "linux")]
+// CUDA kernel FFI (Linux only; stubbed when built without nvcc/CUDA)
+#[cfg(all(target_os = "linux", not(qdp_no_cuda)))]
 unsafe extern "C" {
     /// Launch amplitude encoding kernel
     /// Returns CUDA error code (0 = success)
@@ -190,8 +190,8 @@ unsafe extern "C" {
     ) -> i32;
 }
 
-// Dummy implementation for non-Linux (allows compilation)
-#[cfg(not(target_os = "linux"))]
+// Dummy implementation for non-Linux and Linux builds without CUDA (allows 
linking)
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn launch_amplitude_encode(
     _input_d: *const f64,
@@ -204,7 +204,7 @@ pub extern "C" fn launch_amplitude_encode(
     999 // Error: CUDA unavailable
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn launch_amplitude_encode_f32(
     _input_d: *const f32,
@@ -217,7 +217,21 @@ pub extern "C" fn launch_amplitude_encode_f32(
     999
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
+#[unsafe(no_mangle)]
+pub extern "C" fn launch_amplitude_encode_batch(
+    _input_batch_d: *const f64,
+    _state_batch_d: *mut c_void,
+    _inv_norms_d: *const f64,
+    _num_samples: usize,
+    _input_len: usize,
+    _state_len: usize,
+    _stream: *mut c_void,
+) -> i32 {
+    999
+}
+
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn launch_l2_norm(
     _input_d: *const f64,
@@ -228,7 +242,7 @@ pub extern "C" fn launch_l2_norm(
     999
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn launch_l2_norm_batch(
     _input_batch_d: *const f64,
@@ -240,7 +254,7 @@ pub extern "C" fn launch_l2_norm_batch(
     999
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn convert_state_to_float(
     _input_state_d: *const CuDoubleComplex,
@@ -251,7 +265,7 @@ pub extern "C" fn convert_state_to_float(
     999
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn launch_basis_encode(
     _basis_index: usize,
@@ -262,7 +276,7 @@ pub extern "C" fn launch_basis_encode(
     999
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn launch_basis_encode_batch(
     _basis_indices_d: *const usize,
@@ -275,7 +289,7 @@ pub extern "C" fn launch_basis_encode_batch(
     999
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn launch_angle_encode(
     _angles_d: *const f64,
@@ -287,7 +301,7 @@ pub extern "C" fn launch_angle_encode(
     999
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(any(not(target_os = "linux"), qdp_no_cuda))]
 #[unsafe(no_mangle)]
 pub extern "C" fn launch_angle_encode_batch(
     _angles_batch_d: *const f64,
diff --git a/qdp/qdp-kernels/tests/amplitude_encode.rs 
b/qdp/qdp-kernels/tests/amplitude_encode.rs
index 0d69ca9ee..7ee181bfd 100644
--- a/qdp/qdp-kernels/tests/amplitude_encode.rs
+++ b/qdp/qdp-kernels/tests/amplitude_encode.rs
@@ -16,6 +16,11 @@
 
 // Tests for amplitude encoding CUDA kernel
 
+// Allow unused_unsafe: in no-CUDA builds, stub functions are not unsafe,
+// but in CUDA builds, the extern "C" functions require unsafe blocks.
+// The compiler can't statically determine which path is taken.
+#![allow(unused_unsafe)]
+
 #[cfg(target_os = "linux")]
 use cudarc::driver::{CudaDevice, DevicePtr, DevicePtrMut};
 #[cfg(target_os = "linux")]

Reply via email to