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=kernels/cuda");
println!("cargo:rerun-if-changed=kernels/ptx");
if env::var("CARGO_FEATURE_CUDA").is_ok() {
if env::var("CARGO_FEATURE_CUDA_BUILD_PTX").is_ok() {
compile_cuda_kernels();
} else {
stage_prebuilt_ptx();
}
}
if is_nightly() {
println!("cargo:rustc-cfg=rustc_is_nightly");
}
}
fn is_nightly() -> bool {
let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string());
let output = Command::new(rustc).arg("--version").output();
if let Ok(output) = output {
if let Ok(stdout) = String::from_utf8(output.stdout) {
return stdout.contains("nightly");
}
}
false
}
fn stage_prebuilt_ptx() {
println!("cargo:rerun-if-env-changed=VECTOR_TA_PREBUILT_PTX_DIR");
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
let ptx_dir = if let Ok(dir) = env::var("VECTOR_TA_PREBUILT_PTX_DIR") {
PathBuf::from(dir)
} else {
manifest_dir.join("kernels/ptx/compute_89")
};
if !ptx_dir.is_dir() {
panic!(
"Prebuilt PTX directory not found: {}. \
Enable `--features cuda-build-ptx` to compile PTX with nvcc, or set VECTOR_TA_PREBUILT_PTX_DIR to a directory containing *.ptx files.",
ptx_dir.display()
);
}
let mut ptx_files: Vec<PathBuf> = Vec::new();
for entry in std::fs::read_dir(&ptx_dir).expect("read prebuilt PTX dir") {
let entry = entry.expect("read prebuilt PTX dir entry");
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) == Some("ptx") {
ptx_files.push(path);
}
}
if ptx_files.is_empty() {
panic!(
"No prebuilt PTX files (*.ptx) found in {}. \
Enable `--features cuda-build-ptx` to compile PTX with nvcc.",
ptx_dir.display()
);
}
for src in ptx_files {
println!("cargo:rerun-if-changed={}", src.display());
let file_name = src
.file_name()
.expect("PTX file name")
.to_string_lossy()
.to_string();
let dst = out_dir.join(&file_name);
std::fs::copy(&src, &dst).unwrap_or_else(|e| {
panic!(
"Failed copying prebuilt PTX {} -> {}: {e}",
src.display(),
dst.display()
)
});
}
}
fn compile_cuda_kernels() {
println!("cargo:rerun-if-changed=kernels/cuda");
println!("cargo:rerun-if-env-changed=CUDA_ARCH");
println!("cargo:rerun-if-env-changed=CUDA_ARCHS");
println!("cargo:rerun-if-env-changed=CUDA_FILTER");
println!("cargo:rerun-if-env-changed=CUDA_KERNEL_DIR");
println!("cargo:rerun-if-env-changed=NVCC");
println!("cargo:rerun-if-env-changed=NVCC_ARGS");
println!("cargo:rerun-if-env-changed=CUDA_DEBUG");
println!("cargo:rerun-if-env-changed=CUDA_FAST_MATH");
println!("cargo:rerun-if-env-changed=VECTOR_TA_PREBUILD_PTX_DIR");
let cuda_path = find_cuda_path();
compile_alma_kernel(&cuda_path);
compile_cwma_kernel(&cuda_path);
compile_epma_kernel(&cuda_path);
compile_cora_wave_kernel(&cuda_path);
compile_ehlers_ecema_kernel(&cuda_path);
compile_kama_kernel(&cuda_path);
compile_highpass_kernel(&cuda_path);
compile_nama_kernel(&cuda_path);
compile_wma_kernel(&cuda_path);
compile_sinwma_kernel(&cuda_path);
compile_tradjema_kernel(&cuda_path);
compile_volume_adjusted_ma_kernel(&cuda_path);
compile_supersmoother_3_pole_kernel(&cuda_path);
compile_wto_kernel(&cuda_path);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/buff_averages_kernel.cu",
"buff_averages_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/dema_kernel.cu",
"dema_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/dma_kernel.cu",
"dma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/edcf_kernel.cu",
"edcf_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/ehlers_itrend_kernel.cu",
"ehlers_itrend_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/ehlers_kama_kernel.cu",
"ehlers_kama_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/ehlers_pma_kernel.cu",
"ehlers_pma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/pma_kernel.cu",
"pma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/ehma_kernel.cu",
"ehma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/ema_kernel.cu",
"ema_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/apo_kernel.cu",
"apo_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/frama_kernel.cu",
"frama_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/fwma_kernel.cu",
"fwma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/gaussian_kernel.cu",
"gaussian_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/highpass2_kernel.cu",
"highpass2_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/decycler_kernel.cu",
"decycler_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/hma_kernel.cu",
"hma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/hwma_kernel.cu",
"hwma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/jma_kernel.cu",
"jma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/jsa_kernel.cu",
"jsa_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/linreg_kernel.cu",
"linreg_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/linearreg_intercept_kernel.cu",
"linearreg_intercept_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/linearreg_slope_kernel.cu",
"linearreg_slope_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/tsf_kernel.cu",
"tsf_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/maaq_kernel.cu",
"maaq_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/mama_kernel.cu",
"mama_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/mwdx_kernel.cu",
"mwdx_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/nma_kernel.cu",
"nma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/vidya_kernel.cu",
"vidya_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/pwma_kernel.cu",
"pwma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/reflex_kernel.cu",
"reflex_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/sama_kernel.cu",
"sama_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/sgf_kernel.cu",
"sgf_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/sma_kernel.cu",
"sma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/smma_kernel.cu",
"smma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/sqwma_kernel.cu",
"sqwma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/srwma_kernel.cu",
"srwma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/supersmoother_kernel.cu",
"supersmoother_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/swma_kernel.cu",
"swma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/tema_kernel.cu",
"tema_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/tilson_kernel.cu",
"tilson_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/trendflex_kernel.cu",
"trendflex_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/trima_kernel.cu",
"trima_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/trix_kernel.cu",
"trix_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/uma_kernel.cu",
"uma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/vlma_kernel.cu",
"vlma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/vama_kernel.cu",
"vama_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/vpwma_kernel.cu",
"vpwma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/vwap_kernel.cu",
"vwap_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/vwma_kernel.cu",
"vwma_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/vidya_kernel.cu",
"vidya_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/vwmacd_kernel.cu",
"vwmacd_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/avsl_kernel.cu",
"avsl_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/wilders_kernel.cu",
"wilders_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/zlema_kernel.cu",
"zlema_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/alligator_kernel.cu",
"alligator_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/correlation_cycle_kernel.cu",
"correlation_cycle_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/otto_kernel.cu",
"otto_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/mab_kernel.cu",
"mab_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/rsmk_kernel.cu",
"rsmk_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/mean_ad_kernel.cu",
"mean_ad_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/macz_kernel.cu",
"macz_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/qstick_kernel.cu",
"qstick_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/ott_kernel.cu",
"ott_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/wad_kernel.cu", "wad_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/var_kernel.cu", "var_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/adosc_kernel.cu",
"adosc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/ao_kernel.cu",
"ao_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/bop_kernel.cu",
"bop_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/coppock_kernel.cu",
"coppock_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/gatorosc_kernel.cu",
"gatorosc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/macd_kernel.cu",
"macd_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/mom_kernel.cu",
"mom_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/roc_kernel.cu",
"roc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/rsx_kernel.cu",
"rsx_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/srsi_kernel.cu",
"srsi_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/vosc_kernel.cu", "vosc_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/safezonestop_kernel.cu",
"safezonestop_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/rocr_kernel.cu", "rocr_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/nadaraya_watson_envelope_kernel.cu",
"nadaraya_watson_envelope_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/mfi_kernel.cu",
"mfi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/willr_kernel.cu",
"willr_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/acosc_kernel.cu",
"acosc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/aroonosc_kernel.cu",
"aroonosc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/cfo_kernel.cu",
"cfo_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/fosc_kernel.cu",
"fosc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/dpo_kernel.cu",
"dpo_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/lrsi_kernel.cu",
"lrsi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/ppo_kernel.cu",
"ppo_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/tsi_kernel.cu",
"tsi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/stoch_kernel.cu",
"stoch_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/aso_kernel.cu",
"aso_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/cg_kernel.cu",
"cg_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/cmo_kernel.cu",
"cmo_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/reverse_rsi_kernel.cu",
"reverse_rsi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/rsi_kernel.cu",
"rsi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/dti_kernel.cu",
"dti_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/emv_kernel.cu",
"emv_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/kdj_kernel.cu",
"kdj_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/stochf_kernel.cu",
"stochf_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/squeeze_momentum_kernel.cu",
"squeeze_momentum_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/ttm_squeeze_kernel.cu",
"ttm_squeeze_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/cci_kernel.cu",
"cci_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/chop_kernel.cu",
"chop_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/dec_osc_kernel.cu",
"dec_osc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/fisher_kernel.cu",
"fisher_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/ift_rsi_kernel.cu",
"ift_rsi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/ultosc_kernel.cu",
"ultosc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/wavetrend_kernel.cu",
"wavetrend_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/cci_cycle_kernel.cu",
"cci_cycle_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/msw_kernel.cu",
"msw_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/kst_kernel.cu",
"kst_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/qqe_kernel.cu",
"qqe_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/rocp_kernel.cu",
"rocp_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/rvi_kernel.cu",
"rvi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/stc_kernel.cu",
"stc_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/moving_averages/wclprice_kernel.cu",
"wclprice_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/sar_kernel.cu", "sar_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/alphatrend_kernel.cu",
"alphatrend_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/medprice_kernel.cu",
"medprice_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/pattern_recognition_kernel.cu",
"pattern_recognition_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/bandpass_kernel.cu",
"bandpass_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/aroon_kernel.cu",
"aroon_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/zscore_kernel.cu",
"zscore_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/yang_zhang_volatility_kernel.cu",
"yang_zhang_volatility_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/garman_klass_volatility_kernel.cu",
"garman_klass_volatility_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/voss_kernel.cu", "voss_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/cksp_kernel.cu", "cksp_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/emd_kernel.cu", "emd_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/minmax_kernel.cu",
"minmax_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/bollinger_bands_width_kernel.cu",
"bollinger_bands_width_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/deviation_kernel.cu",
"deviation_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/range_filter_kernel.cu",
"range_filter_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/kaufmanstop_kernel.cu",
"kaufmanstop_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/mass_kernel.cu", "mass_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/oscillators/kvo_kernel.cu",
"kvo_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/natr_kernel.cu", "natr_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/linearreg_angle_kernel.cu",
"linearreg_angle_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/net_myrsi_kernel.cu",
"net_myrsi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/percentile_nearest_rank_kernel.cu",
"percentile_nearest_rank_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/prb_kernel.cu", "prb_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/vi_kernel.cu", "vi_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/vpci_kernel.cu", "vpci_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/mod_god_mode_kernel.cu",
"mod_god_mode_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/bollinger_bands_kernel.cu",
"bollinger_bands_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/ad_kernel.cu", "ad_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/devstop_kernel.cu",
"devstop_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/fvg_trailing_stop_kernel.cu",
"fvg_trailing_stop_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/ttm_trend_kernel.cu",
"ttm_trend_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/nvi_kernel.cu", "nvi_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/pvi_kernel.cu", "pvi_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/vpt_kernel.cu", "vpt_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/supertrend_kernel.cu",
"supertrend_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/medium_ad_kernel.cu",
"medium_ad_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/di_kernel.cu", "di_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/atr_kernel.cu", "atr_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/chande_kernel.cu",
"chande_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/cvi_kernel.cu", "cvi_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/dvdiqqe_kernel.cu",
"dvdiqqe_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/er_kernel.cu", "er_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/pfe_kernel.cu", "pfe_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/keltner_kernel.cu",
"keltner_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/adx_kernel.cu", "adx_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/dm_kernel.cu", "dm_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/chandelier_exit_kernel.cu",
"chandelier_exit_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/damiani_volatmeter_kernel.cu",
"damiani_volatmeter_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/dx_kernel.cu", "dx_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/eri_kernel.cu", "eri_kernel.ptx");
compile_kernel(&cuda_path, "kernels/cuda/obv_kernel.cu", "obv_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/halftrend_kernel.cu",
"halftrend_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/pivot_kernel.cu",
"pivot_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/ui_kernel.cu", "ui_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/stddev_kernel.cu",
"stddev_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/donchian_kernel.cu",
"donchian_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/adxr_kernel.cu", "adxr_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/correl_hl_kernel.cu",
"correl_hl_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/efi_kernel.cu", "efi_kernel.ptx");
compile_kernel(
&cuda_path,
"kernels/cuda/marketefi_kernel.cu",
"marketefi_kernel.ptx",
);
compile_kernel(
&cuda_path,
"kernels/cuda/kurtosis_kernel.cu",
"kurtosis_kernel.ptx",
);
compile_kernel(&cuda_path, "kernels/cuda/lpc_kernel.cu", "lpc_kernel.ptx");
}
fn find_cuda_path() -> String {
env::var("CUDA_PATH")
.or_else(|_| env::var("CUDA_HOME"))
.unwrap_or_else(|_| {
if cfg!(target_os = "windows") {
use std::fs;
let base = "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA";
if let Ok(entries) = fs::read_dir(base) {
let mut best: Option<(u32, u32, String)> = None;
for e in entries.flatten() {
if let Ok(name) = e.file_name().into_string() {
if let Some(stripped) = name.strip_prefix('v') {
let mut it = stripped.split('.');
let major = it.next().and_then(|s| s.parse::<u32>().ok());
let minor =
it.next().and_then(|s| s.parse::<u32>().ok()).unwrap_or(0);
if let Some(maj) = major {
let cand = (maj, minor, format!("{base}/{}", name));
if let Some(cur) = &best {
if cand.0 > cur.0 || (cand.0 == cur.0 && cand.1 > cur.1) {
best = Some(cand);
}
} else {
best = Some(cand);
}
}
}
}
}
if let Some((_, _, path)) = best {
eprintln!("Found CUDA at: {}", path);
return path;
}
}
"C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v13.0".to_string()
} else {
"/usr/local/cuda".to_string()
}
})
}
fn compile_alma_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/alma_kernel.cu",
"alma_kernel.ptx",
);
}
fn compile_cwma_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/cwma_kernel.cu",
"cwma_kernel.ptx",
);
}
fn compile_cora_wave_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/cora_wave_kernel.cu",
"cora_wave_kernel.ptx",
);
}
fn compile_epma_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/epma_kernel.cu",
"epma_kernel.ptx",
);
}
fn compile_ehlers_ecema_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/ehlers_ecema_kernel.cu",
"ehlers_ecema_kernel.ptx",
);
}
fn compile_kama_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/kama_kernel.cu",
"kama_kernel.ptx",
);
}
fn compile_highpass_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/highpass_kernel.cu",
"highpass_kernel.ptx",
);
}
fn compile_nama_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/nama_kernel.cu",
"nama_kernel.ptx",
);
}
fn compile_wma_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/wma_kernel.cu",
"wma_kernel.ptx",
);
}
fn compile_sinwma_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/sinwma_kernel.cu",
"sinwma_kernel.ptx",
);
}
fn compile_tradjema_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/tradjema_kernel.cu",
"tradjema_kernel.ptx",
);
}
fn compile_volume_adjusted_ma_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/volume_adjusted_ma_kernel.cu",
"volume_adjusted_ma_kernel.ptx",
);
}
fn compile_supersmoother_3_pole_kernel(cuda_path: &str) {
compile_kernel(
cuda_path,
"kernels/cuda/moving_averages/supersmoother_3_pole_kernel.cu",
"supersmoother_3_pole_kernel.ptx",
);
}
fn compile_wto_kernel(cuda_path: &str) {
compile_kernel(cuda_path, "kernels/cuda/wto_kernel.cu", "wto_kernel.ptx");
}
fn compile_kernel(cuda_path: &str, rel_src: &str, ptx_name: &str) {
use std::process::Command;
let src_path = if let Ok(root) = env::var("CUDA_KERNEL_DIR") {
let root = root.trim_end_matches(['/', '\\']);
let prefix = "kernels/cuda/";
if rel_src.starts_with(prefix) {
format!("{}/{}", root, &rel_src[prefix.len()..])
} else {
rel_src.to_string()
}
} else {
rel_src.to_string()
};
println!("cargo:rerun-if-changed={}", src_path);
if let Ok(filt) = env::var("CUDA_FILTER") {
let mut any = false;
for tok in filt.split(|c: char| c == ',' || c.is_ascii_whitespace()) {
let t = tok.trim();
if !t.is_empty() && rel_src.contains(t) {
any = true;
break;
}
}
if !any {
eprintln!("Skipping {} due to CUDA_FILTER", rel_src);
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
let ptx_path = out_dir.join(ptx_name);
let placeholder =
".version 7.0\n.target compute_80\n.address_size 64\n// placeholder PTX (no kernels)\n";
std::fs::write(&ptx_path, placeholder).expect("write placeholder PTX");
return;
}
}
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
if cfg!(target_os = "windows") && env::var("VCINSTALLDIR").is_err() {
eprintln!(
"Warning: VCINSTALLDIR not set. CUDA compilation may require running inside a Visual Studio Developer Command Prompt."
);
}
let nvcc = if let Ok(nvcc_env) = env::var("NVCC") {
nvcc_env
} else if cfg!(target_os = "windows") {
format!("{}/bin/nvcc.exe", cuda_path)
} else {
format!("{}/bin/nvcc", cuda_path)
};
let ptx_path = out_dir.join(ptx_name);
let mut cmd = Command::new(&nvcc);
fn normalize_arch(s: &str) -> String {
let t = s.trim();
if t.is_empty() {
return String::new();
}
if t.starts_with("sm_") {
return t.replacen("sm_", "compute_", 1);
}
if t.starts_with("compute_") {
return t.to_string();
}
let digits: String = t.chars().filter(|c| c.is_ascii_digit()).collect();
if digits.len() >= 2 {
return format!("compute_{}{}", &digits[0..1], &digits[1..2]);
}
t.to_string()
}
let arch = {
if let Ok(list) = env::var("CUDA_ARCHS") {
let first = list
.split(|c: char| c == ',' || c.is_ascii_whitespace())
.find(|t| !t.trim().is_empty())
.map(|s| normalize_arch(s));
first
.filter(|s| !s.is_empty())
.unwrap_or_else(|| "compute_89".to_string())
} else if let Ok(a) = env::var("CUDA_ARCH") {
let n = normalize_arch(&a);
if n.is_empty() {
"compute_89".to_string()
} else {
n
}
} else {
"compute_89".to_string()
}
};
cmd.args(&[
"-std=c++17",
"--expt-relaxed-constexpr",
"--extended-lambda",
"-ptx",
"-O3",
]);
match env::var("CUDA_FAST_MATH").as_deref() {
Ok("0") => {}
_ => {
cmd.arg("--use_fast_math");
}
}
if env::var("CUDA_DEBUG").ok().as_deref() == Some("1") {
cmd.arg("-lineinfo");
}
cmd.args(&[
"-arch",
&arch,
"-o",
ptx_path.to_str().expect("ptx path"),
&src_path,
]);
if let Ok(extra) = env::var("NVCC_ARGS") {
for tok in extra.split_whitespace() {
if !tok.is_empty() {
cmd.arg(tok);
}
}
}
if cfg!(target_os = "windows") {
cmd.arg("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH");
cmd.arg("-allow-unsupported-compiler");
if let Ok(vs_path) = find_vs_installation() {
cmd.arg("-ccbin").arg(vs_path);
}
}
eprintln!("Running nvcc command: {:?}", cmd);
let mut output = cmd.output().expect("Failed to execute nvcc");
if !output.status.success() {
let out_s = String::from_utf8_lossy(&output.stdout);
let err_s = String::from_utf8_lossy(&output.stderr);
let maybe_arch_fail = err_s.contains("unsupported gpu architecture")
|| err_s.contains("Value 'compute_")
|| out_s.contains("unsupported gpu architecture");
if arch != "compute_80" && maybe_arch_fail {
eprintln!(
"Falling back to -arch=compute_80 for {rel_src} (nvcc doesn't support {})",
arch
);
let mut cmd2 = Command::new(&nvcc);
cmd2.args(&[
"-std=c++17",
"--expt-relaxed-constexpr",
"--extended-lambda",
"-ptx",
"-O3",
]);
if env::var("CUDA_FAST_MATH").ok().as_deref() != Some("0") {
cmd2.arg("--use_fast_math");
}
if env::var("CUDA_DEBUG").ok().as_deref() == Some("1") {
cmd2.arg("-lineinfo");
}
cmd2.args(&[
"-arch",
"compute_80",
"-o",
ptx_path.to_str().expect("ptx path"),
&src_path,
]);
if let Ok(extra) = env::var("NVCC_ARGS") {
for tok in extra.split_whitespace() {
if !tok.is_empty() {
cmd2.arg(tok);
}
}
}
if cfg!(target_os = "windows") {
cmd2.arg("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH");
cmd2.arg("-allow-unsupported-compiler");
if let Ok(vs_path) = find_vs_installation() {
cmd2.arg("-ccbin").arg(vs_path);
}
}
eprintln!("Running nvcc command: {:?}", cmd2);
output = cmd2.output().expect("Failed to execute nvcc (fallback)");
}
}
if !output.status.success() {
eprintln!("CUDA compilation failed for {rel_src}!");
eprintln!("stdout: {}", String::from_utf8_lossy(&output.stdout));
eprintln!("stderr: {}", String::from_utf8_lossy(&output.stderr));
if cfg!(target_os = "windows")
&& String::from_utf8_lossy(&output.stderr).contains("Cannot find compiler 'cl.exe'")
{
eprintln!("\n=== CUDA Build Error: Missing Visual Studio C++ Compiler ===");
eprintln!("nvcc requires the Microsoft Visual C++ compiler (cl.exe) to be available.");
eprintln!("Install Visual Studio Build Tools 2022 or run cargo from a Developer Command Prompt.");
eprintln!("===========================================================\n");
}
panic!("nvcc compilation failed");
}
println!(
"Successfully compiled {} to {}",
src_path,
ptx_path.display()
);
if let Ok(prebuild_dir) = env::var("VECTOR_TA_PREBUILD_PTX_DIR") {
let prebuild_dir = PathBuf::from(prebuild_dir);
std::fs::create_dir_all(&prebuild_dir).expect("create VECTOR_TA_PREBUILD_PTX_DIR");
let dst = prebuild_dir.join(ptx_name);
std::fs::copy(&ptx_path, &dst).unwrap_or_else(|e| {
panic!(
"Failed copying compiled PTX {} -> {}: {e}",
ptx_path.display(),
dst.display()
)
});
}
}
#[cfg(target_os = "windows")]
fn find_vs_installation() -> Result<String, ()> {
let vs_paths = [
"C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC",
"C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC",
"C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC",
"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC",
"C:/Program Files/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC",
"C:/Program Files/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC",
"C:/Program Files/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC",
];
for vs_base in &vs_paths {
if let Ok(entries) = std::fs::read_dir(vs_base) {
if let Some(msvc_version) = entries
.filter_map(|e| e.ok())
.filter_map(|e| e.file_name().into_string().ok())
.filter(|name| name.starts_with("14."))
.max()
{
let cl_path = format!("{}/{}/bin/Hostx64/x64", vs_base, msvc_version);
if std::path::Path::new(&format!("{}/cl.exe", cl_path)).exists() {
eprintln!("Found cl.exe at: {}", cl_path);
return Ok(cl_path);
}
}
}
}
Err(())
}
#[cfg(not(target_os = "windows"))]
fn find_vs_installation() -> Result<String, ()> {
Err(())
}