Skip to content

Modernize build system to use pyproject.toml and build wheels #267

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4aa4ef0
greenlet 3.0.0 drops support for python 3.6
mayantaylor Aug 3, 2024
d928ba0
draft pyproject.toml
mayantaylor Aug 4, 2024
02137a0
adding templated build wheel yaml
mayantaylor Aug 4, 2024
6691369
Merge branch 'maya/version-updates' of https://github.com/UIUC-PPL/ch…
mayantaylor Aug 4, 2024
caf3095
set up build wheel action
mayantaylor Aug 4, 2024
8e568e8
set up testpypi upload action
mayantaylor Aug 5, 2024
b348996
don't need cmake? not used
mayantaylor Aug 5, 2024
24a546c
cleanup
mayantaylor Aug 13, 2024
1e39a5b
adding pypy builds
mayantaylor Aug 25, 2024
1c9fc93
Merge remote-tracking branch 'origin/main' into maya/modernize-build
mayantaylor Aug 25, 2024
71e3c6a
work around pypy dev0 checkout
mayantaylor Aug 25, 2024
519f49f
adding comments
mayantaylor Aug 25, 2024
3e95006
updating installation instructions
mayantaylor Aug 26, 2024
acdaaa8
action to publish to pypi
mayantaylor Aug 26, 2024
0a86514
tmp commit to get action to flush
mayantaylor Aug 26, 2024
ac5e394
tmp commit to get action to flush on PR
mayantaylor Aug 26, 2024
12ed471
restoring upload action
mayantaylor Aug 26, 2024
c15d8d2
adding source dist
mayantaylor Aug 26, 2024
3650c7b
fetch full depth
mayantaylor Aug 26, 2024
b24c6ce
adding source dist to upload
mayantaylor Aug 26, 2024
9b102c5
line break
ritvikrao Aug 28, 2024
d45528e
experiment without github charm token
mayantaylor Aug 28, 2024
9494b2a
cleanup - somehow checkout charm_src got duplicated
mayantaylor Aug 28, 2024
9e6cf3f
remove manual requirements installation instructions (handled by pip …
mayantaylor Aug 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/build_wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Build wheels

on: workflow_dispatch

jobs:
build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch full history, necessary for git describe in setup.py

- name: Build sdist
run: pipx run build --sdist

- uses: actions/upload-artifact@v4
with:
name: cibw-sdist
path: dist/*.tar.gz

build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, macos-13, macos-14]

steps:
- uses: actions/setup-python@v5
with:
python-version: 3.8
if: runner.os == 'macOS' && runner.arch == 'ARM64'

- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch full history, necessary for git describe in setup.py

- name: Checkout charm_src # is this best practice? should we use a submodule?
uses: actions/checkout@v4
with:
repository: charmplusplus/charm
token: ${{ secrets.GITHUB_TOKEN }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the token here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we don't, I removed it

path: charm_src/charm
fetch-depth: 0 # Fetch full history, necessary for commit_str parsing in setup.py

- name: Checkout charm_src # is this best practice? should we use a submodule?
uses: actions/checkout@v4
with:
repository: charmplusplus/charm
token: ${{ secrets.GITHUB_TOKEN }}
path: charm_src/charm
fetch-depth: 0 # Fetch full history, necessary for commit_str parsing in setup.py

- name: Build wheels
env:
CIBW_SKIP: "*-manylinux_i686 *-manylinux_ppc64le *-manylinux_s390x *musllinux_*"
uses: pypa/cibuildwheel@v2.20.0

- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
39 changes: 39 additions & 0 deletions .github/workflows/upload_pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Publish wheels to pypi

on:
workflow_dispatch:
inputs:
workflow_id:
description: "The workflow ID to pull wheels from"
required: true
type: string

jobs:
publish:
name: Publish Python 🐍 distribution 📦 to PyPI
runs-on: ubuntu-latest

environment:
name: pypi
url: https://pypi.org/p/charm4py

permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing

steps:
- name: Download all the dists
uses: dawidd6/action-download-artifact@v2
with:
# download all the wheels
path: unmerged
run_id: ${{ github.event.inputs.workflow_id }}
workflow: build_wheels.yml

- name: Merge files to dist
run: |
mkdir dist
mv unmerged/*/*.whl dist
mv unmerged/*/*.tar.gz dist

- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
41 changes: 41 additions & 0 deletions .github/workflows/upload_testpypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Publish wheels to testpypi

on:
workflow_dispatch:
inputs:
workflow_id:
description: "The workflow ID to pull wheels from"
required: true
type: string

jobs:
publish_test:
name: Publish Python 🐍 distribution 📦 to TestPyPI
runs-on: ubuntu-latest

environment:
name: testpypi
url: https://test.pypi.org/p/charm4py

permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing

steps:
- name: Download all the dists
uses: dawidd6/action-download-artifact@v2
with:
# download all the wheels
path: unmerged
run_id: ${{ github.event.inputs.workflow_id }}
workflow: build_wheels.yml

- name: Merge files to dist
run: |
mkdir dist
mv unmerged/*/*.whl dist
mv unmerged/*/*.tar.gz dist

- name: Publish distribution 📦 to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
79 changes: 43 additions & 36 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,82 +7,89 @@ Install
Charm4py runs on Linux, macOS, Windows, Raspberry Pi, and a wide variety of clusters and
supercomputer environments (including many supercomputers in the TOP500).

Charm4py runs on Python 3.4+. Charm4py has been tested with the
Charm4py runs on Python 3.7+. Charm4py has been tested with the
following Python implementations:
CPython (most common implementation) and PyPy_.


.. _PyPy: https://pypy.org

Installing Charm4Py binaries (via pip)
---------------------------------------

Installing Charm4Py on a laptop/personal machine
------------------------------------------------
The easiest way to install Charm4Py is via pip. Currently, pip wheels are available for Linux and macOS.

This install process covers the installation of Charm4Py on a laptop or personal machine, as opposed to a cluster.
To install the latest release of Charm4Py, run::

$ pip install charm4py

This will install the latest stable release of Charm4Py, using the default underlying Charm++ build
(see the `Charm++ manual`_ for more information on the different builds of Charm++). If you want to
use a specific Charm++ build, you can install and build Charm4Py from source.

Installing Charm4Py from source
------------------------------------------------------------

This install process covers the installation of Charm4Py from source.

Before installing, you need the following prerequisites:
- CPython: numpy, greenlet and cython (``pip3 install 'numpy>=1.10.0' cython greenlet``)
- CPython: numpy, greenlet and cython (``pip install numpy>=1.10.0 greenlet>=3.0.0 cython>=3.0.0``)
- PyPy: none

You can get these prerequisites by running the following command::

$ pip3 install -r requirements.txt
$ pip install -r requirements.txt

The first step is to clone the Charm4py repository from Git::

$ git clone https://github.com/charmplusplus/charm4py.git
$ cd charm4py

Next, create a folder called charm_src in the charm4py repo, and then clone the Charm++ repo
into that folder::
Next, clone the Charm++ repo into charm_src::

$ mkdir charm_src && cd charm_src
$ git clone https://github.com/charmplusplus/charm.git
$ git clone https://github.com/charmplusplus/charm.git charm_src/charm

Once this is done, there are two ways to build Charm4py. The first way is to change back up
into the Charm4Py directory and run the install script::
Once this is done, there are two ways to build Charm4py. The first is to simply run the installation
from the Charm4py root. This method will use the default Charm++ backend::

$ cd ..
$ python3 setup.py install
$ pip install .

The other option is to manually build Charm++ before building Charm4py. To do this, change to
the charm directory and run the following build command::
The other option is to manually build Charm++ before building Charm4py. This may be necessary
if you want to configure Charm++ differently from the default. To do this, change to
the charm directory and run the following build command, then build Charm4Py::

$ cd charm
$ ./build charm4py netlrts-<os>-<architecture> -j<N> --with-production

For building on a laptop, you must use a netlrts build of Charm4Py. Check the Charm++ documentation
to identify the correct os and architecture command to pass into the build command. The -j option
is a cmake option that launches N threads for the make.

Then, return to the charm4py directory and run setup.py::

$ ./build charm4py <target-architecture> -j<N> --with-production
$ cd ../..
$ python3 setup.py install
$ pip install .

Finally, if necessary, when installing dependencies or when running the install script, add the --user
option to the Python command to complete the installation without permission errors.

After building, you can run Charm4py examples. One example you can try is
array_hello.py, which can be run as follows::

$ cd examples/hello
$ python -m charmrun.start +p2 array_hello.py

Installing Charm4Py on a cluster machine
----------------------------------------

To install Charm4Py on a cluster machine, you will generally follow the same steps as above, but
with the following changes. First, when building Charm++, use the MPI build instead of the netlrts
build::
Choosing your target architecture when building from source
------------------------------------------------------------

$ ./build charm4py mpi-<os>-<architecture> -j<N> --with-production
When building from source, as described above, you must chose the appropriate target architecture.

Next, pass in the MPI option to the python setup script::
For building on a laptop or personal machine, you must use a netlrts build of Charm4Py.
For example, to build for a personal machine running macOS with ARM processors, using 4 cmake
threads, you would run::

$ ./build charm4py netlrts-darwin-arm -j4 --with-production

$ python3 setup.py install --mpi

Finally, if necessary, when installing dependencies or when running the install script, add the --user
option to the Python command to complete the installation without permission errors.
To install Charm4Py on a cluster machine, you will generally want to chose a different backend.
For example, to use Charm4Py with MPI, build the Charm backend as follows::

$ ./build charm4py mpi-<os>-<architecture> -j<N> --with-production

Check the Charm++ documentation to identify the correct os and architecture command
to pass into the build command.

.. _manual: https://charm.readthedocs.io/en/latest/charm++/manual.html#installing-charm
44 changes: 44 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[build-system]
requires = ["setuptools>=43.0.0", "cython>=3.0.0", "numpy>=1.10.0"]
build-backend = "setuptools.build_meta"

[project]
description = 'Charm4py Parallel Programming Framework'
authors = [
{ name = "Juan Galvez", email = "jjgalvez@illinois.edu" },
{ name = "Maya Taylor", email = "mayat4@illinois.edu" },
]
maintainers = [{ name = "Maya Taylor", email = "mayat4@illinois.edu" }]
name = "charm4py"
dynamic = ["version"]
readme = { file = "README.rst", content-type = "text/x-rst" }
keywords = [
"parallel",
"parallel programming",
"distributed computing",
"distributed",
"hpc",
"HPC",
"runtime",
]
requires-python = ">=3.7"
dependencies = ["numpy>=1.10.0", "greenlet>=3.0.0"]
classifiers = [
'Intended Audience :: Developers',
'License :: Free for non-commercial use',
'Operating System :: MacOS :: MacOS X',
'Operating System :: POSIX',
'Operating System :: POSIX :: Linux',
'Operating System :: Microsoft :: Windows',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Topic :: System :: Distributed Computing',
'Topic :: System :: Clustering',
]

[project.urls]
Documentation = "https://charm4py.readthedocs.io"
Repository = "https://github.com/charmplusplus/charm4py"

[project.scripts]
charmrun = 'charmrun.start:start'
7 changes: 2 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
cython>=3.0.0
numpy
numpy>=1.10.0
greenlet>=3.0.0

# Required for the charm++ build:
cmake
cython>=3.0.0
38 changes: 7 additions & 31 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,13 @@ def check_libcharm_version(charm_src_dir):
def check_cffi():
try:
import cffi
version = tuple(int(v) for v in cffi.__version__.split('.'))
version_str = cffi.__version__.split('.')

# pypy3.9 returns version string like '1.17.0.dev0'
if (len(version_str) > 3):
version_str = version_str[:3]

version = tuple(int(v) for v in version_str)
if version < (1, 7):
raise DistutilsSetupError('Charm4py requires cffi >= 1.7. '
'Installed version is ' + cffi.__version__)
Expand Down Expand Up @@ -369,42 +375,12 @@ def install(self):
additional_setup_keywords['cffi_modules'] = 'charm4py/charmlib/charmlib_cffi_build.py:ffibuilder'


with open('README.rst', 'r') as f:
long_description = f.read()


setuptools.setup(
name='charm4py',
version=charm4py_version,
author='Juan Galvez and individual contributors',
author_email='jjgalvez@illinois.edu',
description='Charm4py Parallel Programming Framework',
long_description=long_description,
url='https://github.com/charmplusplus/charm4py',
keywords='parallel parallel-programming distributed distributed-computing hpc HPC runtime',
packages=setuptools.find_packages(),
package_data={
'charm4py': ['libcharm_version'],
},
entry_points={
'console_scripts': [
'charmrun = charmrun.start:start',
],
},
install_requires=['numpy>=1.10.0', 'greenlet>=3.0.0', 'cython>=3.0.0', 'cmake'],
python_requires='~=3.6',
classifiers=[
'Intended Audience :: Developers',
'License :: Free for non-commercial use',
'Operating System :: MacOS :: MacOS X',
'Operating System :: POSIX',
'Operating System :: POSIX :: Linux',
'Operating System :: Microsoft :: Windows',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Topic :: System :: Distributed Computing',
'Topic :: System :: Clustering',
],
ext_modules=extensions,
cmdclass = {'build_py': custom_build_py,
'build_ext': custom_build_ext,
Expand Down