├── src
└── cmake
│ ├── py.typed
│ ├── _version.pyi
│ ├── __main__.py
│ └── __init__.py
├── docs
├── authors.rst
├── history.rst
├── contributing.rst
├── usage.rst
├── installation.rst
├── make_a_release.rst
├── index.rst
├── update_cmake_version.rst
├── building.rst
├── build_system.rst
└── conf.py
├── .gitattributes
├── .github
├── release.yml
├── dependabot.yml
└── workflows
│ ├── update-dependencies.yml
│ └── build.yml
├── .coveragerc
├── AUTHORS.rst
├── .git_archival.txt
├── tests
├── __init__.py
└── test_cmake.py
├── HISTORY.rst
├── .readthedocs.yaml
├── scripts
├── utils.sh
├── manylinux-build-and-install-openssl.sh
├── install-static-clang.sh
├── update_openssl_version.py
└── update_cmake_version.py
├── .pre-commit-config.yaml
├── .gitignore
├── LICENSE_BSD_3
├── CMakeUrls.cmake
├── CONTRIBUTING.rst
├── README.rst
├── _build_backend
└── backend.py
├── noxfile.py
├── pyproject.toml
├── LICENSE_Apache_20
└── CMakeLists.txt
/src/cmake/py.typed:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/cmake/_version.pyi:
--------------------------------------------------------------------------------
1 | version: str
2 |
--------------------------------------------------------------------------------
/docs/authors.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../AUTHORS.rst
2 |
--------------------------------------------------------------------------------
/docs/history.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../HISTORY.rst
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | .git_archival.txt export-subst
2 |
--------------------------------------------------------------------------------
/docs/contributing.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../CONTRIBUTING.rst
2 |
--------------------------------------------------------------------------------
/src/cmake/__main__.py:
--------------------------------------------------------------------------------
1 | from cmake import cmake
2 |
3 | if __name__ == "__main__":
4 | cmake()
5 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | exclude:
3 | authors:
4 | - dependabot[bot]
5 | - pre-commit-ci[bot]
6 |
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | branch = True
3 | include = cmake/*.py
4 | omit = cmake/_version.py
5 |
6 | [xml]
7 | output = tests/coverage.xml
8 |
--------------------------------------------------------------------------------
/AUTHORS.rst:
--------------------------------------------------------------------------------
1 | =======
2 | Credits
3 | =======
4 |
5 | Please see the GitHub project page at https://github.com/scikit-build/cmake-python-distributions/graphs/contributors
6 |
--------------------------------------------------------------------------------
/.git_archival.txt:
--------------------------------------------------------------------------------
1 | node: 535af4c8b8d2711ceabff507875fa27953a8a9e6
2 | node-date: 2025-12-21T08:24:31+01:00
3 | describe-name: 4.2.1
4 | ref-names: HEAD -> main, tag: 4.2.1
5 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from contextlib import contextmanager
3 |
4 |
5 | @contextmanager
6 | def push_argv(argv):
7 | old_argv = sys.argv
8 | sys.argv = argv
9 | yield
10 | sys.argv = old_argv
11 |
--------------------------------------------------------------------------------
/docs/usage.rst:
--------------------------------------------------------------------------------
1 | =====
2 | Usage
3 | =====
4 |
5 | After :doc:`installing ` the package using `pip`, the executables
6 | ``cmake``, ``cpack`` and ``ctest`` will be available in the ``PATH`` and can be
7 | used to configure and build any projects.
8 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | ============
2 | Installation
3 | ============
4 |
5 | Install package with pip
6 | ------------------------
7 |
8 | To install with pip::
9 |
10 | $ pip install cmake
11 |
12 | Install from source
13 | -------------------
14 |
15 | See :doc:`building`
16 |
--------------------------------------------------------------------------------
/HISTORY.rst:
--------------------------------------------------------------------------------
1 | .. :changelog:
2 |
3 | History
4 | -------
5 |
6 | cmake-python-distributions was initially developed in September 2016 by
7 | Jean-Christophe Fillion-Robin to facilitate the distribution of project using
8 | `scikit-build `_ and depending on CMake.
9 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # Read the Docs configuration file
2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3 |
4 | version: 2
5 |
6 | build:
7 | os: ubuntu-22.04
8 | tools:
9 | python: "3.12"
10 | commands:
11 | - asdf plugin add uv
12 | - asdf install uv latest
13 | - asdf global uv latest
14 | - uv run --only-group docs sphinx-build -T -b html -d docs/_build/doctrees -D language=en docs $READTHEDOCS_OUTPUT/html
15 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Maintain dependencies for GitHub Actions
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: "weekly"
8 | groups:
9 | actions:
10 | patterns:
11 | - "*"
12 | # Maintain dependencies for pip constraints-ci.txt
13 | - package-ecosystem: "pip"
14 | directory: "/"
15 | schedule:
16 | interval: "daily"
17 | allow:
18 | - dependency-name: "cmake"
19 | - dependency-name: "ninja"
20 |
--------------------------------------------------------------------------------
/scripts/utils.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | # Copied from https://github.com/pypa/manylinux/blob/main/docker/build_scripts/build_utils.sh
6 | function check_var {
7 | if [ -z "$1" ]; then
8 | echo "required variable not defined"
9 | exit 1
10 | fi
11 | }
12 |
13 | # Copied from https://github.com/pypa/manylinux/blob/main/docker/build_scripts/build_utils.sh
14 | function check_sha256sum {
15 | local fname=$1
16 | check_var ${fname}
17 | local sha256=$2
18 | check_var ${sha256}
19 |
20 | echo "${sha256} ${fname}" > ${fname}.sha256
21 | sha256sum -c ${fname}.sha256
22 | rm -f ${fname}.sha256
23 | }
24 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | ci:
2 | autoupdate_commit_msg: "chore(deps): update pre-commit hooks"
3 | autofix_commit_msg: "style: pre-commit fixes"
4 | autoupdate_schedule: "monthly"
5 |
6 | repos:
7 | - repo: https://github.com/pre-commit/pre-commit-hooks
8 | rev: v6.0.0
9 | hooks:
10 | - id: check-added-large-files
11 | - id: check-case-conflict
12 | - id: check-merge-conflict
13 | - id: check-symlinks
14 | - id: check-yaml
15 | - id: debug-statements
16 | - id: end-of-file-fixer
17 | - id: mixed-line-ending
18 | - id: trailing-whitespace
19 |
20 | - repo: https://github.com/astral-sh/ruff-pre-commit
21 | rev: "v0.14.7"
22 | hooks:
23 | - id: ruff
24 | args: [--fix, --show-fixes]
25 |
26 | - repo: https://github.com/pre-commit/mirrors-mypy
27 | rev: "v1.19.0"
28 | hooks:
29 | - id: mypy
30 | files: ^(src|scripts)
31 | additional_dependencies: [types-requests]
32 | args: []
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # This project
2 | archive-cache
3 | src/cmake/data/*
4 | env.json
5 | skbuild
6 | CMake-src
7 | standalone-build
8 | standalone-x86-build
9 | standalone-x64-build
10 |
11 | # Python
12 | *.py[cod]
13 |
14 | # C extensions
15 | *.so
16 |
17 | # Packages
18 | *.egg
19 | *.eggs
20 | *.egg-info
21 | dist
22 | build
23 | _skbuild
24 | eggs
25 | parts
26 | bin
27 | var
28 | sdist
29 | develop-eggs
30 | .installed.cfg
31 | lib
32 | lib64
33 | wheelhouse
34 |
35 | # Installer logs
36 | pip-log.txt
37 |
38 | # Unit test / coverage reports
39 | .cache
40 | .coverage
41 | .pytest_cache
42 | .tox
43 | coverage.xml
44 | htmlcov
45 |
46 | # Translations
47 | *.mo
48 |
49 | # Mr Developer
50 | .mr.developer.cfg
51 | .project
52 | .pydevproject
53 |
54 | # Complexity
55 | output/*.html
56 | output/*/index.html
57 |
58 | # Sphinx
59 | docs/_build
60 |
61 | # IDE junk
62 | .idea/*
63 | *.swp
64 |
65 | # Output from cibuildwheel
66 | wheelhouse/
67 |
68 | # Version
69 | _version.py
70 |
71 | CMakeCache.txt
72 | CMakeFiles
73 |
--------------------------------------------------------------------------------
/LICENSE_BSD_3:
--------------------------------------------------------------------------------
1 | CMake is distributed under the OSI-approved BSD 3-clause License:
2 |
3 | CMake - Cross Platform Makefile Generator
4 | Copyright 2000-2014 Kitware, Inc.
5 | Copyright 2000-2011 Insight Software Consortium
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions
10 | are met:
11 |
12 | * Redistributions of source code must retain the above copyright
13 | notice, this list of conditions and the following disclaimer.
14 |
15 | * Redistributions in binary form must reproduce the above copyright
16 | notice, this list of conditions and the following disclaimer in the
17 | documentation and/or other materials provided with the distribution.
18 |
19 | * Neither the names of Kitware, Inc., the Insight Software Consortium,
20 | nor the names of their contributors may be used to endorse or promote
21 | products derived from this software without specific prior written
22 | permission.
23 |
24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 |
--------------------------------------------------------------------------------
/CMakeUrls.cmake:
--------------------------------------------------------------------------------
1 |
2 | #-----------------------------------------------------------------------------
3 | # CMake sources
4 | set(unix_source_url "https://github.com/Kitware/CMake/releases/download/v4.2.1/cmake-4.2.1.tar.gz")
5 | set(unix_source_sha256 "414aacfac54ba0e78e64a018720b64ed6bfca14b587047b8b3489f407a14a070")
6 |
7 | set(windows_source_url "https://github.com/Kitware/CMake/releases/download/v4.2.1/cmake-4.2.1.zip")
8 | set(windows_source_sha256 "e63276266293d820eca862b6596cbca7657458ef61eebefaf920eaccc33666f8")
9 |
10 | #-----------------------------------------------------------------------------
11 | # CMake binaries
12 |
13 | set(linux32_binary_url "NA") # Linux 32-bit binaries not available
14 | set(linux32_binary_sha256 "NA")
15 |
16 | set(linux64_binary_url "https://github.com/Kitware/CMake/releases/download/v4.2.1/cmake-4.2.1-linux-x86_64.tar.gz")
17 | set(linux64_binary_sha256 "c059bff1e97a2b6b5b0c0872263627486345ad0ed083298cb21cff2eda883980")
18 |
19 | set(macos10_10_binary_url "https://github.com/Kitware/CMake/releases/download/v4.2.1/cmake-4.2.1-macos10.10-universal.tar.gz")
20 | set(macos10_10_binary_sha256 "3c57c20465cd22487dbe689e2821651479a404c55a4118ac8fdb46f22dac1c48")
21 |
22 | set(win32_binary_url "https://github.com/Kitware/CMake/releases/download/v4.2.1/cmake-4.2.1-windows-i386.zip")
23 | set(win32_binary_sha256 "696129556482da90293f9d64c1fa68dbe06b0ede80331d7da9aaa03aada6aecf")
24 |
25 | set(win64_binary_url "https://github.com/Kitware/CMake/releases/download/v4.2.1/cmake-4.2.1-windows-x86_64.zip")
26 | set(win64_binary_sha256 "dfc2b2afac257555e3b9ce375b12b2883964283a366c17fec96cf4d17e4f1677")
27 |
28 | set(winarm64_binary_url "https://github.com/Kitware/CMake/releases/download/v4.2.1/cmake-4.2.1-windows-arm64.zip")
29 | set(winarm64_binary_sha256 "96b097ca3a019cd62839d4805958ad0163dd1adedcfbe578730d57c098aaf667")
30 |
--------------------------------------------------------------------------------
/docs/make_a_release.rst:
--------------------------------------------------------------------------------
1 | .. _making_a_release:
2 |
3 | ================
4 | Making a release
5 | ================
6 |
7 | A core developer should use the following steps to create a release `X.Y.Z` of
8 | **cmake-python-distributions** on `PyPI`_.
9 |
10 | This is usually done after :ref:`updating_cmake_version`.
11 |
12 | -------------
13 | Prerequisites
14 | -------------
15 |
16 | * All CI tests are passing on `GitHub Actions`_.
17 |
18 | * You have a `GPG signing key `_.
19 |
20 |
21 | ---------------------
22 | `PyPI`_: Step-by-step
23 | ---------------------
24 |
25 | 1. Make sure that all CI tests are passing on `GitHub Actions`_.
26 |
27 |
28 | 2. Download the latest sources if you don't already have them
29 |
30 | .. code:: console
31 |
32 | $ git clone git@github.com:scikit-build/cmake-python-distributions
33 | $ cd cmake-python-distributions
34 |
35 |
36 | 3. Ask nox for the instructions on what to type
37 |
38 | .. code:: console
39 |
40 | $ nox -s tag_release
41 |
42 |
43 | 4. Run the suggested lines, probably something like this:
44 |
45 | .. code:: console
46 |
47 | $ git tag --sign -m 'cmake-python-distributions 4.2.1' 4.2.1 main
48 | $ git push origin 4.2.1
49 |
50 | .. warning::
51 |
52 | We recommend using a `GPG signing key `_
53 | to sign the tag.
54 |
55 |
56 | 5. Check the status of the builds on `GitHub Actions`_.
57 |
58 | 6. Once the builds are completed, check that the distributions are available on `PyPI`_.
59 |
60 | 7. Make a GitHub release based on the tag. This will display the latest version
61 | in the GitHub sidebar, and will notify release watchers of the release.
62 | Title it `Version X.Y.Z` and add a little note about what changed (Python only).
63 |
64 |
65 | .. _GitHub Actions: https://github.com/scikit-build/cmake-python-distributions/actions/workflows/build.yml
66 |
67 | .. _PyPI: https://pypi.org/project/cmake
68 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. CMake Python Distributions documentation main file, created by
2 | sphinx-quickstart on Wed Nov 9 02:28:46 2016.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to CMake Python Distributions's documentation!
7 | ======================================================
8 |
9 | `CMake `_ is used to control the software compilation
10 | process using simple platform and compiler independent configuration files,
11 | and generate native makefiles and workspaces that can be used in the
12 | compiler environment of your choice.
13 |
14 | The suite of CMake tools were created by Kitware in response to the need
15 | for a powerful, cross-platform build environment for open-source projects
16 | such as `ITK `_ and `VTK `_.
17 |
18 | The CMake python wheels provide `CMake 4.2.1 `_.
19 |
20 | .. toctree::
21 | :maxdepth: 2
22 | :caption: User guide
23 |
24 | installation
25 | usage
26 | building
27 | build_system
28 | contributing
29 | authors
30 | history
31 |
32 | .. toctree::
33 | :maxdepth: 2
34 | :caption: For maintainers
35 |
36 | update_cmake_version
37 | make_a_release
38 |
39 |
40 | Indices and tables
41 | ==================
42 |
43 | * :ref:`genindex`
44 | * :ref:`modindex`
45 | * :ref:`search`
46 |
47 |
48 | Resources
49 | =========
50 |
51 | This project is maintained by Jean-Christophe Fillion-Robin from Kitware Inc.
52 | It is covered by the `Apache License, Version 2.0 `_.
53 |
54 | CMake is distributed under the OSI-approved BSD 3-clause License.
55 | For more information about CMake, visit https://cmake.org
56 |
57 | * Documentation: https://cmake-python-distributions.readthedocs.io/en/latest/
58 | * Source code: https://github.com/scikit-build/cmake-python-distributions
59 | * Mailing list: https://groups.google.com/forum/#!forum/scikit-build
60 |
--------------------------------------------------------------------------------
/src/cmake/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import os
4 | import subprocess
5 | import sys
6 | from importlib.metadata import distribution
7 | from pathlib import Path
8 |
9 | from ._version import version as __version__
10 |
11 | TYPE_CHECKING = False
12 |
13 | if TYPE_CHECKING:
14 | from typing import Iterable, NoReturn
15 |
16 |
17 | __all__ = ["CMAKE_BIN_DIR", "CMAKE_DATA", "CMAKE_DOC_DIR", "CMAKE_SHARE_DIR", "__version__", "cmake", "cpack", "ctest"]
18 |
19 |
20 | def __dir__() -> list[str]:
21 | return __all__
22 |
23 |
24 | cmake_executable_path = None
25 | cmake_files = distribution("cmake").files
26 | assert cmake_files is not None, "This is the cmake package so it must be installed and have files"
27 | for script in cmake_files:
28 | if str(script).startswith("cmake/data/bin/cmake"):
29 | resolved_script = Path(script.locate()).resolve(strict=True)
30 | cmake_executable_path = resolved_script.parents[1]
31 | break
32 | CMAKE_DATA = str(cmake_executable_path) if cmake_executable_path else None
33 |
34 | assert CMAKE_DATA is not None
35 | assert os.path.exists(CMAKE_DATA)
36 |
37 | CMAKE_BIN_DIR = os.path.join(CMAKE_DATA, 'bin')
38 | CMAKE_DOC_DIR = os.path.join(CMAKE_DATA, 'doc')
39 | CMAKE_SHARE_DIR = os.path.join(CMAKE_DATA, 'share')
40 |
41 |
42 | def _program(name: str, args: Iterable[str]) -> int:
43 | return subprocess.call([os.path.join(CMAKE_BIN_DIR, name), *args], close_fds=False)
44 |
45 | def _program_exit(name: str, *args: str) -> NoReturn:
46 | if sys.platform.startswith("win"):
47 | raise SystemExit(_program(name, args))
48 | cmake_exe = os.path.join(CMAKE_BIN_DIR, name)
49 | os.execl(cmake_exe, cmake_exe, *args)
50 |
51 |
52 | def ccmake() -> NoReturn:
53 | _program_exit('ccmake', *sys.argv[1:])
54 |
55 |
56 | def cmake() -> NoReturn:
57 | _program_exit('cmake', *sys.argv[1:])
58 |
59 |
60 | def cpack() -> NoReturn:
61 | _program_exit('cpack', *sys.argv[1:])
62 |
63 |
64 | def ctest() -> NoReturn:
65 | _program_exit('ctest', *sys.argv[1:])
66 |
--------------------------------------------------------------------------------
/docs/update_cmake_version.rst:
--------------------------------------------------------------------------------
1 | .. _updating_cmake_version:
2 |
3 | ==========================
4 | Updating the CMake version
5 | ==========================
6 |
7 | A developer should use the following steps to update the version ``X.Y.Z``
8 | of CMake associated with the current CMake python distributions.
9 |
10 | Available CMake archives can be found at https://cmake.org/files.
11 |
12 | Nox procedure
13 | -------------
14 |
15 | If using nox, run::
16 |
17 | nox -s bump --
18 |
19 |
20 | And follow the instructions it gives you. Leave off the version to bump to the latest version. Add `--commit` to run the commit procedure.
21 |
22 | Classic procedure:
23 | ------------------
24 |
25 | 1. Install `requests`::
26 |
27 | $ pip install requests
28 |
29 | 2. Execute `scripts/update_cmake_version.py` command line tool with the desired
30 | ``X.Y.Z`` CMake version available for download. For example::
31 |
32 | $ release=4.2.1
33 | $ ./scripts/update_cmake_version.py $release
34 | Collecting URLs and SHA256s from 'https://api.github.com/repos/Kitware/CMake/releases/tags/v4.2.1'
35 | [...]
36 | Collecting URLs and SHA256s from 'https://api.github.com/repos/Kitware/CMake/releases/tags/v4.2.1' - done
37 | Updating 'CMakeUrls.cmake' with CMake version 4.2.1
38 | Updating 'CMakeUrls.cmake' with CMake version 4.2.1 - done
39 | Updating docs/index.rst
40 | Updating docs/index.rst - done
41 | Updating README.rst
42 | Updating README.rst - done
43 | Updating tests/test_cmake.py
44 | Updating tests/test_cmake.py - done
45 |
46 | 3. Create a topic named `update-to-cmake-X.Y.Z` and commit the changes.
47 | For example::
48 |
49 | release=4.2.1
50 | git switch -c update-to-cmake-$release
51 | git add -u CMakeUrls.cmake docs/index.rst README.rst tests/test_cmake.py docs/update_cmake_version.rst
52 | git commit -m "Update to CMake $release"
53 |
54 | 4. Push the topic and create a `Pull Request`.
55 |
56 | 5. If all CI tests are passing, merge the topic and consider :doc:`making a new
57 | release `.
58 |
--------------------------------------------------------------------------------
/scripts/manylinux-build-and-install-openssl.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #
4 | # Configure, build and install OpenSSL to support building of CMake using manylinux docker images
5 | #
6 |
7 | set -eux
8 | set -o pipefail
9 |
10 | MY_DIR=$(dirname "${BASH_SOURCE[0]}")
11 | source $MY_DIR/utils.sh
12 |
13 | OPENSSL_ROOT=openssl-3.5.4
14 | OPENSSL_HASH=967311f84955316969bdb1d8d4b983718ef42338639c621ec4c34fddef355e99
15 |
16 | cd /tmp
17 |
18 | if ! perl -e 'use 5.10.0' &> /dev/null; then
19 | # perl>=5.10.0 is needed to build openssl
20 | PERL_ROOT=perl-5.32.1
21 | # Hash from https://www.cpan.org/src/5.0/perl-5.32.1.tar.gz.sha256.txt
22 | PERL_HASH=03b693901cd8ae807231b1787798cf1f2e0b8a56218d07b7da44f784a7caeb2c
23 |
24 | curl -fsSLO https://www.cpan.org/src/5.0/${PERL_ROOT}.tar.gz
25 | check_sha256sum ${PERL_ROOT}.tar.gz ${PERL_HASH}
26 | tar -xzf ${PERL_ROOT}.tar.gz
27 | rm -rf ${PERL_ROOT}.tar.gz
28 |
29 | pushd ${PERL_ROOT}
30 | ./Configure -des -Dprefix=/tmp/perl-openssl > /dev/null
31 | make -j$(nproc) > /dev/null
32 | make install > /dev/null
33 | popd
34 | export PATH=/tmp/perl-openssl/bin:${PATH}
35 | else
36 | if [ "${AUDITWHEEL_PLAT:0:9}" == "manylinux" ] && command -v yum >/dev/null 2>&1; then
37 | # more perl modules are needed than the bare minimum already installed in CentOS
38 | # c.f. https://github.com/openssl/openssl/blob/openssl-3.0.0/NOTES-PERL.md#general-notes
39 | yum -y install perl-core
40 | fi
41 | fi
42 |
43 | # Download
44 | curl -fsSLO https://github.com/openssl/openssl/releases/download/${OPENSSL_ROOT}/${OPENSSL_ROOT}.tar.gz
45 | check_sha256sum ${OPENSSL_ROOT}.tar.gz ${OPENSSL_HASH}
46 | tar -xzf ${OPENSSL_ROOT}.tar.gz
47 | rm -rf ${OPENSSL_ROOT}.tar.gz
48 |
49 | LIBATOMIC=
50 | if [ "${AUDITWHEEL_ARCH}" == "i686" ]; then
51 | LIBATOMIC=-latomic
52 | fi
53 | export LDLIBS="${LIBATOMIC}"
54 |
55 | # Configure
56 | pushd ${OPENSSL_ROOT}
57 | ./config no-shared no-tests -fPIC --prefix=/usr/local/ssl --openssldir=/usr/local/ssl > /dev/null
58 |
59 | # Build
60 | make -j$(nproc) > /dev/null
61 |
62 | # Install
63 | make install_sw > /dev/null
64 |
65 | popd
66 | rm -rf ${OPENSSL_ROOT}
67 |
--------------------------------------------------------------------------------
/.github/workflows/update-dependencies.yml:
--------------------------------------------------------------------------------
1 | name: Update Dependencies
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - '.github/workflows/update-dependencies.yml'
7 | - 'scripts/update_cmake_version.py'
8 | - 'scripts/update_openssl_version.py'
9 | - 'noxfile.py'
10 | workflow_dispatch:
11 | schedule:
12 | - cron: '0 6 * * *' # "At 06:00 every day."
13 |
14 | jobs:
15 | update-dep:
16 | name: Update ${{ matrix.dependency_nice }}
17 | if: github.repository_owner == 'scikit-build' || github.event_name != 'schedule'
18 | runs-on: ubuntu-latest
19 | strategy:
20 | fail-fast: false
21 | matrix:
22 | include:
23 | - dependency: "cmake"
24 | dependency_nice: "CMake"
25 | - dependency: "openssl"
26 | dependency_nice: "OpenSSL"
27 | steps:
28 | - uses: actions/checkout@v6
29 | - uses: wntrblm/nox@2025.11.12
30 | - name: "Run update: bump ${{ matrix.dependency_nice }}"
31 | id: bump
32 | run: |
33 | nox --force-color -s bump${{ matrix.dependency != 'cmake' && format('-{0}', matrix.dependency) || '' }}
34 | echo "version=$(nox -s ${{ matrix.dependency }}_version 2>/dev/null)" >> $GITHUB_OUTPUT
35 | - run: echo "${{ matrix.dependency_nice }} version is ${{ steps.bump.outputs.version }}"
36 |
37 | # we use this step to grab a Github App auth token, so that PRs generated by this workflow
38 | # run the GHA tests.
39 | - uses: actions/create-github-app-token@v2
40 | id: app-token
41 | if: github.ref == 'refs/heads/main' && github.repository == 'scikit-build/cmake-python-distributions'
42 | with:
43 | app-id: ${{ secrets.SCIKIT_BUILD_BOT_APP_ID }}
44 | private-key: ${{ secrets.SCIKIT_BUILD_BOT_APP_PRIVATE_KEY }}
45 |
46 | - name: Create Pull Request
47 | if: github.ref == 'refs/heads/main' && github.repository == 'scikit-build/cmake-python-distributions'
48 | uses: peter-evans/create-pull-request@v8
49 | with:
50 | commit-message: '[Bot] Update to ${{ matrix.dependency_nice }} ${{ steps.bump.outputs.version }}'
51 | title: '[Bot] Update to ${{ matrix.dependency_nice }} ${{ steps.bump.outputs.version }}'
52 | body: |
53 | Created by update_${{ matrix.dependency }}_version.py
54 |
55 | PR generated by "Update ${{ matrix.dependency_nice }}" [workflow](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
56 | branch: update-${{ matrix.dependency }}-pr
57 | sign-commits: true
58 | token: ${{ steps.app-token.outputs.token }}
59 | delete-branch: true
60 |
--------------------------------------------------------------------------------
/tests/test_cmake.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 | import sys
4 | import sysconfig
5 | import textwrap
6 | from importlib.metadata import distribution
7 |
8 | import pytest
9 |
10 | import cmake
11 |
12 | from . import push_argv
13 |
14 | all_tools = pytest.mark.parametrize("tool", ["cmake", "cpack", "ctest"])
15 |
16 |
17 | def _run(program, args):
18 | func = getattr(cmake, program)
19 | args = [f"{program}.py", *args]
20 | with push_argv(args), pytest.raises(SystemExit) as excinfo:
21 | func()
22 | assert excinfo.value.code == 0
23 |
24 |
25 | @all_tools
26 | def test_cmake_module(tool, monkeypatch):
27 | monkeypatch.setattr(sys, "platform", "win32") # do not use os.execl
28 | _run(tool, ["--version"])
29 |
30 |
31 | def test_cmake_https(tmpdir, monkeypatch):
32 | monkeypatch.setattr(sys, "platform", "win32") # do not use os.execl
33 | test_script = tmpdir.join("cmake-test-https-download.cmake")
34 | test_script.write(textwrap.dedent(
35 | """
36 | file(
37 | DOWNLOAD
38 | https://github.com/scikit-build/cmake-python-distributions
39 | ${TMP_DIR}/page.html
40 | SHOW_PROGRESS
41 | STATUS status
42 | )
43 | list(GET status 0 error_code)
44 | list(GET status 1 error_msg)
45 | if(error_code)
46 | message(
47 | FATAL_ERROR "error: Failed to download ${url}: ${error_msg}")
48 | endif()
49 | """
50 | ))
51 |
52 | _run("cmake", [f"-DTMP_DIR:PATH={tmpdir}", "-P", str(test_script)])
53 |
54 |
55 | def _get_scripts():
56 | dist = distribution("cmake")
57 | scripts_paths = [os.path.abspath(sysconfig.get_path("scripts", scheme)) for scheme in sysconfig.get_scheme_names()]
58 | scripts = []
59 | for file in dist.files:
60 | if os.path.abspath(str(file.locate().parent)) in scripts_paths:
61 | scripts.append(file.locate().resolve(strict=True))
62 | return scripts
63 |
64 |
65 | @all_tools
66 | def test_cmake_script(tool):
67 | expected_version = "4.2.1"
68 | scripts = [script for script in _get_scripts() if script.stem == tool]
69 | assert len(scripts) == 1
70 | output = subprocess.check_output([str(scripts[0]), "--version"]).decode("ascii")
71 | assert output.splitlines()[0] == f"{tool} version {expected_version}"
72 |
73 |
74 | def test_cmake_main():
75 | expected_version = "4.2.1"
76 | output = subprocess.run([sys.executable, "-m", "cmake", "--version"], text=True, capture_output=True, check=False).stdout
77 | assert output.splitlines()[0] == f"cmake version {expected_version}"
78 |
--------------------------------------------------------------------------------
/CONTRIBUTING.rst:
--------------------------------------------------------------------------------
1 | ============
2 | Contributing
3 | ============
4 |
5 | Contributions are welcome, and they are greatly appreciated! Every
6 | little bit helps, and credit will always be given.
7 |
8 | Types of Contributions
9 | ----------------------
10 |
11 | You can contribute in many ways:
12 |
13 | Report Bugs
14 | ~~~~~~~~~~~
15 |
16 | Report bugs at https://github.com/scikit-build/cmake-python-distributions/issues.
17 |
18 | If you are reporting a bug, please include:
19 |
20 | * Your operating system name and version.
21 | * Any details about your local setup that might be helpful in troubleshooting.
22 | * Detailed steps to reproduce the bug.
23 |
24 | Fix Bugs
25 | ~~~~~~~~
26 |
27 | Look through the GitHub issues for bugs. Anything tagged with "bug"
28 | is open to whoever wants to implement it.
29 |
30 | Implement Features
31 | ~~~~~~~~~~~~~~~~~~
32 |
33 | Look through the GitHub issues for features. Anything tagged with "feature"
34 | is open to whoever wants to implement it.
35 |
36 | Write Documentation
37 | ~~~~~~~~~~~~~~~~~~~
38 |
39 | The cmake-python-distributions project could always use more documentation. We welcome help
40 | with the official cmake-python-distributions docs, in docstrings, or even on blog posts and
41 | articles for the web.
42 |
43 | Submit Feedback
44 | ~~~~~~~~~~~~~~~
45 |
46 | The best way to send feedback is to file an issue at
47 | https://github.com/scikit-build/cmake-python-distributions/issues.
48 |
49 | If you are proposing a new feature:
50 |
51 | * Explain in detail how it would work.
52 | * Keep the scope as narrow as possible, to make it easier to implement.
53 | * Remember that this is a volunteer-driven project, and that contributions
54 | are welcome :)
55 |
56 |
57 | Get Started
58 | -----------
59 |
60 | Ready to contribute? Here's how to set up `cmake-python-distributions` for local development.
61 |
62 | 1. Fork the `cmake-python-distributions` repo on GitHub.
63 |
64 | 2. Clone your fork locally::
65 |
66 | $ git clone git@github.com:your_name_here/cmake-python-distributions.git
67 |
68 | 3. Make sure you have ``nox`` installed (preferably use ``pipx`` or ``brew``
69 | (macOS) if you have those)::
70 |
71 | $ pip install nox
72 | $ cd cmake-python-distributions/
73 |
74 | 4. Create a branch for local development::
75 |
76 | $ git checkout -b name-of-your-bugfix-or-feature
77 |
78 | Now you can make your changes locally.
79 |
80 | 5. When you're done making changes, check that your changes pass linters and
81 | the tests::
82 |
83 | $ nox
84 |
85 | 6. Commit your changes and push your branch to GitHub::
86 |
87 | $ git add .
88 | $ git commit -m "Your detailed description of your changes."
89 | $ git push origin name-of-your-bugfix-or-feature
90 |
91 | 7. Submit a pull request through the GitHub website.
92 |
93 |
94 | Pull Request Guidelines
95 | -----------------------
96 |
97 | Before you submit a pull request, check that it meets these guidelines:
98 |
99 | 1. The pull request should include tests.
100 |
101 | 2. If the pull request adds functionality, the docs should be updated. Put
102 | your new functionality into a function with a docstring, and add the
103 | feature to the list in `README.rst`.
104 |
105 | 3. The pull request should work for Python 2.7, and 3.6+.
106 | Check `GitHub Actions `_
107 | and make sure that the tests pass for all supported Python versions.
108 |
109 |
110 | Tips
111 | ----
112 |
113 | To run a subset of tests::
114 |
115 | $ pytest tests/test_cmake.py
116 | # OR
117 | $ nox -s tests -- tests/test_cmake.py
118 |
--------------------------------------------------------------------------------
/scripts/install-static-clang.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Stop at any error, show all commands
4 | set -exuo pipefail
5 |
6 | TOOLCHAIN_PATH=/opt/clang
7 |
8 | # Download static-clang
9 | DEFAULT_ARCH="$(uname -m)"
10 | if [ "${STATIC_CLANG_ARCH:-}" == "" ]; then
11 | STATIC_CLANG_ARCH="${RUNNER_ARCH:-${DEFAULT_ARCH}}"
12 | fi
13 | case "${STATIC_CLANG_ARCH}" in
14 | ARM64|aarch64|arm64|arm64/*) GO_ARCH=arm64;;
15 | ARM|armv7l|armv8l|arm|arm/v7) GO_ARCH=arm;; # assume arm/v7 for arm
16 | X64|x86_64|amd64|amd64/*) GO_ARCH=amd64;;
17 | X86|i686|386) GO_ARCH=386;;
18 | ppc64le) GO_ARCH=ppc64le;;
19 | riscv64) GO_ARCH=riscv64;;
20 | s390x) GO_ARCH=s390x;;
21 | *) echo "No static-clang toolchain for ${CLANG_ARCH}">2; exit 1;;
22 | esac
23 | STATIC_CLANG_VERSION=21.1.8.0
24 | STATIC_CLANG_FILENAME="static-clang-linux-${GO_ARCH}.tar.xz"
25 | STATIC_CLANG_URL="https://github.com/mayeut/static-clang-images/releases/download/v${STATIC_CLANG_VERSION}/${STATIC_CLANG_FILENAME}"
26 | pushd /tmp
27 | cat<<'EOF' | grep "${STATIC_CLANG_FILENAME}" > "${STATIC_CLANG_FILENAME}.sha256"
28 | dbbf3bd1495c7dff66b20231a45caf49940183bec35cfce9cb2db1ee3b3eda92 static-clang-linux-386.tar.xz
29 | b502f101580e8316331191106cb38e9ee00c5ee3c63fe745e9f359e8d6a1d37c static-clang-linux-amd64.tar.xz
30 | db8a3b03a33521b2541e863477037970208a0954fb2f3c83dab6066ca3466de3 static-clang-linux-arm.tar.xz
31 | 8e99bf94f765f8c27cb45e9b31f2e52ab819388f84b80646ae5daa2b99ad3e10 static-clang-linux-arm64.tar.xz
32 | d3cca48346781172f1a2e313cf18d36a9b9c2a1563abbf977f863aff438602ef static-clang-linux-loong64.tar.xz
33 | 06aad69acda1b9fe1983647129aa685bbd1063d248c4783deefa87b8406f8323 static-clang-linux-ppc64le.tar.xz
34 | 02e2176faa2c0772782cf689c11746c23aca1c4c92d051108674de653372bbd9 static-clang-linux-riscv64.tar.xz
35 | d0c80d791d76843af065e436c180238b2246349a77eece7485279f23ccbe0340 static-clang-linux-s390x.tar.xz
36 | EOF
37 | curl -fsSLO "${STATIC_CLANG_URL}"
38 | sha256sum -c "${STATIC_CLANG_FILENAME}.sha256"
39 | tar -C /opt -xf "${STATIC_CLANG_FILENAME}"
40 | popd
41 |
42 | # configure target triple
43 | case "${AUDITWHEEL_POLICY}-${AUDITWHEEL_ARCH}" in
44 | manylinux*-armv7l) TARGET_TRIPLE=armv7-unknown-linux-gnueabihf;;
45 | musllinux*-armv7l) TARGET_TRIPLE=armv7-alpine-linux-musleabihf;;
46 | manylinux*-ppc64le) TARGET_TRIPLE=powerpc64le-unknown-linux-gnu;;
47 | musllinux*-ppc64le) TARGET_TRIPLE=powerpc64le-alpine-linux-musl;;
48 | manylinux*-*) TARGET_TRIPLE=${AUDITWHEEL_ARCH}-unknown-linux-gnu;;
49 | musllinux*-*) TARGET_TRIPLE=${AUDITWHEEL_ARCH}-alpine-linux-musl;;
50 | esac
51 | case "${AUDITWHEEL_POLICY}-${AUDITWHEEL_ARCH}" in
52 | *-riscv64) M_ARCH="-march=rv64gc";;
53 | *-x86_64) M_ARCH="-march=x86-64";;
54 | *-armv7l) M_ARCH="-march=armv7a";;
55 | manylinux*-i686) M_ARCH="-march=k8 -mtune=generic";; # same as gcc manylinux2014 / manylinux_2_28
56 | musllinux*-i686) M_ARCH="-march=pentium-m -mtune=generic";; # same as gcc musllinux_1_2
57 | esac
58 | GCC_TRIPLE=$(gcc -dumpmachine)
59 |
60 | cat<"${TOOLCHAIN_PATH}/bin/${AUDITWHEEL_PLAT}.cfg"
61 | -target ${TARGET_TRIPLE}
62 | ${M_ARCH:-}
63 | --gcc-toolchain=${DEVTOOLSET_ROOTPATH:-}/usr
64 | --gcc-triple=${GCC_TRIPLE}
65 | EOF
66 |
67 | cat<"${TOOLCHAIN_PATH}/bin/clang.cfg"
68 | @${AUDITWHEEL_PLAT}.cfg
69 | EOF
70 |
71 | cat<"${TOOLCHAIN_PATH}/bin/clang++.cfg"
72 | @${AUDITWHEEL_PLAT}.cfg
73 | EOF
74 |
75 | cat<"${TOOLCHAIN_PATH}/bin/clang-cpp.cfg"
76 | @${AUDITWHEEL_PLAT}.cfg
77 | EOF
78 |
79 | # override entrypoint to add the toolchain to PATH
80 | mv /usr/local/bin/manylinux-entrypoint /usr/local/bin/manylinux-entrypoint-org
81 | cat</usr/local/bin/manylinux-entrypoint
82 | #!/bin/bash
83 |
84 | set -eu
85 |
86 | export PATH="${TOOLCHAIN_PATH}/bin:\${PATH}"
87 | exec /usr/local/bin/manylinux-entrypoint-org "\$@"
88 | EOF
89 |
90 | chmod +x /usr/local/bin/manylinux-entrypoint
91 |
--------------------------------------------------------------------------------
/docs/building.rst:
--------------------------------------------------------------------------------
1 | ===============================
2 | Building the CMake Python wheel
3 | ===============================
4 |
5 | Overview
6 | --------
7 |
8 | This project has been designed to work with `scikit-build-core `_.
9 |
10 | This is done ensuring source files and build artifacts
11 | are copied and/or generated in expected locations.
12 |
13 |
14 | Prerequisites
15 | -------------
16 |
17 | In addition of ``Git``, ``Python`` and `CMake `_, building
18 | the wheel with ``BUILD_CMAKE_FROM_SOURCE`` set to ``ON`` also requires a
19 | ``C++ Compiler``.
20 |
21 |
22 | Quick start
23 | -----------
24 |
25 | Build the CMake Python wheel with the following command::
26 |
27 | python3 -m venv .venv
28 | source .venv/bin/activate
29 | pip install -r requirements-dev.txt build
30 | python -m build --wheel
31 |
32 |
33 | Source distribution (sdist)
34 | ---------------------------
35 |
36 | CMake sources will always be downloaded in the ``/src``
37 | directory.
38 |
39 | This will ensure that the rules specified in ``/MANIFEST.in``
40 | can successfully glob the source files.
41 |
42 | The source distribution is generated using the following
43 | command::
44 |
45 | python -m build --sdist
46 |
47 |
48 | Binary distribution (build, bdist, bdist_wheel)
49 | -----------------------------------------------
50 |
51 | The project has two mode of operations:
52 |
53 | #. build CMake from source (``BUILD_CMAKE_FROM_SOURCE`` set to ``ON``)
54 | #. download CMake binaries (``BUILD_CMAKE_FROM_SOURCE`` set to ``OFF``)
55 |
56 | The binary distribution is generated using the following
57 | command::
58 |
59 | python -m build --wheel
60 |
61 |
62 | Changing the default mode is achieved by explicitly passing the option
63 | to CMake::
64 |
65 | python -m build --wheel -Ccmake.define.BUILD_CMAKE_FROM_SOURCE=ON
66 |
67 |
68 | Default value for ``BUILD_CMAKE_FROM_SOURCE``
69 | ---------------------------------------------
70 |
71 | Depending on the platform, option ``BUILD_CMAKE_FROM_SOURCE`` has
72 | different default:
73 |
74 | - Linux: ON
75 | - MacOSX: OFF
76 | - Windows: OFF
77 |
78 | Controlling verbosity
79 | ---------------------
80 |
81 | configure and build output
82 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
83 |
84 | By default, the output associated to the configure and build steps of the
85 | `CMakeProject-build` external project are logged into files. This can be
86 | changed by setting the ``BUILD_VERBOSE`` option::
87 |
88 | python -m build --wheel -Ccmake.define.BUILD_VERBOSE=ON
89 |
90 |
91 | Optimizations
92 | -------------
93 |
94 | On a given platform, when building different "flavor" of CMake python wheels (one
95 | for each ``-`` tag), the whole process can be made faster in two
96 | ways.
97 |
98 | Caching downloads
99 | ^^^^^^^^^^^^^^^^^
100 |
101 | To avoid the re-download of CMake sources and/or binary packages, passing the
102 | option ``-Ccmake.define.CMakePythonDistributions_ARCHIVE_DOWNLOAD_DIR=/path/to/cache``
103 | enables successive build to re-use existing archives instead of re-downloading them.
104 |
105 | Re-using build tree
106 | ^^^^^^^^^^^^^^^^^^^
107 |
108 | And finally, on a given platform, to avoid rebuilding CMake, the idea is to
109 | first create a standalone build of the CMake project and then building the
110 | wheel using it.
111 |
112 | Step 1: Standalone build::
113 |
114 | mkdir -p standalone-build && cd $_
115 | cmake -DCMakePythonDistributions_ARCHIVE_DOWNLOAD_DIR:PATH=/path/to/cache -G Ninja ../
116 |
117 | Step 2: Faster build reusing download and build directories::
118 |
119 | python -m build -Ccmake.define.CMakePythonDistributions_ARCHIVE_DOWNLOAD_DIR=/path/to/cache
120 | -Ccmake.define.CMakeProject_BINARY_DIR=/path/to/standalone-build
121 |
--------------------------------------------------------------------------------
/scripts/update_openssl_version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # /// script
4 | # dependencies = ["requests"]
5 | # ///
6 |
7 | """
8 | Command line executable allowing to update OpenSSL version.
9 | """
10 |
11 | from __future__ import annotations
12 |
13 | import argparse
14 | import contextlib
15 | import re
16 | import textwrap
17 | from pathlib import Path
18 |
19 | import requests
20 |
21 | TYPE_CHECKING = False
22 |
23 | if TYPE_CHECKING:
24 | from collections.abc import Generator
25 |
26 | ROOT_DIR = Path(__file__).parent.parent.resolve()
27 |
28 |
29 | @contextlib.contextmanager
30 | def _log(txt: str, verbose: bool=True) -> Generator[None, None, None]:
31 | if verbose:
32 | print(txt)
33 | yield
34 | if verbose:
35 | print(txt, "-", "done")
36 |
37 |
38 | def get_openssl_sha256(version: str, verbose: bool=False) -> str:
39 | files_base_url = (
40 | f"https://github.com/openssl/openssl/releases/download/openssl-{version}/openssl-{version}.tar.gz.sha256"
41 | )
42 | with _log(f"Collecting SHA256 from '{files_base_url}'"):
43 | parts = requests.get(files_base_url).content.decode("ascii").strip().split()
44 | sha256 = parts[0]
45 | if len(parts) > 1:
46 | expected_parts = 2 # f"{sha256} {filename}""
47 | assert len(parts) == expected_parts
48 | assert parts[1].lstrip("*") == f"openssl-{version}.tar.gz"
49 | if verbose:
50 | print("got sha256:", sha256)
51 | return sha256
52 |
53 |
54 | def _update_file(filepath: Path, regex: re.Pattern[str], replacement: str) -> None:
55 | with _log(f"Updating {filepath.relative_to(ROOT_DIR)}"):
56 | pattern = re.compile(regex)
57 | with filepath.open() as doc_file:
58 | updated_content = [pattern.sub(replacement, line) for line in doc_file]
59 | with filepath.open("w") as doc_file:
60 | doc_file.writelines(updated_content)
61 |
62 |
63 | def update_openssl_script(version: str, sha256: str) -> None:
64 | pattern = re.compile(r"^OPENSSL_ROOT=.*")
65 | replacement = f"OPENSSL_ROOT=openssl-{version}"
66 | _update_file(
67 | ROOT_DIR / "scripts/manylinux-build-and-install-openssl.sh", pattern, replacement
68 | )
69 | pattern = re.compile(r"^OPENSSL_HASH=.*")
70 | replacement = f"OPENSSL_HASH={sha256}"
71 | _update_file(
72 | ROOT_DIR / "scripts/manylinux-build-and-install-openssl.sh", pattern, replacement
73 | )
74 |
75 |
76 | def main() -> None:
77 | parser = argparse.ArgumentParser(description=__doc__)
78 | parser.add_argument(
79 | "openssl_version",
80 | metavar="OPENSSL_VERSION",
81 | type=str,
82 | help="OpenSSL version",
83 | )
84 | parser.add_argument(
85 | "--collect-only",
86 | action="store_true",
87 | help="If specified, only display the hashsum for the requested version",
88 | )
89 | parser.add_argument(
90 | "--quiet",
91 | action="store_true",
92 | help="Hide the output",
93 | )
94 | args = parser.parse_args()
95 |
96 | sha256 = get_openssl_sha256(args.openssl_version, verbose=args.collect_only)
97 | if args.collect_only:
98 | return
99 |
100 | update_openssl_script(args.openssl_version, sha256)
101 |
102 | if not args.quiet:
103 | msg = """\
104 | Complete! Now run:
105 |
106 | git switch -c update-to-openssl-{release}
107 | git add -u scripts/manylinux-build-and-install-openssl.sh
108 | git commit -m "Update to OpenSSL {release}"
109 | gh pr create --fill --body "Created by update_openssl_version.py"
110 | """
111 | print(textwrap.dedent(msg.format(release=args.openssl_version)))
112 |
113 |
114 | if __name__ == "__main__":
115 | main()
116 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ==========================
2 | CMake Python Distributions
3 | ==========================
4 |
5 | `CMake `_ is used to control the software compilation
6 | process using simple platform and compiler independent configuration files,
7 | and generate native makefiles and workspaces that can be used in the
8 | compiler environment of your choice.
9 |
10 | The suite of CMake tools were created by Kitware in response to the need
11 | for a powerful, cross-platform build environment for open-source projects
12 | such as ITK and VTK.
13 |
14 | The CMake python wheels provide `CMake 4.2.1 `_.
15 |
16 | Latest Release
17 | --------------
18 |
19 | .. table::
20 |
21 | +----------------------------------------------------------------------+---------------------------------------------------------------------------+
22 | | Versions | Downloads |
23 | +======================================================================+===========================================================================+
24 | | .. image:: https://img.shields.io/pypi/v/cmake.svg | .. image:: https://static.pepy.tech/badge/cmake |
25 | | :target: https://pypi.python.org/pypi/cmake | :target: https://pypi.python.org/pypi/cmake |
26 | | | .. image:: https://img.shields.io/pypi/dm/cmake |
27 | | | :target: https://pypi.python.org/pypi/cmake |
28 | +----------------------------------------------------------------------+---------------------------------------------------------------------------+
29 |
30 | Build Status
31 | ------------
32 |
33 | .. table::
34 |
35 | +---------------+--------------------------------------------------------------------------------------------------------------+
36 | | | GitHub Actions (Windows, macOS, Linux) |
37 | +===============+==============================================================================================================+
38 | | PyPI | .. image:: https://github.com/scikit-build/cmake-python-distributions/actions/workflows/build.yml/badge.svg |
39 | | | :target: https://github.com/scikit-build/cmake-python-distributions/actions/workflows/build.yml |
40 | +---------------+--------------------------------------------------------------------------------------------------------------+
41 |
42 | Platforms
43 | ---------
44 |
45 | The following platforms are supported with binary wheels:
46 |
47 | .. table::
48 |
49 | +---------------+---------------------------+
50 | | OS | Arch |
51 | +===============+===========================+
52 | | Windows | | 64-bit |
53 | | | | 32-bit |
54 | +---------------+---------------------------+
55 | | Linux Intel | | manylinux2014+ x86_64 |
56 | | | | musllinux_1_2+ x86_64 |
57 | | | | manylinux2014+ i686 |
58 | | | | musllinux_1_2+ i686 |
59 | +---------------+---------------------------+
60 | | Linux ARM | | manylinux2014+ AArch64 |
61 | | | | musllinux_1_2+ AArch64 |
62 | | | | manylinux_2_31+ armv7l |
63 | | | | musllinux_1_2+ armv7l |
64 | +---------------+---------------------------+
65 | | Linux PowerPC | | manylinux2014+ ppc64le |
66 | | | | musllinux_1_2+ ppc64le |
67 | +---------------+---------------------------+
68 | | Linux IBM Z | | manylinux2014+ s390x |
69 | | | | musllinux_1_2+ s390x |
70 | +---------------+---------------------------+
71 | | Linux RISC-V | | manylinux_2_31+ riscv64 |
72 | | | | musllinux_1_2+ riscv64 |
73 | +---------------+---------------------------+
74 | | macOS 10.10+ | Intel |
75 | +---------------+---------------------------+
76 | | macOS 11+ | Apple Silicon |
77 | +---------------+---------------------------+
78 |
79 | The last version to provide ``manylinux1`` wheels was ``3.22.x``.
80 | The last version to provide Python 3.7 support and ``manylinux2010`` wheels was ``4.0.3``.
81 | The last version to provide Python 2 to Python 3.6 support was ``3.28.x``.
82 |
83 | Maintainers
84 | -----------
85 |
86 | * `How to update CMake version? `_
87 |
88 | * `How to make a release? `_
89 |
90 | Miscellaneous
91 | -------------
92 |
93 | * Documentation: https://cmake-python-distributions.readthedocs.io/en/latest/
94 | * Source code: https://github.com/scikit-build/cmake-python-distributions
95 | * Mailing list: https://groups.google.com/forum/#!forum/scikit-build
96 |
97 | License
98 | -------
99 |
100 | This project is maintained by Jean-Christophe Fillion-Robin from Kitware Inc.
101 | It is covered by the `Apache License, Version 2.0 `_.
102 |
103 | CMake is distributed under the OSI-approved BSD 3-clause License.
104 | For more information about CMake, visit https://cmake.org
105 |
--------------------------------------------------------------------------------
/docs/build_system.rst:
--------------------------------------------------------------------------------
1 | ==============================
2 | Understanding the Build-system
3 | ==============================
4 |
5 |
6 | The build system is described by the ``CMakeLists.txt`` and is composed of few projects each responsible
7 | for a specific task. Once configured, the `Outer Project` is responsible for driving the overall build
8 | composed of multiple project called `external project`. Here is the list of `external project`:
9 |
10 | * ``CMakeProject-src-download``
11 | * ``CMakeProject-binary-download``
12 | * ``CMakeProject-build``
13 | * ``CMakePythonDistributions``: This corresponds to the `Inner Project` represented below.
14 |
15 | The flow chart represented below illustrates which external projects are included based on the configure
16 | options and describes the role of each one:
17 |
18 | .. mermaid::
19 | :align: center
20 |
21 | flowchart LR
22 | subgraph OP[Outer Project]
23 | style OP fill:#FFF0D7
24 | configure["CMakeLists.tct"]
25 | ask_download{"Download source?"}
26 | download_source["Download Source archive"]
27 | reuse_source_dir["Re-use source directory"]
28 | ask_build{"Build from Source?"}
29 | download_binaries["CMakeProject-binary-download"]
30 | build_cmake["CMakeProject-build"]
31 | strip_executables["Strip executables"]
32 | ask_inner_build{"Which files to install?"}
33 | install_pre_built["Install prebuilt binaries"]
34 | install_cmake_project["Install CMake project"]
35 |
36 | configure --> ask_download
37 |
38 | subgraph EP1[ExternalProject: CMakeProject-src-download]
39 | style EP1 fill:#E7CA92
40 | ask_download -->|yes| download_source
41 | ask_download -->|no| reuse_source_dir
42 | end
43 |
44 | download_source --> ask_build
45 | reuse_source_dir --> ask_build
46 |
47 | subgraph EP2[External Projects]
48 | style EP2 fill:#E7CA92
49 | ask_build -->|no| download_binaries
50 | ask_build -->|yes| build_cmake
51 | build_cmake --> strip_executables
52 | end
53 |
54 | download_binaries --> ask_inner_build
55 | strip_executables --> ask_inner_build
56 |
57 | subgraph IP[Inner Project: CMakePythonDistributions]
58 | style IP fill:#a1acc2
59 | ask_inner_build -->|no| install_pre_built
60 | ask_inner_build -->|yes| install_cmake_project
61 | end
62 | end
63 |
64 |
65 | +----------------------------------------+--------------------------------------------------------------------------+
66 | | **Node Title** | **Description** |
67 | +========================================+==========================================================================+
68 | | CMakeLists | CMake configuration file |
69 | +----------------------------------------+--------------------------------------------------------------------------+
70 | | Download source ? | If option ``CMakeProject_SOURCE_DIR`` is set, skip source download. |
71 | +----------------------------------------+--------------------------------------------------------------------------+
72 | | Download Source archive | External project downloading archives from https://cmake.org/files/. |
73 | +----------------------------------------+--------------------------------------------------------------------------+
74 | | Re-use source directory | Empty external project. |
75 | +----------------------------------------+--------------------------------------------------------------------------+
76 | | Build from Source ? | Answer based on option ``BUILD_CMAKE_FROM_SOURCE`` |
77 | +----------------------------------------+--------------------------------------------------------------------------+
78 | | CMakeProject-binary-download | External project downloading pre-built binary archives from |
79 | | | https://cmake.org/files/. |
80 | +----------------------------------------+--------------------------------------------------------------------------+
81 | | CMakeProject-build | External project building CMake from source. |
82 | +----------------------------------------+--------------------------------------------------------------------------+
83 | | Strip executables | If possible, reduce wheel size stripping cmake, cpack and ctest |
84 | | | executables |
85 | +----------------------------------------+--------------------------------------------------------------------------+
86 | | Which files to install? | Answer based on option ``BUILD_CMAKE_FROM_SOURCE`` |
87 | +----------------------------------------+--------------------------------------------------------------------------+
88 | | Install prebuilt binaries | Recursively glob all files and explicitly add install rules. |
89 | +----------------------------------------+--------------------------------------------------------------------------+
90 | | Install CMake project | Achieved by including ``${CMakeProject_BINARY_DIR}/cmake_install.cmake`` |
91 | +----------------------------------------+--------------------------------------------------------------------------+
92 |
--------------------------------------------------------------------------------
/_build_backend/backend.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import os
4 |
5 | from scikit_build_core import build as _orig
6 |
7 | if hasattr(_orig, "prepare_metadata_for_build_editable"):
8 | prepare_metadata_for_build_editable = _orig.prepare_metadata_for_build_editable
9 | if hasattr(_orig, "prepare_metadata_for_build_wheel"):
10 | prepare_metadata_for_build_wheel = _orig.prepare_metadata_for_build_wheel
11 | build_editable = _orig.build_editable
12 | build_sdist = _orig.build_sdist
13 | get_requires_for_build_editable = _orig.get_requires_for_build_editable
14 | get_requires_for_build_sdist = _orig.get_requires_for_build_sdist
15 |
16 |
17 | def _strtobool(value: str) -> bool:
18 | """
19 | Converts a environment variable string into a boolean value.
20 | """
21 | if not value:
22 | return False
23 | value = value.lower()
24 | if value.isdigit():
25 | return bool(int(value))
26 | return value not in {"n", "no", "off", "false", "f"}
27 |
28 |
29 | def get_requires_for_build_wheel(
30 | config_settings: dict[str, str | list[str]] | None = None,
31 | ) -> list[str]:
32 | packages_orig = _orig.get_requires_for_build_wheel(config_settings)
33 | allow_cmake = _strtobool(os.environ.get("CMAKE_PYTHON_DIST_ALLOW_CMAKE_DEP", ""))
34 | allow_ninja = any(
35 | _strtobool(os.environ.get(var, ""))
36 | for var in ("CMAKE_PYTHON_DIST_FORCE_NINJA_DEP", "CMAKE_PYTHON_DIST_ALLOW_NINJA_DEP")
37 | )
38 | packages = []
39 | for package in packages_orig:
40 | package_name = package.lower().split(">")[0].strip()
41 | if package_name == "cmake" and not allow_cmake:
42 | continue
43 | if package_name == "ninja" and not allow_ninja:
44 | continue
45 | packages.append(package)
46 | return packages
47 |
48 |
49 | def _bootstrap_build(temp_path: str, config_settings: dict[str, list[str] | str] | None = None) -> str:
50 | import hashlib
51 | import platform
52 | import re
53 | import shutil
54 | import subprocess
55 | import tarfile
56 | import urllib.request
57 | import zipfile
58 | from pathlib import Path
59 |
60 | env = os.environ.copy()
61 | temp_path_ = Path(temp_path)
62 |
63 | archive_dir = temp_path_
64 | if config_settings:
65 | archive_dir = Path(config_settings.get("cmake.define.CMakePythonDistributions_ARCHIVE_DOWNLOAD_DIR", archive_dir))
66 | archive_dir.mkdir(parents=True, exist_ok=True)
67 |
68 | if os.name == "posix":
69 | if "MAKE" not in env:
70 | make_path = None
71 | make_candidates = ("gmake", "make", "smake")
72 | for candidate in make_candidates:
73 | make_path = shutil.which(candidate)
74 | if make_path is not None:
75 | break
76 | if make_path is None:
77 | msg = f"Could not find a make program. Tried {make_candidates!r}"
78 | raise ValueError(msg)
79 | env["MAKE"] = make_path
80 | make_path = env["MAKE"]
81 | kind = "unix_source"
82 | else:
83 | assert os.name == "nt"
84 | machine = platform.machine()
85 | kinds = {
86 | "x86": "win32_binary",
87 | "AMD64": "win64_binary",
88 | "ARM64": "winarm64_binary",
89 | }
90 | if machine not in kinds:
91 | msg = f"Could not find CMake required to build on a {machine} system"
92 | raise ValueError(msg)
93 | kind = kinds[machine]
94 |
95 |
96 | cmake_urls = Path("CMakeUrls.cmake").read_text()
97 | archive_url = re.findall(rf'set\({kind}_url\s+"(?P.*)"\)$', cmake_urls, flags=re.MULTILINE)[0]
98 | archive_sha256 = re.findall(rf'set\({kind}_sha256\s+"(?P.*)"\)$', cmake_urls, flags=re.MULTILINE)[0]
99 |
100 | archive_name = archive_url.rsplit("/", maxsplit=1)[1]
101 | archive_path = archive_dir / archive_name
102 | if not archive_path.exists():
103 | with urllib.request.urlopen(archive_url) as response:
104 | archive_path.write_bytes(response.read())
105 |
106 | sha256 = hashlib.sha256(archive_path.read_bytes()).hexdigest()
107 | if archive_sha256.lower() != sha256.lower():
108 | msg = f"Invalid sha256 for {archive_url!r}. Expected {archive_sha256!r}, got {sha256!r}"
109 | raise ValueError(msg)
110 |
111 | if os.name == "posix":
112 | assert archive_name.endswith(".tar.gz")
113 | tar_filter_kwargs = {"filter": "tar"} if hasattr(tarfile, "tar_filter") else {}
114 | with tarfile.open(archive_path) as tar:
115 | tar.extractall(path=temp_path_, **tar_filter_kwargs)
116 |
117 | parallel_str = env.get("CMAKE_BUILD_PARALLEL_LEVEL", "1")
118 | parallel = max(0, int(parallel_str) if parallel_str.isdigit() else 1) or os.cpu_count() or 1
119 |
120 | bootstrap_path = next(temp_path_.glob("cmake-*/bootstrap"))
121 | prefix_path = temp_path_ / "cmake-install"
122 | cmake_path = prefix_path / "bin" / "cmake"
123 | bootstrap_args = [f"--prefix={prefix_path}", "--no-qt-gui", "--no-debugger", f"--parallel={parallel}", "--", "-DBUILD_TESTING=OFF", "-DBUILD_CursesDialog:BOOL=OFF"]
124 | previous_cwd = Path().absolute()
125 | os.chdir(bootstrap_path.parent)
126 | try:
127 | subprocess.run([bootstrap_path, *bootstrap_args], env=env, check=True)
128 | subprocess.run([make_path, "-j", f"{parallel}"], env=env, check=True)
129 | subprocess.run([make_path, "install"], env=env, check=True)
130 | finally:
131 | os.chdir(previous_cwd)
132 | else:
133 | assert archive_name.endswith(".zip")
134 | with zipfile.ZipFile(archive_path) as zip_:
135 | zip_.extractall(path=temp_path_)
136 | cmake_path = next(temp_path_.glob("cmake-*/bin/cmake.exe"))
137 |
138 | return str(cmake_path)
139 |
140 |
141 | def build_wheel(
142 | wheel_directory: str,
143 | config_settings: dict[str, list[str] | str] | None = None,
144 | metadata_directory: str | None = None,
145 | ) -> str:
146 | from scikit_build_core.errors import CMakeNotFoundError
147 |
148 | try:
149 | return _orig.build_wheel(wheel_directory, config_settings, metadata_directory)
150 | except CMakeNotFoundError:
151 | if os.name not in {"posix", "nt"}:
152 | raise
153 | # Let's try bootstrapping CMake
154 | import tempfile
155 | with tempfile.TemporaryDirectory() as temp_path:
156 | cmake_path = _bootstrap_build(temp_path, config_settings)
157 | assert cmake_path
158 | os.environ["CMAKE_EXECUTABLE"] = cmake_path
159 | return _orig.build_wheel(wheel_directory, config_settings, metadata_directory)
160 |
--------------------------------------------------------------------------------
/noxfile.py:
--------------------------------------------------------------------------------
1 | # /// script
2 | # dependencies = ["nox>=2025.2.9"]
3 | # ///
4 |
5 | import argparse
6 | import re
7 | from pathlib import Path
8 |
9 | import nox
10 |
11 | nox.needs_version = ">=2025.2.9"
12 | nox.options.default_venv_backend = "uv|virtualenv"
13 |
14 | BUILD_ENV = {
15 | "MACOSX_DEPLOYMENT_TARGET": "10.10",
16 | "ARCHFLAGS": "-arch x86_64 -arch arm64",
17 | }
18 |
19 | wheel = ""
20 |
21 |
22 | @nox.session
23 | def build(session: nox.Session) -> str:
24 | """
25 | Make an SDist and a wheel.
26 | """
27 | session.log(
28 | "The files produced locally by this job are not intended to be redistributable"
29 | )
30 | extra = ["--installer=uv"] if session.venv_backend == "uv" else []
31 | session.install("build")
32 | tmpdir = session.create_tmp()
33 | session.run("python", "-m", "build", "--outdir", tmpdir, *extra, env=BUILD_ENV)
34 | (wheel_path,) = Path(tmpdir).glob("*.whl")
35 | (sdist_path,) = Path(tmpdir).glob("*.tar.gz")
36 | Path("dist").mkdir(exist_ok=True)
37 | wheel_path.rename(f"dist/{wheel_path.name}")
38 | sdist_path.rename(f"dist/{sdist_path.name}")
39 |
40 | global wheel
41 | wheel = f"dist/{wheel_path.name}"
42 |
43 |
44 | @nox.session
45 | def lint(session: nox.Session) -> str:
46 | """
47 | Run linters on the codebase.
48 | """
49 | session.install("pre-commit")
50 | session.run("pre-commit", "run", "-a")
51 |
52 |
53 | @nox.session(requires=["build"])
54 | def tests(session: nox.Session) -> str:
55 | """
56 | Run the tests.
57 | """
58 | pyproject = nox.project.load_toml("pyproject.toml")
59 | deps = nox.project.dependency_groups(pyproject, "test")
60 | session.install(wheel, *deps)
61 | session.run("pytest", *session.posargs)
62 |
63 |
64 | @nox.session(reuse_venv=True, default=False)
65 | def docs(session: nox.Session) -> None:
66 | """
67 | Build the docs. Pass "--non-interactive" to avoid serve. Pass "-- -b linkcheck" to check links.
68 | """
69 | pyproject = nox.project.load_toml("pyproject.toml")
70 | deps = nox.project.dependency_groups(pyproject, "docs")
71 |
72 | parser = argparse.ArgumentParser()
73 | parser.add_argument(
74 | "-b", dest="builder", default="html", help="Build target (default: html)"
75 | )
76 | args, posargs = parser.parse_known_args(session.posargs)
77 | serve = args.builder == "html" and session.interactive
78 |
79 | extra_installs = ["sphinx-autobuild"] if serve else []
80 | session.install(*deps, *extra_installs)
81 | session.chdir("docs")
82 |
83 | if args.builder == "linkcheck":
84 | session.run(
85 | "sphinx-build", "-b", "linkcheck", ".", "_build/linkcheck", *posargs
86 | )
87 | return
88 |
89 | shared_args = (
90 | "-n", # nitpicky mode
91 | "-T", # full tracebacks
92 | f"-b={args.builder}",
93 | ".",
94 | f"_build/{args.builder}",
95 | *posargs,
96 | )
97 |
98 | if serve:
99 | session.run(
100 | "sphinx-autobuild", "--open-browser", "--ignore=.build", *shared_args
101 | )
102 | else:
103 | session.run("sphinx-build", "--keep-going", *shared_args)
104 |
105 | def _bump(session: nox.Session, name: str, repository: str, branch: str, script: str, files) -> None:
106 | parser = argparse.ArgumentParser()
107 | parser.add_argument(
108 | "--commit", action="store_true", help="Make a branch and commit."
109 | )
110 | parser.add_argument(
111 | "version", nargs="?", help="The version to process - leave off for latest."
112 | )
113 | args = parser.parse_args(session.posargs)
114 |
115 | if args.version is None:
116 | session.install("lastversion", "requests")
117 | lastversion_args = []
118 | if branch:
119 | lastversion_args.extend(("--branch", branch, "--only", f"{branch}."))
120 | lastversion_args.append(repository)
121 | version = session.run("lastversion", *lastversion_args, log=False, silent=True).strip()
122 | else:
123 | session.install("requests")
124 | version = args.version
125 |
126 | extra = ["--quiet"] if args.commit else []
127 | session.run("python", script, version, *extra)
128 |
129 | if args.commit:
130 | session.run("git", "switch", "-c", f"update-to-{name.lower()}-{version}", external=True)
131 | session.run("git", "add", "-u", *files, external=True)
132 | session.run("git", "commit", "-m", f"Update to {name} {version}", external=True)
133 | session.log(
134 | f'Complete! Now run: gh pr create --fill --body "Created by running `nox -s {session.name} -- --commit`"'
135 | )
136 |
137 |
138 | @nox.session(default=False)
139 | def bump(session: nox.Session) -> None:
140 | """
141 | Set to a new version, use -- , otherwise will use the latest version.
142 | """
143 | files = (
144 | "pyproject.toml",
145 | "CMakeUrls.cmake",
146 | "docs/index.rst",
147 | "README.rst",
148 | "tests/test_cmake.py",
149 | "docs/update_cmake_version.rst",
150 | )
151 | _bump(session, "CMake", "kitware/cmake", "", "scripts/update_cmake_version.py", files)
152 |
153 |
154 | @nox.session(name="bump-openssl", default=False)
155 | def bump_openssl(session: nox.Session) -> None:
156 | """
157 | Set openssl to a new version, use -- , otherwise will use the latest version.
158 | """
159 | files = (
160 | "scripts/manylinux-build-and-install-openssl.sh",
161 | )
162 | _bump(session, "OpenSSL", "openssl/openssl", "3.5", "scripts/update_openssl_version.py", files)
163 |
164 |
165 | def _get_version() -> str:
166 | txt = Path("pyproject.toml").read_text()
167 | return next(iter(re.finditer(r'^version = "([\d\.]+)"$', txt, flags=re.MULTILINE))).group(1)
168 |
169 |
170 | @nox.session(venv_backend="none", default=False)
171 | def tag_release(session: nox.Session) -> None:
172 | """
173 | Print instructions for tagging a release and pushing it to GitHub.
174 | """
175 |
176 | session.log("Run the following commands to make a release:")
177 | current_version = _get_version()
178 | print(f"git tag --sign -m 'cmake-python-distributions {current_version}' {current_version} main")
179 | print(f"git push origin {current_version}")
180 |
181 |
182 | @nox.session(venv_backend="none", default=False)
183 | def cmake_version(session: nox.Session) -> None: # noqa: ARG001
184 | """
185 | Print upstream cmake version.
186 | """
187 |
188 | current_version = _get_version()
189 | print(".".join(current_version.split(".")[:3]))
190 |
191 |
192 | @nox.session(venv_backend="none", default=False)
193 | def openssl_version(session: nox.Session) -> None: # noqa: ARG001
194 | """
195 | Print upstream OpenSSL version.
196 | """
197 | txt = Path("scripts/manylinux-build-and-install-openssl.sh").read_text()
198 | current_version = next(iter(re.finditer(r'^OPENSSL_ROOT=openssl-([\d\.]+)$', txt, flags=re.MULTILINE))).group(1)
199 | print(".".join(current_version.split(".")[:3]))
200 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["scikit-build-core>=0.10"]
3 | build-backend = "backend"
4 | backend-path = ["_build_backend"]
5 |
6 | [project]
7 | name = "cmake"
8 | version = "4.2.1"
9 | description = "CMake is an open-source, cross-platform family of tools designed to build, test and package software"
10 | keywords = ["CMake", "build", "c++", "fortran", "cross-platform", "cross-compilation"]
11 | readme = "README.rst"
12 | license = {text = "Apache 2.0"}
13 | authors = [
14 | {name = "Jean-Christophe Fillion-Robin", email = "jchris.fillionr@kitware.com"},
15 | ]
16 | classifiers = [
17 | "License :: OSI Approved :: Apache Software License",
18 | "License :: OSI Approved :: BSD License",
19 | "Programming Language :: C",
20 | "Programming Language :: C++",
21 | "Programming Language :: Fortran",
22 | "Programming Language :: Python",
23 | "Operating System :: OS Independent",
24 | "Development Status :: 5 - Production/Stable",
25 | "Intended Audience :: Developers",
26 | "Topic :: Software Development :: Build Tools",
27 | "Typing :: Typed"
28 | ]
29 | requires-python = ">=3.8"
30 |
31 | [project.urls]
32 | Homepage = "https://cmake.org"
33 | Documentation = "https://cmake-python-distributions.readthedocs.io"
34 | Source = "https://github.com/scikit-build/cmake-python-distributions"
35 | "Mailing list" = "https://groups.google.com/forum/#!forum/scikit-build"
36 | "Bug Tracker" = "https://github.com/scikit-build/cmake-python-distributions/issues"
37 |
38 | [project.scripts]
39 | ccmake = "cmake:ccmake"
40 | cmake = "cmake:cmake"
41 | cpack = "cmake:cpack"
42 | ctest = "cmake:ctest"
43 |
44 |
45 | [dependency-groups]
46 | test = [
47 | "coverage>=4.2",
48 | "pytest>=6",
49 | "pytest-cov>=2.4.0",
50 | ]
51 | docs = [
52 | "docutils",
53 | "funcparserlib>=1.0.0",
54 | "furo",
55 | "pygments",
56 | "sphinx",
57 | "sphinxcontrib-mermaid",
58 | "tomli; python_version<'3.11'",
59 | ]
60 | dev = [{ include-group="test" }]
61 |
62 |
63 | [tool.scikit-build]
64 | minimum-version = "build-system.requires"
65 | build-dir = "build/{wheel_tag}"
66 | cmake.version = "CMakeLists.txt"
67 | ninja.make-fallback = true
68 | wheel.py-api = "py3"
69 | wheel.expand-macos-universal-tags = true
70 | wheel.install-dir = "cmake/data"
71 |
72 | [[tool.scikit-build.generate]]
73 | path = "cmake/_version.py"
74 | template = '''
75 | version = "${version}"
76 | '''
77 |
78 | [[tool.scikit-build.overrides]]
79 | if.env.CMAKE_PYTHON_DIST_FORCE_NINJA_DEP = true
80 | ninja.make-fallback = false
81 |
82 | [[tool.scikit-build.overrides]]
83 | if.state = "metadata_wheel"
84 | wheel.cmake = false
85 | wheel.platlib = true
86 |
87 |
88 | [tool.pytest.ini_options]
89 | minversion = "6.0"
90 | testpaths = ["tests"]
91 |
92 |
93 | [tool.cibuildwheel]
94 | archs = ["auto64", "auto32"]
95 | build = "cp310-*"
96 | test-groups = ["test"]
97 | test-command = "pytest {project}/tests"
98 | build-verbosity = 1
99 | build-frontend = "build[uv]"
100 | config-settings."cmake.define.RUN_CMAKE_TEST" = "ON"
101 | environment = { CMAKE_PYTHON_DIST_FORCE_NINJA_DEP = "1" }
102 | manylinux-x86_64-image = "manylinux2014"
103 | manylinux-i686-image = "manylinux2014"
104 | manylinux-aarch64-image = "manylinux2014"
105 | manylinux-ppc64le-image = "manylinux2014"
106 | manylinux-s390x-image = "manylinux2014"
107 | manylinux-armv7l-image = "manylinux_2_31"
108 | manylinux-riscv64-image = "ghcr.io/mayeut/manylinux_2_31:2025.11.22-1"
109 | musllinux-x86_64-image = "musllinux_1_2"
110 | musllinux-i686-image = "musllinux_1_2"
111 | musllinux-aarch64-image = "musllinux_1_2"
112 | musllinux-ppc64le-image = "musllinux_1_2"
113 | musllinux-s390x-image = "musllinux_1_2"
114 | musllinux-armv7l-image = "musllinux_1_2"
115 | musllinux-riscv64-image = "musllinux_1_2"
116 |
117 | [[tool.cibuildwheel.overrides]]
118 | select = "*-macos*"
119 | inherit.environment = "append"
120 | environment = { MACOSX_DEPLOYMENT_TARGET = "10.10" }
121 |
122 | [[tool.cibuildwheel.overrides]]
123 | select = "*-*linux*"
124 | before-all = "./scripts/install-static-clang.sh && ./scripts/manylinux-build-and-install-openssl.sh"
125 | inherit.environment = "prepend"
126 | environment = { CC = "/opt/clang/bin/clang", CXX = "/opt/clang/bin/clang++", LDFLAGS = "-fuse-ld=lld -Wl,--build-id", PKG_CONFIG_PATH = "/usr/local/ssl/lib/pkgconfig" }
127 | inherit.environment-pass = "prepend"
128 | environment-pass = ["RUNNER_ARCH"]
129 | inherit.config-settings = "prepend"
130 | config-settings."cmake.define.OPENSSL_ROOT_DIR" = "/usr/local/ssl"
131 | config-settings."cmake.define.OPENSSL_USE_STATIC_LIBS" = "ON"
132 | config-settings."cmake.define.CMAKE_LINKER_TYPE" = "LLD"
133 | config-settings."cmake.define.CMAKE_JOB_POOL_COMPILE" = "compile"
134 | config-settings."cmake.define.CMAKE_JOB_POOL_LINK" = "link"
135 | config-settings."cmake.define.CMAKE_JOB_POOLS" = "compile=4;link=1"
136 |
137 | [[tool.cibuildwheel.overrides]]
138 | select = ["*-manylinux_armv7l"]
139 | inherit.config-settings = "append"
140 | # disable some tests
141 | # - RunCMake.CompilerId fails because architecture id is not detected properly for gfortran on Ubuntu 20.04 https://gitlab.kitware.com/cmake/cmake/-/issues/27129
142 | config-settings."cmake.define.RUN_CMAKE_TEST_EXCLUDE" = "RunCMake.CompilerId"
143 |
144 | [[tool.cibuildwheel.overrides]]
145 | select = ["*-musllinux_*"]
146 | inherit.config-settings = "append"
147 | # disable some tests
148 | # - BootstrapTest fails with custom OpenSSL and probably does not make much sense for this project
149 | # - ExportImport|RunCMake.install|RunCMake.file-GET_RUNTIME_DEPENDENCIES: c.f. https://discourse.cmake.org/t/cmake-test-suite-failing-on-alpine-linux/5064
150 | config-settings."cmake.define.RUN_CMAKE_TEST_EXCLUDE" = "BootstrapTest|CTestTestFdSetSize|ExportImport|RunCMake.install|RunCMake.RuntimePath|RunCMake.file-GET_RUNTIME_DEPENDENCIES"
151 |
152 | [[tool.cibuildwheel.overrides]]
153 | select = ["*linux_ppc64le", "*linux_s390x", "*linux_riscv64"]
154 | inherit.config-settings = "append"
155 | # disable tests on those platforms, QEMU is taking to long for jobs to pass on GHA
156 | config-settings."cmake.define.RUN_CMAKE_TEST" = "OFF"
157 |
158 | [[tool.cibuildwheel.overrides]]
159 | select = ["*-musllinux_{ppc64le,s390x,riscv64}"]
160 | build-frontend = "pip"
161 |
162 |
163 | [tool.mypy]
164 | files = ["src", "scripts"]
165 | python_version = "3.8"
166 | strict = true
167 | enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
168 | warn_unreachable = true
169 |
170 |
171 | [tool.ruff.lint]
172 | extend-select = [
173 | "ARG", # flake8-unused-arguments
174 | "B", # flake8-bugbear
175 | "C4", # flake8-comprehensions
176 | "EXE", # flake8-executable
177 | "G", # flake8-logging-format
178 | "I", # isort
179 | "ICN", # flake8-import-conventions
180 | "ISC", # flake8-implicit-str-concat
181 | "PGH", # pygrep-hooks
182 | "PIE", # flake8-pie
183 | "PL", # pylint
184 | "PT", # flake8-pytest-style
185 | "RET", # flake8-return
186 | "RUF", # Ruff-specific
187 | "SIM", # flake8-simplify
188 | "UP", # pyupgrade
189 | ]
190 | ignore = [
191 | "PLR09", # Too many X
192 | ]
193 | exclude = ["src/cmake/_version.py"]
194 | flake8-unused-arguments.ignore-variadic-names = true
195 |
196 | [tool.ruff.lint.per-file-ignores]
197 | "_build_backend/backend.py" = ["PLC0415"]
198 | "docs/conf.py" = ["E402"]
199 | "*.pyi" = ["ARG001"]
200 | "noxfile.py" = ["PLW0603"]
201 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | #
2 | # CMake Python Distributions documentation build configuration file, created by
3 | # sphinx-quickstart on Wed Nov 9 02:28:46 2016.
4 | #
5 | # This file is execfile()d with the current directory set to its
6 | # containing dir.
7 | #
8 | # Note that not all possible configuration values are present in this
9 | # autogenerated file.
10 | #
11 | # All configuration values have a default; values that are commented out
12 | # serve to show the default.
13 |
14 | # If extensions (or modules to document with autodoc) are in another directory,
15 | # add these directories to sys.path here. If the directory is relative to the
16 | # documentation root, use os.path.abspath to make it absolute, like shown here.
17 | #
18 | import sys
19 | from pathlib import Path
20 |
21 | if sys.version_info < (3, 11):
22 | from tomli import tomllib
23 | else:
24 | import tomllib
25 |
26 | DIR = Path(__file__).parent.resolve()
27 | pyproject = DIR.parent / "pyproject.toml"
28 |
29 | # -- Options for blockdiag extension --------------------------------------
30 |
31 | blockdiag_antialias = True
32 |
33 | # -- General configuration ------------------------------------------------
34 |
35 | # If your documentation needs a minimal Sphinx version, state it here.
36 | #
37 | # needs_sphinx = '1.0'
38 |
39 | # Add any Sphinx extension module names here, as strings. They can be
40 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
41 | # ones.
42 | extensions = ['sphinxcontrib.mermaid']
43 |
44 | # Add any paths that contain templates here, relative to this directory.
45 | templates_path = ['_templates']
46 |
47 | # The suffix(es) of source filenames.
48 | # You can specify multiple suffix as a list of string:
49 | #
50 | # source_suffix = ['.rst', '.md']
51 | source_suffix = '.rst'
52 |
53 | # The encoding of source files.
54 | #
55 | # source_encoding = 'utf-8-sig'
56 |
57 | # The main toctree document.
58 | main_doc = 'index'
59 |
60 | # General information about the project.
61 | project = 'CMake Python Distributions'
62 | copyright = '2016, Jean-Christophe Fillion-Robin'
63 | author = 'Jean-Christophe Fillion-Robin'
64 |
65 | # The version info for the project you're documenting, acts as replacement for
66 | # |version| and |release|, also used in various other places throughout the
67 | # built documents.
68 | with pyproject.open('rb') as f:
69 | release = tomllib.load(f)["project"]["version"]
70 |
71 | # A shorter version
72 | version = ".".join(release.split(".")[:2])
73 |
74 | # The language for content autogenerated by Sphinx. Refer to documentation
75 | # for a list of supported languages.
76 | #
77 | # This is also used if you do content translation via gettext catalogs.
78 | # Usually you set "language" from the command line for these cases.
79 | language = 'en'
80 |
81 | # There are two options for replacing |today|: either, you set today to some
82 | # non-false value, then it is used:
83 | #
84 | # today = ''
85 | #
86 | # Else, today_fmt is used as the format for a strftime call.
87 | #
88 | # today_fmt = '%B %d, %Y'
89 |
90 | # List of patterns, relative to source directory, that match files and
91 | # directories to ignore when looking for source files.
92 | # This patterns also effect to html_static_path and html_extra_path
93 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
94 |
95 | # The reST default role (used for this markup: `text`) to use for all
96 | # documents.
97 | #
98 | # default_role = None
99 |
100 | # If true, '()' will be appended to :func: etc. cross-reference text.
101 | #
102 | # add_function_parentheses = True
103 |
104 | # If true, the current module name will be prepended to all description
105 | # unit titles (such as .. function::).
106 | #
107 | # add_module_names = True
108 |
109 | # If true, sectionauthor and moduleauthor directives will be shown in the
110 | # output. They are ignored by default.
111 | #
112 | # show_authors = False
113 |
114 | # The name of the Pygments (syntax highlighting) style to use.
115 | pygments_style = 'sphinx'
116 |
117 | # A list of ignored prefixes for module index sorting.
118 | # modindex_common_prefix = []
119 |
120 | # If true, keep warnings as "system message" paragraphs in the built documents.
121 | # keep_warnings = False
122 |
123 | # If true, `todo` and `todoList` produce output, else they produce nothing.
124 | todo_include_todos = False
125 |
126 |
127 | # -- Options for HTML output ----------------------------------------------
128 |
129 | # The theme to use for HTML and HTML Help pages. See the documentation for
130 | # a list of builtin themes.
131 | #
132 | html_theme = 'furo'
133 |
134 |
135 | html_theme_options = {
136 | "source_repository": "https://github.com/scikit-build/cmake-python-distributions",
137 | "source_branch": "main",
138 | "source_directory": "docs/",
139 | "footer_icons": [
140 | {
141 | "name": "GitHub",
142 | "url": "https://github.com/scikit-build/cmake-python-distributions",
143 | "html": """
144 |
147 | """,
148 | "class": "",
149 | },
150 | ],
151 | }
152 | html_copy_source = False
153 | html_show_sourcelink = False
154 |
155 |
156 |
157 | # -- Options for LaTeX output ---------------------------------------------
158 |
159 | latex_elements = {
160 | # The paper size ('letterpaper' or 'a4paper').
161 | #
162 | # 'papersize': 'letterpaper',
163 |
164 | # The font size ('10pt', '11pt' or '12pt').
165 | #
166 | # 'pointsize': '10pt',
167 |
168 | # Additional stuff for the LaTeX preamble.
169 | #
170 | # 'preamble': '',
171 |
172 | # Latex figure (float) alignment
173 | #
174 | # 'figure_align': 'htbp',
175 | }
176 |
177 | # Grouping the document tree into LaTeX files. List of tuples
178 | # (source start file, target name, title,
179 | # author, documentclass [howto, manual, or own class]).
180 | latex_documents = [
181 | (main_doc, 'CMakePythonDistributions.tex', 'CMake Python Distributions Documentation',
182 | 'Jean-Christophe Fillion-Robin', 'manual'),
183 | ]
184 |
185 |
186 | # -- Options for manual page output ---------------------------------------
187 |
188 | # One entry per manual page. List of tuples
189 | # (source start file, name, description, authors, manual section).
190 | man_pages = [
191 | (main_doc, 'cmakepythondistributions', 'CMake Python Distributions Documentation',
192 | [author], 1)
193 | ]
194 |
195 | # If true, show URL addresses after external links.
196 | #
197 | # man_show_urls = False
198 |
199 |
200 | # -- Options for Texinfo output -------------------------------------------
201 |
202 | # Grouping the document tree into Texinfo files. List of tuples
203 | # (source start file, target name, title, author,
204 | # dir menu entry, description, category)
205 | texinfo_documents = [
206 | (main_doc, 'CMakePythonDistributions', 'CMake Python Distributions Documentation',
207 | author, 'CMakePythonDistributions', 'One line description of project.',
208 | 'Miscellaneous'),
209 | ]
210 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: '0 18 * * 5' # "At 18:00 on Friday."
7 | pull_request:
8 | push:
9 | branches:
10 | - main
11 | - py2-legacy
12 | - v3.x
13 | tags:
14 | - "*.*.*"
15 |
16 | concurrency:
17 | group: ${{ github.workflow }}-${{ github.ref }}
18 | cancel-in-progress: true
19 |
20 | jobs:
21 | lint:
22 | name: Lint
23 | runs-on: ubuntu-latest
24 | steps:
25 | - uses: actions/checkout@v6
26 | - uses: actions/setup-python@v6
27 | with:
28 | python-version: "3.x"
29 | - uses: pre-commit/action@v3.0.1
30 |
31 |
32 | build_wheels:
33 | name: Build ${{ matrix.build }}${{ matrix.arch }} wheels on ${{ matrix.os }}
34 | needs: [lint]
35 | runs-on: ${{ matrix.os }}
36 | strategy:
37 | fail-fast: false
38 | matrix:
39 | include:
40 | - os: ubuntu-latest
41 | arch: "x86_64"
42 | build: "manylinux_"
43 | - os: ubuntu-latest
44 | arch: "x86_64"
45 | build: "musllinux_"
46 | - os: ubuntu-latest
47 | arch: "i686"
48 | build: "manylinux_"
49 | - os: ubuntu-latest
50 | arch: "i686"
51 | build: "musllinux_"
52 | - os: ubuntu-24.04-arm
53 | arch: "aarch64"
54 | build: "manylinux_"
55 | - os: ubuntu-24.04-arm
56 | arch: "aarch64"
57 | build: "musllinux_"
58 | - os: ubuntu-latest
59 | arch: "ppc64le"
60 | build: "manylinux_"
61 | - os: ubuntu-latest
62 | arch: "ppc64le"
63 | build: "musllinux_"
64 | - os: ubuntu-latest
65 | arch: "s390x"
66 | build: "manylinux_"
67 | - os: ubuntu-latest
68 | arch: "s390x"
69 | build: "musllinux_"
70 | - os: ubuntu-latest
71 | arch: "riscv64"
72 | build: "manylinux_"
73 | - os: ubuntu-latest
74 | arch: "riscv64"
75 | build: "musllinux_"
76 | - os: ubuntu-24.04-arm
77 | arch: "armv7l"
78 | build: "manylinux_"
79 | - os: ubuntu-24.04-arm
80 | arch: "armv7l"
81 | build: "musllinux_"
82 | - os: windows-2022
83 | arch: "AMD64"
84 | build: ""
85 | - os: windows-11-arm
86 | arch: "ARM64"
87 | build: ""
88 | - os: windows-2022
89 | arch: "x86"
90 | build: ""
91 | - os: macos-14
92 | arch: "universal2"
93 | build: ""
94 |
95 | steps:
96 | - uses: actions/checkout@v6
97 | with:
98 | fetch-depth: 0 # required for versioneer to find tags
99 |
100 | - uses: astral-sh/setup-uv@v7
101 | with:
102 | enable-cache: false
103 |
104 | - name: Set up QEMU
105 | uses: docker/setup-qemu-action@v3.7.0
106 | if: matrix.arch == 'ppc64le' || matrix.arch == 'riscv64' || matrix.arch == 's390x'
107 |
108 | - name: Build wheels
109 | uses: pypa/cibuildwheel@v3.3
110 | env:
111 | CIBW_ARCHS: "${{ matrix.arch }}"
112 | CIBW_BUILD: "cp310-${{ matrix.build }}*"
113 |
114 | - uses: actions/upload-artifact@v6
115 | with:
116 | name: cibw-${{ runner.os }}-${{ matrix.build }}${{ matrix.arch }}
117 | path: ./wheelhouse/*.whl
118 |
119 | build_sdist:
120 | name: Build source distribution
121 | needs: [lint]
122 | runs-on: ubuntu-latest
123 | steps:
124 | - uses: actions/checkout@v6
125 | with:
126 | fetch-depth: 0 # required for versioneer to find tags
127 |
128 | - name: Build SDist
129 | run: pipx run build --sdist
130 |
131 | - uses: actions/upload-artifact@v6
132 | with:
133 | name: cibw-sdist
134 | path: dist/*.tar.gz
135 |
136 | test_sdist:
137 | name: Test SDist with python ${{ matrix.python }}
138 | needs: [build_sdist]
139 | runs-on: ubuntu-latest
140 | strategy:
141 | fail-fast: false
142 | matrix:
143 | python: ["3.8", "3.13"]
144 |
145 | steps:
146 | - uses: actions/checkout@v6
147 | - uses: astral-sh/setup-uv@v7
148 | with:
149 | enable-cache: false
150 |
151 | - name: Setup environment
152 | run: |
153 | uv venv --python ${{ matrix.python }}
154 | uv pip install --group test
155 |
156 | - name: Install dependencies
157 | run: |
158 | sudo apt-get update
159 | sudo apt-get install -y --no-install-recommends libssl-dev
160 |
161 | - uses: actions/download-artifact@v7
162 | with:
163 | name: cibw-sdist
164 | path: dist
165 |
166 | - name: Install SDist
167 | env:
168 | CMAKE_ARGS: "-DBUILD_CMAKE_FROM_SOURCE:BOOL=OFF"
169 | run: |
170 | uv pip install dist/*.tar.gz
171 | rm -rf dist
172 |
173 | - name: Test installed SDist
174 | run: .venv/bin/pytest ./tests
175 |
176 | bootstrap_build:
177 | name: Source only build on ${{ matrix.os }}
178 | needs: [lint]
179 | runs-on: ${{ matrix.os }}
180 | strategy:
181 | fail-fast: false
182 | matrix:
183 | os: ["ubuntu-latest", "windows-latest", "macos-latest"]
184 |
185 | steps:
186 | - uses: actions/checkout@v6
187 | - uses: actions/setup-python@v6
188 | id: python
189 | with:
190 | python-version: "3.x"
191 |
192 | - name: Remove cmake and ninja
193 | shell: bash
194 | run: |
195 | # Remove cmake and ninja
196 | set -euxo pipefail
197 | # https://github.com/scikit-build/scikit-build-core/blob/3943920fa267dc83f9295279bea1c774c0916f13/src/scikit_build_core/program_search.py#L51
198 | # https://github.com/scikit-build/scikit-build-core/blob/3943920fa267dc83f9295279bea1c774c0916f13/src/scikit_build_core/program_search.py#L70
199 | for TOOL in cmake cmake3 ninja-build ninja samu; do
200 | while which ${TOOL}; do
201 | if [ "$RUNNER_OS" == "Windows" ]; then
202 | rm -f "$(which ${TOOL})"
203 | else
204 | sudo rm -f $(which -a ${TOOL})
205 | fi
206 | done
207 | done
208 |
209 | - name: Build SDist
210 | run: pipx run --python '${{ steps.python.outputs.python-path }}' build --sdist
211 |
212 | - name: Install dependencies
213 | if: runner.os == 'Linux'
214 | run: |
215 | sudo apt-get update
216 | sudo apt-get install -y --no-install-recommends libssl-dev
217 |
218 | - name: Install SDist
219 | shell: bash
220 | env:
221 | CMAKE_ARGS: "-DBUILD_CMAKE_FROM_SOURCE:BOOL=OFF"
222 | CMAKE_BUILD_PARALLEL_LEVEL: "4"
223 | MACOSX_DEPLOYMENT_TARGET: "10.10"
224 | run: |
225 | python -m pip install -v --no-binary='cmake,ninja' dist/*.tar.gz
226 | rm -rf dist
227 |
228 | - name: Test installed SDist
229 | shell: bash
230 | run: python -m pip install pytest pytest-cov && pytest ./tests
231 |
232 | check_dist:
233 | name: Check dist
234 | needs: [build_wheels, build_sdist, test_sdist, bootstrap_build]
235 | runs-on: ubuntu-latest
236 | steps:
237 | - uses: actions/download-artifact@v7
238 | with:
239 | pattern: cibw-*
240 | merge-multiple: true
241 | path: dist
242 |
243 | - run: pipx run twine check --strict dist/*
244 |
245 | upload_pypi:
246 | name: Upload to PyPI
247 | needs: [check_dist]
248 | runs-on: ubuntu-latest
249 | if: github.event_name == 'push' && github.repository == 'scikit-build/cmake-python-distributions' && startsWith(github.ref, 'refs/tags/')
250 | environment:
251 | name: pypi
252 | url: https://pypi.org/p/cmake
253 | permissions:
254 | id-token: write
255 | attestations: write
256 | steps:
257 | - uses: actions/download-artifact@v7
258 | with:
259 | pattern: cibw-*
260 | merge-multiple: true
261 | path: dist
262 |
263 | - name: Generate artifact attestation for sdist and wheel
264 | uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
265 | with:
266 | subject-path: "dist/cmake-*"
267 |
268 | - uses: pypa/gh-action-pypi-publish@release/v1
269 | with:
270 | attestations: true
271 |
--------------------------------------------------------------------------------
/scripts/update_cmake_version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # /// script
4 | # dependencies = ["requests"]
5 | # ///
6 |
7 | """
8 | Command line executable allowing to update CMakeUrls.cmake given a CMake
9 | version.
10 | """
11 |
12 | from __future__ import annotations
13 |
14 | import argparse
15 | import contextlib
16 | import re
17 | import textwrap
18 | from pathlib import Path
19 |
20 | import requests
21 |
22 | TYPE_CHECKING = False
23 |
24 | if TYPE_CHECKING:
25 | from collections.abc import Generator, Mapping
26 |
27 |
28 | ROOT_DIR = Path(__file__).parent.parent.resolve()
29 |
30 |
31 | @contextlib.contextmanager
32 | def _log(txt: str, verbose: bool = True) -> Generator[None, None, None]:
33 | if verbose:
34 | print(txt)
35 | yield
36 | if verbose:
37 | print(f"{txt} - done")
38 |
39 |
40 | def _major_minor(version: str) -> str:
41 | """Given a string of the form ``X.Y.Z``, returns ``X.Y``."""
42 | return ".".join(version.split(".")[:2])
43 |
44 |
45 | def get_cmake_archive_urls_and_sha256s(version: str, verbose: bool=False) -> dict[str,tuple[str, str]]:
46 | files_base_url = (
47 | f"https://api.github.com/repos/Kitware/CMake/releases/tags/v{version}"
48 | )
49 |
50 | with _log(f"Collecting URLs and SHA256s from '{files_base_url}'"):
51 |
52 | assets = requests.get(files_base_url).json()["assets"]
53 |
54 | sha_256_file = f"cmake-{version}-SHA-256.txt"
55 |
56 | expected_files = {
57 | f"cmake-{version}.tar.gz": "unix_source",
58 | f"cmake-{version}.zip": "win_source",
59 | f"cmake-{version}-linux-x86_64.tar.gz": "linux64_binary",
60 | f"cmake-{version}-macos10.10-universal.tar.gz": "macos10_10_binary",
61 | f"cmake-{version}-windows-i386.zip": "win32_binary",
62 | f"cmake-{version}-windows-x86_64.zip": "win64_binary",
63 | f"cmake-{version}-windows-arm64.zip": "winarm64_binary",
64 | }
65 |
66 | # Get SHA256s for each asset
67 | shas = {}
68 | for asset in assets:
69 | if asset["name"] == sha_256_file:
70 | sha_256_url = asset["browser_download_url"]
71 | for line in requests.get(sha_256_url).text.splitlines():
72 | file = line.split()[1].strip()
73 | if file in expected_files:
74 | sha256 = line.split()[0].strip()
75 | identifier = expected_files[file]
76 | shas[identifier] = sha256
77 | assert len(shas) == len(expected_files), f"{len(shas)} != {len(expected_files)}"
78 |
79 | # Get download URLs for each asset
80 | urls = {}
81 | for asset in assets:
82 | if asset["name"] in expected_files:
83 | identifier = expected_files[asset["name"]]
84 | urls[identifier] = asset["browser_download_url"]
85 | if len(urls) != len(expected_files):
86 | expected_files_by_identifier = {
87 | value: key for key, value in expected_files.items()
88 | }
89 | missing_files = []
90 | for identifier in set(expected_files.values()) - set(urls.keys()):
91 | missing_files.append(expected_files_by_identifier[identifier])
92 | raise RuntimeError(
93 | f"Couldn't find {missing_files} at {files_base_url}"
94 | )
95 |
96 | # combine the URLs and SHA256s into a single dictionary
97 | zipped = {}
98 | for value in expected_files.values():
99 | print(f"[{value}]\n{urls[value]}\n{shas[value]}\n")
100 | zipped[value] = (urls[value], shas[value])
101 | assert len(zipped) == len(expected_files)
102 |
103 | if verbose:
104 | for identifier, (url, sha256) in zipped.items():
105 | print(f"[{identifier}]\n{url}\n{sha256}\n")
106 |
107 | return zipped
108 |
109 |
110 | def generate_cmake_variables(urls_and_sha256s: Mapping[str, tuple[str, str]]) -> str:
111 | template_inputs = {}
112 |
113 | # Get SHA256s and URLs
114 | for var_prefix, urls_and_sha256s_values in urls_and_sha256s.items():
115 | template_inputs[f"{var_prefix}_url"] = urls_and_sha256s_values[0]
116 | template_inputs[f"{var_prefix}_sha256"] = urls_and_sha256s_values[1]
117 |
118 | return textwrap.dedent(
119 | """
120 | #-----------------------------------------------------------------------------
121 | # CMake sources
122 | set(unix_source_url "{unix_source_url}")
123 | set(unix_source_sha256 "{unix_source_sha256}")
124 |
125 | set(windows_source_url "{win_source_url}")
126 | set(windows_source_sha256 "{win_source_sha256}")
127 |
128 | #-----------------------------------------------------------------------------
129 | # CMake binaries
130 |
131 | set(linux32_binary_url "NA") # Linux 32-bit binaries not available
132 | set(linux32_binary_sha256 "NA")
133 |
134 | set(linux64_binary_url "{linux64_binary_url}")
135 | set(linux64_binary_sha256 "{linux64_binary_sha256}")
136 |
137 | set(macos10_10_binary_url "{macos10_10_binary_url}")
138 | set(macos10_10_binary_sha256 "{macos10_10_binary_sha256}")
139 |
140 | set(win32_binary_url "{win32_binary_url}")
141 | set(win32_binary_sha256 "{win32_binary_sha256}")
142 |
143 | set(win64_binary_url "{win64_binary_url}")
144 | set(win64_binary_sha256 "{win64_binary_sha256}")
145 |
146 | set(winarm64_binary_url "{winarm64_binary_url}")
147 | set(winarm64_binary_sha256 "{winarm64_binary_sha256}")
148 | """
149 | ).format(**template_inputs)
150 |
151 |
152 | def update_cmake_urls_script(version: str) -> set[str]:
153 | content = generate_cmake_variables(get_cmake_archive_urls_and_sha256s(version))
154 | cmake_urls_filename = "CMakeUrls.cmake"
155 | cmake_urls_filepath = ROOT_DIR / cmake_urls_filename
156 |
157 | msg = f"Updating '{cmake_urls_filename}' with CMake version {version}"
158 | with _log(msg), cmake_urls_filepath.open("w") as cmake_file:
159 | cmake_file.write(content)
160 |
161 | return {cmake_urls_filename}
162 |
163 |
164 | def _update_file(filepath: Path, regex: re.Pattern[str], replacement: str) -> None:
165 | with _log(f"Updating {filepath.relative_to(ROOT_DIR)}"):
166 | pattern = re.compile(regex)
167 | with filepath.open() as doc_file:
168 | updated_content = [pattern.sub(replacement, line) for line in doc_file]
169 | with filepath.open("w") as doc_file:
170 | doc_file.writelines(updated_content)
171 |
172 |
173 | def update_docs(version: str) -> set[str]:
174 | pattern = re.compile(
175 | r"CMake \d.(\d)+.\d "
176 | )
177 | replacement = f"CMake {version} "
178 | files = {"docs/index.rst", "README.rst"}
179 | for filename in files:
180 | _update_file(ROOT_DIR / filename, pattern, replacement)
181 | return files
182 |
183 |
184 | def update_tests(version: str) -> set[str]:
185 | pattern = re.compile(r'expected_version = "\d.\d+.\d"')
186 | replacement = f'expected_version = "{version}"'
187 | filename = "tests/test_cmake.py"
188 | _update_file(
189 | ROOT_DIR / filename, pattern, replacement
190 | )
191 | return {filename}
192 |
193 |
194 | def update_pyproject_toml(version: str) -> set[str]:
195 | pattern = re.compile(r'^version = "[\w\.]+"$')
196 | replacement = f'version = "{version}"'
197 | filename = "pyproject.toml"
198 | _update_file(
199 | ROOT_DIR / filename, pattern, replacement
200 | )
201 | return {filename}
202 |
203 |
204 | def update_raw_versions(version: str, filename: str) -> set[str]:
205 | pattern = re.compile(r"\d\.\d+\.\d")
206 | replacement = version
207 | _update_file(
208 | ROOT_DIR / filename, pattern, replacement
209 | )
210 | return {filename}
211 |
212 |
213 | def main() -> None:
214 | parser = argparse.ArgumentParser(description=__doc__)
215 | parser.add_argument(
216 | "cmake_version",
217 | metavar="CMAKE_VERSION",
218 | type=str,
219 | help="CMake version of the form X.Y.Z",
220 | )
221 | parser.add_argument(
222 | "--collect-only",
223 | action="store_true",
224 | help="If specified, only display the archive URLs and associated hashsums",
225 | )
226 | parser.add_argument(
227 | "--quiet",
228 | action="store_true",
229 | help="Hide the output",
230 | )
231 | args = parser.parse_args()
232 |
233 | if args.collect_only:
234 | get_cmake_archive_urls_and_sha256s(args.cmake_version, verbose=True)
235 | return
236 |
237 | filenames = set()
238 | filenames |= update_cmake_urls_script(args.cmake_version)
239 | filenames |= update_docs(args.cmake_version)
240 | filenames |= update_tests(args.cmake_version)
241 | filenames |= update_raw_versions(args.cmake_version, "docs/update_cmake_version.rst")
242 | filenames |= update_raw_versions(args.cmake_version, "docs/make_a_release.rst")
243 | filenames |= update_pyproject_toml(args.cmake_version)
244 |
245 | if args.quiet:
246 | return
247 |
248 | msg = f"""\
249 | Complete! Now run:
250 |
251 | git switch -c update-to-cmake-{args.cmake_version}
252 | git add -u {' '.join(filenames)}
253 | git commit -m "Update to CMake {args.cmake_version}"
254 | gh pr create --fill --body "Created by update_cmake_version.py"
255 | """
256 | print(textwrap.dedent(msg))
257 |
258 |
259 | if __name__ == "__main__":
260 | main()
261 |
--------------------------------------------------------------------------------
/LICENSE_Apache_20:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "[]" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright [yyyy] [name of copyright owner]
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
192 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15...4.0)
2 |
3 | #
4 | # For more details, see docs/building.rst
5 | #
6 |
7 | project(CMakePythonDistributions NONE)
8 |
9 | # Set a default build type if none was specified
10 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
11 | message(STATUS "Setting build type to 'Release' as none was specified.")
12 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
13 | mark_as_advanced(CMAKE_BUILD_TYPE)
14 | # Set the possible values of build type for cmake-gui
15 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
16 | endif()
17 |
18 | if(NOT DEFINED CMakePythonDistributions_SUPERBUILD)
19 | set(CMakePythonDistributions_SUPERBUILD 1)
20 | endif()
21 |
22 | if(CMakePythonDistributions_SUPERBUILD)
23 |
24 | enable_language(CXX)
25 |
26 | #-----------------------------------------------------------------------------
27 | # Options
28 | set(default ON)
29 | if(WIN32 OR APPLE)
30 | set(default OFF)
31 | endif()
32 | option(BUILD_CMAKE_FROM_SOURCE "Build CMake from source" ${default})
33 |
34 | option(BUILD_VERBOSE "Build reporting additional information (e.g download progress, ...)" ON)
35 |
36 | option(RUN_CMAKE_TEST "Run CMake test suite when built from sources" OFF)
37 |
38 | set(RUN_CMAKE_TEST_EXCLUDE "BootstrapTest" CACHE STRING "CMake test suite exclusion regex")
39 |
40 | set(CMakePythonDistributions_ARCHIVE_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}"
41 | CACHE PATH "Directory where to download archives"
42 | )
43 |
44 | message(STATUS "***************************************************")
45 | message(STATUS "Build CMake from source: ${BUILD_CMAKE_FROM_SOURCE}")
46 | message(STATUS "***************************************************")
47 |
48 | include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeUrls.cmake)
49 |
50 | #-----------------------------------------------------------------------------
51 | # Which archives ?
52 |
53 | function(check_archive_var archive_var)
54 | if(NOT DEFINED "${archive_var}_url")
55 | message(FATAL_ERROR "Failed to determine which archive to download: '${archive_var}_url' variable is not defined")
56 | endif()
57 | if(NOT DEFINED "${archive_var}_sha256")
58 | message(FATAL_ERROR "Could you make sure variable '${archive_var}_sha256' is defined ?")
59 | endif()
60 | endfunction()
61 |
62 | set(src_archive "unix_source")
63 | if(WIN32)
64 | set(src_archive "windows_source")
65 | endif()
66 | check_archive_var("${src_archive}")
67 |
68 | set(binary_archive "linux32_binary")
69 | if(CMAKE_SIZEOF_VOID_P EQUAL 8)
70 | set(binary_archive "linux64_binary")
71 | endif()
72 | if(APPLE)
73 | if(CMAKE_OSX_DEPLOYMENT_TARGET AND "${CMAKE_OSX_DEPLOYMENT_TARGET}" VERSION_LESS "10.10")
74 | message(FATAL_ERROR "Unsupported macOS deployment target: ${CMAKE_OSX_DEPLOYMENT_TARGET} is less than 10.10")
75 | else()
76 | set(binary_archive "macos10_10_binary")
77 | endif()
78 | endif()
79 | if(WIN32)
80 | set(binary_archive "win32_binary")
81 | if(CMAKE_SIZEOF_VOID_P EQUAL 8)
82 | if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ARM64" OR "$ENV{SETUPTOOLS_EXT_SUFFIX}" MATCHES arm64)
83 | set(binary_archive "winarm64_binary")
84 | else()
85 | set(binary_archive "win64_binary")
86 | endif()
87 | endif()
88 | endif()
89 | check_archive_var("${binary_archive}")
90 |
91 | #-----------------------------------------------------------------------------
92 | include(ExternalProject)
93 |
94 | # Add an empty external project
95 | function(cpd_ExternalProject_Add_Empty proj depends)
96 | set(depends_args)
97 | if(NOT depends STREQUAL "")
98 | set(depends_args DEPENDS ${depends})
99 | endif()
100 | ExternalProject_add(${proj}
101 | SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}
102 | DOWNLOAD_COMMAND ""
103 | UPDATE_COMMAND ""
104 | CONFIGURE_COMMAND ""
105 | BUILD_COMMAND ""
106 | BUILD_IN_SOURCE 1
107 | INSTALL_COMMAND ""
108 | ${depends_args}
109 | )
110 | endfunction()
111 |
112 | # Add an external project step named `forceconfigure` to `project_name` ensuring
113 | # the project will always be reconfigured.
114 | #
115 | # Copied from ExternalProjectDependency.cmake (commontk/Artichoke@613e3739a)
116 | function(cpd_ExternalProject_AlwaysConfigure proj)
117 | _ep_get_step_stampfile(${proj} "configure" stampfile)
118 | ExternalProject_Add_Step(${proj} forceconfigure
119 | COMMAND ${CMAKE_COMMAND} -E remove ${stampfile}
120 | COMMENT "Forcing configure step for '${proj}'"
121 | DEPENDEES build
122 | ALWAYS 1
123 | )
124 | endfunction()
125 |
126 | # Note: To minimize confusion between variables defined by CMake and
127 | # variables used in this project. The following convention applies:
128 | # CMakeProject_xxx : Variables defined in this project
129 | # CMAKE_xxx : Variables set by CMake
130 |
131 | set(${PROJECT_NAME}_CMAKE_CACHE_ARG)
132 |
133 | set(ep_download_no_progress_args)
134 | set(ep_log_configure_build_args)
135 | if(NOT BUILD_VERBOSE)
136 | set(ep_download_no_progress_args
137 | DOWNLOAD_NO_PROGRESS 1
138 | )
139 | set(ep_log_configure_build_args
140 | LOG_CONFIGURE 1
141 | LOG_BUILD 1
142 | )
143 | endif()
144 |
145 | set(ep_download_extract_timestamp_arg)
146 | if(CMAKE_VERSION VERSION_EQUAL "3.24" OR CMAKE_VERSION VERSION_GREATER "3.24")
147 | # See https://cmake.org/cmake/help/latest/policy/CMP0135.html
148 | set(ep_download_extract_timestamp_arg DOWNLOAD_EXTRACT_TIMESTAMP 1)
149 | endif()
150 |
151 | #
152 | # CMakeProject_SOURCE_DIR: Always expect the sources (needed for `sdist`)
153 | #
154 | if(NOT DEFINED CMakeProject_SOURCE_DIR)
155 | set(CMakeProject_SOURCE_DIR "${CMAKE_SOURCE_DIR}/CMake-src")
156 |
157 | # Download selected source archive
158 | ExternalProject_add(CMakeProject-src-download
159 | SOURCE_DIR ${CMakeProject_SOURCE_DIR}
160 | URL ${${src_archive}_url}
161 | URL_HASH SHA256=${${src_archive}_sha256}
162 | DOWNLOAD_DIR ${CMakePythonDistributions_ARCHIVE_DOWNLOAD_DIR}
163 | USES_TERMINAL_DOWNLOAD 1
164 | CONFIGURE_COMMAND ""
165 | BUILD_COMMAND ""
166 | BUILD_IN_SOURCE 1
167 | INSTALL_COMMAND ""
168 | ${ep_download_extract_timestamp_arg}
169 | ${ep_download_no_progress_args}
170 | )
171 | message(STATUS "SuperBuild - CMakeProject-src-download")
172 | message(STATUS "SuperBuild - CMakeProject-src-download - URL: ${${src_archive}_url}")
173 | else()
174 | cpd_ExternalProject_Add_Empty(CMakeProject-src-download "")
175 | message(STATUS "SuperBuild - CMakeProject-src-download")
176 | endif()
177 | message(STATUS "SuperBuild - CMakeProject-src-download - CMakeProject_SOURCE_DIR: ${CMakeProject_SOURCE_DIR}")
178 |
179 | if(NOT EXISTS ${CMakeProject_SOURCE_DIR})
180 | message(FATAL_ERROR "CMakeProject_SOURCE_DIR variable is defined but corresponds to nonexistent directory")
181 | endif()
182 |
183 | list(APPEND ${PROJECT_NAME}_DEPENDS CMakeProject-src-download)
184 |
185 | if(BUILD_CMAKE_FROM_SOURCE)
186 |
187 | #
188 | # CMakeProject_BINARY_DIR
189 | #
190 | if(NOT DEFINED CMakeProject_BINARY_DIR)
191 |
192 | # cmake cache arguments
193 | set(_cmake_cache_args)
194 |
195 | if(UNIX AND NOT APPLE)
196 | # glibc check
197 | # as of CMake 3.23.0, the minimum supported version of libuv is 1.28.0.
198 | # this implies that the minimum supported glibc version is 2.12
199 | # https://github.com/libuv/libuv/blob/v1.x/SUPPORTED_PLATFORMS.md
200 | include(CheckSymbolExists)
201 | check_symbol_exists(__GLIBC__ "stdlib.h" HAS_GLIBC_MAJOR)
202 | check_symbol_exists(__GLIBC_MINOR__ "stdlib.h" HAS_GLIBC_MINOR)
203 | if(HAS_GLIBC_MAJOR AND HAS_GLIBC_MINOR AND (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"))
204 | execute_process(COMMAND echo __GLIBC__ COMMAND "${CMAKE_CXX_COMPILER}" -E -P -imacros stdlib.h - OUTPUT_VARIABLE GLIBC_MAJOR_)
205 | string(STRIP "${GLIBC_MAJOR_}" GLIBC_MAJOR)
206 | execute_process(COMMAND echo __GLIBC_MINOR__ COMMAND "${CMAKE_CXX_COMPILER}" -E -P -imacros stdlib.h - OUTPUT_VARIABLE GLIBC_MINOR_)
207 | string(STRIP "${GLIBC_MINOR_}" GLIBC_MINOR)
208 | if("${GLIBC_MAJOR}.${GLIBC_MINOR}" VERSION_LESS "2.12")
209 | message(FATAL_ERROR "GLIBC ${GLIBC_MAJOR}.${GLIBC_MINOR} not supported")
210 | endif()
211 | endif()
212 |
213 | # Y2K38 support
214 | include(CMakePushCheckState)
215 | cmake_push_check_state(RESET)
216 | set(CMAKE_REQUIRED_DEFINITIONS -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64)
217 | set(CMAKE_EXTRA_INCLUDE_FILES "time.h")
218 | include(CheckTypeSize)
219 | check_type_size(time_t SIZEOF_TIME_T LANGUAGE CXX)
220 | cmake_pop_check_state()
221 | if(HAVE_SIZEOF_TIME_T)
222 | if(SIZEOF_TIME_T LESS 8)
223 | list(APPEND _cmake_cache_args
224 | -DCMake_TEST_NO_64BIT_TIME:BOOL=TRUE
225 | )
226 | message(STATUS "SuperBuild - CMakeProject-build - 64-bit time tests disabled")
227 | endif()
228 | endif()
229 | endif()
230 |
231 | if(DEFINED CMAKE_BUILD_TYPE)
232 | list(APPEND _cmake_cache_args
233 | -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
234 | )
235 | endif()
236 | if(DEFINED CMAKE_TOOLCHAIN_FILE)
237 | list(APPEND _cmake_cache_args
238 | -DCMAKE_TOOLCHAIN_FILE:STRING=${CMAKE_TOOLCHAIN_FILE}
239 | )
240 | endif()
241 | foreach(var_name IN ITEMS
242 | CMAKE_BUILD_PARALLEL_LEVEL
243 | CMAKE_JOB_POOLS
244 | CMAKE_JOB_POOL_COMPILE
245 | CMAKE_JOB_POOL_LINK
246 | CMAKE_LINKER_TYPE
247 | )
248 | if(DEFINED ${var_name})
249 | list(APPEND _cmake_cache_args
250 | -D${var_name}:STRING=${${var_name}}
251 | )
252 | message(STATUS "SuperBuild - CMakeProject-build - ${var_name}: ${${var_name}}")
253 | endif()
254 | endforeach()
255 |
256 | if(DEFINED OPENSSL_ROOT_DIR)
257 | list(APPEND _cmake_cache_args
258 | -DOPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR}
259 | )
260 | message(STATUS "SuperBuild - CMakeProject-build - OPENSSL_ROOT_DIR: ${OPENSSL_ROOT_DIR}")
261 | endif()
262 |
263 | if(DEFINED OPENSSL_USE_STATIC_LIBS)
264 | list(APPEND _cmake_cache_args
265 | -DOPENSSL_USE_STATIC_LIBS:BOOL=${OPENSSL_USE_STATIC_LIBS}
266 | )
267 | message(STATUS "SuperBuild - CMakeProject-build - OPENSSL_USE_STATIC_LIBS: ${OPENSSL_USE_STATIC_LIBS}")
268 | endif()
269 |
270 | if(DEFINED CMAKE_CXX_STANDARD)
271 | list(APPEND _cmake_cache_args
272 | -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD}
273 | )
274 | message(STATUS "SuperBuild - CMakeProject-build - CMAKE_CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
275 | endif()
276 |
277 | set(_cmake_args )
278 | if(UNIX AND (NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD"))
279 | # Since CMAKE_C_FLAGS and CMAKE_EXE_LINKER_FLAGS arguments contain spaces, we generate an initial
280 | # cache file.
281 | file(WRITE "${CMAKE_BINARY_DIR}/initial-cache.txt"
282 | "set(CMAKE_C_FLAGS \"-D_POSIX_C_SOURCE=199506L -D_POSIX_SOURCE=1 -D_SVID_SOURCE=1 -D_BSD_SOURCE=1\" CACHE STRING \"Initial cache\" FORCE)
283 | set(CMAKE_EXE_LINKER_FLAGS \"-lstdc++ -lgcc -lrt\" CACHE STRING \"Initial cache\" FORCE)
284 | ")
285 | set(_cmake_args
286 | CMAKE_ARGS -C "${CMAKE_BINARY_DIR}/initial-cache.txt"
287 | )
288 | endif()
289 |
290 | # cmake
291 | set(CMakeProject_BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeProject-build)
292 |
293 | ExternalProject_add(CMakeProject-build
294 | SOURCE_DIR ${CMakeProject_SOURCE_DIR}
295 | BINARY_DIR ${CMakeProject_BINARY_DIR}
296 | DOWNLOAD_COMMAND ""
297 | UPDATE_COMMAND ""
298 | BUILD_ALWAYS 1
299 | ${_cmake_args}
300 | CMAKE_CACHE_ARGS
301 | -DBUILD_CursesDialog:BOOL=ON
302 | -DCMAKE_USE_OPENSSL:BOOL=ON
303 | -DBUILD_TESTING:BOOL=ON
304 | -DCMake_INSTALL_DEPENDENCIES:BOOL=ON
305 | -DCMAKE_INSTALL_MESSAGE:STRING=NEVER
306 | ${_cmake_cache_args}
307 | USES_TERMINAL_CONFIGURE 1
308 | USES_TERMINAL_BUILD 1
309 | ${ep_log_configure_build_args}
310 | INSTALL_COMMAND ""
311 | DEPENDS
312 | CMakeProject-src-download
313 | )
314 |
315 | set(CMAKEPROJECT_BUILD_LAST_STEP "build")
316 |
317 | if(RUN_CMAKE_TEST)
318 | include(ProcessorCount)
319 | ProcessorCount(NB_CPU)
320 | if(NB_CPU EQUAL 0)
321 | set(NB_CPU 2)
322 | endif()
323 | ExternalProject_Add_Step(CMakeProject-build run_cmake_test_suite
324 | DEPENDEES ${CMAKEPROJECT_BUILD_LAST_STEP}
325 | COMMENT "Running CMake test suite, exclusion list: '${RUN_CMAKE_TEST_EXCLUDE}'"
326 | COMMAND ./bin/ctest --force-new-ctest-process --stop-on-failure --output-on-failure -j${NB_CPU} -E ${RUN_CMAKE_TEST_EXCLUDE}
327 | WORKING_DIRECTORY ${CMakeProject_BINARY_DIR}
328 | USES_TERMINAL 1
329 | )
330 | set(CMAKEPROJECT_BUILD_LAST_STEP "run_cmake_test_suite")
331 | endif()
332 | else()
333 | cpd_ExternalProject_Add_Empty(CMakeProject-build "CMakeProject-src-download")
334 | endif()
335 | message(STATUS "SuperBuild - CMakeProject-build")
336 | message(STATUS "SuperBuild - CMakeProject-build - CMakeProject_BINARY_DIR: ${CMakeProject_BINARY_DIR}")
337 |
338 | if(NOT EXISTS ${CMakeProject_BINARY_DIR})
339 | message(FATAL_ERROR "CMakeProject_BINARY_DIR variable is defined but corresponds to nonexistent directory")
340 | endif()
341 |
342 | list(APPEND ${PROJECT_NAME}_DEPENDS CMakeProject-build)
343 | list(APPEND ${PROJECT_NAME}_CMAKE_CACHE_ARG
344 | -DCMakeProject_BINARY_DIR:PATH=${CMakeProject_BINARY_DIR}
345 | )
346 |
347 | else()
348 |
349 | #
350 | # CMakeProject_BINARY_DISTRIBUTION_DIR
351 | #
352 |
353 | if(${binary_archive}_sha256 STREQUAL "NA")
354 | message(FATAL_ERROR "Pre-built archives not available for '${binary_archive}'. Consider setting BUILD_CMAKE_FROM_SOURCE to ON.")
355 | endif()
356 |
357 | set(CMakeProject_BINARY_DISTRIBUTION_DIR "${CMAKE_BINARY_DIR}/CMakeProject-binary-distribution")
358 |
359 | # Download selected binary archive
360 | ExternalProject_add(CMakeProject-binary-download
361 | SOURCE_DIR ${CMakeProject_BINARY_DISTRIBUTION_DIR}
362 | URL ${${binary_archive}_url}
363 | URL_HASH SHA256=${${binary_archive}_sha256}
364 | DOWNLOAD_DIR ${CMakePythonDistributions_ARCHIVE_DOWNLOAD_DIR}
365 | USES_TERMINAL_DOWNLOAD 1
366 | CONFIGURE_COMMAND ""
367 | BUILD_COMMAND ""
368 | BUILD_IN_SOURCE 1
369 | INSTALL_COMMAND ""
370 | ${ep_download_extract_timestamp_arg}
371 | ${ep_download_no_progress_args}
372 | )
373 | message(STATUS "SuperBuild - CMakeProject-binary-download")
374 | message(STATUS "SuperBuild - CMakeProject-binary-download - URL: ${${binary_archive}_url}")
375 |
376 | list(APPEND ${PROJECT_NAME}_DEPENDS CMakeProject-binary-download)
377 | list(APPEND ${PROJECT_NAME}_CMAKE_CACHE_ARG
378 | -DCMakeProject_BINARY_DISTRIBUTION_DIR:PATH=${CMakeProject_BINARY_DISTRIBUTION_DIR}
379 | )
380 |
381 | endif()
382 |
383 | ExternalProject_add(${PROJECT_NAME}
384 | SOURCE_DIR ${CMAKE_SOURCE_DIR}
385 | BINARY_DIR ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build
386 | DOWNLOAD_COMMAND ""
387 | UPDATE_COMMAND ""
388 | CMAKE_CACHE_ARGS
389 | -D${PROJECT_NAME}_SUPERBUILD:BOOL=0
390 | -DBUILD_CMAKE_FROM_SOURCE:BOOL=${BUILD_CMAKE_FROM_SOURCE}
391 | -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX}
392 | ${${PROJECT_NAME}_CMAKE_CACHE_ARG}
393 | USES_TERMINAL_CONFIGURE 1
394 | USES_TERMINAL_BUILD 1
395 | INSTALL_COMMAND ""
396 | DEPENDS
397 | ${${PROJECT_NAME}_DEPENDS}
398 | )
399 | message(STATUS "SuperBuild - ${PROJECT_NAME}")
400 |
401 | cpd_ExternalProject_AlwaysConfigure(${PROJECT_NAME})
402 |
403 | # This adds an "install" target in the top-level directory. The
404 | # target will simply include the install rules associated with the
405 | # inner build
406 | install(SCRIPT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build/cmake_install.cmake)
407 |
408 | else()
409 |
410 | #-----------------------------------------------------------------------------
411 | if(BUILD_CMAKE_FROM_SOURCE)
412 |
413 | # Install CMakeProject
414 | install(CODE "
415 | message(STATUS \"Install CMake project\")
416 | include\(\"${CMakeProject_BINARY_DIR}/cmake_install.cmake\")
417 | ")
418 |
419 | #-----------------------------------------------------------------------------
420 | else()
421 |
422 | set(CMAKE_INSTALL_MESSAGE "NEVER")
423 |
424 | if(APPLE)
425 | set(distribution_root "${CMakeProject_BINARY_DISTRIBUTION_DIR}/CMake.app/Contents")
426 | else()
427 | set(distribution_root "${CMakeProject_BINARY_DISTRIBUTION_DIR}")
428 | endif()
429 |
430 | # Install all files from binary distribution
431 | file(GLOB_RECURSE binary_distribution_files
432 | LIST_DIRECTORIES FALSE
433 | ${distribution_root}/*
434 | )
435 | foreach(file IN LISTS binary_distribution_files)
436 | # Skip symlinks like "CMake.app/Contents/Frameworks/QtWidgets.framework/Versions/Current"
437 | if(IS_SYMLINK ${file})
438 | continue()
439 | endif()
440 |
441 | # skip some mac app bundle files
442 | set(find_index -1)
443 | foreach(name IN ITEMS CodeResources Info.plist Frameworks _CodeSignature MacOS PlugIns Resources doc/cmake/html man)
444 | string(FIND "${file}" "${distribution_root}/${name}" find_index)
445 | if("${find_index}" EQUAL 0)
446 | break()
447 | endif()
448 | endforeach()
449 | if("${find_index}" EQUAL 0)
450 | continue()
451 | endif()
452 |
453 | get_filename_component(directory ${file} DIRECTORY)
454 | file(RELATIVE_PATH relative_directory ${distribution_root} ${directory})
455 | set(type FILES)
456 | if(relative_directory STREQUAL "bin")
457 | set(type PROGRAMS)
458 | endif()
459 | set(_permissions)
460 | get_filename_component(filename ${file} NAME)
461 | if(filename MATCHES "ccmake|cmake|cmake-gui|cpack|ctest")
462 | set(_permissions PERMISSIONS
463 | OWNER_READ OWNER_WRITE OWNER_EXECUTE
464 | GROUP_READ GROUP_EXECUTE
465 | WORLD_READ WORLD_EXECUTE
466 | )
467 | endif()
468 | install(${type} ${file} DESTINATION "${relative_directory}" ${_permissions})
469 | endforeach()
470 | endif()
471 | endif()
472 |
--------------------------------------------------------------------------------