Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CI: Add wheels for musllinux (closes #1382) #1461

Merged
merged 1 commit into from
Dec 4, 2024
Merged

Conversation

necabo
Copy link
Contributor

@necabo necabo commented Dec 3, 2024

I wasn't sure if I could safely run github CI on my fork, so there might be some issues that I missed.
I did test these changes locally though using a local installation of cibuildwheel and this script:

#!/usr/bin/env bash

export CIBW_SKIP="pp*-win* pp31*"
export CIBW_ARCHS="x86_64"
export CIBW_ENVIRONMENT_LINUX="PROJ_WHEEL=true PROJ_NETWORK=ON PROJ_VERSION=9.5.0 PROJ_DIR=/project/pyproj/proj_dir"
export CIBW_BEFORE_ALL_LINUX="bash ./ci/proj-compile-wheels.sh"
export CIBW_TEST_REQUIRES="cython pytest numpy --config-settings=setup-args=\"-Dallow-noblas=true\""
export CIBW_BEFORE_TEST="python -m pip install shapely pandas xarray || echo \"Optional requirements install failed \""
export CIBW_TEST_COMMAND="pyproj -v && python -c \"import pyproj; pyproj.Proj(init='epsg:4269')\" && cp -r {package}/test . && python -m pytest test -v -s"

cibuildwheel

The commit message contains some more information on the changes. Let me know if you have questions or if something is missing.

Remove *musllinux* from CIBW_SKIP to instruct cibuildwheel to build
wheels for musllinux and adjust proj-compile-wheels.sh script
accordingly.
cibuildwheel always uses the same image (musllinux_1_2, docs:
https://cibuildwheel.pypa.io/en/stable/options/#linux-image) for these
builds which is alpine-based. Thus, at least for now, it should be
enough to just detect running alpine and add alpine-specific commands to
the script where needed.
Copy link

codecov bot commented Dec 3, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.50%. Comparing base (6a38287) to head (b4ad743).
Report is 5 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1461   +/-   ##
=======================================
  Coverage   96.50%   96.50%           
=======================================
  Files          20       20           
  Lines        1830     1830           
=======================================
  Hits         1766     1766           
  Misses         64       64           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@necabo
Copy link
Contributor Author

necabo commented Dec 3, 2024

Apparently I missed an error from pip install shapely when testing locally. I just happened to see it in the logs:

collapse/expand logs
  Building wheels for collected packages: shapely
    Building wheel for shapely (pyproject.toml): started
    Building wheel for shapely (pyproject.toml): finished with status 'error'
    error: subprocess-exited-with-error
    
    × Building wheel for shapely (pyproject.toml) did not run successfully.
    │ exit code: 1
    ╰─> [149 lines of output]
        Could not find geos-config executable. Either append the path to geos-config to PATH or manually provide the include_dirs, library_dirs, libraries and other link args for compiling against a GEOS version >=3.5.
        running bdist_wheel
        running build
        running build_py
        creating build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/affinity.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/_ragged_array.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/errors.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/_enum.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/_geometry.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/geos.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/wkb.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/validation.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/prepared.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/set_operations.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/io.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/__init__.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/coordinates.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/strtree.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/wkt.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/plotting.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/_version.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/linear.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/creation.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/predicates.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/coords.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/measurement.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/speedups.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/testing.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/constructive.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/ops.py -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/decorators.py -> build/lib.linux-x86_64-cpython-310/shapely
        creating build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_testing.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_io.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_constructive.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_predicates.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_linear.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_set_operations.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_coordinates.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_strtree.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/common.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/__init__.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_plotting.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_ragged_array.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_measurement.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_creation.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_geometry.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_misc.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        copying shapely/tests/test_creation_indices.py -> build/lib.linux-x86_64-cpython-310/shapely/tests
        creating build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/multipoint.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/multipolygon.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/linestring.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/geo.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/polygon.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/point.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/conftest.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/__init__.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/multilinestring.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/base.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        copying shapely/geometry/collection.py -> build/lib.linux-x86_64-cpython-310/shapely/geometry
        creating build/lib.linux-x86_64-cpython-310/shapely/algorithms
        copying shapely/algorithms/polylabel.py -> build/lib.linux-x86_64-cpython-310/shapely/algorithms
        copying shapely/algorithms/__init__.py -> build/lib.linux-x86_64-cpython-310/shapely/algorithms
        copying shapely/algorithms/_oriented_envelope.py -> build/lib.linux-x86_64-cpython-310/shapely/algorithms
        copying shapely/algorithms/cga.py -> build/lib.linux-x86_64-cpython-310/shapely/algorithms
        creating build/lib.linux-x86_64-cpython-310/shapely/vectorized
        copying shapely/vectorized/__init__.py -> build/lib.linux-x86_64-cpython-310/shapely/vectorized
        creating build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_locale.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_vectorized.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_wkt.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_singularity.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_predicates.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_transform.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_pickle.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_shared_paths.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_invalid_geometries.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_wkb.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_substring.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/conftest.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/__init__.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_svg.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_polygonize.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_split.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_ndarrays.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_nearest.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_linear_referencing.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_minimum_clearance.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_union.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_orient.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_operators.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_cga.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_create_inconsistent_dimensionality.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_voronoi_diagram.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_box.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_buffer.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_linemerge.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_products_z.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_clip_by_rect.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_snap.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_delaunay.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_polylabel.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/threading_test.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_make_valid.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_shape.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_persist.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_affinity.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_operations.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_validation.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_parallel_offset.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_mapping.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_prepared.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_geointerface.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_empty_polygons.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        copying shapely/tests/legacy/test_equality.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/legacy
        creating build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_hash.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_collection.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_multipoint.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_geometry_base.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_multipolygon.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_point.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/__init__.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_multilinestring.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_polygon.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_multi.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_decimal.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_format.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_linestring.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_coords.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_emptiness.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/tests/geometry/test_equality.py -> build/lib.linux-x86_64-cpython-310/shapely/tests/geometry
        copying shapely/_pygeos_api.pxd -> build/lib.linux-x86_64-cpython-310/shapely
        copying shapely/_geos.pxd -> build/lib.linux-x86_64-cpython-310/shapely
        UPDATING build/lib.linux-x86_64-cpython-310/shapely/_version.py
        set build/lib.linux-x86_64-cpython-310/shapely/_version.py to '2.0.6'
        running build_ext
        building 'shapely.lib' extension
        creating build/temp.linux-x86_64-cpython-310/src
        gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tmp/pip-build-env-rnmmis8r/overlay/lib/python3.10/site-packages/numpy/_core/include -I/tmp/tmp.BMnlOF/venv/include -I/opt/_internal/cpython-3.10.15/include/python3.10 -c src/c_api.c -o build/temp.linux-x86_64-cpython-310/src/c_api.o
        In file included from src/c_api.h:22,
                         from src/c_api.c:15:
        src/geos.h:15:10: fatal error: geos_c.h: No such file or directory
           15 | #include <geos_c.h>
              |          ^~~~~~~~~~
        compilation terminated.
        error: command '/usr/bin/gcc' failed with exit code 1
        [end of output]
    
    note: This error originates from a subprocess, and is likely not a problem with pip.
    ERROR: Failed building wheel for shapely
  Failed to build shapely
  ERROR: ERROR: Failed to build installable wheels for some pyproject.toml based projects (shapely)
  Optional requirements install failed

I assume the tests pass regardless because of this line.

From my understanding the produced wheel will still work but I'll take a closer look tomorrow to see if I can get shapely to build successfully or ideally install from wheel (how ironic).

@necabo
Copy link
Contributor Author

necabo commented Dec 4, 2024

As evident from above logs, pip install shapely fails when building its wheel because it's missing header files for geos.
Here are two possible solutions:

  1. Ensure the header files are present and shapely installs correctly. I'm not sure if there is a cleaner approach but this patch should work:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 0bea4c1..cdc6f0d 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -153,7 +153,9 @@ jobs:
           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"
-          CIBW_BEFORE_TEST: python -m pip install shapely pandas xarray || echo "Optional requirements install failed"
+          CIBW_BEFORE_TEST: >
+            test -f /etc/alpine-release && apk add geos-dev
+            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')"  &&

I successfully tested this locally using a modified version of the script I posted initially:

#!/usr/bin/env bash

export CIBW_SKIP="pp*-win* pp31*"
export CIBW_ARCHS="x86_64"
export CIBW_ENVIRONMENT_LINUX="PROJ_WHEEL=true PROJ_NETWORK=ON PROJ_VERSION=9.5.0 PROJ_DIR=/project/pyproj/proj_dir"
export CIBW_BEFORE_ALL_LINUX="bash ./ci/proj-compile-wheels.sh"
export CIBW_TEST_REQUIRES="cython pytest numpy --config-settings=setup-args=\"-Dallow-noblas=true\""
export CIBW_BEFORE_TEST="test -f /etc/alpine-release && apk add geos-dev; python -m pip install shapely pandas xarray || echo \"Optional requirements install failed \""
export CIBW_TEST_COMMAND="pyproj -v && python -c \"import pyproj; pyproj.Proj(init='epsg:4269')\" && cp -r {package}/test . && python -m pytest test -v -s"

cibuildwheel
  1. Ignore the error. From my understanding the wheel builds correctly, it just skips some of the tests that require shapely to be installed. The error is also very likely to be temporary since shapely already merged a PR to add musllinux wheels. Their plan appears to be to include the wheels starting from shapely 2.1.

Let me know which approach you prefer or if you have other ideas on how to solve this.

@snowman2
Copy link
Member

snowman2 commented Dec 4, 2024

Thanks @necabo 👍. Since wheels for shapely are coming soon and the tests pass, I think we're okay to proceed without installing geos.

@snowman2 snowman2 added installation-issues Issue related to installation problems. cicd CICD Related labels Dec 4, 2024
@snowman2 snowman2 added this to the 3.7.1 milestone Dec 4, 2024
@snowman2 snowman2 merged commit 42aa92f into pyproj4:main Dec 4, 2024
23 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cicd CICD Related installation-issues Issue related to installation problems.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants