Skip to content

Commit 1bbc5c0

Browse files
committed
Move QNN SDK into backends/qualcomm/CMakeLists.txt
1 parent 9d68039 commit 1bbc5c0

File tree

4 files changed

+119
-88
lines changed

4 files changed

+119
-88
lines changed

backends/qualcomm/CMakeLists.txt

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,53 @@ get_filename_component(
2323
_common_include_directories "${EXECUTORCH_SOURCE_DIR}/.." ABSOLUTE
2424
)
2525

26-
if(NOT DEFINED QNN_SDK_ROOT)
27-
message(
28-
FATAL_ERROR
29-
"Please define QNN_SDK_ROOT, e.g. cmake <..> -DQNN_SDK_ROOT=<...>"
30-
)
31-
elseif(CMAKE_TOOLCHAIN_FILE MATCHES ".*(iOS|ios\.toolchain)\.cmake$")
26+
if(CMAKE_TOOLCHAIN_FILE MATCHES ".*(iOS|ios\.toolchain)\.cmake$")
3227
message(FATAL_ERROR "ios is not supported by Qualcomm AI Engine Direct")
3328
endif()
3429

30+
set(_qnn_host_is_linux_x86 FALSE)
31+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux"
32+
AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|i.86)$")
33+
set(_qnn_host_is_linux_x86 TRUE)
34+
endif()
35+
36+
if(NOT DEFINED QNN_SDK_ROOT)
37+
if(_qnn_host_is_linux_x86)
38+
find_package(Python3 COMPONENTS Interpreter REQUIRED)
39+
message(STATUS "QNN_SDK_ROOT not provided, downloading Qualcomm SDK")
40+
execute_process(
41+
COMMAND
42+
${Python3_EXECUTABLE}
43+
${EXECUTORCH_SOURCE_DIR}/backends/qualcomm/scripts/download_qnn_sdk.py
44+
--print-sdk-path
45+
WORKING_DIRECTORY ${EXECUTORCH_SOURCE_DIR}
46+
RESULT_VARIABLE _qnn_sdk_download_result
47+
OUTPUT_VARIABLE _qnn_sdk_download_output
48+
ERROR_VARIABLE _qnn_sdk_download_error
49+
OUTPUT_STRIP_TRAILING_WHITESPACE
50+
)
51+
if(NOT _qnn_sdk_download_result EQUAL 0
52+
OR _qnn_sdk_download_output STREQUAL "")
53+
message(
54+
FATAL_ERROR
55+
"Failed to download Qualcomm SDK. stdout: ${_qnn_sdk_download_output}\n"
56+
"stderr: ${_qnn_sdk_download_error}"
57+
)
58+
endif()
59+
set(
60+
QNN_SDK_ROOT
61+
${_qnn_sdk_download_output}
62+
CACHE PATH "Qualcomm SDK root directory" FORCE
63+
)
64+
else()
65+
message(
66+
FATAL_ERROR
67+
"Please define QNN_SDK_ROOT, e.g. cmake <..> -DQNN_SDK_ROOT=<...>"
68+
)
69+
endif()
70+
endif()
71+
72+
set(ENV{QNN_SDK_ROOT} ${QNN_SDK_ROOT})
3573
message(STATUS "Using qnn sdk root ${QNN_SDK_ROOT}")
3674
message(STATUS "Using EXECUTORCH_SOURCE_DIR ${EXECUTORCH_SOURCE_DIR}")
3775

@@ -214,7 +252,9 @@ add_subdirectory(
214252
install(
215253
TARGETS qnn_executorch_backend
216254
EXPORT ExecuTorchTargets
217-
DESTINATION ${CMAKE_INSTALL_LIBDIR}
255+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/executorch/backends/qualcomm
256+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/executorch/backends/qualcomm
257+
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/executorch/backends/qualcomm
218258
)
219259

220260
# QNN pybind
@@ -275,4 +315,10 @@ if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64")
275315
${QNN_EXECUTORCH_ROOT_DIR}/aot/python
276316
${CMAKE_CURRENT_BINARY_DIR}/qnn_executorch/python
277317
)
318+
319+
install(
320+
TARGETS PyQnnManagerAdaptor PyQnnWrapperAdaptor
321+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/executorch/backends/qualcomm/python
322+
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/executorch/backends/qualcomm/python
323+
)
278324
endif()

backends/qualcomm/scripts/download_qnn_sdk.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Add these imports for additional logging
1+
import argparse
22
import ctypes
33
import logging
44
import os
@@ -592,3 +592,46 @@ def install_qnn_sdk() -> bool:
592592

593593
# libc++ and QNN SDK setup
594594
return _ensure_libcxx_stack() and _ensure_qnn_sdk_lib()
595+
596+
597+
def main(argv: Optional[List[str]] = None) -> int:
598+
parser = argparse.ArgumentParser(
599+
description="Helper utility for Qualcomm SDK staging."
600+
)
601+
parser.add_argument(
602+
"--dst-folder",
603+
type=pathlib.Path,
604+
default=SDK_DIR,
605+
help="Destination directory for the Qualcomm SDK.",
606+
)
607+
parser.add_argument(
608+
"--print-sdk-path",
609+
action="store_true",
610+
help="Print the resolved Qualcomm SDK path to stdout.",
611+
)
612+
parser.add_argument(
613+
"--install-sdk",
614+
action="store_true",
615+
help="Ensure the SDK and runtime libraries are staged and loaded.",
616+
)
617+
args = parser.parse_args(argv)
618+
619+
logging.basicConfig(level=logging.INFO)
620+
621+
sdk_path: Optional[pathlib.Path]
622+
if args.install_sdk:
623+
if not install_qnn_sdk():
624+
return 1
625+
sdk_path = pathlib.Path(os.environ.get("QNN_SDK_ROOT", args.dst_folder))
626+
else:
627+
sdk_path = _download_qnn_sdk(dst_folder=args.dst_folder)
628+
if sdk_path is None:
629+
return 1
630+
631+
if args.print_sdk_path and sdk_path is not None:
632+
print(sdk_path)
633+
return 0
634+
635+
636+
if __name__ == "__main__":
637+
raise SystemExit(main())

setup.py

Lines changed: 19 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@
5757
import site
5858
import subprocess
5959
import sys
60-
import sysconfig
61-
import tempfile
6260

6361
from distutils import log # type: ignore[import-not-found]
6462
from distutils.sysconfig import get_python_lib # type: ignore[import-not-found]
@@ -463,84 +461,6 @@ def run(self):
463461
if self._ran_build:
464462
return
465463

