Skip to content

Commit 7dc9cac

Browse files
authored
Host the document using RTD. (#4)
- Build a CPU-only pyhwloc in the sphinx conf. - Deduplicate the commit hash.
1 parent 7b4a84b commit 7dc9cac

12 files changed

Lines changed: 162 additions & 44 deletions

File tree

.github/workflows/main.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,10 @@ jobs:
193193
- name: Install hwloc
194194
shell: pwsh
195195
run: |
196+
$Env:HWLOC_VERSION = $(cat ./dev/hwloc_version)
196197
git clone https://github.com/open-mpi/hwloc.git
197198
cd hwloc
198-
git checkout 82d8d2c1ad17e0b48f046f997271e45946bd342e
199+
git checkout $Env:HWLOC_VERSION
199200
200201
cd contrib/windows-cmake
201202
mkdir build

.readthedocs.yaml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@ version: 2
88
build:
99
os: ubuntu-24.04
1010
tools:
11-
python: "3.12"
11+
python: "miniconda-latest"
12+
apt_packages:
13+
- doxygen
1214

1315
# Build documentation in the "docs/" directory with Sphinx
1416
sphinx:
1517
configuration: docs/source/conf.py
1618

17-
# Optionally, but recommended,
18-
# declare the Python requirements required to build your documentation
19-
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
20-
# python:
21-
# install:
22-
# - requirements: docs/requirements.txt
19+
conda:
20+
environment: dev/pyhwloc_dev.yml

CMakeLists.txt

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ project(pyhwloc LANGUAGES C VERSION 0.0.0)
88
list(APPEND CMAKE_MODULE_PATH "${pyhwloc_SOURCE_DIR}/cmake/")
99

1010
option(PYHWLOC_FETCH_HWLOC "Fetch hwloc from GitHub instead of using system version" OFF)
11+
option(PYHWLOC_WITH_CUDA "Add CUDA-related components" ON)
1112

1213
set(PYHWLOC_BUILD_HWLOC_CMAKE OFF)
1314
if(WIN32)
@@ -23,10 +24,12 @@ if(PYHWLOC_FETCH_HWLOC)
2324
set(PYHWLOC_CONFIG_HWLOC OFF CACHE BOOL "")
2425

2526
include(FetchContent)
27+
file(READ ${pyhwloc_SOURCE_DIR}/dev/hwloc_version HWLOC_VERSION)
28+
message(STATUS "HWLOC_VERSION: ${HWLOC_VERSION}")
2629
FetchContent_Declare(
2730
hwloc
2831
GIT_REPOSITORY https://github.com/open-mpi/hwloc.git
29-
GIT_TAG 82d8d2c1ad17e0b48f046f997271e45946bd342e
32+
GIT_TAG ${HWLOC_VERSION}
3033
)
3134

3235
# Configure hwloc build options
@@ -41,7 +44,7 @@ if(PYHWLOC_FETCH_HWLOC)
4144
-G ${CMAKE_GENERATOR}
4245
-DCMAKE_INSTALL_PREFIX=${PYHWLOC_OUTPUT_DIR}
4346
-DBUILD_SHARED_LIBS=ON
44-
-DHWLOC_WITH_CUDA=ON
47+
-DHWLOC_WITH_CUDA=${PYHWLOC_WITH_CUDA}
4548
-DHWLOC_ENABLE_PLUGINS=ON
4649
WORKING_DIRECTORY ${hwloc_SOURCE_DIR}
4750
)
@@ -93,26 +96,29 @@ else()
9396
endif()
9497

9598
message(STATUS "HWLOC_LIBRARY: ${HWLOC_LIBRARY}")
96-
find_package(CUDAToolkit REQUIRED COMPONENTS nvml cuda_driver cudart_static)
9799

98100
target_link_libraries(pyhwloc PRIVATE ${HWLOC_LIBRARY})
99101
target_include_directories(pyhwloc PRIVATE ${HWLOC_INCLUDE_DIR})
100102
list(APPEND PYHWLOC_LIBS pyhwloc)
101103

