setup.py 7.17 KB
Newer Older
Minjie Wang's avatar
Minjie Wang committed
1
2
#!/usr/bin/env python
# -*- coding: utf-8 -*-
3
import glob
4
import os
Minjie Wang's avatar
Minjie Wang committed
5
import shutil
6
7
import sys
import sysconfig
Minjie Wang's avatar
Minjie Wang committed
8

9
from setuptools import find_packages, setup
Minjie Wang's avatar
Minjie Wang committed
10
from setuptools.dist import Distribution
11
from setuptools.extension import Extension
Minjie Wang's avatar
Minjie Wang committed
12

13

Minjie Wang's avatar
Minjie Wang committed
14
15
class BinaryDistribution(Distribution):
    def has_ext_modules(self):
16
        return True
Minjie Wang's avatar
Minjie Wang committed
17

18

Minjie Wang's avatar
Minjie Wang committed
19
20
CURRENT_DIR = os.path.dirname(__file__)

21

Minjie Wang's avatar
Minjie Wang committed
22
23
def get_lib_path():
    """Get library path, name and version"""
24
    # We can not import `libinfo.py` in setup.py directly since __init__.py
Minjie Wang's avatar
Minjie Wang committed
25
    # Will be invoked which introduces dependences
26
27
    libinfo_py = os.path.join(CURRENT_DIR, "./dgl/_ffi/libinfo.py")
    libinfo = {"__file__": libinfo_py}
28
    exec(
29
30
        compile(open(libinfo_py, "rb").read(), libinfo_py, "exec"),
        libinfo,
31
        libinfo,
32
33
    )
    version = libinfo["__version__"]
Gan Quan's avatar
Gan Quan committed
34

35
    lib_path = libinfo["find_lib_path"]()
Gan Quan's avatar
Gan Quan committed
36
37
    libs = [lib_path[0]]

Minjie Wang's avatar
Minjie Wang committed
38
39
    return libs, version

40

peizhou001's avatar
peizhou001 committed
41
def get_lib_pattern(lib_name):
42
    if sys.platform.startswith("linux"):
peizhou001's avatar
peizhou001 committed
43
        lib_pattern = f"lib{lib_name}_*.so"
44
    elif sys.platform.startswith("darwin"):
peizhou001's avatar
peizhou001 committed
45
        lib_pattern = f"lib{lib_name}_*.dylib"
46
    elif sys.platform.startswith("win"):
peizhou001's avatar
peizhou001 committed
47
        lib_pattern = f"{lib_name}_*.dll"
48
    else:
49
        raise NotImplementedError("Unsupported system: %s" % sys.platform)
peizhou001's avatar
peizhou001 committed
50
    return lib_pattern
51
52


Minjie Wang's avatar
Minjie Wang committed
53
LIBS, VERSION = get_lib_path()
54
BACKENDS = ["pytorch"]
peizhou001's avatar
peizhou001 committed
55
56
57
58
59
60
61
62
63
64


def remove_lib(lib_name):
    for lib_path in glob.glob(
        os.path.join(CURRENT_DIR, "dgl", lib_name, get_lib_pattern(lib_name))
    ):
        try:
            os.remove(lib_path)
        except BaseException:
            pass
65

66

67
68
69
70
def cleanup():
    # Wheel cleanup
    try:
        os.remove("MANIFEST.in")
71
    except BaseException:
72
73
74
75
76
77
        pass

    for path in LIBS:
        _, libname = os.path.split(path)
        try:
            os.remove(os.path.join("dgl", libname))
78
        except BaseException:
79
80
            pass
    for backend in BACKENDS:
peizhou001's avatar
peizhou001 committed
81
        remove_lib("tensoradapter")
Minjie Wang's avatar
Minjie Wang committed
82

83
        if backend == "pytorch":
peizhou001's avatar
peizhou001 committed
84
85
            remove_lib("dgl_sparse")
            remove_lib("graphbolt")
86

