Repository navigation
Expand file tree
/
Copy pathsetup.py
More file actions
389 lines (336 loc) · 13.6 KB
/
Copy pathsetup.py
File metadata and controls
389 lines (336 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# ------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# ------------------------------------------------------------------------
# pylint: disable=C0103
import datetime
import logging
import platform
import shlex
import subprocess
import sys
from glob import glob
from os import environ, getcwd, path, remove
from shutil import copyfile
from setuptools import setup
from setuptools.command.build_ext import build_ext as _build_ext
from setuptools.command.install import install as InstallCommandBase
nightly_build = False
wheel_name_suffix = None
logger = logging.getLogger()
def parse_arg_remove_boolean(argv, arg_name):
arg_value = False
if arg_name in sys.argv:
arg_value = True
argv.remove(arg_name)
return arg_value
def parse_arg_remove_string(argv, arg_name_equal):
arg_value = None
for arg in sys.argv[1:]:
if arg.startswith(arg_name_equal):
arg_value = arg[len(arg_name_equal) :]
sys.argv.remove(arg)
break
return arg_value
# Any combination of the following arguments can be applied
if parse_arg_remove_boolean(sys.argv, "--nightly_build"):
nightly_build = True
wheel_name_suffix = parse_arg_remove_string(sys.argv, "--wheel_name_suffix=")
version_suffix = parse_arg_remove_string(sys.argv, "--version_suffix=")
package_name = "onnxruntime-qnn"
qnn_version = parse_arg_remove_string(sys.argv, "--qnn_version=")
# PEP 513 defined manylinux1_x86_64 and manylinux1_i686
# PEP 571 defined manylinux2010_x86_64 and manylinux2010_i686
# PEP 599 defines the following platform tags:
# manylinux2014_x86_64
# manylinux2014_i686
# manylinux2014_aarch64
# manylinux2014_armv7l
# manylinux2014_ppc64
# manylinux2014_ppc64le
# manylinux2014_s390x
manylinux_tags = [
"manylinux1_i686",
"manylinux1_x86_64",
"manylinux2010_i686",
"manylinux2010_x86_64",
"manylinux2014_aarch64",
"manylinux2014_armv7l",
"manylinux2014_i686",
"manylinux2014_ppc64",
"manylinux2014_ppc64le",
"manylinux2014_s390x",
"manylinux2014_x86_64",
"manylinux_2_28_aarch64",
"manylinux_2_28_x86_64",
"manylinux_2_34_aarch64",
"manylinux_2_34_x86_64",
"manylinux_2_35_x86_64",
]
is_manylinux = environ.get("AUDITWHEEL_PLAT", None) in manylinux_tags
class build_ext(_build_ext): # noqa: N801
def build_extension(self, ext):
dest_file = self.get_ext_fullpath(ext.name)
logger.info("copying %s -> %s", ext.sources[0], dest_file)
copyfile(ext.sources[0], dest_file)
try:
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
class bdist_wheel(_bdist_wheel): # noqa: N801
"""Helper functions to create wheel package"""
def finalize_options(self):
_bdist_wheel.finalize_options(self)
# Insist that this wheel contains more than Python source
self.root_is_pure = False
def run(self):
qnn_dependencies = ["libcdsprpc.so"]
_bdist_wheel.run(self)
if is_manylinux and not disable_auditwheel_repair:
assert self.dist_dir is not None
file = glob(path.join(self.dist_dir, "*linux*.whl"))[0]
logger.info("repairing %s for manylinux1", file)
# Pin to the build's target platform tag. Without --plat, auditwheel
# auto-detects the lowest policy the binaries qualify for and emits a
# compressed tag set (e.g. manylinux_2_34_x86_64.manylinux_2_35_x86_64).
auditwheel_plat = environ["AUDITWHEEL_PLAT"]
auditwheel_cmd = ["auditwheel", "-v", "repair", "--plat", auditwheel_plat, "-w", self.dist_dir, file]
for dep in qnn_dependencies:
auditwheel_cmd.extend(["--exclude", dep])
logger.info("Running %s", " ".join([shlex.quote(arg) for arg in auditwheel_cmd]))
try:
subprocess.run(auditwheel_cmd, check=True, stdout=subprocess.PIPE)
# auditwheel 6.x treats --plat as a ceiling and still emits a compressed
# tag set listing every lower policy the binaries also satisfy. Collapse
# that to the single target tag so the wheel filename is unambiguous.
repaired = glob(path.join(self.dist_dir, "*manylinux*.whl"))[0]
retag_cmd = [
"python",
"-m",
"wheel",
"tags",
"--remove",
"--platform-tag",
auditwheel_plat,
repaired,
]
logger.info("Running %s", " ".join([shlex.quote(arg) for arg in retag_cmd]))
subprocess.run(retag_cmd, check=True, stdout=subprocess.PIPE)
finally:
logger.info("removing %s", file)
remove(file)
except ImportError as error:
print("Error importing dependencies:")
print(error)
bdist_wheel = None
class InstallCommand(InstallCommandBase):
def finalize_options(self):
ret = InstallCommandBase.finalize_options(self)
self.install_lib = self.install_platlib
return ret
providers_qnn = "onnxruntime_providers_qnn"
if platform.system() == "Linux":
providers_qnn = "lib" + providers_qnn + ".so"
elif platform.system() == "Windows":
providers_qnn = providers_qnn + ".dll"
# Additional binaries
dl_libs = []
libs = []
if platform.system() == "Linux" or platform.system() == "AIX":
dl_libs.append(providers_qnn)
# QNN-EP is built as shared libs
libs.append(providers_qnn)
# QNN
qnn_deps = [
"libGenie.so",
"libHtpPrepare.so",
"libQnnGpu.so",
"libQnnHtp.so",
"libQnnHtpNetRunExtensions.so",
"libQnnHtpPrepare.so",
"libQnnHtpV68Skel.so",
"libQnnHtpV68Stub.so",
"libQnnHtpV69Skel.so",
"libQnnHtpV69Stub.so",
"libQnnHtpV73Skel.so",
"libQnnHtpV73Stub.so",
"libQnnHtpV75Skel.so",
"libQnnHtpV75Stub.so",
"libQnnHtpV79Skel.so",
"libQnnHtpV79Stub.so",
"libQnnHtpV81Skel.so",
"libQnnHtpV81Stub.so",
"libQnnIr.so",
"libQnnSaver.so",
"libQnnSystem.so",
]
dl_libs.extend(qnn_deps)
else:
# QNN-EP is built as shared libs
libs = [providers_qnn]
# QNN V68/V73/V81 dependencies
qnn_deps = [
"Genie.dll",
"HtpPrepare.dll",
"QnnGpu.dll",
"QnnHtp.dll",
"QnnHtpNetRunExtensions.dll",
"QnnHtpPrepare.dll",
"QnnHtpV68Stub.dll",
"QnnHtpV73Stub.dll",
"QnnHtpV81Stub.dll",
"QnnIr.dll",
"QnnSaver.dll",
"QnnSystem.dll",
"libQnnHtpV68Skel.so",
"libQnnHtpV73Skel.so",
"libQnnHtpV81Skel.so",
"libqnnhtpv73.cat",
"libqnnhtpv81.cat",
]
libs.extend(qnn_deps)
if is_manylinux or platform.system() == "Linux":
data = list(dl_libs)
else:
data = list(libs)
ext_modules = []
# Extra files such as EULA and ThirdPartyNotices (and Qualcomm License, only for QNN release packages)
extra = ["LICENSE", "ThirdPartyNotices.txt", "Privacy.md", "Qualcomm_LICENSE.pdf"]
# QAIRT SDK pybind extensions bundled next to deploy_multi_soc_ep_context.py
# (.so on Linux, .pyd on Windows).
if sys.version_info[:2] == (3, 12):
if platform.system() == "Windows":
dlc_utils_libs = ["libDlModelToolsPy312.pyd"]
else:
dlc_utils_libs = ["libDlModelToolsPy312.so"]
else:
dlc_utils_libs = []
# Description
readme_file = "docs/python/README.rst"
README = path.join(getcwd(), readme_file)
if not path.exists(README):
this = path.dirname(__file__)
README = path.join(this, readme_file)
if not path.exists(README):
raise FileNotFoundError("Unable to find 'README.rst'")
with open(README, encoding="utf-8") as fdesc:
long_description = fdesc.read()
data_files = []
requirements_file = "requirements.txt"
disable_auditwheel_repair = parse_arg_remove_boolean(sys.argv, "--disable_auditwheel_repair")
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: POSIX :: Linux",
"Operating System :: Microsoft :: Windows",
"Operating System :: MacOS",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Mathematics",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Topic :: Software Development",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Libraries :: Python Modules",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]
packages = ["onnxruntime_qnn"]
package_data = {"onnxruntime_qnn": data + extra + dlc_utils_libs}
version_number = ""
with open("VERSION_NUMBER") as f:
version_number = f.readline().strip()
if nightly_build:
# https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables
build_suffix = environ.get("BUILD_BUILDNUMBER")
if build_suffix is None:
# The following line is only for local testing
build_suffix = str(datetime.datetime.now().date().strftime("%Y%m%d"))
else:
build_suffix = build_suffix.replace(".", "")
if len(build_suffix) > 8 and len(build_suffix) < 12:
# we want to format the build_suffix to avoid (the 12th run on 20210630 vs the first run on 20210701):
# 2021063012 > 202107011
# in above 2021063012 is treated as the latest which is incorrect.
# we want to convert the format to:
# 20210630012 < 20210701001
# where the first 8 digits are date. the last 3 digits are run count.
# as long as there are less than 1000 runs per day, we will not have the problem.
# to test this code locally, run:
# NIGHTLY_BUILD=1 BUILD_BUILDNUMBER=202107011 python tools/ci_build/build.py --config RelWithDebInfo \
# --enable_training --use_cuda --cuda_home /usr/local/cuda --cudnn_home /usr/lib/x86_64-linux-gnu/ \
# --nccl_home /usr/lib/x86_64-linux-gnu/ --build_dir build/Linux --build --build_wheel --skip_tests \
# --cuda_version 11.1
def check_date_format(date_str):
try:
datetime.datetime.strptime(date_str, "%Y%m%d")
return True
except Exception:
return False
def reformat_run_count(count_str):
try:
count = int(count_str)
if count >= 0 and count < 1000:
return f"{count:03}"
elif count >= 1000:
raise RuntimeError(f"Too many builds for the same day: {count}")
return ""
except Exception:
return ""
build_suffix_is_date_format = check_date_format(build_suffix[:8])
build_suffix_run_count = reformat_run_count(build_suffix[8:])
if build_suffix_is_date_format and build_suffix_run_count:
build_suffix = build_suffix[:8] + build_suffix_run_count
elif len(build_suffix) >= 12:
raise RuntimeError(f'Incorrect build suffix: "{build_suffix}"')
version_number = version_number + ".dev" + build_suffix
elif not nightly_build and version_suffix:
version_number += "." + version_suffix
if wheel_name_suffix:
package_name = f"{package_name}-{wheel_name_suffix}"
cmd_classes = {}
if bdist_wheel is not None:
cmd_classes["bdist_wheel"] = bdist_wheel
cmd_classes["install"] = InstallCommand
cmd_classes["build_ext"] = build_ext
requirements_path = path.join(getcwd(), requirements_file)
if not path.exists(requirements_path):
this = path.dirname(__file__)
requirements_path = path.join(this, requirements_file)
if not path.exists(requirements_path):
raise FileNotFoundError("Unable to find " + requirements_file)
with open(requirements_path) as f:
install_requires = f.read().splitlines()
def save_build_and_package_info(package_name, version_number, qnn_version):
sys.path.append(path.join(path.dirname(__file__), "onnxruntime", "python"))
version_path = path.join("onnxruntime_qnn", "build_and_package_info.py")
with open(version_path, "w") as f:
f.write(f"package_name = '{package_name}'\n")
f.write(f"__version__ = '{version_number}'\n")
if qnn_version:
f.write(f"qnn_version = '{qnn_version}'\n")
save_build_and_package_info(package_name, version_number, qnn_version)
extras_require = {}
setup(
name=package_name,
version=version_number,
description="ONNX Runtime QNN is an onnxruntime execution provider optimized for Qualcomm AI accelerators",
long_description=long_description,
long_description_content_type="text/x-rst",
author="Qualcomm Technologies, Inc.",
author_email="onnxruntime-qnn@qti.qualcomm.com",
cmdclass=cmd_classes,
license="MIT License",
packages=packages,
ext_modules=ext_modules,
package_data=package_data,
url="https://github.com/onnxruntime/onnxruntime-qnn/blob/main/docs/execution_providers/QNN-ExecutionProvider.md",
download_url="https://github.com/onnxruntime/onnxruntime-qnn/tags",
data_files=data_files,
install_requires=install_requires,
extras_require=extras_require,
python_requires=">=3.11",
keywords="onnx machine learning qnn qualcomm",
classifiers=classifiers,
)