102-
add_library(pyhwloc_cuda SHARED src/ext/cudr.c)
103-
target_link_libraries(pyhwloc_cuda PRIVATE CUDA::cuda_driver ${HWLOC_LIBRARY})
104-
target_include_directories(pyhwloc_cuda PRIVATE ${HWLOC_INCLUDE_DIR})
105-
list(APPEND PYHWLOC_LIBS pyhwloc_cuda)
104+
if(PYHWLOC_WITH_CUDA)
105+
find_package(CUDAToolkit REQUIRED COMPONENTS nvml cuda_driver cudart_static)
106106

107-
add_library(pyhwloc_cudart SHARED src/ext/cudart.c)
108-
target_link_libraries(pyhwloc_cudart PRIVATE CUDA::cudart ${HWLOC_LIBRARY})
109-
target_include_directories(pyhwloc_cudart PRIVATE ${HWLOC_INCLUDE_DIR})
110-
list(APPEND PYHWLOC_LIBS pyhwloc_cudart)
107+
add_library(pyhwloc_cuda SHARED src/ext/cudr.c)
108+
target_link_libraries(pyhwloc_cuda PRIVATE CUDA::cuda_driver ${HWLOC_LIBRARY})
109+
target_include_directories(pyhwloc_cuda PRIVATE ${HWLOC_INCLUDE_DIR})
110+
list(APPEND PYHWLOC_LIBS pyhwloc_cuda)
111111

112-
add_library(pyhwloc_nvml SHARED src/ext/nvml.c)
113-
target_link_libraries(pyhwloc_nvml PRIVATE CUDA::nvml ${HWLOC_LIBRARY})
114-
target_include_directories(pyhwloc_nvml PRIVATE ${HWLOC_INCLUDE_DIR})
115-
list(APPEND PYHWLOC_LIBS pyhwloc_nvml)
112+
add_library(pyhwloc_cudart SHARED src/ext/cudart.c)
113+
target_link_libraries(pyhwloc_cudart PRIVATE CUDA::cudart ${HWLOC_LIBRARY})
114+
target_include_directories(pyhwloc_cudart PRIVATE ${HWLOC_INCLUDE_DIR})
115+
list(APPEND PYHWLOC_LIBS pyhwloc_cudart)
116+
117+
add_library(pyhwloc_nvml SHARED src/ext/nvml.c)
118+
target_link_libraries(pyhwloc_nvml PRIVATE CUDA::nvml ${HWLOC_LIBRARY})
119+
target_include_directories(pyhwloc_nvml PRIVATE ${HWLOC_INCLUDE_DIR})
120+
list(APPEND PYHWLOC_LIBS pyhwloc_nvml)
121+
endif()
116122

117123
include(GenerateExportHeader)
118124

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Python Interface for the Portable Hardware Locality (hwloc) Library
22
===================================================================
33

4-
- `Official site <https://www.open-mpi.org/projects/hwloc/>`__ of the hwloc library.
4+
- `Document <https://pyhwloc.readthedocs.io/>`__.
5+
- `Official site <https://www.open-mpi.org/projects/hwloc/>`__ of the hwloc library.

dev/Dockerfile.cpu

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ RUN \
1818
git clone https://github.com/doxygen/doxygen.git && \
1919
cd doxygen && git checkout d49be63057d71f487312f43339516bc92cc685fa && cd -
2020

21+
COPY hwloc_version ws/hwloc_version
22+
2123
RUN \
2224
cd /ws/ && \
2325
git clone https://github.com/open-mpi/hwloc.git && \
24-
cd hwloc && git checkout 82d8d2c1ad17e0b48f046f997271e45946bd342e && cd -
26+
cd hwloc && git checkout $(cat /ws/hwloc_version) && cd -
2527

2628
SHELL ["mamba", "run", "--no-capture-output", "-n", "base", "/bin/bash", "-c"]
2729

dev/hwloc_version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
82d8d2c1ad17e0b48f046f997271e45946bd342e

