diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a61fa32dc..90ce84e97 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -137,44 +137,39 @@ jobs: mkdir -p ${GITHUB_WORKSPACE}/pyproj/proj_dir/share/proj cp "$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }}/share/proj/"* ${GITHUB_WORKSPACE}/pyproj/proj_dir/share/proj/ + # Part of cibuildwheel's settings are set dynamically so they cannot + # be moved to pyproject.toml + # avoid duplication between jobs by setting environment variables + # via GITHUB_ENV so they persist between steps + + - name: Setup cibuildwheel environment (all platforms) + run: | + echo "PROJ_WHEEL='true'" >> "$GITHUB_ENV" + echo "PROJ_NETWORK=ON" >> "$GITHUB_ENV" + echo "PROJ_VERSION=${{ env.PROJ_VERSION }}" >> "$GITHUB_ENV" + echo "CIBW_ARCHS=${{ matrix.arch }}" >> "$GITHUB_ENV" + + - name: Setup additional environment (linux) + if: ${{ startswith( matrix.os , 'ubuntu' ) }} + run: | + echo "PROJ_DIR=/project/pyproj/proj_dir" >> "$GITHUB_ENV" + + - name: Setup additional environment (macos) + if: ${{ startswith( matrix.os , 'macos' ) }} + run: | + echo "PROJ_DIR=${GITHUB_WORKSPACE}/pyproj/proj_dir" >> "$GITHUB_ENV" + echo 'CIBW_ENVIRONMENT=CMAKE_OSX_ARCHITECTURES='${{ matrix.cmake_osx_architectures }}' MACOSX_DEPLOYMENT_TARGET=${{ matrix.macos_deployment_target }} LDFLAGS="${LDFLAGS} -Wl,-rpath,${GITHUB_WORKSPACE}/pyproj/proj_dir/lib"' >> "$GITHUB_ENV" + + - name: Setup additional environment (windows) + if: ${{ startswith( matrix.os , 'windows' ) }} + # repair-wheel: add Windows System32 explicitly to the path + # see https://github.com/adang1345/delvewheel/issues/54 + run: | + echo 'PROJ_DIR=$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }}' >> "$GITHUB_ENV" + echo 'CIBW_REPAIR_WHEEL_COMMAND="delvewheel repair --add-path C:/Windows/System32 --add-path C:/vcpkg/installed/${{ matrix.triplet }}/bin -w {dest_dir} {wheel}"' >> "$GITHUB_ENV" + - name: Build wheels uses: pypa/cibuildwheel@v4.3.1 - env: - CIBW_ARCHS: ${{ matrix.arch }} - CIBW_ENVIRONMENT_LINUX: - PROJ_WHEEL=true - PROJ_NETWORK=ON - PROJ_VERSION=${{ env.PROJ_VERSION }} - PROJ_DIR=/project/pyproj/proj_dir - CIBW_ENVIRONMENT_MACOS: - PROJ_WHEEL=true - PROJ_NETWORK=ON - PROJ_VERSION=${{ env.PROJ_VERSION }} - PROJ_DIR=${GITHUB_WORKSPACE}/pyproj/proj_dir - CMAKE_OSX_ARCHITECTURES='${{ matrix.cmake_osx_architectures }}' - MACOSX_DEPLOYMENT_TARGET=${{ matrix.macos_deployment_target }} - LDFLAGS="${LDFLAGS} -Wl,-rpath,${GITHUB_WORKSPACE}/pyproj/proj_dir/lib" - CIBW_ENVIRONMENT_WINDOWS: - PROJ_WHEEL=true - PROJ_NETWORK=ON - PROJ_VERSION=${{ env.PROJ_VERSION }} - PROJ_DIR=$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }} - # Rename Git's link.exe to avoid conflict with MSVC link.exe (meson issue) - CIBW_BEFORE_BUILD_WINDOWS: > - python -m pip install delvewheel && - if exist "C:\Program Files\Git\usr\bin\link.exe" (rename "C:\Program Files\Git\usr\bin\link.exe" "link.exe.bak") - # Add Windows System32 explicitly to the path https://github.com/adang1345/delvewheel/issues/54 - CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path C:/Windows/System32 --add-path C:/vcpkg/installed/${{ matrix.triplet }}/bin -w {dest_dir} {wheel}" - CIBW_BEFORE_ALL_LINUX: bash ./ci/proj-compile-wheels.sh - CIBW_BEFORE_ALL_MACOS: bash ./ci/proj-compile-wheels.sh - CIBW_TEST_REQUIRES: cython pytest numpy --config-settings=setup-args="-Dallow-noblas=true" - # Install numpy first so Shapely can find numpy headers during build - CIBW_BEFORE_TEST: python -m pip install numpy && python -m pip install shapely pandas xarray || echo "Optional requirements install failed" - CIBW_TEST_COMMAND: > - pyproj -v && - python -c "import pyproj; pyproj.Proj(init='epsg:4269')" && - cp -r {package}/test . && - python -m pytest test -v -s - name: Upload artifacts uses: actions/upload-artifact@v7 diff --git a/pyproject.toml b/pyproject.toml index f003d114a..fae5f557d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,6 +104,34 @@ include = ["pyproj", "pyproj.*"] [tool.setuptools.dynamic] version = {attr = "pyproj.__version__"} +[tool.cibuildwheel] +test-groups = ["test"] +test-sources = ["test"] +test-command = [ + "pyproj -v", + '''python -c "import pyproj; pyproj.Proj(init='epsg:4269')"''', + "python -m pytest test -v -s", +] +environment-pass = [ + "PROJ_DIR", + "PROJ_NETWORK", + "PROJ_VERSION", + "PROJ_WHEEL", +] + +[tool.cibuildwheel.config-settings] +setup-args = "-Dallow-noblas=true" + +[tool.cibuildwheel.linux] +before-all = "bash ./ci/proj-compile-wheels.sh" + +[tool.cibuildwheel.macos] +before-all = "bash ./ci/proj-compile-wheels.sh" + +[tool.cibuildwheel.windows] +# Rename Git's link.exe to avoid conflict with MSVC link.exe (meson issue) +before-build = 'if exist "C:\Program Files\Git\usr\bin\link.exe" (rename "C:\Program Files\Git\usr\bin\link.exe" "link.exe.bak")' + [tool.ruff] line-length = 88 fix = true diff --git a/setup.py b/setup.py index 54d682065..a178b41d8 100644 --- a/setup.py +++ b/setup.py @@ -4,6 +4,7 @@ import shutil import subprocess import sys +from functools import partial from pathlib import Path from setuptools import Extension, setup @@ -69,27 +70,28 @@ def get_proj_dir() -> Path: This function finds the base PROJ directory. """ proj_dir_environ = os.environ.get("PROJ_DIR") - proj_dir: Path | None = None + log = partial(print, file=sys.stderr) if proj_dir_environ is not None: proj_dir = Path(proj_dir_environ) - if proj_dir is None and INTERNAL_PROJ_DIR.exists(): + log("Using proj specified by environment variable PROJ_DIR", end=" ") + elif INTERNAL_PROJ_DIR.exists(): proj_dir = INTERNAL_PROJ_DIR - print(f"Internally compiled directory being used {INTERNAL_PROJ_DIR}.") - elif proj_dir is None and not INTERNAL_PROJ_DIR.exists(): - proj = shutil.which("proj", path=sys.prefix) - if proj is None: - proj = shutil.which("proj") + log("Using proj from internal compiled directory", end=" ") + else: + proj = shutil.which("proj", path=sys.prefix) or shutil.which("proj") if proj is None: raise SystemExit( "proj executable not found. Please set the PROJ_DIR variable. " "For more information see: " "https://pyproj4.github.io/pyproj/stable/installation.html" ) - proj_dir = Path(proj).parent.parent - elif proj_dir is not None and proj_dir.exists(): - print("PROJ_DIR is set, using existing PROJ installation..\n") - else: - raise SystemExit(f"ERROR: Invalid path for PROJ_DIR {proj_dir}") + proj_dir = Path(proj).parents[1] + log("Using proj auto-discovered executable", end=" ") + log(proj_dir) + if not proj_dir.exists(): + raise SystemExit(f"ERROR: not such file or directory {proj_dir}") + if not proj_dir.is_dir(): + raise SystemExit(f"ERROR: {proj_dir} exists but is not a directory") return proj_dir