Skip to content

Commit 8dd23c9

Browse files
1e-toetotmeni
and
etotmeni
authored
setup.py for building C++ backend (#168)
Co-authored-by: etotmeni <elena.totmenina@intel.com>
1 parent 7c16e04 commit 8dd23c9

File tree

6 files changed

+141
-81
lines changed

6 files changed

+141
-81
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
88
- Device descriptors "max_compute_units", "max_work_item_dimensions", "max_work_item_sizes", "max_work_group_size", "max_num_sub_groups" and "aspects" for int64 atomics inside dpctl C API and inside the dpctl.SyclDevice class.
99
- MemoryUSM* classes moved to `dpctl.memory` module, added support for aligned allocation, added support for `prefetch` and `mem_advise` (sychronous) methods, implemented `copy_to_host`, `copy_from_host` and `copy_from_device` methods, pickling support, and zero-copy interoperability with Python objects which implement `__sycl_usm_array_inerface__` protocol.
1010
- Helper scripts to generate API documentation for both C API and Python.
11+
- setup.py builds C++ backend for develop and install commands.
1112

1213
### Fixed
1314
- Compiler warnings when building libDPPLSyclInterface and the Cython extensions.

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ conda build --croot=C:/tmp conda-recipe
3636
conda install dpctl
3737
```
3838

39+
Build and Install with setuptools
40+
=================================
41+
dpCtl relies on DPC++ runtime. With Intel oneAPI installed you should activate it.
42+
43+
For install:
44+
```cmd
45+
python setup.py install
46+
```
47+
48+
For development:
49+
```cmd
50+
python setup.py develop
51+
```
52+
3953
Using dpCtl
4054
===========
4155
dpCtl relies on DPC++ runtime. With Intel oneAPI installed you should activate it.

conda-recipe/bld.bat

+1-39
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,7 @@ IF %ERRORLEVEL% NEQ 0 (
33
echo "oneAPI compiler activation failed"
44
exit /b 1
55
)
6-
REM conda uses %ERRORLEVEL% but FPGA scripts can set it. So it should be reseted.
7-
set ERRORLEVEL=
8-
9-
set "CC=clang-cl.exe"
10-
set "CXX=dpcpp.exe"
11-
12-
rmdir /S /Q build_cmake
13-
mkdir build_cmake
14-
cd build_cmake
15-
16-
set "DPCPP_ROOT=%ONEAPI_ROOT%\compiler\latest\windows"
17-
set "INSTALL_PREFIX=%cd%\..\install"
18-
19-
rmdir /S /Q "%INSTALL_PREFIX%"
20-
21-
cmake -G Ninja ^
22-
-DCMAKE_BUILD_TYPE=Release ^
23-
"-DCMAKE_INSTALL_PREFIX=%INSTALL_PREFIX%" ^
24-
"-DCMAKE_PREFIX_PATH=%LIBRARY_PREFIX%" ^
25-
"-DDPCPP_ROOT=%DPCPP_ROOT%" ^
26-
"%SRC_DIR%\backends"
27-
IF %ERRORLEVEL% NEQ 0 exit /b 1
28-
29-
ninja -n
30-
ninja install
31-
IF %ERRORLEVEL% NEQ 0 exit /b 1
32-
33-
cd ..
34-
xcopy install\lib\*.lib dpctl /E /Y
35-
xcopy install\bin\*.dll dpctl /E /Y
36-
37-
mkdir dpctl\include
38-
xcopy backends\include dpctl\include /E /Y
39-
40-
41-
REM required by _sycl_core(dpctl)
42-
set "DPPL_SYCL_INTERFACE_LIBDIR=dpctl"
43-
set "DPPL_SYCL_INTERFACE_INCLDIR=dpctl\include"
446

457
"%PYTHON%" setup.py clean --all
46-
"%PYTHON%" setup.py build install
8+
"%PYTHON%" setup.py install
479
IF %ERRORLEVEL% NEQ 0 exit /b 1

conda-recipe/build.sh

+1-41
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,10 @@
44
if [ ! -z "${ONEAPI_ROOT}" ]; then
55
# Suppress error b/c it could fail on Ubuntu 18.04
66
source ${ONEAPI_ROOT}/compiler/latest/env/vars.sh || true
7-
export CC=clang
8-
export CXX=clang++
97
else
108
echo "DPCPP is needed to build DPPL. Abort!"
119
exit 1
1210
fi
1311

14-
rm -rf build_cmake
15-
mkdir build_cmake
16-
pushd build_cmake
17-
18-
INSTALL_PREFIX=`pwd`/../install
19-
rm -rf ${INSTALL_PREFIX}
20-
21-
PYTHON_INC=`${PYTHON} -c "import distutils.sysconfig; \
22-
print(distutils.sysconfig.get_python_inc())"`
23-
NUMPY_INC=`${PYTHON} -c "import numpy; print(numpy.get_include())"`
24-
DPCPP_ROOT=${ONEAPI_ROOT}/compiler/latest/linux/
25-
26-
cmake \
27-
-DCMAKE_BUILD_TYPE=Release \
28-
-DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \
29-
-DCMAKE_PREFIX_PATH=${INSTALL_PREFIX} \
30-
-DDPCPP_ROOT=${DPCPP_ROOT} \
31-
-DPYTHON_INCLUDE_DIR=${PYTHON_INC} \
32-
-DNUMPY_INCLUDE_DIR=${NUMPY_INC} \
33-
../backends
34-
35-
make -j 4 && make install
36-
37-
popd
38-
cp install/lib/*.so dpctl/
39-
40-
mkdir -p dpctl/include
41-
cp -r backends/include/* dpctl/include
42-
43-
44-
# required by dpctl.sycl_core
45-
export DPPL_SYCL_INTERFACE_LIBDIR=dpctl
46-
export DPPL_SYCL_INTERFACE_INCLDIR=dpctl/include
47-
48-
49-
# FIXME: How to pass this using setup.py? This flags is needed when
50-
# dpcpp compiles the generated cpp file.
51-
export CFLAGS="-fPIC -O3 ${CFLAGS}"
5212
${PYTHON} setup.py clean --all
53-
${PYTHON} setup.py build install
13+
${PYTHON} setup.py install

scripts/build_backend.py

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import os
2+
import sys
3+
import subprocess
4+
import shutil
5+
import glob
6+
7+
IS_WIN = False
8+
IS_LIN = False
9+
10+
if "linux" in sys.platform:
11+
IS_LIN = True
12+
elif sys.platform in ["win32", "cygwin"]:
13+
IS_WIN = True
14+
else:
15+
assert False, sys.platform + " not supported"
16+
17+
ONEAPI_ROOT = os.environ.get("ONEAPI_ROOT")
18+
19+
if IS_LIN:
20+
DPCPP_ROOT = os.path.join(ONEAPI_ROOT, "compiler/latest/linux")
21+
if IS_WIN:
22+
DPCPP_ROOT = os.path.join(ONEAPI_ROOT, "compiler\latest\windows")
23+
24+
dpctl_dir = os.getcwd()
25+
build_cmake_dir = os.path.join(dpctl_dir, "build_cmake")
26+
if os.path.exists(build_cmake_dir):
27+
shutil.rmtree(build_cmake_dir)
28+
os.mkdir(build_cmake_dir)
29+
os.chdir(build_cmake_dir)
30+
31+
INSTALL_PREFIX = os.path.join(dpctl_dir, "install")
32+
if os.path.exists(INSTALL_PREFIX):
33+
shutil.rmtree(INSTALL_PREFIX)
34+
35+
backends_dir = os.path.join(dpctl_dir, "backends")
36+
37+
if IS_LIN:
38+
cmake_args = [
39+
"cmake",
40+
"-DCMAKE_BUILD_TYPE=Release",
41+
"-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX,
42+
"-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX,
43+
"-DDPCPP_ROOT=" + DPCPP_ROOT,
44+
"-DCMAKE_C_COMPILER:PATH=" + os.path.join(DPCPP_ROOT, "bin", "clang"),
45+
"-DCMAKE_CXX_COMPILER:PATH=" + os.path.join(DPCPP_ROOT, "bin", "clang++"),
46+
backends_dir,
47+
]
48+
subprocess.check_call(cmake_args, stderr=subprocess.STDOUT, shell=False)
49+
subprocess.check_call(["make", "-j", "4"])
50+
subprocess.check_call(["make", "install"])
51+
52+
os.chdir(dpctl_dir)
53+
for file in glob.glob(os.path.join(dpctl_dir, "install", "lib", "*.so")):
54+
shutil.copy(file, os.path.join(dpctl_dir, "dpctl"))
55+
56+
if IS_WIN:
57+
cmake_args = [
58+
"cmake",
59+
"-G",
60+
"Ninja",
61+
"-DCMAKE_BUILD_TYPE=Release",
62+
"-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX,
63+
"-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX,
64+
"-DDPCPP_ROOT=" + DPCPP_ROOT,
65+
backends_dir,
66+
]
67+
subprocess.check_call(cmake_args, stderr=subprocess.STDOUT, shell=True)
68+
subprocess.check_call(["ninja", "-n"])
69+
subprocess.check_call(["ninja", "install"])
70+
71+
os.chdir(dpctl_dir)
72+
for file in glob.glob(os.path.join(dpctl_dir, "install", "lib", "*.lib")):
73+
shutil.copy(file, os.path.join(dpctl_dir, "dpctl"))
74+
75+
for file in glob.glob(os.path.join(dpctl_dir, "install", "bin", "*.dll")):
76+
shutil.copy(file, os.path.join(dpctl_dir, "dpctl"))
77+
78+
include_dir = os.path.join(dpctl_dir, "dpctl", "include")
79+
if os.path.exists(include_dir):
80+
shutil.rmtree(include_dir)
81+
82+
shutil.copytree(os.path.join(dpctl_dir, "backends", "include"), include_dir)

setup.py

+42-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
import os.path
2626
import sys
2727
import versioneer
28+
import subprocess
2829

30+
import setuptools.command.install as orig_install
31+
import setuptools.command.develop as orig_develop
2932
from setuptools import setup, Extension, find_packages
3033
from Cython.Build import cythonize
3134

@@ -48,6 +51,20 @@
4851
else:
4952
assert False, sys.platform + " not supported"
5053

54+
if IS_LIN:
55+
DPCPP_ROOT = os.environ["ONEAPI_ROOT"] + "/compiler/latest/linux"
56+
os.environ["CC"] = DPCPP_ROOT + "/bin/clang"
57+
os.environ["CXX"] = DPCPP_ROOT + "/bin/clang++"
58+
os.environ["DPPL_SYCL_INTERFACE_LIBDIR"] = "dpctl"
59+
os.environ["DPPL_SYCL_INTERFACE_INCLDIR"] = "dpctl/include"
60+
os.environ["CFLAGS"] = "-fPIC"
61+
62+
elif IS_WIN:
63+
os.environ["CC"] = "clang-cl.exe"
64+
os.environ["CXX"] = "dpcpp.exe"
65+
os.environ["DPPL_SYCL_INTERFACE_LIBDIR"] = "dpctl"
66+
os.environ["DPPL_SYCL_INTERFACE_INCLDIR"] = "dpctl\include"
67+
5168
dppl_sycl_interface_lib = os.environ["DPPL_SYCL_INTERFACE_LIBDIR"]
5269
dppl_sycl_interface_include = os.environ["DPPL_SYCL_INTERFACE_INCLDIR"]
5370
sycl_lib = os.environ["ONEAPI_ROOT"] + "\compiler\latest\windows\lib"
@@ -99,6 +116,11 @@ def get_suppressed_warning_flags():
99116
return []
100117

101118

119+
def build_backend():
120+
build_script = os.path.join(os.getcwd(), "scripts", "build_backend.py")
121+
subprocess.check_call([sys.executable, build_script])
122+
123+
102124
def extensions():
103125
# Security flags
104126
eca = get_sdl_cflags()
@@ -161,10 +183,29 @@ def extensions():
161183
return exts
162184

163185

186+
class install(orig_install.install):
187+
def run(self):
188+
build_backend()
189+
return super().run()
190+
191+
192+
class develop(orig_develop.develop):
193+
def run(self):
194+
build_backend()
195+
return super().run()
196+
197+
198+
def _get_cmdclass():
199+
cmdclass = versioneer.get_cmdclass()
200+
cmdclass["install"] = install
201+
cmdclass["develop"] = develop
202+
return cmdclass
203+
204+
164205
setup(
165206
name="dpctl",
166207
version=versioneer.get_version(),
167-
cmdclass=versioneer.get_cmdclass(),
208+
cmdclass=_get_cmdclass(),
168209
description="A lightweight Python wrapper for a subset of OpenCL and SYCL.",
169210
license="Apache 2.0",
170211
author="Intel Corporation",

0 commit comments

Comments
 (0)