docs/source/build.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,11 @@ A complete list of options available for the ``--config-settings=``:
9999
- ``build-dir=/path/to/build/dir`` for specifying a build dir.
100100
- ``hwloc-src-dir=/path/to/hwloc-src`` for using a local checkout of hwloc. This assumes
101101
the src directory is the git repo, which is not the same as the release tarball.
102-
- ``hwloc-root-dir=/path/to/hwloc`` to specify the path of an existing hwloc installation.
102+
- ``hwloc-root-dir=/path/to/hwloc`` to specify the path of an existing binary hwloc
103+
installation.
103104
- ``fetch-hwloc=True`` to build the fat wheel.
105+
- ``with-cuda=False`` to build pyhwloc without CUDA plugins. This is used for building
106+
document in a minimum environment and is not tested for other purposes.
104107

105108
The binary wheel uses plugins by default. Due to the plugins support, all symbols from
106109
hwloc are loaded into the linker's public name space using

docs/source/conf.py

Lines changed: 105 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
from __future__ import annotations
1010

1111
import os
12+
import subprocess
13+
import sys
14+
import tempfile
15+
from contextlib import contextmanager
16+
from typing import Iterator
1217

1318
project = "pyhwloc"
1419
copyright = "2025, Jiaming Yuan"
@@ -36,21 +41,6 @@
3641

3742
intersphinx_mapping = {"python": ("https://docs.python.org/3.10", None)}
3843

39-
# -- Breathe
40-
breathe_default_project = "pyhwloc"
41-
breathe_domain_by_extension = {"h": "c"}
42-
43-
CURR_PATH = os.path.dirname(os.path.abspath(os.path.expanduser(__file__))) # source
44-
PROJECT_ROOT = os.path.normpath(os.path.join(CURR_PATH, os.path.pardir, os.path.pardir))
45-
46-
hwloc_xml_path = os.environ.get("PYHWLOC_XML_PATH", None)
47-
if hwloc_xml_path is None:
48-
hwloc_xml_path = os.path.join(
49-
PROJECT_ROOT, os.path.pardir, "hwloc/doc/doxygen-doc/xml"
50-
)
51-
breathe_projects = {"pyhwloc": hwloc_xml_path}
52-
print("beathe projects", breathe_projects)
53-
5444
# -- Build environment
5545

