Skip to content

Improve QNN backend build-from-source user experience#17990

Open
abhinaykukkadapu wants to merge 6 commits intogh/abhinaykukkadapu/17/basefrom
gh/abhinaykukkadapu/17/head
Open

Improve QNN backend build-from-source user experience#17990
abhinaykukkadapu wants to merge 6 commits intogh/abhinaykukkadapu/17/basefrom
gh/abhinaykukkadapu/17/head

Conversation

@abhinaykukkadapu
Copy link
Contributor

@abhinaykukkadapu abhinaykukkadapu commented Mar 7, 2026

Stack from ghstack (oldest at bottom):

  • Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
    QNN SDK auto-downloads for all build paths (editable installs,
    build.sh), not just wheel builds
  • Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
    build dir, so SDK survives build dir cleans and is shared across
    all build flows
  • Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
    auto-download during configure when SDK is not set
  • Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
    ANDROID_NDK_ROOT is not set
  • Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
    used, with a buggy test that never triggered)
  • Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
    matching wheel behavior so editable installs build QNN out of the box
  • Redirect download_qnn_sdk.py progress output to stderr when
    --print-sdk-path is used, so cmake can capture the path cleanly

Test Plan/ User journeys

Verified end-to-end on Linux x86_64 with QNN SDK v2.37.0.250724.

AOT user: pip install executorch and import

First-time import (no SDK on disk):
Unset QNN_SDK_ROOT, clear ~/.cache/executorch/qnn/, then:

>>> import executorch.backends.qualcomm
[QNN] Downloading Qualcomm AI Runtime SDK v2.37.0.250724...
[QNN] Downloading: 645/1291 MB (50%)
[QNN] Downloading: 1291/1291 MB (100%)
[QNN] Download complete.
[QNN] Extracting SDK...
[QNN] Downloading libc++ (LLVM 14.0.0)...
[QNN] QNN SDK v2.37.0.250724 ready at ~/.cache/executorch/qnn/sdk-2.37.0.250724

User sees download progress instead of a silent multi-minute hang. SDK is stored in ~/.cache/, not inside the pip package directory.

Second import (SDK already cached):

>>> import executorch.backends.qualcomm
[QNN] Using cached QNN SDK v2.37.0.250724 at ~/.cache/executorch/qnn/sdk-2.37.0.250724

Instant — no re-download.

User has their own SDK installation:

$ export QNN_SDK_ROOT=/opt/qnn/2.37.0
>>> import executorch.backends.qualcomm
[QNN] Using QNN SDK at /opt/qnn/2.37.0 (from QNN_SDK_ROOT)

Respects the user's path, no download attempted.

Scripted usage (--print-sdk-path):

$ SDK_PATH=$(python3 backends/qualcomm/scripts/download_qnn_sdk.py --print-sdk-path)
$ echo $SDK_PATH
/home/user/.cache/executorch/qnn/sdk-2.37.0.250724

Stdout contains only the path — progress output goes to stderr, so shell capture works cleanly.

Build-from-source user: pip install -e . or build.sh

Zero-config build (no env vars set):

$ pip install -e . --no-build-isolation
  ...
  -- QNN_SDK_ROOT not set. Auto-downloading QNN SDK...
  -- EXECUTORCH_BUILD_QNN: ON
  ...
  Building target qnn_executorch_backend

QNN backend is built automatically. The SDK is auto-downloaded to ~/.cache/ during CMake configure.

Opting out of QNN:

$ CMAKE_ARGS="-DEXECUTORCH_BUILD_QNN=OFF" pip install -e . --no-build-isolation
  ...
  -- EXECUTORCH_BUILD_QNN: OFF

No SDK download, no QNN targets built.

Build with pre-existing SDK:

$ export QNN_SDK_ROOT=~/.cache/executorch/qnn/sdk-2.37.0.250724
$ pip install -e . --no-build-isolation
  ...
  -- EXECUTORCH_BUILD_QNN: ON
  Building target qnn_executorch_backend

Uses the provided SDK. No "Auto-downloading" message.

Shell build (build.sh) follows the same pattern:

$ bash backends/qualcomm/scripts/build.sh --skip_linux_android
[QNN] QNN_SDK_ROOT not set. SDK will be auto-downloaded during cmake configure.
  -- Auto-downloading QNN SDK...
  -- EXECUTORCH_BUILD_QNN: ON

With QNN_SDK_ROOT set, it skips the download and uses the provided path.

SDK survives build directory clean:

$ rm -rf build-x86/
$ bash backends/qualcomm/scripts/build.sh --skip_linux_android

No re-download — SDK lives in ~/.cache/, independent of the build directory.

- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

[ghstack-poisoned]
@pytorch-bot
Copy link

pytorch-bot bot commented Mar 7, 2026

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/17990

Note: Links to docs will display an error until the docs builds have been completed.

❌ 1 New Failure, 3 Unrelated Failures

As of commit 716c04b with merge base 043a3a1 (image):

NEW FAILURE - The following job has failed:

BROKEN TRUNK - The following jobs failed but were present on the merge base:

👉 Rebase onto the `viable/strict` branch to avoid these failures

This comment was automatically generated by Dr. CI and updates every 15 minutes.

abhinaykukkadapu added a commit that referenced this pull request Mar 7, 2026
- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

ghstack-source-id: 4cb0e5f
Pull Request resolved: #17990
@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Mar 7, 2026
@github-actions
Copy link

github-actions bot commented Mar 7, 2026

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

[ghstack-poisoned]
abhinaykukkadapu added a commit that referenced this pull request Mar 7, 2026
- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

ghstack-source-id: d3980d2
Pull Request resolved: #17990
- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

[ghstack-poisoned]
abhinaykukkadapu added a commit that referenced this pull request Mar 7, 2026
- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

ghstack-source-id: 6208f6d
Pull Request resolved: #17990
@abhinaykukkadapu
Copy link
Contributor Author

Hi @cccclai, @haowhsu-quic, @shewu-quic, any thoughts or improvements you have in mind to improve user experience of ET- Qualcomm. Please see the userflows in both the PRs. Thanks!

@winskuo-quic
Copy link
Collaborator

Hi @abhinaykukkadapu,
Thanks for improving QNN backend build experience.
For the automated download QNN SDK flow, I would like to know if it exports QNN_SDK_ROOT as environment variable after downloading QNN SDK. If not, do you think export QNN_SDK_ROOT for user will improve the user experience? The reason is that in Qualcomm python example scripts, we will try to get QNN_SDK_ROOT from env, like following: (

qnn_sdk=os.getenv("QNN_SDK_ROOT"),
)

@abhinaykukkadapu
Copy link
Contributor Author

Hi @abhinaykukkadapu, Thanks for improving QNN backend build experience. For the automated download QNN SDK flow, I would like to know if it exports QNN_SDK_ROOT as environment variable after downloading QNN SDK. If not, do you think export QNN_SDK_ROOT for user will improve the user experience? The reason is that in Qualcomm python example scripts, we will try to get QNN_SDK_ROOT from env, like following: (

qnn_sdk=os.getenv("QNN_SDK_ROOT"),

)

Thanks, so, right now we set the QNN_SDK_ROOT, LD_LIBRARY_PATH for the python process, if someone runs this script, there are imports such as from executorch.backends.qualcomm so that specific python process would get it.

- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly


## Test Plan/ User journeys

Verified end-to-end on Linux x86_64 with QNN SDK v2.37.0.250724.

### AOT user: `pip install executorch` and import

**First-time import (no SDK on disk):**
Unset `QNN_SDK_ROOT`, clear `~/.cache/executorch/qnn/`, then:
```
>>> import executorch.backends.qualcomm
[QNN] Downloading Qualcomm AI Runtime SDK v2.37.0.250724...
[QNN] Downloading: 645/1291 MB (50%)
[QNN] Downloading: 1291/1291 MB (100%)
[QNN] Download complete.
[QNN] Extracting SDK...
[QNN] Downloading libc++ (LLVM 14.0.0)...
[QNN] QNN SDK v2.37.0.250724 ready at ~/.cache/executorch/qnn/sdk-2.37.0.250724
```
User sees download progress instead of a silent multi-minute hang. SDK is stored in `~/.cache/`, not inside the pip package directory.

