diff --git a/.circleci/config.yml b/.circleci/config.yml index 26e7a35..11bb19b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,6 +6,14 @@ version: 2 export PATH=/root/.cargo/bin:$PATH cargo build -v +.cuda_bindgen: &cuda_bindgen + name: Test cuda bindgen + command: | + export PATH=/root/.cargo/bin:$PATH + rustup component add rustfmt + cd cuda-bindgen + cargo run -- -a test_binding /usr/local/cuda + .job_apt_template: &job_apt steps: - checkout @@ -13,10 +21,12 @@ version: 2 name: Install Rust command: | apt update - apt install -y curl + apt install -y curl clang curl https://sh.rustup.rs -sSf | sh -s -- -y - run: <<: *cargo + - run: + <<: *cuda_bindgen .job_yum_template: &job_yum steps: @@ -24,10 +34,12 @@ version: 2 - run: name: Install Rust command: | - yum install -y curl + yum install -y curl clang curl https://sh.rustup.rs -sSf | sh -s -- -y - run: <<: *cargo + - run: + <<: *cuda_bindgen jobs: latest: @@ -102,30 +114,6 @@ jobs: <<: *job_yum docker: - image: nvidia/cuda:7.0-devel-centos7 - 10.0-devel-centos6: - <<: *job_yum - docker: - - image: nvidia/cuda:10.0-devel-centos6 - 9.2-devel-centos6: - <<: *job_yum - docker: - - image: nvidia/cuda:9.2-devel-centos6 - 9.1-devel-centos6: - <<: *job_yum - docker: - - image: nvidia/cuda:9.1-devel-centos6 - 9.0-devel-centos6: - <<: *job_yum - docker: - - image: nvidia/cuda:9.0-devel-centos6 - 8.0-devel-centos6: - <<: *job_yum - docker: - - image: nvidia/cuda:8.0-devel-centos6 - 7.5-devel-centos6: - <<: *job_yum - docker: - - image: nvidia/cuda:7.5-devel-centos6 workflows: version: 2 @@ -149,9 +137,3 @@ workflows: - 8.0-devel-centos7 - 7.5-devel-centos7 - 7.0-devel-centos7 - - 10.0-devel-centos6 - - 9.2-devel-centos6 - - 9.1-devel-centos6 - - 9.0-devel-centos6 - - 8.0-devel-centos6 - - 7.5-devel-centos6 diff --git a/cuda-bindgen/Cargo.toml b/cuda-bindgen/Cargo.toml new file mode 100644 index 0000000..6c46005 --- /dev/null +++ b/cuda-bindgen/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cuda-bindgen" +version = "0.1.0" +authors = ["Toshiki Teramura "] +edition = "2018" + +[dependencies] +bindgen = "0.46" +structopt = "0.2" +env_logger = "0.6" diff --git a/cuda-bindgen/src/main.rs b/cuda-bindgen/src/main.rs new file mode 100644 index 0000000..1b4bb83 --- /dev/null +++ b/cuda-bindgen/src/main.rs @@ -0,0 +1,149 @@ +use env_logger; +use std::{ + fs, + path::{Path, PathBuf}, +}; +use structopt::StructOpt; + +#[derive(StructOpt)] +#[structopt( + name = "cuda-bindgen", + about = "Generate CUDA binding to Rust", + raw(setting = "structopt::clap::AppSettings::ColoredHelp") +)] +struct CudaBindgen { + /// Output directory + #[structopt(name = "output")] + output: PathBuf, + + /// Path where the CUDA is Installed + #[structopt(name = "cuda_path")] + cuda_path: PathBuf, + + /// Build CUDA Driver API + #[structopt(long = "driver")] + driver: bool, + + /// Build CUDA Runtime API + #[structopt(long = "runtime")] + runtime: bool, + + /// Build cuBLAS API + #[structopt(long = "cublas")] + cublas: bool, + + /// Build all APIs + #[structopt(long = "all", short = "a")] + all: bool, +} + +fn builder(cuda_path: &Path, header_name: &str) -> Option { + let header = cuda_path.join(header_name); + if !header.exists() { + return None; + } + Some( + bindgen::builder() + .header(header.to_str().unwrap()) + .clang_arg(format!("-I{}", cuda_path.display())), + ) +} + +fn main() { + env_logger::init(); + let opt = CudaBindgen::from_args(); + + // check CUDA + if !opt.cuda_path.is_dir() { + panic!("CUDA does not exist at {:?}", opt.cuda_path); + } + let cuda_inc_path = opt.cuda_path.join("include"); + + // ready output directory + let out_path = opt.output; + fs::create_dir_all(&out_path).expect("Unable to create output directory"); + + if opt.driver || opt.all { + builder(&cuda_inc_path, "cuda.h") + .expect("cuda.h does not exist") + .whitelist_recursively(false) + .whitelist_type("^CU.*") + .whitelist_type("^cuuint(32|64)_t") + .whitelist_type("^cudaError_enum") + .whitelist_var("^CU.*") + .whitelist_function("^cu.*") + .default_enum_style(bindgen::EnumVariation::Rust) + .generate() + .expect("Unable to generate CUDA bindings") + .write_to_file(out_path.join("cuda.rs")) + .expect("Unable to write CUDA bindings"); + + builder(&cuda_inc_path, "cuComplex.h") + .expect("cuComplex.h does not exist") + .whitelist_recursively(false) + .whitelist_type("^cu.*Complex$") + .default_enum_style(bindgen::EnumVariation::Rust) + .generate() + .expect("Unable to generate CUComplex bindings") + .write_to_file(out_path.join("cucomplex.rs")) + .expect("Unable to write CUComplex bindings"); + + builder(&cuda_inc_path, "vector_types.h") + .expect("vector_types.h does not exist") + .whitelist_type("^u?char[0-9]$") + .whitelist_type("^dim[0-9]$") + .whitelist_type("^double[0-9]$") + .whitelist_type("^float[0-9]$") + .whitelist_type("^u?int[0-9]$") + .whitelist_type("^u?long[0-9]$") + .whitelist_type("^u?longlong[0-9]$") + .whitelist_type("^u?short[0-9]$") + .default_enum_style(bindgen::EnumVariation::Rust) + .derive_copy(true) + .generate() + .expect("Unable to generate vector types bindings") + .write_to_file(out_path.join("vector_types.rs")) + .expect("Unable to write vector types bindings"); + + if let Some(builder) = builder(&cuda_inc_path, "library_types.h") { + builder + .whitelist_recursively(false) + .whitelist_type("^cuda.*") + .whitelist_type("^libraryPropertyType.*") + .default_enum_style(bindgen::EnumVariation::Rust) + .generate() + .expect("Unable to generate library types bindings") + .write_to_file(out_path.join("library_types.rs")) + .expect("Unable to write library types bindings"); + } + } + + if opt.runtime || opt.all { + builder(&cuda_inc_path, "cuda_runtime.h") + .expect("cuda_runtime.h does not exist") + .whitelist_recursively(false) + .whitelist_type("^cuda.*") + .whitelist_type("^surfaceReference") + .whitelist_type("^textureReference") + .whitelist_var("^cuda.*") + .whitelist_function("^cuda.*") + .default_enum_style(bindgen::EnumVariation::Rust) + .generate() + .expect("Unable to generate CUDA RT bindings") + .write_to_file(out_path.join("cuda_runtime.rs")) + .expect("Unable to write CUDA RT bindings"); + } + + if opt.cublas || opt.all { + builder(&cuda_inc_path, "cublas.h") + .expect("cublas.h does not exist") + .whitelist_recursively(false) + .whitelist_type("^cublas.*") + .whitelist_function("^cublas.*") + .default_enum_style(bindgen::EnumVariation::Rust) + .generate() + .expect("Unable to generate CUBLAS bindings") + .write_to_file(out_path.join("cublas.rs")) + .expect("Unable to write CUBLAS bindings"); + } +}