5646
os.environ["PYHWLOC_SPHINX"] = "1"
@@ -62,3 +52,103 @@
6252
# path to where to save gallery generated output
6353
"gallery_dirs": ["examples"],
6454
}
55+
56+
57+
def is_readthedocs_build() -> bool:
58+
if os.environ.get("READTHEDOCS", None) == "True":
59+
return True
60+
return False
61+
62+
63+
def normpath(path: str) -> str:
64+
return os.path.normpath(os.path.abspath(path))
65+
66+
67+
@contextmanager
68+
def _chdir(dirname: str) -> Iterator[None]:
69+
pwd = normpath(os.path.curdir)
70+
try:
71+
os.chdir(dirname)
72+
yield
73+
finally:
74+
os.chdir(pwd)
75+
76+
77+
def build_pyhwloc_xml() -> str:
78+
"""Build and install pyhwloc, returns the path to the doxygen xml files."""
79+
if sys.platform == "win32":
80+
raise NotImplementedError("Read the docs environment should be Linux.")
81+
82+
hwloc_version_path = os.path.join(
83+
PROJECT_ROOT,
84+
"dev",
85+
"hwloc_version",
86+
)
87+
with open(hwloc_version_path, "r") as fd:
88+
hwloc_version = fd.read().strip()
89+
90+
with tempfile.TemporaryDirectory() as tmpdir:
91+
pwd = normpath(os.path.curdir)
92+
script = f"""#!/usr/bin/env bash
93+
# Clone
94+
git clone https://github.com/open-mpi/hwloc.git
95+
cd hwloc
96+
git checkout {hwloc_version}
97+
98+
# Config
99+
./autogen.sh
100+
./configure --disable-nvml --enable-doxygen
101+
102+
# Build doc
103+
cd doc
104+
HWLOC_DOXYGEN_GENERATE_XML=YES doxygen ./doxygen.cfg
105+
# Result is in `hwloc/doc/doxygen-doc/xml`
106+
107+
# Copy and cleanup
108+
cp -r doxygen-doc/xml {pwd}/
109+
cd ..
110+
git clean -xdf
111+
"""
112+
script_path = os.path.join(tmpdir, "build_xml.sh")
113+
with open(script_path, "w") as fd:
114+
fd.write(script)
115+
116+
with _chdir(tmpdir):
117+
subprocess.check_call(["bash", script_path])
118+
xml_path = os.path.join(pwd, "xml")
119+
120+
# Install pyhwloc while we have the hwloc source
121+
hwloc_src_dir = os.path.join(tmpdir, "hwloc")
122+
subprocess.check_call(
123+
[
124+
"pip",
125+
"install",
126+
PROJECT_ROOT,
127+
"--config-settings=fetch-hwloc=True",
128+
f"--config-settings=hwloc-src-dir={hwloc_src_dir}",
129+
"--config-settings=with-cuda=False",
130+
"--no-deps",
131+
"--no-build-isolation",
132+
]
133+
)
134+
135+
return xml_path
136+
137+
138+
# -- Breathe
139+
breathe_default_project = "pyhwloc"
140+
breathe_domain_by_extension = {"h": "c"}
141+
142+
CURR_PATH = os.path.dirname(os.path.abspath(os.path.expanduser(__file__))) # source
143+
PROJECT_ROOT = os.path.normpath(os.path.join(CURR_PATH, os.path.pardir, os.path.pardir))
144+
145+
if is_readthedocs_build():
146+
hwloc_xml_path: str | None = build_pyhwloc_xml()
147+
else:
148+
hwloc_xml_path = os.environ.get("PYHWLOC_XML_PATH", None)
149+
if hwloc_xml_path is None:
150+
hwloc_xml_path = os.path.join(
151+
PROJECT_ROOT, os.path.pardir, "hwloc/doc/doxygen-doc/xml"
152+
)
153+
breathe_projects = {"pyhwloc": hwloc_xml_path}
154+
print("breathe projects", breathe_projects)

docs/source/dev.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ Symbol Conflicts
88
The hwloc is loaded into the public linker name space to support hwloc plugins. This might
99
have unintended consequences.
1010

11+
Update hwloc
12+
============
13+
14+
Update the commit hash in ``dev/hwloc_version``.
15+
1116
Design Decisions
1217
================
1318

hatch/backend.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import hatchling.build
1212

13-
from .hook import BUILD_KEY, FETCH_KEY, ROOT_KEY, SRC_KEY
13+
from .hook import BUILD_KEY, CUDA_KEY, FETCH_KEY, ROOT_KEY, SRC_KEY
1414

1515

1616
@contextmanager
@@ -26,6 +26,10 @@ def build_config(config_settings: dict[str, Any] | None) -> Iterator[None]:
2626
os.environ[SRC_KEY] = config_settings["hwloc-src-dir"]
2727
if "hwloc-root-dir" in config_settings:
2828
os.environ[ROOT_KEY] = config_settings["hwloc-root-dir"]
29+
if "with-cuda" in config_settings:
30+
v = config_settings["with-cuda"]
31+
assert v in ("True", "False")
32+
os.environ[CUDA_KEY] = v
2933
try:
3034
yield
3135
finally:
@@ -37,6 +41,8 @@ def build_config(config_settings: dict[str, Any] | None) -> Iterator[None]:
3741
del os.environ[SRC_KEY]
3842
if ROOT_KEY in os.environ:
3943
del os.environ[ROOT_KEY]
44+
if CUDA_KEY in os.environ:
45+
del os.environ[CUDA_KEY]
4046

4147

4248
def build_wheel(

0 commit comments

Comments
 (0)