466-
try:
467-
# Following code is for building the Qualcomm backend.
468-
from backends.qualcomm.scripts.download_qnn_sdk import (
469-
_download_qnn_sdk,
470-
is_linux_x86,
471-
)
472-
473-
if is_linux_x86():
474-
os.environ["EXECUTORCH_BUILDING_WHEEL"] = "1"
475-
476-
with tempfile.TemporaryDirectory() as tmpdir:
477-
tmp_path = Path(tmpdir)
478-
sdk_path = _download_qnn_sdk(dst_folder=tmp_path)
479-
480-
if not sdk_path:
481-
raise RuntimeError(
482-
"Qualcomm SDK not found, cannot build backend"
483-
)
484-
485-
# Determine paths
486-
prj_root = Path(__file__).parent.resolve()
487-
build_sh = prj_root / "backends/qualcomm/scripts/build.sh"
488-
build_root = prj_root / "build-x86"
489-
490-
if not build_sh.exists():
491-
raise FileNotFoundError(f"{build_sh} not found")
492-
493-
# Run build.sh with SDK path exported
494-
env = dict(**os.environ)
495-
env["QNN_SDK_ROOT"] = str(sdk_path)
496-
subprocess.check_call(
497-
[
498-
str(build_sh),
499-
"--skip_linux_android",
500-
"--skip_linux_embedded",
501-
],
502-
env=env,
503-
)
504-
505-
# Copy the main .so into the wheel package
506-
so_src = (
507-
build_root / "backends/qualcomm/libqnn_executorch_backend.so"
508-
)
509-
so_dst = Path(
510-
self.get_ext_fullpath(
511-
"executorch.backends.qualcomm.qnn_backend"
512-
)
513-
)
514-
self.mkpath(str(so_dst.parent)) # ensure destination exists
515-
self.copy_file(str(so_src), str(so_dst))
516-
logging.info(f"Copied Qualcomm backend: {so_src} -> {so_dst}")
517-
518-
# Copy Python adaptor .so files
519-
ext_suffix = sysconfig.get_config_var("EXT_SUFFIX")
520-
521-
so_files = [
522-
(
523-
"executorch.backends.qualcomm.python.PyQnnManagerAdaptor",
524-
prj_root
525-
/ f"backends/qualcomm/python/PyQnnManagerAdaptor{ext_suffix}",
526-
),
527-
(
528-
"executorch.backends.qualcomm.python.PyQnnWrapperAdaptor",
529-
prj_root
530-
/ f"backends/qualcomm/python/PyQnnWrapperAdaptor{ext_suffix}",
531-
),
532-
]
533-
534-
for module_name, so_src in so_files:
535-
so_dst = Path(self.get_ext_fullpath(module_name))
536-
self.mkpath(str(so_dst.parent))
537-
self.copy_file(str(so_src), str(so_dst))
538-
logging.info(f"Copied Qualcomm backend: {so_src} -> {so_dst}")
539-
540-
except ImportError:
541-
logging.error("Fail to build Qualcomm backend")
542-
logging.exception("Import error")
543-
544464
if self.editable_mode:
545465
self._ran_build = True
546466
self.run_command("build")
@@ -918,5 +838,24 @@ def run(self): # noqa C901
918838
is_dynamic_lib=True,
919839
dependent_cmake_flags=["EXECUTORCH_BUILD_KERNELS_LLM_AOT"],
920840
),
841+
BuiltFile(
842+
src_dir="%CMAKE_CACHE_DIR%/backends/qualcomm/%BUILD_TYPE%/",
843+
src_name="qnn_executorch_backend",
844+
dst="executorch/backends/qualcomm/",
845+
is_dynamic_lib=True,
846+
dependent_cmake_flags=["EXECUTORCH_BUILD_QNN"],
847+
),
848+
BuiltExtension(
849+
src_dir="%CMAKE_CACHE_DIR%/backends/qualcomm/python/%BUILD_TYPE%/",
850+
src="PyQnnManagerAdaptor.*",
851+
modpath="executorch.backends.qualcomm.python.PyQnnManagerAdaptor",
852+
dependent_cmake_flags=["EXECUTORCH_BUILD_QNN"],
853+
),
854+
BuiltExtension(
855+
src_dir="%CMAKE_CACHE_DIR%/backends/qualcomm/python/%BUILD_TYPE%/",
856+
src="PyQnnWrapperAdaptor.*",
857+
modpath="executorch.backends.qualcomm.python.PyQnnWrapperAdaptor",
858+
dependent_cmake_flags=["EXECUTORCH_BUILD_QNN"],
859+
),
921860
],
922861
)

tools/cmake/preset/pybind.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
3535
set_overridable_option(EXECUTORCH_BUILD_EXTENSION_TRAINING ON)
3636
set_overridable_option(EXECUTORCH_BUILD_EXTENSION_LLM_RUNNER ON)
3737
set_overridable_option(EXECUTORCH_BUILD_EXTENSION_LLM ON)
38+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|i.86)$")
39+
set_overridable_option(EXECUTORCH_BUILD_QNN ON)
40+
endif()
3841
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME STREQUAL
3942
"WIN32"
4043
)

0 commit comments

Comments
 (0)