diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 018d9eec..f026dc58 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -41,6 +41,60 @@ jobs: command: test args: --manifest-path=fftw/Cargo.toml --features=${{ matrix.feature }} --no-default-features + ios: + runs-on: macos-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v1 + - name: Force XCode + run: sudo xcode-select -switch /Applications/Xcode.app + - name: Install targets + run: rustup target install aarch64-apple-ios + - uses: actions-rs/cargo@v1 + with: + command: test + args: > + --all-targets + --manifest-path=fftw/Cargo.toml + --target aarch64-apple-ios + --features=source + --no-default-features + --no-run + + android: + runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + targets: ["aarch64-linux-android", "armv7-linux-androideabi"] + steps: + - uses: nttld/setup-ndk@v1 + with: + ndk-version: r21d + - name: Show env + env: + OUTPUT_NDK_PATH: ${{ steps.setup-ndk.outputs.ndk-path }} + run: > + ls /usr/local/lib/android/sdk/ndk/; + echo ANDROID_NDK_ROOT=$ANDROID_NDK_ROOT; + echo ${{ steps.setup-ndk.outputs.ndk-path }}; + echo output-ndk-path=$OUTPUT_NDK_PATH; + - uses: actions/checkout@v1 + - name: Install targets + run: rustup target install aarch64-linux-android armv7-linux-androideabi + - uses: actions-rs/cargo@v1 + with: + command: test + args: > + --all-targets + --manifest-path=fftw/Cargo.toml + --target ${{ matrix.targets }} + --features=source + --no-default-features + --no-run + --verbose + linux: runs-on: ubuntu-18.04 strategy: diff --git a/fftw-src/build.rs b/fftw-src/build.rs index e01b12fc..56d41990 100644 --- a/fftw-src/build.rs +++ b/fftw-src/build.rs @@ -1,5 +1,6 @@ use anyhow::Result; -use std::env::var; +use cc; +use std::env::{set_var, var}; use std::fs::{canonicalize, File}; use std::io::{copy, Write}; use std::path::{Path, PathBuf}; @@ -38,12 +39,12 @@ fn download_archive_windows(out_dir: &Path) -> Result<()> { .arg("/MACHINE:X64") .arg(format!("/DEF:lib{}.def", name)) .arg(format!("/OUT:lib{}.lib", name)) - .current_dir(out_dir)) + .current_dir(out_dir)); } Ok(()) } -fn build_unix(out_dir: &Path) { +fn build_unix(out_dir: &Path, flags: &[&str]) { let src_dir = PathBuf::from(var("CARGO_MANIFEST_DIR").unwrap()).join("fftw-3.3.8"); let out_src_dir = out_dir.join("src"); fs_extra::dir::copy( @@ -60,10 +61,15 @@ fn build_unix(out_dir: &Path) { ) .unwrap(); if !out_dir.join("lib/libfftw3.a").exists() { - build_fftw(&[], &out_src_dir, &out_dir); + build_fftw(flags, &out_src_dir, &out_dir); } if !out_dir.join("lib/libfftw3f.a").exists() { - build_fftw(&["--enable-single"], &out_src_dir, &out_dir); + let mut flags = flags.to_vec(); + flags.push("--enable-single"); + if var("CARGO_CFG_TARGET_ARCH").unwrap().starts_with("armv7") { + flags.push("--enable-neon"); + } + build_fftw(&flags, &out_src_dir, &out_dir); } } @@ -73,6 +79,8 @@ fn build_fftw(flags: &[&str], src_dir: &Path, out_dir: &Path) { .arg("--with-pic") .arg("--enable-static") .arg("--disable-doc") + .arg("--enable-threads") + .arg("--with-combined-threads") .arg(format!("--prefix={}", out_dir.display())) .args(flags) .current_dir(&src_dir), @@ -83,13 +91,20 @@ fn build_fftw(flags: &[&str], src_dir: &Path, out_dir: &Path) { run(Command::new("make").arg("install").current_dir(&src_dir)); } -fn run(command: &mut Command) { +fn run(command: &mut Command) -> String { println!("Running: {:?}", command); - match command.status() { - Ok(status) => { - if !status.success() { - panic!("`{:?}` failed: {}", command, status); + match command.output() { + Ok(output) => { + if !output.status.success() { + panic!( + "`{:?}` failed: {}\nstdout:\n{}\nstderr:\n{}", + command, + output.status, + unsafe { String::from_utf8_unchecked(output.stdout) }, + unsafe { String::from_utf8_unchecked(output.stderr) } + ); } + return String::from_utf8(output.stdout).unwrap(); } Err(error) => { panic!("failed to execute `{:?}`: {}", command, error); @@ -98,16 +113,138 @@ fn run(command: &mut Command) { } fn main() { + println!("cargo:rerun-if-cahnged=build.rs"); let out_dir = PathBuf::from(var("OUT_DIR").unwrap()); - if cfg!(target_os = "windows") { - download_archive_windows(&out_dir).unwrap(); - println!("cargo:rustc-link-search={}", out_dir.display()); - println!("cargo:rustc-link-lib=libfftw3-3"); - println!("cargo:rustc-link-lib=libfftw3f-3"); - } else { - build_unix(&out_dir); - println!("cargo:rustc-link-search={}", out_dir.join("lib").display()); - println!("cargo:rustc-link-lib=static=fftw3"); - println!("cargo:rustc-link-lib=static=fftw3f"); + let target = var("TARGET").unwrap(); + let triple = target.split("-").collect::>(); + let target_os = var("CARGO_CFG_TARGET_OS").unwrap(); + let arch = match triple[0] { + "aarch64" => "arm64", + "armv7" => "armv7", + "armv7s" => "armv7s", + "x86" => "x86", + "x86_64" => "x86_64", + &_ => panic!("Unsupported platform {}", target_os), + }; + match target_os.as_ref() { + "ios" => { + let tool = cc::Build::new() + .target(&target) + .flag_if_supported(&format!("-march={}", arch)) + .get_compiler(); + set_var("CC", tool.cc_env()); + set_var("CFLAGS", tool.cflags_env()); + let sysroot = + run(Command::new("xcrun").args(&["--sdk", "iphoneos", "--show-sdk-path"])); + let args = &[ + &format!("--with-sysroot={}", sysroot.trim()), + "--host=arm-apple-darwin", + ]; + build_unix(&out_dir, args); + println!("cargo:rustc-link-search={}", out_dir.join("lib").display()); + println!("cargo:rustc-link-lib=static=fftw3"); + println!("cargo:rustc-link-lib=static=fftw3f"); + } + "android" => { + let tool = cc::Build::new() + .target(&target) + .flag_if_supported("-mfloat-abi=softfp") + .flag_if_supported("-mfpu=neon") + .get_compiler(); + let mut cc = Command::new(tool.cc_env()) + .arg("--version") + .status() + .ok() + .and_then(|status| { + if status.success() { + Some(tool.cc_env()) + } else { + None + } + }); + let ndk_root: PathBuf = var("ANDROID_NDK_ROOT") + .map_err(|_| var("ANDROID_NDK_HOME")) + .expect("ndk not found, please set ANDROID_NDK_ROOT to where ndk installed.") + .into(); + let mut sysroot: String = "".to_string(); + if cc.is_none() { + let host = var("HOST").unwrap(); + let triple = host.split("-").collect::>(); + let toolchain = ndk_root + .join("toolchains/llvm/prebuilt") + .join(&format!("{}-{}", triple[2], triple[0])) + .join("bin"); + if !toolchain.exists() { + panic!(format!( + "Unsupported platform {}, ndk toolchain dose not exists, {}!", + host, + toolchain.display() + )); + }; + match target.as_str() { + "aarch64-linux-android" => { + set_var("AR", toolchain.join("aarch64-linux-android-ar")); + set_var("AS", toolchain.join("aarch64-linux-android-as")); + set_var("LD", toolchain.join("aarch64-linux-android-ld")); + set_var("STRIP", toolchain.join("aarch64-linux-android-strip")); + set_var("RANLIB", toolchain.join("aarch64-linux-android-ranlib")); + cc = Some( + toolchain + .join("aarch64-linux-android21-clang") + .into_os_string(), + ); + sysroot = format!( + "--with-sysroot={}/platforms/android-21/arch-arm64", + ndk_root.display() + ); + } + "armv7-linux-androideabi" => { + set_var("AR", toolchain.join("arm-linux-androideabi-ar")); + set_var("AS", toolchain.join("arm-linux-androideabi-as")); + set_var("LD", toolchain.join("arm-linux-androideabi-ld")); + set_var("STRIP", toolchain.join("arm-linux-androideabi-strip")); + set_var("RANLIB", toolchain.join("arm-linux-androideabi-ranlib")); + cc = Some( + toolchain + .join("armv7a-linux-androideabi21-clang") + .into_os_string(), + ); + sysroot = format!( + "--with-sysroot={}/platforms/android-21/arch-arm", + ndk_root.display() + ); + } + &_ => { + unimplemented!(); + } + }; + }; + set_var("CFLAGS", tool.cflags_env()); + set_var("CC", cc.unwrap()); + let cross = format!("--host={}", target); + if target.starts_with("arm") { + build_unix(&out_dir, &[cross.as_str(), sysroot.as_str()]); + } else { + build_unix(&out_dir, &[cross.as_str(), sysroot.as_str()]); + } + println!("cargo:rustc-link-search={}", out_dir.join("lib").display()); + println!("cargo:rustc-link-lib=static=fftw3"); + println!("cargo:rustc-link-lib=static=fftw3f"); + } + "windows" => { + download_archive_windows(&out_dir).unwrap(); + println!("cargo:rustc-link-search={}", out_dir.display()); + println!("cargo:rustc-link-lib=libfftw3-3"); + println!("cargo:rustc-link-lib=libfftw3f-3"); + } + _ => { + if var("CARGO_CFG_TARGET_FAMILY").unwrap_or("".to_string()) != "unix" { + panic!("Unsupported platform {}", target_os); + } + build_unix(&out_dir, &[]); + println!("cargo:rustc-link-search={}", out_dir.join("lib").display()); + println!("cargo:rustc-link-lib=static=fftw3"); + println!("cargo:rustc-link-lib=static=fftw3f"); + } } }