**Second import (SDK already cached):**
```
>>> import executorch.backends.qualcomm
[QNN] Using cached QNN SDK v2.37.0.250724 at ~/.cache/executorch/qnn/sdk-2.37.0.250724
```
Instant — no re-download.

**User has their own SDK installation:**
```
$ export QNN_SDK_ROOT=/opt/qnn/2.37.0
>>> import executorch.backends.qualcomm
[QNN] Using QNN SDK at /opt/qnn/2.37.0 (from QNN_SDK_ROOT)
```
Respects the user's path, no download attempted.

**Scripted usage (`--print-sdk-path`):**
```
$ SDK_PATH=$(python3 backends/qualcomm/scripts/download_qnn_sdk.py --print-sdk-path)
$ echo $SDK_PATH
/home/user/.cache/executorch/qnn/sdk-2.37.0.250724
```
Stdout contains only the path — progress output goes to stderr, so shell capture works cleanly.

### Build-from-source user: `pip install -e .` or `build.sh`

**Zero-config build (no env vars set):**
```
$ pip install -e . --no-build-isolation
  ...
  -- QNN_SDK_ROOT not set. Auto-downloading QNN SDK...
  -- EXECUTORCH_BUILD_QNN: ON
  ...
  Building target qnn_executorch_backend
```
QNN backend is built automatically. The SDK is auto-downloaded to `~/.cache/` during CMake configure.

**Opting out of QNN:**
```
$ CMAKE_ARGS="-DEXECUTORCH_BUILD_QNN=OFF" pip install -e . --no-build-isolation
  ...
  -- EXECUTORCH_BUILD_QNN: OFF
```
No SDK download, no QNN targets built.

**Build with pre-existing SDK:**
```
$ export QNN_SDK_ROOT=~/.cache/executorch/qnn/sdk-2.37.0.250724
$ pip install -e . --no-build-isolation
  ...
  -- EXECUTORCH_BUILD_QNN: ON
  Building target qnn_executorch_backend
```
Uses the provided SDK. No "Auto-downloading" message.

**Shell build (`build.sh`) follows the same pattern:**
```
$ bash backends/qualcomm/scripts/build.sh --skip_linux_android
[QNN] QNN_SDK_ROOT not set. SDK will be auto-downloaded during cmake configure.
  -- Auto-downloading QNN SDK...
  -- EXECUTORCH_BUILD_QNN: ON
```
With `QNN_SDK_ROOT` set, it skips the download and uses the provided path.

**SDK survives build directory clean:**
```
$ rm -rf build-x86/
$ bash backends/qualcomm/scripts/build.sh --skip_linux_android
```
No re-download — SDK lives in `~/.cache/`, independent of the build directory.


[ghstack-poisoned]
abhinaykukkadapu added a commit that referenced this pull request Mar 11, 2026
- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

ghstack-source-id: 9bb1eeb
Pull Request resolved: #17990
@abhinaykukkadapu abhinaykukkadapu linked an issue Mar 12, 2026 that may be closed by this pull request
@abhinaykukkadapu
Copy link
Contributor Author

@haowhsu-quic bumping this PR up for review thanks, i will merge both at once including #17989

echo "First, you need to set the environment variable for QNN_SDK_ROOT"
echo ", and if you want to build the android version of executor runner"
echo ", you need to export ANDROID_NDK_ROOT=/path/to/android_ndkXX"
echo "(or export TOOLCHAIN_ROOT_HOST=/path/to/sysroots/xx_host, "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you keep this for Yocto linux toolchain guide? thanks.

- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly


## Test Plan/ User journeys

Verified end-to-end on Linux x86_64 with QNN SDK v2.37.0.250724.

### AOT user: `pip install executorch` and import

