Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Replace setup.py with pyproject.toml #9021

Merged
merged 61 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
18dfb02
Initial setup of pyproject.toml
hcho3 Apr 11, 2023
2469e98
Fix path in sdist
hcho3 Apr 11, 2023
7037c80
Full support for sdist
hcho3 Apr 11, 2023
662ab40
Remove setup.py
hcho3 Apr 11, 2023
b3490db
Fix
hcho3 Apr 11, 2023
bae6d9b
Use hatchling backend to reduce boilerplate
hcho3 Apr 13, 2023
e3585ff
Use proper logger
hcho3 Apr 13, 2023
0018b66
Don't include hatch_build.py in sdist
hcho3 Apr 13, 2023
95ad176
Rename to make it less verbose
hcho3 Apr 13, 2023
359f1e4
Support 'pip install .'
hcho3 Apr 14, 2023
a08ed15
Update build-time requirements
hcho3 Apr 14, 2023
8505ea9
Support editable installation
hcho3 Apr 14, 2023
ca05770
Fix lint
hcho3 Apr 14, 2023
9997b7b
Add type annotation
hcho3 Apr 14, 2023
9dab333
Fix type annotation
hcho3 Apr 14, 2023
7c06956
More fix
hcho3 Apr 14, 2023
823f8f1
Fix formatting
hcho3 Apr 14, 2023
d2e5a65
Support CMake args
hcho3 Apr 14, 2023
c5460be
More formatting fix
hcho3 Apr 14, 2023
9b11778
Add URL for build doc
hcho3 Apr 14, 2023
9260613
Install hatchling when linting
hcho3 Apr 14, 2023
d7799c8
Remove setup.py sdist from CI
hcho3 Apr 14, 2023
2c73f75
Support building libxgboost in Windows
hcho3 Apr 14, 2023
10482b9
Remove all uses of setup.py from CI
hcho3 Apr 14, 2023
da2e8bb
Support Apple Silicon + cibuildwheel
hcho3 Apr 14, 2023
3eec9f7
Fallback if OpenMP isn't available
hcho3 Apr 14, 2023
7ee3ff8
Check libxgboost if editable
hcho3 Apr 14, 2023
63d88dc
On Conda, it's python-build
hcho3 Apr 14, 2023
cea6899
Update change_version.py script to update pyproject.toml
hcho3 Apr 14, 2023
9d002fc
Remove setup.py from dev script
hcho3 Apr 14, 2023
c0b4999
Update docs
hcho3 Apr 14, 2023
3bf0357
Integrate insert_vcomp140 into build backend
hcho3 Apr 14, 2023
702e4ea
Ensure that vcomp140.dll exists
hcho3 Apr 14, 2023
25856c1
Add optional flag bundle_vcomp140_dll
hcho3 Apr 14, 2023
58b2dc2
Better doc
hcho3 Apr 14, 2023
a38d26c
Add doc for Python packaging
hcho3 Apr 14, 2023
e3d4cf1
Fix mypy check
hcho3 Apr 14, 2023
37aeac8
Clean up build instructions
hcho3 Apr 14, 2023
886802a
Fix pip wheel
hcho3 Apr 14, 2023
8ffcc20
Upgrade to Pip 23+ on Windows
hcho3 Apr 14, 2023
5d58da0
Add Pip version requirement in doc
hcho3 Apr 14, 2023
d15d623
Filter bundle_vcomp140_dll from CMake args
hcho3 Apr 14, 2023
d2fd761
Update build-win64-gpu.ps1
hcho3 Apr 14, 2023
9f43ad7
Update build-win64-gpu.ps1
hcho3 Apr 14, 2023
bca703a
Last fix
hcho3 Apr 15, 2023
31cec82
Don't bundle vcomp140.dll
hcho3 Apr 15, 2023
3374512
Document that redist is required
hcho3 Apr 15, 2023
3d5c126
Update install.rst
hcho3 Apr 15, 2023
7d5e422
Remove unused import
hcho3 Apr 15, 2023
ae7c03c
Document that pip 21.3+ is required
hcho3 Apr 15, 2023
65ac71f
Use Pip 21.3+
hcho3 Apr 15, 2023
346472f
Simplify lint_python.py
hcho3 Apr 15, 2023
143d7ef
Revise python_packaging.rst
hcho3 Apr 19, 2023
73e3c77
Address reviewer's comment
hcho3 Apr 19, 2023
953c9bd
Insert missing 'the'
hcho3 Apr 19, 2023
fd7f1eb
Fix typo
hcho3 Apr 19, 2023
889b60c
Fix formatting
hcho3 Apr 19, 2023
c62e2d0
Fix build
hcho3 Apr 19, 2023
dbd9590
Fix formatting
hcho3 Apr 19, 2023
77df443
Fix formatting
hcho3 Apr 19, 2023
a85657b
Address reviewer's feedback
hcho3 Apr 20, 2023
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
13 changes: 8 additions & 5 deletions .github/workflows/python_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
run: |
cd python-package
python --version
python setup.py sdist
python -m build --sdist
pip install -v ./dist/xgboost-*.tar.gz
cd ..
python -c 'import xgboost'
Expand All @@ -92,6 +92,9 @@ jobs:
auto-update-conda: true
python-version: ${{ matrix.python-version }}
activate-environment: test
- name: Install build
run: |
conda install -c conda-forge python-build
- name: Display Conda env
run: |
conda info
Expand All @@ -100,7 +103,7 @@ jobs:
run: |
cd python-package
python --version
python setup.py sdist
python -m build --sdist
pip install -v ./dist/xgboost-*.tar.gz
cd ..
python -c 'import xgboost'
Expand Down Expand Up @@ -147,7 +150,7 @@ jobs:
run: |
cd python-package
python --version
python setup.py install
pip install -v .

