diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3869255e..497aa776 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,6 +16,7 @@ jobs: - proj-sys-ubuntu - proj-macos - proj-sys-macos + - proj-sys-windows steps: - name: Mark the job as a success if: success() @@ -119,3 +120,89 @@ jobs: uses: actions/checkout@v2 - run: brew install proj - run: cargo test ${{ matrix.features }} + + proj-sys-windows: + name: proj-sys windows + if: "!contains(github.event.head_commit.message, '[skip ci]')" + runs-on: windows-latest + env: + _PROJ_SYS_TEST_EXPECT_BUILD_FROM_SRC: 0 + strategy: + fail-fast: false + matrix: + config: + - { + target: "x86_64-pc-windows-msvc", + VCPKG_DEFAULT_TRIPLET: "x64-windows-static", + RUSTFLAGS: "-Ctarget-feature=+crt-static", + features: "", + } + - { + target: "x86_64-pc-windows-msvc", + VCPKG_DEFAULT_TRIPLET: "x64-windows-static-md", + features: "", + } + - { + target: "x86_64-pc-windows-msvc", + VCPKG_DEFAULT_TRIPLET: "x64-windows", + VCPKGRS_DYNAMIC: 1, + # "cargo test --doc" broken with dynamic lib on CI machine (missing dll) + features: "--all-targets", + } + # - { + # target: "i686-pc-windows-msvc", + # VCPKG_DEFAULT_TRIPLET: "x86-windows-static", + # RUSTFLAGS: "-Ctarget-feature=+crt-static", + # features: "", + # } + # - { + # target: "i686-pc-windows-msvc", + # VCPKG_DEFAULT_TRIPLET: "x86-windows-static-md", + # features: "", + # } + # - { + # target: "i686-pc-windows-msvc", + # VCPKG_DEFAULT_TRIPLET: "x86-windows", + # VCPKGRS_DYNAMIC: 1, + # features: "--all-targets", + # } + steps: + - uses: actions/checkout@v2 + - name: Install vcpkg + run: | + git clone https://github.com/Microsoft/vcpkg.git vcp + # PROJ version 7.2.1 - https://github.com/microsoft/vcpkg/search?q=proj4&type=commits + git -C vcp checkout 8fe4184c6a17e237d8b864b6d10e0b520334a093 + vcp\bootstrap-vcpkg.bat -disableMetrics + - name: Set env + shell: bash + run: echo "VCPKG_ROOT=${{ github.workspace }}\vcp" >> $GITHUB_ENV + - name: Install LLVM and Clang + uses: KyleMayes/install-llvm-action@v1 + with: + version: "10.0" + directory: ${{ runner.temp }}/llvm + - name: Set LIBCLANG_PATH + run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV + - name: install proj lib + env: + VCPKG_DEFAULT_TRIPLET: "${{ matrix.config.VCPKG_DEFAULT_TRIPLET }}" + shell: bash + run: | + set -ex + echo VCPKG_ROOT=${VCPKG_ROOT} + ${VCPKG_ROOT}/vcpkg install proj + - name: Run integration tests + env: + VCPKG_DEFAULT_TRIPLET: "${{ matrix.config.VCPKG_DEFAULT_TRIPLET }}" + RUSTFLAGS: ${{ matrix.config.RUSTFLAGS }} + shell: bash + run: | + set -ex + rustup target add ${{ matrix.config.target }} + rustc --version + cargo --version + echo dyn=${{ matrix.config.VCPKGRS_DYNAMIC }} + if [ '${{ matrix.config.VCPKGRS_DYNAMIC }}' != '' ] ; then export VCPKGRS_DYNAMIC=1 ; fi + cargo build --target ${{ matrix.config.target }} ${{ matrix.config.features }} + cargo test --target ${{ matrix.config.target }} ${{ matrix.config.features }} diff --git a/proj-sys/Cargo.toml b/proj-sys/Cargo.toml index d23da520..8b01ec7a 100644 --- a/proj-sys/Cargo.toml +++ b/proj-sys/Cargo.toml @@ -19,6 +19,10 @@ cmake = "0.1" flate2 = "1.0.14" tar = "0.4.26" +[target.'cfg(target_env = "msvc")'.build-dependencies] +vcpkg = "0.2.11" +winapi-build = "0.1.1" + [features] nobuild = [] bundled_proj = [] diff --git a/proj-sys/build.rs b/proj-sys/build.rs index 4a18e321..de49c2b1 100644 --- a/proj-sys/build.rs +++ b/proj-sys/build.rs @@ -3,6 +3,10 @@ use cmake; use flate2::read::GzDecoder; use std::fs::File; +#[cfg(target_env = "msvc")] +use vcpkg; +#[cfg(target_env = "msvc")] +use build; use pkg_config; use std::env; use std::path::PathBuf; @@ -10,6 +14,56 @@ use tar::Archive; const MINIMUM_PROJ_VERSION: &str = "7.2.1"; +#[cfg(target_env = "msvc")] +fn try_vcpkg() -> Result> { + build::link("shell32", true); + build::link("ole32", true); + let lib = vcpkg::Config::new() + .emit_includes(true) + .find_package("proj"); + + if let Err(_e) = lib { + eprintln!("vcpkg proj library not found, trying pkg_config"); + return try_pkg_config() + } + + let include_path = lib.unwrap() + .include_paths[0] + .clone(); + + Ok(include_path) +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg() -> Result> { + try_pkg_config() +} + +fn try_pkg_config() -> Result> { + pkg_config::Config::new() + .atleast_version(MINIMUM_PROJ_VERSION) + .probe("proj") + .and_then(|pk| { + eprintln!("found acceptable libproj already installed at: {:?}", pk.link_paths[0]); + if let Ok(val) = &env::var("_PROJ_SYS_TEST_EXPECT_BUILD_FROM_SRC") { + if val != "0" { + panic!("for testing purposes: existing package was found, but should not have been"); + } + } + + // Tell cargo to tell rustc to link the system proj + // shared library. + println!("cargo:rustc-link-search=native={:?}", pk.link_paths[0]); + println!("cargo:rustc-link-lib=proj"); + + Ok(pk.include_paths[0].clone()) + }) + .or_else(|err| { + eprintln!("pkg-config unable to find existing libproj installation: {}", err); + build_from_source() + }) +} + #[cfg(feature = "nobuild")] fn main() {} // Skip the build script on docs.rs @@ -19,28 +73,7 @@ fn main() -> Result<(), Box> { eprintln!("feature flags specified source build"); build_from_source()? } else { - pkg_config::Config::new() - .atleast_version(MINIMUM_PROJ_VERSION) - .probe("proj") - .and_then(|pk| { - eprintln!("found acceptable libproj already installed at: {:?}", pk.link_paths[0]); - if let Ok(val) = &env::var("_PROJ_SYS_TEST_EXPECT_BUILD_FROM_SRC") { - if val != "0" { - panic!("for testing purposes: existing package was found, but should not have been"); - } - } - - // Tell cargo to tell rustc to link the system proj - // shared library. - println!("cargo:rustc-link-search=native={:?}", pk.link_paths[0]); - println!("cargo:rustc-link-lib=proj"); - - Ok(pk.include_paths[0].clone()) - }) - .or_else(|err| { - eprintln!("pkg-config unable to find existing libproj installation: {}", err); - build_from_source() - })? + try_vcpkg()? }; // The bindgen::Builder is the main entry point diff --git a/src/proj.rs b/src/proj.rs index 14095111..a63dd408 100644 --- a/src/proj.rs +++ b/src/proj.rs @@ -1036,8 +1036,8 @@ mod test { let t = proj .convert(MyPoint::new(4760096.421921, 3744293.729449)) .unwrap(); - assert_relative_eq!(t.x(), 1450880.2910605003); - assert_relative_eq!(t.y(), 1141263.0111604529); + assert_relative_eq!(t.x(), 1450880.2910605003, epsilon = 1e-8); + assert_relative_eq!(t.y(), 1141263.0111604529, epsilon = 1e-8); } #[test] // Carry out a projection from geodetic coordinates @@ -1066,8 +1066,8 @@ mod test { let t = stereo70 .project(MyPoint::new(500119.70352012233, 500027.77896348457), true) .unwrap(); - assert_relative_eq!(t.x(), 0.43633200013698786); - assert_relative_eq!(t.y(), 0.8028510000110507); + assert_relative_eq!(t.x(), 0.43633200013698786, epsilon = 1e-14); + assert_relative_eq!(t.y(), 0.8028510000110507, epsilon = 1e-14); } #[test] // Carry out an inverse projection to geodetic coordinates @@ -1159,8 +1159,8 @@ mod test { MyPoint::new(4760197.421921, 3744394.729449), ]; ft_to_m.convert_array(&mut v).unwrap(); - assert_relative_eq!(v[0].x(), 1450880.2910605003f64); - assert_relative_eq!(v[1].y(), 1141293.7960220198); + assert_relative_eq!(v[0].x(), 1450880.2910605003f64, epsilon = 1e-8); + assert_relative_eq!(v[1].y(), 1141293.7960220198, epsilon = 1e-8); } #[test] @@ -1173,8 +1173,8 @@ mod test { // 👽 let usa_m = MyPoint::new(-115.797615, 37.2647978); let usa_ft = to_feet.convert(usa_m).unwrap(); - assert_eq!(6693625.67217475, usa_ft.x()); - assert_eq!(3497301.5918027186, usa_ft.y()); + assert_relative_eq!(6693625.67217475, usa_ft.x(),epsilon = 1e-8); + assert_relative_eq!(3497301.5918027186, usa_ft.y(), epsilon = 1e-8); } #[test]