Skip to content

Commit 0ecd18e

Browse files
authored
Remove use of python setup.py develop/install (#2716)
A warning that `python setup.py develop` is deprecated and will no longer be supported at the end of October, 2025 has been ongoing for some time when using dpnp build driver scripts, and can be seen in the CI. The PR proposes instead relying on `pip` for installing dpnp in scripts, and reworks the scripts to maintain use of `scikit-build`. In the future, this will also simplify a transition to `scikit-build-core`. This PR also introduces options * `--clean` and `--skip-editable` to `build_locally` driver * `--clean` and `--skip-pytest` to `gen_coverage` driver Also it includes update of the documentation with new build instruction.
1 parent 7b73f74 commit 0ecd18e

File tree

7 files changed

+658
-421
lines changed

7 files changed

+658
-421
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum
4343
* Updated tests to reflect the new scalar conversion rules for non-0D `usm_ndarray` [#2694](https://github.com/IntelPython/dpnp/pull/2694)
4444
* Compile indexing extension with `-fno-sycl-id-queries-fit-in-int` to support huge arrays [#2721](https://github.com/IntelPython/dpnp/pull/2721)
4545
* Updated `dpnp.fix` to reuse `dpnp.trunc` internally [#2722](https://github.com/IntelPython/dpnp/pull/2722)
46+
* Changed the build scripts and documentation due to `python setup.py develop` deprecation notice [#2716](https://github.com/IntelPython/dpnp/pull/2716)
4647

4748
### Deprecated
4849

CMakeLists.txt

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ set(DPNP_TARGET_CUDA
107107
Set to a truthy value (e.g., ON, TRUE) to use default architecture (sm_50), \
108108
or to a specific architecture like sm_80."
109109
)
110-
set(HIP_TARGETS "" CACHE STRING "HIP architecture for target")
110+
set(DPNP_TARGET_HIP "" CACHE STRING "HIP architecture for target")
111111

112112
set(_dpnp_sycl_targets)
113113
set(_use_onemath OFF)
@@ -135,18 +135,28 @@ if("x${DPNP_SYCL_TARGETS}" STREQUAL "x")
135135
set(_use_onemath_cuda ON)
136136
endif()
137137

138-
if(HIP_TARGETS)
139-
if(HIP_TARGETS MATCHES "^gfx")
138+
if(DPNP_TARGET_HIP)
139+
if(DPNP_TARGET_HIP MATCHES "^gfx")
140140
if("x${_dpnp_sycl_targets}" STREQUAL "x")
141-
set(_dpnp_sycl_targets "amd_gpu_${HIP_TARGETS},spir64-unknown-unknown")
141+
set(_dpnp_sycl_targets
142+
"amd_gpu_${DPNP_TARGET_HIP},spir64-unknown-unknown"
143+
)
142144
else()
143-
set(_dpnp_sycl_targets "amd_gpu_${HIP_TARGETS},${_dpnp_sycl_targets}")
145+
set(_dpnp_sycl_targets
146+
"amd_gpu_${DPNP_TARGET_HIP},${_dpnp_sycl_targets}"
147+
)
144148
endif()
149+
145150
set(_use_onemath_hip ON)
151+
set(HIP_TARGETS
152+
${DPNP_TARGET_HIP}
153+
CACHE STRING
154+
"HIP GPU targets for oneMath"
155+
)
146156
else()
147157
message(
148158
FATAL_ERROR
149-
"Invalid value for HIP_TARGETS: \"${HIP_TARGETS}\". "
159+
"Invalid value for DPNP_TARGET_HIP: \"${DPNP_TARGET_HIP}\". "
150160
"Expected an architecture name starting with 'gfx', e.g. 'gfx1030'."
151161
)
152162
endif()
@@ -159,11 +169,15 @@ else()
159169
endif()
160170

161171
if("${DPNP_SYCL_TARGETS}" MATCHES "amd_gpu_")
162-
set(_use_onemath_hip ON)
163-
164-
if("x${HIP_TARGETS}" STREQUAL "x")
165-
message(FATAL_ERROR "HIP_TARGETS must be specified when using HIP backend")
172+
if("x${DPNP_TARGET_HIP}" STREQUAL "x")
173+
message(
174+
FATAL_ERROR
175+
"DPNP_TARGET_HIP must be specified when using HIP backend"
176+
)
166177
endif()
178+
179+
set(_use_onemath_hip ON)
180+
set(HIP_TARGETS ${DPNP_TARGET_HIP} CACHE STRING "HIP GPU targets for oneMath")
167181
endif()
168182

169183
if("${DPNP_SYCL_TARGETS}" MATCHES "amdgcn-amd-amdhsa")
@@ -295,6 +309,16 @@ else()
295309
message(FATAL_ERROR "Unsupported system.")
296310
endif()
297311

312+
# Define flags for CMAKE_BUILD_TYPE=Coverage
313+
set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_DEBUG} -O1 -g1 -DDEBUG")
314+
set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG} -O1 -g1 -DDEBUG")
315+
set(CMAKE_MODULE_LINKER_FLAGS_COVERAGE "${CMAKE_MODULE_LINKER_FLAGS_DEBUG}")
316+
mark_as_advanced(
317+
CMAKE_C_FLAGS_COVERAGE
318+
CMAKE_CXX_FLAGS_COVERAGE
319+
CMAKE_MODULE_LINKER_FLAGS_COVERAGE
320+
)
321+
298322
if(DPNP_GENERATE_COVERAGE)
299323
string(
300324
CONCAT PROFILE_FLAGS

doc/0.builddoc.sh

Lines changed: 0 additions & 11 deletions
This file was deleted.

doc/quick_start_guide.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,15 @@ To build and install the package on Linux OS, run:
112112

113113
.. code-block:: bash
114114
115-
python setup.py install -- -G Ninja -DCMAKE_C_COMPILER:PATH=icx -DCMAKE_CXX_COMPILER:PATH=icpx
115+
python setup.py build_ext --inplace -- -G Ninja -DCMAKE_C_COMPILER:PATH=icx -DCMAKE_CXX_COMPILER:PATH=icpx
116+
python -m pip install -e .
116117
117118
To build and install the package on Windows OS, run:
118119

119120
.. code-block:: bash
120121
121-
python setup.py install -- -G Ninja -DCMAKE_C_COMPILER:PATH=icx -DCMAKE_CXX_COMPILER:PATH=icx
122+
python setup.py build_ext --inplace -- -G Ninja -DCMAKE_C_COMPILER:PATH=icx -DCMAKE_CXX_COMPILER:PATH=icx
123+
python -m pip install -e .
122124
123125
Alternatively, to develop on Linux OS, you can use the driver script:
124126

scripts/_build_helper.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
# *****************************************************************************
2+
# Copyright (c) 2026, Intel Corporation
3+
# All rights reserved.
4+
#
5+
# Redistribution and use in source and binary forms, with or without
6+
# modification, are permitted provided that the following conditions are met:
7+
# - Redistributions of source code must retain the above copyright notice,
8+
# this list of conditions and the following disclaimer.
9+
# - Redistributions in binary form must reproduce the above copyright notice,
10+
# this list of conditions and the following disclaimer in the documentation
11+
# and/or other materials provided with the distribution.
12+
# - Neither the name of the copyright holder nor the names of its contributors
13+
# may be used to endorse or promote products derived from this software
14+
# without specific prior written permission.
15+
#
16+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26+
# THE POSSIBILITY OF SUCH DAMAGE.
27+
# *****************************************************************************
28+
29+
import os
30+
import shutil
31+
import subprocess
32+
import sys
33+
import warnings
34+
35+
36+
def get_dpctl_cmake_dir():
37+
"""
38+
If dpctl is locally built using `script/build_locally.py`, it is needed
39+
to pass the -DDpctl_ROOT=$(python -m dpctl --cmakedir) during the build.
40+
If dpctl is conda installed, it is optional to pass this parameter.
41+
42+
"""
43+
44+
process = subprocess.Popen(
45+
[sys.executable, "-m", "dpctl", "--cmakedir"],
46+
stdout=subprocess.PIPE,
47+
stderr=subprocess.PIPE,
48+
)
49+
output, error = process.communicate()
50+
if process.returncode == 0:
51+
return output.decode("utf-8").strip()
52+
53+
raise RuntimeError(
54+
"Failed to retrieve dpctl cmake directory: "
55+
+ error.decode("utf-8").strip()
56+
)
57+
58+
59+
def resolve_compilers(
60+
oneapi: bool,
61+
c_compiler: str,
62+
cxx_compiler: str,
63+
compiler_root: str,
64+
):
65+
is_linux = "linux" in sys.platform
66+
67+
if oneapi or (
68+
c_compiler is None and cxx_compiler is None and compiler_root is None
69+
):
70+
return "icx", ("icpx" if is_linux else "icx")
71+
72+
if (
73+
(c_compiler is None or not os.path.isabs(c_compiler))
74+
and (cxx_compiler is None or not os.path.isabs(cxx_compiler))
75+
and (not compiler_root or not os.path.exists(compiler_root))
76+
):
77+
raise RuntimeError(
78+
"--compiler-root option must be set when using non-default DPC++ "
79+
"layout unless absolute paths are provided for both compilers"
80+
)
81+
82+
# default values
83+
if c_compiler is None:
84+
c_compiler = "icx"
85+
if cxx_compiler is None:
86+
cxx_compiler = "icpx" if is_linux else "icx"
87+
88+
compiler_paths = []
89+
for name, opt_name in (
90+
(c_compiler, "--c-compiler"),
91+
(cxx_compiler, "--cxx-compiler"),
92+
):
93+
if os.path.isabs(name):
94+
path = name
95+
else:
96+
path = os.path.join(compiler_root, name)
97+
98+
if not os.path.exists(path):
99+
raise RuntimeError(
100+
f"{opt_name} value {name} not found and {path} not exist"
101+
)
102+
103+
compiler_paths.append(path)
104+
return tuple(compiler_paths)
105+
106+
107+
def resolve_onemath(
108+
onemath: bool,
109+
onemath_dir: str,
110+
target_cuda: str = None,
111+
target_hip: str = None,
112+
onemkl_interfaces: bool = False,
113+
onemkl_interfaces_dir: str = None,
114+
):
115+
# always enable build with oneMath i/f when oneMath path is passed
116+
if onemath_dir:
117+
onemath = True
118+
119+
# always enable build with oneMath i/f for CUDA or HIP target
120+
if target_cuda or target_hip:
121+
onemath = True
122+
123+
# TODO: onemkl_interfaces and onemkl_interfaces_dir are deprecated in
124+
# dpnp-0.19.0 and should be removed in dpnp-0.20.0.
125+
if onemkl_interfaces:
126+
warnings.warn(
127+
"Using 'onemkl_interfaces' is deprecated. Please use 'onemath' instead.",
128+
DeprecationWarning,
129+
stacklevel=2,
130+
)
131+
onemath = True
132+
if onemkl_interfaces_dir is not None:
133+
warnings.warn(
134+
"Using 'onemkl_interfaces_dir' is deprecated. Please use 'onemath_dir' instead.",
135+
DeprecationWarning,
136+
stacklevel=2,
137+
)
138+
onemath_dir = onemkl_interfaces_dir
139+
return onemath, onemath_dir
140+
141+
142+
def run(cmd: list[str], env: dict[str, str] = None, cwd: str = None):
143+
print("+", " ".join(cmd))
144+
subprocess.check_call(
145+
cmd, env=env or os.environ.copy(), cwd=cwd or os.getcwd()
146+
)
147+
148+
149+
def capture_cmd_output(cmd: list[str], cwd: str = None):
150+
print("+", " ".join(cmd))
151+
return (
152+
subprocess.check_output(cmd, cwd=cwd or os.getcwd())
153+
.decode("utf-8")
154+
.strip("\n")
155+
)
156+
157+
158+
def err(msg: str, script: str):
159+
raise RuntimeError(f"[{script}] error: {msg}")
160+
161+
162+
def log_cmake_args(cmake_args: list[str], script: str):
163+
print(f"[{script}] Using CMake args:\n{' '.join(cmake_args)}")
164+
165+
166+
def make_cmake_args(
167+
c_compiler: str = None,
168+
cxx_compiler: str = None,
169+
dpctl_cmake_dir: str = None,
170+
onemath: bool = False,
171+
onemath_dir: str = None,
172+
verbose: bool = False,
173+
other_opts: str = None,
174+
):
175+
args = [
176+
f"-DCMAKE_C_COMPILER:PATH={c_compiler}" if c_compiler else "",
177+
f"-DCMAKE_CXX_COMPILER:PATH={cxx_compiler}" if cxx_compiler else "",
178+
f"-DDpctl_ROOT={dpctl_cmake_dir}" if dpctl_cmake_dir else "",
179+
]
180+
181+
if onemath:
182+
args.append("-DDPNP_USE_ONEMATH=ON")
183+
if onemath_dir:
184+
args.append(f"-DDPNP_ONEMATH_DIR={onemath_dir}")
185+
186+
if verbose:
187+
args.append("-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON")
188+
if other_opts:
189+
args.extend(other_opts.split())
190+
191+
return args
192+
193+
194+
def build_extension(
195+
setup_dir: str,
196+
env: dict[str, str],
197+
cmake_args: list[str],
198+
cmake_executable: str = None,
199+
generator: str = None,
200+
build_type: str = None,
201+
):
202+
cmd = [sys.executable, "setup.py", "build_ext", "--inplace"]
203+
if cmake_executable:
204+
cmd.append(f"--cmake-executable={cmake_executable}")
205+
if generator:
206+
cmd.append(f"--generator={generator}")
207+
if build_type:
208+
cmd.append(f"--build-type={build_type}")
209+
if cmake_args:
210+
cmd.append("--")
211+
cmd += cmake_args
212+
run(
213+
cmd,
214+
env=env,
215+
cwd=setup_dir,
216+
)
217+
218+
219+
def install_editable(setup_dir: str, env: dict[str, str]):
220+
run(
221+
[
222+
sys.executable,
223+
"-m",
224+
"pip",
225+
"install",
226+
"-e",
227+
".",
228+
"--no-build-isolation",
229+
],
230+
env=env,
231+
cwd=setup_dir,
232+
)
233+
234+
235+
def clean_build_dir(setup_dir: str):
236+
if (
237+
not isinstance(setup_dir, str)
238+
or not setup_dir
239+
or not os.path.isdir(setup_dir)
240+
):
241+
raise RuntimeError(f"Invalid setup directory provided: '{setup_dir}'")
242+
target = os.path.join(setup_dir, "_skbuild")
243+
if os.path.exists(target):
244+
print(f"Cleaning build directory: {target}")
245+
try:
246+
shutil.rmtree(target)
247+
except Exception as e:
248+
print(f"Failed to remove build directory: '{target}'")
249+
raise e

0 commit comments

Comments
 (0)