Skip to content

Commit 6136555

Browse files
Closes #777
When scikit-build assembles dpctl, it runs cmake with "_skbuild/*/cmake-build" being its build directory, "_skbuild/*/cmake-install" being its install directory. It then runs setuptools.setup to execute build_py steps using "_skbuild/*/setuptools" as its build_base. Since sycl interface library is registered in package-data, it is copied from cmake-install (where is has symbolic links) to setuptools (where unpatched setuptools.command.build_py command follows them turning them into hard files). Then, when running install_lib step, files from _"skbuild/*/setuptools/lib/dpctl" are copied into site-packages/dpctl using copy_tree, which also follows symbolic links, hence turning them into hard links). This PR transfers logic from pre-scikit-build setup.py to fix hard links as post setuptools.command.install.run() step). A test is added to tests/test_service.py to verify that on Linux some of library files are symbolic links.
1 parent 902fa01 commit 6136555

File tree

2 files changed

+66
-6
lines changed

2 files changed

+66
-6
lines changed

dpctl/tests/test_service.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import os
2424
import os.path
2525
import re
26+
import sys
2627

2728
import pytest
2829

@@ -129,3 +130,25 @@ def test_dev_utils():
129130
with pytest.raises(ValueError):
130131
with ctx_mngr(log_dir="/not_a_dir"):
131132
dpctl.SyclDevice().parent_device
133+
134+
135+
def test_syclinterface():
136+
install_dir = os.path.dirname(os.path.abspath(dpctl.__file__))
137+
paths = glob.glob(os.path.join(install_dir, "*DPCTLSyclInterface*"))
138+
if "linux" in sys.platform:
139+
assert len(paths) > 1 and any(
140+
[os.path.islink(fn) for fn in paths]
141+
), "All library instances are hard links"
142+
elif sys.platform in ["win32", "cygwin"]:
143+
exts = []
144+
for fn in paths:
145+
_, file_ext = os.path.splitext(fn)
146+
exts.append(file_ext.lower())
147+
assert (
148+
".lib" in exts
149+
), "Installation does not have DPCTLSyclInterface.lib"
150+
assert (
151+
".dll" in exts
152+
), "Installation does not have DPCTLSyclInterface.dll"
153+
else:
154+
raise RuntimeError("Unsupported system")

setup.py

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17+
import glob
1718
import os.path
1819
import pathlib
1920
import shutil
21+
import sys
2022

2123
import skbuild
2224
import skbuild.setuptools_wrap
2325
import skbuild.utils
2426
from setuptools import find_packages
27+
from skbuild.command.build_py import build_py as _skbuild_build_py
28+
from skbuild.command.install import install as _skbuild_install
2529

2630
import versioneer
2731

@@ -30,11 +34,6 @@
3034
long_description = file.read()
3135

3236

33-
def _get_cmdclass():
34-
cmdclass = versioneer.get_cmdclass()
35-
return cmdclass
36-
37-
3837
def cleanup_destination(cmake_manifest):
3938
"""Delete library files from dpctl/ folder before
4039
letting skbuild copy them over to avoid errors.
@@ -52,7 +51,9 @@ def cleanup_destination(cmake_manifest):
5251
return cmake_manifest
5352

5453

55-
def _patched_copy_file(src_file, dest_file, hide_listing=True):
54+
def _patched_copy_file(
55+
src_file, dest_file, hide_listing=True, preserve_mode=True
56+
):
5657
"""Copy ``src_file`` to ``dest_file`` ensuring parent directory exists.
5758
5859
By default, message like `creating directory /path/to/package` and
@@ -79,6 +80,42 @@ def _patched_copy_file(src_file, dest_file, hide_listing=True):
7980
skbuild.setuptools_wrap._copy_file = _patched_copy_file
8081

8182

83+
class BuildPyCmd(_skbuild_build_py):
84+
def copy_file(self, src, dst, preserve_mode=True):
85+
_patched_copy_file(src, dst, preserve_mode=preserve_mode)
86+
return (dst, 1)
87+
88+
89+
class InstallCmd(_skbuild_install):
90+
def run(self):
91+
ret = super().run()
92+
if "linux" in sys.platform:
93+
dpctl_build_dir = os.path.join(
94+
os.path.dirname(__file__), self.build_lib, "dpctl"
95+
)
96+
dpctl_install_dir = os.path.join(self.install_libbase, "dpctl")
97+
for fn in glob.glob(
98+
os.path.join(dpctl_install_dir, "*DPCTLSyclInterface.so*")
99+
):
100+
os.remove(fn)
101+
shutil.copy(
102+
src=os.path.join(dpctl_build_dir, os.path.basename(fn)),
103+
dst=dpctl_install_dir,
104+
follow_symlinks=False,
105+
)
106+
return ret
107+
108+
109+
def _get_cmdclass():
110+
cmdclass = versioneer.get_cmdclass(
111+
cmdclass={
112+
"build_py": BuildPyCmd,
113+
"install": InstallCmd,
114+
}
115+
)
116+
return cmdclass
117+
118+
82119
skbuild.setup(
83120
name="dpctl",
84121
version=versioneer.get_version(),

0 commit comments

Comments
 (0)