- name: Test Python package
run: |
Expand Down Expand Up @@ -194,7 +197,7 @@ jobs:
run: |
cd python-package
python --version
python setup.py bdist_wheel --universal
pip wheel -v . --wheel-dir dist/
pip install ./dist/*.whl

- name: Test Python package
Expand Down Expand Up @@ -238,7 +241,7 @@ jobs:
run: |
cd python-package
python --version
python setup.py install
pip install -v .

- name: Test Python package
run: |
Expand Down
10 changes: 8 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ option(USE_NVTX "Build with cuda profiling annotations. Developers only." OFF)
set(NVTX_HEADER_DIR "" CACHE PATH "Path to the stand-alone nvtx header")
option(RABIT_MOCK "Build rabit with mock" OFF)
option(HIDE_CXX_SYMBOLS "Build shared library and hide all C++ symbols" OFF)
option(KEEP_BUILD_ARTIFACTS_IN_BINARY_DIR "Output build artifacts in CMake binary dir" OFF)
## CUDA
option(USE_CUDA "Build with GPU acceleration" OFF)
option(USE_NCCL "Build with NCCL to enable distributed GPU support." OFF)
Expand Down Expand Up @@ -268,8 +269,13 @@ if (JVM_BINDINGS)
xgboost_target_defs(xgboost4j)
endif (JVM_BINDINGS)

set_output_directory(runxgboost ${xgboost_SOURCE_DIR})
set_output_directory(xgboost ${xgboost_SOURCE_DIR}/lib)
if (KEEP_BUILD_ARTIFACTS_IN_BINARY_DIR)
set_output_directory(runxgboost ${xgboost_BINARY_DIR})
set_output_directory(xgboost ${xgboost_BINARY_DIR}/lib)
else ()
set_output_directory(runxgboost ${xgboost_SOURCE_DIR})
set_output_directory(xgboost ${xgboost_SOURCE_DIR}/lib)
hcho3 marked this conversation as resolved.
Show resolved Hide resolved
endif ()
# Ensure these two targets do not build simultaneously, as they produce outputs with conflicting names
add_dependencies(xgboost runxgboost)

Expand Down
2 changes: 1 addition & 1 deletion dev/release-artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def make_pysrc_wheel(release: str, outdir: str) -> None:
os.mkdir(dist)

with DirectoryExcursion(os.path.join(ROOT, "python-package")):
subprocess.check_call(["python", "setup.py", "sdist"])
subprocess.check_call(["python", "-m", "build", "--sdist"])
src = os.path.join(DIST, f"xgboost-{release}.tar.gz")
subprocess.check_call(["twine", "check", src])
shutil.move(src, os.path.join(dist, f"xgboost-{release}.tar.gz"))
Expand Down
136 changes: 65 additions & 71 deletions doc/build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ systems. If the instructions do not work for you, please feel free to ask quest
Consider installing XGBoost from a pre-built binary, to avoid the trouble of building XGBoost from the source. Checkout :doc:`Installation Guide </install>`.

.. contents:: Contents
:local:

.. _get_source:

Expand Down Expand Up @@ -152,11 +153,11 @@ On Windows, run CMake as follows:

mkdir build
cd build
cmake .. -G"Visual Studio 14 2015 Win64" -DUSE_CUDA=ON
cmake .. -G"Visual Studio 17 2022" -A x64 -DUSE_CUDA=ON

(Change the ``-G`` option appropriately if you have a different version of Visual Studio installed.)

The above cmake configuration run will create an ``xgboost.sln`` solution file in the build directory. Build this solution in release mode as a x64 build, either from Visual studio or from command line:
The above cmake configuration run will create an ``xgboost.sln`` solution file in the build directory. Build this solution in Release mode, either from Visual studio or from command line:

.. code-block:: bash

Expand All @@ -176,110 +177,103 @@ Building Python Package with Default Toolchains
===============================================
There are several ways to build and install the package from source:

1. Use Python setuptools directly
1. Build C++ core with CMake first

The XGBoost Python package supports most of the setuptools commands, here is a list of tested commands:
You can first build C++ library using CMake as described in :ref:`build_shared_lib`.
After compilation, a shared library will appear in ``lib/`` directory.
On Linux distributions, the shared library is ``lib/libxgboost.so``.
The install script ``pip install .`` will reuse the shared library instead of compiling
it from scratch, making it quite fast to run.

.. code-block:: bash

python setup.py install # Install the XGBoost to your current Python environment.
python setup.py build # Build the Python package.
python setup.py build_ext # Build only the C++ core.
python setup.py sdist # Create a source distribution
python setup.py bdist # Create a binary distribution
python setup.py bdist_wheel # Create a binary distribution with wheel format

Running ``python setup.py install`` will compile XGBoost using default CMake flags. For
passing additional compilation options, append the flags to the command. For example,
to enable CUDA acceleration and NCCL (distributed GPU) support:

.. code-block:: bash
.. code-block:: console

python setup.py install --use-cuda --use-nccl
$ cd python-package/
$ pip install . # Will re-use lib/libxgboost.so

Please refer to ``setup.py`` for a complete list of available options. Some other
options used for development are only available for using CMake directly. See next
section on how to use CMake with setuptools manually.
2. Install the Python package directly

You can install the created distribution packages using pip. For example, after running
``sdist`` setuptools command, a tar ball similar to ``xgboost-1.0.0.tar.gz`` will be
created under the ``dist`` directory. Then you can install it by invoking the following
command under ``dist`` directory:
You can navigate to ``python-package/`` directory and install the Python package directly
by running

.. code-block:: bash
.. code-block:: console

# under python-package directory
cd dist
pip install ./xgboost-1.0.0.tar.gz
$ cd python-package/
$ pip install -v .

which will compile XGBoost's native (C++) code using default CMake flags.
To enable additional compilation options, pass corresponding ``--config-settings``:

For details about these commands, please refer to the official document of `setuptools
<https://setuptools.readthedocs.io/en/latest/>`_, or just Google "how to install Python
package from source". XGBoost Python package follows the general convention.
Setuptools is usually available with your Python distribution, if not you can install it
via system command. For example on Debian or Ubuntu:
.. code-block:: console

.. code-block:: bash
$ pip install -v . --config-settings use_cuda=True --config-settings use_nccl=True

sudo apt-get install python-setuptools
Use Pip 22.1 or later to use ``--config-settings`` option.

Here are the available options for ``--config-settings``:

For cleaning up the directory after running above commands, ``python setup.py clean`` is
not sufficient. After copying out the build result, simply running ``git clean -xdf``
under ``python-package`` is an efficient way to remove generated cache files. If you
find weird behaviors in Python build or running linter, it might be caused by those
cached files.
.. literalinclude:: ../python-package/packager/build_config.py
:language: python
:start-at: @dataclasses.dataclass
:end-before: def _set_config_setting(

For using develop command (editable installation), see next section.
``use_system_libxgboost`` is a special option. See Item 4 below for
detailed description.

.. code-block::
.. note:: Verbose flag recommended

python setup.py develop # Create a editable installation.
pip install -e . # Same as above, but carried out by pip.
As ``pip install .`` will build C++ code, it will take a while to complete.
To ensure that the build is progressing successfully, we suggest that
you add the verbose flag (``-v``) when invoking ``pip install``.


2. Build C++ core with CMake first
3. Editable installation

This is mostly for C++ developers who don't want to go through the hooks in Python
setuptools. You can build C++ library directly using CMake as described in above
sections. After compilation, a shared object (or called dynamic linked library, jargon
depending on your platform) will appear in XGBoost's source tree under ``lib/``
directory. On Linux distributions it's ``lib/libxgboost.so``. From there all Python
setuptools commands will reuse that shared object instead of compiling it again. This
is especially convenient if you are using the editable installation, where the installed
package is simply a link to the source tree. We can perform rapid testing during
development. Here is a simple bash script does that:
To further enable rapid development and iteration, we provide an **editable installation**.
In an editable installation, the installed package is simply a symbolic link to your
working copy of the XGBoost source code. So every changes you make to your source
directory will be immediately visible to the Python interpreter. Here is how to
install XGBoost as editable installation:

.. code-block:: bash

# Under xgboost source tree.
# Under xgboost source directory
mkdir build
cd build
cmake ..
make -j$(nproc)
# Build shared library libxgboost.so
cmake .. -GNinja
ninja
# Install as editable installation
cd ../python-package
pip install -e . # or equivalently python setup.py develop
pip install -e .

4. Use ``libxgboost.so`` on system path.

3. Use ``libxgboost.so`` on system path.
This option is useful for package managers that wish to separately package
``libxgboost.so`` and the XGBoost Python package. For example, Conda
publishes ``libxgboost`` (for the shared library) and ``py-xgboost``
(for the Python package).

This is for distributing xgboost in a language independent manner, where
``libxgboost.so`` is separately packaged with Python package. Assuming `libxgboost.so`
is already presented in system library path, which can be queried via:
To use this option, first make sure that ``libxgboost.so`` exists in the system library path:

.. code-block:: python

import sys
import os
os.path.join(sys.prefix, 'lib')
import pathlib
libpath = pathlib.Path(sys.prefix).joinpath("lib", "libxgboost.so")
assert libpath.exists()

Then one only needs to provide an user option when installing Python package to reuse the
shared object in system path:
Then pass ``use_system_libxgboost=True`` option to ``pip install``:

.. code-block:: bash

cd xgboost/python-package
python setup.py install --use-system-libxgboost
cd python-package
pip install . --config-settings use_system_libxgboost=True


.. note::

See :doc:`contrib/python_packaging` for instructions on packaging
and distributing XGBoost as Python distributions.

.. _python_mingw:

Expand All @@ -297,7 +291,7 @@ So you may want to build XGBoost with GCC own your own risk. This presents some
2. ``-O3`` is OK.
3. ``-mtune=native`` is also OK.
4. Don't use ``-march=native`` gcc flag. Using it causes the Python interpreter to crash if the DLL was actually used.
5. You may need to provide the lib with the runtime libs. If ``mingw32/bin`` is not in ``PATH``, build a wheel (``python setup.py bdist_wheel``), open it with an archiver and put the needed dlls to the directory where ``xgboost.dll`` is situated. Then you can install the wheel with ``pip``.
5. You may need to provide the lib with the runtime libs. If ``mingw32/bin`` is not in ``PATH``, build a wheel (``pip wheel``), open it with an archiver and put the needed dlls to the directory where ``xgboost.dll`` is situated. Then you can install the wheel with ``pip``.

******************************
Building R Package From Source
Expand Down
5 changes: 3 additions & 2 deletions doc/contrib/ci.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ calls ``cibuildwheel`` to build the wheel. The ``cibuildwheel`` is a library tha
suitable Python environment for each OS and processor target. Since we don't have Apple Silion
machine in GitHub Actions, cross-compilation is needed; ``cibuildwheel`` takes care of the complex
task of cross-compiling a Python wheel. (Note that ``cibuildwheel`` will call
``setup.py bdist_wheel``. Since XGBoost has a native library component, ``setup.py`` contains
a glue code to call CMake and a C++ compiler to build the native library on the fly.)
``pip wheel``. Since XGBoost has a native library component, we created a customized build
backend that hooks into ``pip``. The customized backend contains the glue code to compile the native
library on the fly.)

*********************************************************
Reproduce CI testing environments using Docker containers
Expand Down
1 change: 1 addition & 0 deletions doc/contrib/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Here are guidelines for contributing to various aspect of the XGBoost project:
Community Guideline <community>
donate
coding_guide
python_packaging
unit_tests
Docs and Examples <docs>
git_guide
Expand Down
83 changes: 83 additions & 0 deletions doc/contrib/python_packaging.rst
hcho3 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
###########################################
Notes on packaging XGBoost's Python package
###########################################


.. contents:: Contents
:local:

.. _packaging_python_xgboost:

***************************************************
How to build binary wheels and source distributions
hcho3 marked this conversation as resolved.
Show resolved Hide resolved
***************************************************

Wheels and source distributions (sdist for short) are the two main
mechanisms for packaging and distributing Python packages.

* A **source distribution** (sdist) is a tarball (``.tar.gz`` extension) that
contains the source code.
* A **wheel** is a ZIP-compressed archive (with ``.whl`` extension)
representing a *built* distribution. Unlike an sdist, a wheel can contain
compiled components. The compiled components are compiled prior to distribution,
making it more convenient for end-users to install a wheel. Wheels containing
compiled components are referred to as **binary wheels**.

See `Python Packaging User Guide <https://packaging.python.org/en/latest/>`_
to learn more about how Python packages in general are packaged and
distributed.

For the remainder of this document, we will focus on packaging and
distributing XGBoost.

Building sdists
===============

In the case of XGBoost, an sdist contains both the Python code as well as
the C++ code, so that the core part of XGBoost can be compiled into the
shared libary ``libxgboost.so`` [#shared_lib_name]_.

You can obtain an sdist as follows:

.. code-block:: console

$ python -m build --sdist .

(You'll need to install the ``build`` package first:
``pip install build`` or ``conda install python-build``.)

Running ``pip install`` with an sdist will launch CMake and a C++ compiler
to compile the bundled C++ code into ``libxgboost.so``:

.. code-block:: console

$ pip install -v xgboost-2.0.0.tar.gz # Add -v to show build progress

Building binary wheels
======================

You can also build a wheel as follows:

.. code-block:: console

$ pip wheel --no-deps -v .

Notably, the resulting wheel contains a copy of the shared library
``libxgboost.so`` [#shared_lib_name]_. The wheel is a **binary wheel**,
since it contains a compiled binary.


Running ``pip install`` with the binary wheel will extract the content of
the wheel into the current Python environment. Since the wheel already
contains a pre-built copy of ``libxgboost.so``, it does not have to be
built at the time of install. So ``pip install`` with the binary wheel
completes quickly:

.. code-block:: console

$ pip install xgboost-2.0.0-py3-none-linux_x86_64.whl # Completes quickly

.. rubric:: Foonotes
hcho3 marked this conversation as resolved.
Show resolved Hide resolved

.. [#shared_lib_name] The name of the shared library file will differ
depending on the operating system in use. See :ref:`build_shared_lib`.
Loading