**First-time import (no SDK on disk):**
Unset `QNN_SDK_ROOT`, clear `~/.cache/executorch/qnn/`, then:
```
>>> import executorch.backends.qualcomm
[QNN] Downloading Qualcomm AI Runtime SDK v2.37.0.250724...
[QNN] Downloading: 645/1291 MB (50%)
[QNN] Downloading: 1291/1291 MB (100%)
[QNN] Download complete.
[QNN] Extracting SDK...
[QNN] Downloading libc++ (LLVM 14.0.0)...
[QNN] QNN SDK v2.37.0.250724 ready at ~/.cache/executorch/qnn/sdk-2.37.0.250724
```
User sees download progress instead of a silent multi-minute hang. SDK is stored in `~/.cache/`, not inside the pip package directory.

**Second import (SDK already cached):**
```
>>> import executorch.backends.qualcomm
[QNN] Using cached QNN SDK v2.37.0.250724 at ~/.cache/executorch/qnn/sdk-2.37.0.250724
```
Instant — no re-download.

**User has their own SDK installation:**
```
$ export QNN_SDK_ROOT=/opt/qnn/2.37.0
>>> import executorch.backends.qualcomm
[QNN] Using QNN SDK at /opt/qnn/2.37.0 (from QNN_SDK_ROOT)
```
Respects the user's path, no download attempted.

**Scripted usage (`--print-sdk-path`):**
```
$ SDK_PATH=$(python3 backends/qualcomm/scripts/download_qnn_sdk.py --print-sdk-path)
$ echo $SDK_PATH
/home/user/.cache/executorch/qnn/sdk-2.37.0.250724
```
Stdout contains only the path — progress output goes to stderr, so shell capture works cleanly.

### Build-from-source user: `pip install -e .` or `build.sh`

**Zero-config build (no env vars set):**
```
$ pip install -e . --no-build-isolation
  ...
  -- QNN_SDK_ROOT not set. Auto-downloading QNN SDK...
  -- EXECUTORCH_BUILD_QNN: ON
  ...
  Building target qnn_executorch_backend
```
QNN backend is built automatically. The SDK is auto-downloaded to `~/.cache/` during CMake configure.

**Opting out of QNN:**
```
$ CMAKE_ARGS="-DEXECUTORCH_BUILD_QNN=OFF" pip install -e . --no-build-isolation
  ...
  -- EXECUTORCH_BUILD_QNN: OFF
```
No SDK download, no QNN targets built.

**Build with pre-existing SDK:**
```
$ export QNN_SDK_ROOT=~/.cache/executorch/qnn/sdk-2.37.0.250724
$ pip install -e . --no-build-isolation
  ...
  -- EXECUTORCH_BUILD_QNN: ON
  Building target qnn_executorch_backend
```
Uses the provided SDK. No "Auto-downloading" message.

**Shell build (`build.sh`) follows the same pattern:**
```
$ bash backends/qualcomm/scripts/build.sh --skip_linux_android
[QNN] QNN_SDK_ROOT not set. SDK will be auto-downloaded during cmake configure.
  -- Auto-downloading QNN SDK...
  -- EXECUTORCH_BUILD_QNN: ON
```
With `QNN_SDK_ROOT` set, it skips the download and uses the provided path.

**SDK survives build directory clean:**
```
$ rm -rf build-x86/
$ bash backends/qualcomm/scripts/build.sh --skip_linux_android
```
No re-download — SDK lives in `~/.cache/`, independent of the build directory.


[ghstack-poisoned]
abhinaykukkadapu added a commit that referenced this pull request Mar 17, 2026
- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

ghstack-source-id: f468f13
Pull Request resolved: #17990
- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly


## Test Plan/ User journeys

Verified end-to-end on Linux x86_64 with QNN SDK v2.37.0.250724.

### AOT user: `pip install executorch` and import

**First-time import (no SDK on disk):**
Unset `QNN_SDK_ROOT`, clear `~/.cache/executorch/qnn/`, then:
```
>>> import executorch.backends.qualcomm
[QNN] Downloading Qualcomm AI Runtime SDK v2.37.0.250724...
[QNN] Downloading: 645/1291 MB (50%)
[QNN] Downloading: 1291/1291 MB (100%)
[QNN] Download complete.
[QNN] Extracting SDK...
[QNN] Downloading libc++ (LLVM 14.0.0)...
[QNN] QNN SDK v2.37.0.250724 ready at ~/.cache/executorch/qnn/sdk-2.37.0.250724
```
User sees download progress instead of a silent multi-minute hang. SDK is stored in `~/.cache/`, not inside the pip package directory.