87
    # Remove build artifacts.
Rhett Ying's avatar
Rhett Ying committed
88
    dir_to_remove = ["build", "dgl.egg-info"]
89
90
91
92
93
    for dir_ in dir_to_remove:
        print(f"Removing {dir_}")
        if os.path.isdir(dir_):
            shutil.rmtree(dir_)

94

95
96
def config_cython():
    """Try to configure cython and return cython configuration"""
97
98
99
100
    if sys.platform.startswith("win"):
        print(
            "WARNING: Cython is not supported on Windows, will compile without cython module"
        )
101
102
103
104
        return []
    sys_cflags = sysconfig.get_config_var("CFLAGS")

    if "i386" in sys_cflags and "x86_64" in sys_cflags:
105
        print(
106
107
            "WARNING: Cython library may not be compiled correctly with both i386 and x64"
        )
108
109
110
        return []
    try:
        from Cython.Build import cythonize
111

112
113
114
115
116
117
118
        # from setuptools.extension import Extension
        if sys.version_info >= (3, 0):
            subdir = "_cy3"
        else:
            subdir = "_cy2"
        ret = []
        path = "dgl/_ffi/_cython"
119
120
        library_dirs = ["dgl", "../build/Release", "../build"]
        libraries = ["dgl"]
121
122
123
        for fn in os.listdir(path):
            if not fn.endswith(".pyx"):
                continue
124
125
126
127
128
129
130
131
132
133
134
135
            ret.append(
                Extension(
                    "dgl._ffi.%s.%s" % (subdir, fn[:-4]),
                    ["dgl/_ffi/_cython/%s" % fn],
                    include_dirs=[
                        "../include/",
                        "../third_party/dmlc-core/include",
                        "../third_party/dlpack/include",
                    ],
                    library_dirs=library_dirs,
                    libraries=libraries,
                    # Crashes without this flag with GCC 5.3.1
136
                    extra_compile_args=["-std=c++17"],
137
138
139
                    language="c++",
                )
            )
Xin Yao's avatar
Xin Yao committed
140
141
142
        return cythonize(
            ret, force=True, compiler_directives={"language_level": "3"}
        )
143
    except ImportError:
144
145
146
        print(
            "WARNING: Cython is not installed, will compile without cython module"
        )
147
148
        return []

149

peizhou001's avatar
peizhou001 committed
150
151
152
153
154
def copy_lib(lib_name, backend=""):
    for lib_path in glob.glob(
        os.path.join(dir_, lib_name, backend, get_lib_pattern(lib_name))
    ):
        lib_file_name = os.path.basename(lib_path)
Xin Yao's avatar
Xin Yao committed
155
        dst_dir_ = os.path.join(CURRENT_DIR, "dgl", lib_name, backend)
peizhou001's avatar
peizhou001 committed
156
157
158
159
160
161
162
163
        os.makedirs(
            dst_dir_,
            exist_ok=True,
        )
        shutil.copy(
            os.path.join(dir_, lib_name, backend, lib_file_name),
            dst_dir_,
        )
Xin Yao's avatar
Xin Yao committed
164
        fo.write(f"include dgl/{lib_name}/{backend}/{lib_file_name}\n")
peizhou001's avatar
peizhou001 committed
165
166


Minjie Wang's avatar
Minjie Wang committed
167
168
include_libs = False
wheel_include_libs = False
169
if "bdist_wheel" in sys.argv or os.getenv("CONDA_BUILD"):
Gan Quan's avatar
Gan Quan committed
170
    wheel_include_libs = True
171
172
elif "clean" in sys.argv:
    cleanup()
Gan Quan's avatar
Gan Quan committed
173
174
else:
    include_libs = True
Minjie Wang's avatar
Minjie Wang committed
175
176
177
178
179
180
181

setup_kwargs = {}

# For bdist_wheel only
if wheel_include_libs:
    with open("MANIFEST.in", "w") as fo:
        for path in LIBS:
182
            shutil.copy(path, os.path.join(CURRENT_DIR, "dgl"))
183
            dir_, libname = os.path.split(path)
Minjie Wang's avatar
Minjie Wang committed
184
            fo.write("include dgl/%s\n" % libname)
185
186

        for backend in BACKENDS:
peizhou001's avatar
peizhou001 committed
187
            copy_lib("tensoradapter", backend)
188
            if backend == "pytorch":
peizhou001's avatar
peizhou001 committed
189
190
                copy_lib("dgl_sparse")
                copy_lib("graphbolt")
191
    setup_kwargs = {"include_package_data": True}
Minjie Wang's avatar
Minjie Wang committed
192

peizhou001's avatar
peizhou001 committed
193
194
195

def get_lib_file_path(lib_name, backend=""):
    return (
Xin Yao's avatar
Xin Yao committed
196
        f"dgl/{lib_name}/{backend}",
peizhou001's avatar
peizhou001 committed
197
198
199
200
201
202
203
204
205
206
207
        glob.glob(
            os.path.join(
                os.path.dirname(os.path.relpath(path, CURRENT_DIR)),
                lib_name,
                backend,
                get_lib_pattern(lib_name),
            )
        ),
    )


Minjie Wang's avatar
Minjie Wang committed
208
# For source tree setup
Gan Quan's avatar
Gan Quan committed
209
# Conda build also includes the binary library
Minjie Wang's avatar
Minjie Wang committed
210
211
if include_libs:
    rpath = [os.path.relpath(path, CURRENT_DIR) for path in LIBS]
212
    data_files = [("dgl", rpath)]
213
214
    for path in LIBS:
        for backend in BACKENDS:
peizhou001's avatar
peizhou001 committed
215
            data_files.append(get_lib_file_path("tensoradapter", backend))
216
            if backend == "pytorch":
peizhou001's avatar
peizhou001 committed
217
218
                data_files.append(get_lib_file_path("dgl_sparse"))
                data_files.append(get_lib_file_path("graphbolt"))
219
    setup_kwargs = {"include_package_data": True, "data_files": data_files}
Minjie Wang's avatar
Minjie Wang committed
220

221
222
223
224
225
226
227
228
229
230
231
232
233
# Configure dependencies.
install_requires = [
    "numpy>=1.14.0",
    "scipy>=1.1.0",
    "networkx>=2.1",
    "requests>=2.19.0",
    "tqdm",
    "psutil>=5.8.0",
    "torchdata>=0.5.0",
]
if "DGLBACKEND" in os.environ and os.environ["DGLBACKEND"] != "pytorch":
    install_requires.pop(install_requires.index("torchdata>=0.5.0"))

Minjie Wang's avatar
Minjie Wang committed
234
setup(
235
    name="dgl" + os.getenv("DGL_PACKAGE_SUFFIX", ""),
Minjie Wang's avatar
Minjie Wang committed
236
    version=VERSION,
237
    description="Deep Graph Library",
Minjie Wang's avatar
Minjie Wang committed
238
    zip_safe=False,
239
240
    maintainer="DGL Team",
    maintainer_email="wmjlyjemaine@gmail.com",
Minjie Wang's avatar
Minjie Wang committed
241
    packages=find_packages(),
242
    install_requires=install_requires,
243
    url="https://github.com/dmlc/dgl",
Minjie Wang's avatar
Minjie Wang committed
244
    distclass=BinaryDistribution,
245
    ext_modules=config_cython(),
Minjie Wang's avatar
Minjie Wang committed
246
    classifiers=[
247
248
249
        "Development Status :: 3 - Alpha",
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: Apache Software License",
Minjie Wang's avatar
Minjie Wang committed
250
    ],
251
    license="APACHE",
peizhou001's avatar
peizhou001 committed
252
    **setup_kwargs,
Minjie Wang's avatar
Minjie Wang committed
253
254
255
)

if wheel_include_libs:
256
    cleanup()