**Second import (SDK already cached):**
```
>>> import executorch.backends.qualcomm
[QNN] Using cached QNN SDK v2.37.0.250724 at ~/.cache/executorch/qnn/sdk-2.37.0.250724
```
Instant — no re-download.

**User has their own SDK installation:**
```
$ export QNN_SDK_ROOT=/opt/qnn/2.37.0
>>> import executorch.backends.qualcomm
[QNN] Using QNN SDK at /opt/qnn/2.37.0 (from QNN_SDK_ROOT)
```
Respects the user's path, no download attempted.

**Scripted usage (`--print-sdk-path`):**
```
$ SDK_PATH=$(python3 backends/qualcomm/scripts/download_qnn_sdk.py --print-sdk-path)
$ echo $SDK_PATH
/home/user/.cache/executorch/qnn/sdk-2.37.0.250724
```
Stdout contains only the path — progress output goes to stderr, so shell capture works cleanly.

### Build-from-source user: `pip install -e .` or `build.sh`

**Zero-config build (no env vars set):**
```
$ pip install -e . --no-build-isolation
  ...
  -- QNN_SDK_ROOT not set. Auto-downloading QNN SDK...
  -- EXECUTORCH_BUILD_QNN: ON
  ...
  Building target qnn_executorch_backend
```
QNN backend is built automatically. The SDK is auto-downloaded to `~/.cache/` during CMake configure.

**Opting out of QNN:**
```
$ CMAKE_ARGS="-DEXECUTORCH_BUILD_QNN=OFF" pip install -e . --no-build-isolation
  ...
  -- EXECUTORCH_BUILD_QNN: OFF
```
No SDK download, no QNN targets built.

**Build with pre-existing SDK:**
```
$ export QNN_SDK_ROOT=~/.cache/executorch/qnn/sdk-2.37.0.250724
$ pip install -e . --no-build-isolation
  ...
  -- EXECUTORCH_BUILD_QNN: ON
  Building target qnn_executorch_backend
```
Uses the provided SDK. No "Auto-downloading" message.

**Shell build (`build.sh`) follows the same pattern:**
```
$ bash backends/qualcomm/scripts/build.sh --skip_linux_android
[QNN] QNN_SDK_ROOT not set. SDK will be auto-downloaded during cmake configure.
  -- Auto-downloading QNN SDK...
  -- EXECUTORCH_BUILD_QNN: ON
```
With `QNN_SDK_ROOT` set, it skips the download and uses the provided path.

**SDK survives build directory clean:**
```
$ rm -rf build-x86/
$ bash backends/qualcomm/scripts/build.sh --skip_linux_android
```
No re-download — SDK lives in `~/.cache/`, independent of the build directory.


[ghstack-poisoned]
abhinaykukkadapu added a commit that referenced this pull request Mar 17, 2026
- Remove EXECUTORCH_BUILD_WHEEL_DO_NOT_USE gate in CMakeLists.txt so
  QNN SDK auto-downloads for all build paths (editable installs,
  build.sh), not just wheel builds
- Use shared cache dir (~/.cache/executorch/qnn/) instead of cmake
  build dir, so SDK survives build dir cleans and is shared across
  all build flows
- Remove hard QNN_SDK_ROOT requirement from build.sh — cmake handles
  auto-download during configure when SDK is not set
- Auto-download Android NDK in build.sh via install_qnn_sdk.sh when
  ANDROID_NDK_ROOT is not set
- Fix PYTHON_EXECUTABLE default in build.sh (was checked before being
  used, with a buggy test that never triggered)
- Default EXECUTORCH_BUILD_QNN to ON on Linux x86 in pybind preset,
  matching wheel behavior so editable installs build QNN out of the box
- Redirect download_qnn_sdk.py progress output to stderr when
  --print-sdk-path is used, so cmake can capture the path cleanly

ghstack-source-id: 46b5178
Pull Request resolved: #17990
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve qualcomm end-to-end user experience

3 participants