Skip to content

Commit 9014e21

Browse files
committed
update
1 parent a6cd6ee commit 9014e21

File tree

3 files changed

+102
-88
lines changed

3 files changed

+102
-88
lines changed

backends/qualcomm/__init__.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
import os
33
import pathlib
44

5-
from .scripts.download_qnn_sdk import _download_qnn_sdk, _load_libcxx_libs, SDK_DIR
5+
from .scripts.download_qnn_sdk import (
6+
_download_qnn_sdk,
7+
_get_libcxx_dir,
8+
_load_libcxx_libs,
9+
_stage_libcxx,
10+
)
611

7-
LLVM_VERSION = "14.0.0"
8-
PKG_ROOT = pathlib.Path(__file__).parent.parent
9-
LIBCXX_DIR = PKG_ROOT / "sdk" / f"libcxx-{LLVM_VERSION}"
12+
# Path to executorch/backends/qualcomm/
13+
PKG_ROOT = pathlib.Path(__file__).parent.parent / "qualcomm"
1014

1115
# --- Qualcomm SDK handling ---
1216
qnn_root = os.environ.get("QNN_SDK_ROOT")
@@ -30,17 +34,12 @@
3034
raise
3135

3236
# --- libc++ handling ---
33-
if LIBCXX_DIR.exists():
34-
include_path = LIBCXX_DIR / "include"
35-
lib_path = LIBCXX_DIR / "lib"
37+
# Path to executorch/backends/
38+
_libcxx_dir = _get_libcxx_dir(PKG_ROOT)
3639

37-
# Prepend paths to environment
38-
os.environ["CPLUS_INCLUDE_PATH"] = (
39-
f"{include_path}:{os.environ.get('CPLUS_INCLUDE_PATH','')}"
40-
)
41-
os.environ["LD_LIBRARY_PATH"] = f"{lib_path}:{os.environ.get('LD_LIBRARY_PATH','')}"
42-
os.environ["LIBRARY_PATH"] = f"{lib_path}:{os.environ.get('LIBRARY_PATH','')}"
43-
44-
_load_libcxx_libs(lib_path)
45-
else:
46-
print(f"libc++ not found at {LIBCXX_DIR}, please check installation.")
40+
# Stage (download if missing) and load
41+
try:
42+
_stage_libcxx(_libcxx_dir)
43+
_load_libcxx_libs(_libcxx_dir)
44+
except Exception as e:
45+
print(f"[libcxx] Warning: failed to stage/load libc++: {e}")

backends/qualcomm/scripts/download_qnn_sdk.py

Lines changed: 86 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
import tarfile
88
import tempfile
99
import urllib.request
10+
import zipfile
1011
from typing import Optional
1112

13+
from tqdm import tqdm
14+
1215
SDK_DIR = pathlib.Path(__file__).parent.parent / "sdk" / "qnn"
1316
PKG_ROOT = pathlib.Path(__file__).parent
1417

@@ -110,63 +113,90 @@ def _extract_zip(archive_path, content_dir, target_dir):
110113
print(f"Extracting {archive_path} to {target_dir}")
111114
print(f"Looking for content in subdirectory: {content_dir}")
112115

113-
# Add your zip extraction code here, with additional logging
114-
# For example:
115-
import zipfile
116+
target_dir.mkdir(parents=True, exist_ok=True)
116117

117118
with zipfile.ZipFile(archive_path, "r") as zip_ref:
118-
# List all files in the archive
119-
print("Files in archive:")
120-
for file in zip_ref.namelist():
121-
print(f" {file}")
122-
123-
# Extract only the specific content directory
124-
for file in zip_ref.namelist():
125-
if file.startswith(content_dir):
126-
# Extract with path relative to content_dir
127-
relative_path = os.path.relpath(file, content_dir)
128-
if relative_path == ".":
129-
continue # Skip the directory entry itself
130-
target_path = target_dir / relative_path
131-
if file.endswith("/"):
132-
# Create directory
133-
target_path.mkdir(parents=True, exist_ok=True)
134-
else:
135-
# Extract file
136-
with zip_ref.open(file) as source, open(
137-
target_path, "wb"
138-
) as target:
139-
shutil.copyfileobj(source, target)
140-
print(f"Extracted: {relative_path}")
119+
# Filter files that start with content_dir
120+
files_to_extract = [f for f in zip_ref.namelist() if f.startswith(content_dir)]
141121

122+
for file in tqdm(files_to_extract, desc="Extracting files"):
123+
relative_path = os.path.relpath(file, content_dir)
124+
if relative_path == ".":
125+
continue # skip the root directory itself
142126

143-
LLVM_VERSION = "14.0.0"
144-
LIBCXX_LIB_DIR = (
145-
PKG_ROOT / "executorch" / "backends" / "qualcomm" / "sdk" / f"libcxx-{LLVM_VERSION}"
146-
)
147-
LIBCXX_BASE_NAME = f"clang+llvm-{LLVM_VERSION}-x86_64-linux-gnu-ubuntu-20.04"
127+
target_path = target_dir / relative_path
128+
129+
if file.endswith("/"):
130+
target_path.mkdir(parents=True, exist_ok=True)
131+
else:
132+
target_path.parent.mkdir(
133+
parents=True, exist_ok=True
134+
) # ensure parent exists
135+
with zip_ref.open(file) as source, open(target_path, "wb") as target:
136+
shutil.copyfileobj(source, target)
148137

149138

150-
def stage_libcxx(target_dir: pathlib.Path):
139+
def _extract_tar(archive_path: pathlib.Path, prefix: str, target_dir: pathlib.Path):
151140
"""
152-
Download (if needed) and stage libc++ shared libraries into the wheel package.
153-
- target_dir: destination folder in the wheel, e.g.
154-
executorch/backends/qualcomm/sdk/libcxx-14.0.0
141+
Extract files from a tar.gz archive into target_dir, stripping a prefix.
142+
143+
Args:
144+
archive_path (pathlib.Path): Path to the .tar.gz or .tgz archive.
145+
prefix (str): Prefix folder inside the archive to strip.
146+
target_dir (pathlib.Path): Destination directory.
155147
"""
148+
with tarfile.open(archive_path, "r:gz") as tf:
149+
for m in tf.getmembers():
150+
if not m.name.startswith(prefix + "/"):
151+
continue
152+
relpath = pathlib.Path(m.name).relative_to(prefix)
153+
if not relpath.parts or relpath.parts[0] == "..":
154+
continue
155+
156+
out_path = target_dir / relpath
157+
if m.isdir():
158+
out_path.mkdir(parents=True, exist_ok=True)
159+
else:
160+
out_path.parent.mkdir(parents=True, exist_ok=True)
161+
src = tf.extractfile(m)
162+
if src is None:
163+
# Skip non-regular files (links, devices, etc.)
164+
continue
165+
with src, open(out_path, "wb") as dst:
166+
dst.write(src.read())
167+
168+
169+
LLVM_VERSION = "14.0.0"
170+
LIBCXX_BASE_NAME = f"clang+llvm-{LLVM_VERSION}-x86_64-linux-gnu-ubuntu-18.04"
171+
LLVM_URL = f"https://github.com/llvm/llvm-project/releases/download/llvmorg-{LLVM_VERSION}/{LIBCXX_BASE_NAME}.tar.xz"
172+
173+
REQUIRED_LIBS = [
174+
"libc++.so.1.0",
175+
"libc++abi.so.1.0",
176+
"libunwind.so.1",
177+
"libm.so.6",
178+
"libpython3.10.so.1.0", # optional, include if needed
179+
]
180+
181+
182+
def _get_libcxx_dir(pkg_root: pathlib.Path) -> pathlib.Path:
183+
"""Path where libc++ should be staged in the wheel."""
184+
return pkg_root / "sdk" / f"libcxx-{LLVM_VERSION}"
185+
186+
187+
def _stage_libcxx(target_dir: pathlib.Path):
188+
"""Download LLVM tarball and stage only the needed .so files."""
156189
target_dir.mkdir(parents=True, exist_ok=True)
157190

158-
# Check if already staged
159-
existing_files = list(target_dir.glob("*"))
160-
if existing_files:
161-
print(f"[libcxx] Already staged at {target_dir}, skipping")
191+
# Already staged?
192+
if all((target_dir / libname).exists() for libname in REQUIRED_LIBS):
193+
print(f"[libcxx] Already staged at {target_dir}, skipping download")
162194
return
163195

164-
# URL to a tarball with prebuilt libc++ shared libraries
165-
LLVM_URL = f"https://github.com/llvm/llvm-project/releases/download/llvmorg-{LLVM_VERSION}/{LIBCXX_BASE_NAME}.tar.xz"
166196
temp_tar = pathlib.Path("/tmp") / f"{LIBCXX_BASE_NAME}.tar.xz"
167-
temp_extract = pathlib.Path("/tmp") / f"{LIBCXX_BASE_NAME}"
197+
temp_extract = pathlib.Path("/tmp") / LIBCXX_BASE_NAME
168198

169-
# Download if not already exists
199+
# Download tarball if missing
170200
if not temp_tar.exists():
171201
print(f"[libcxx] Downloading {LLVM_URL}")
172202
urllib.request.urlretrieve(LLVM_URL, temp_tar)
@@ -176,26 +206,24 @@ def stage_libcxx(target_dir: pathlib.Path):
176206
with tarfile.open(temp_tar, "r:xz") as tar:
177207
tar.extractall(temp_extract.parent)
178208

179-
# Copy only the required .so files
209+
# Copy required .so files
180210
lib_src = temp_extract / "lib"
181-
required_files = [
182-
"libc++.so.1.0",
183-
"libc++abi.so.1.0",
184-
"libunwind.so.1",
185-
"libm.so.6",
186-
"libpython3.10.so.1.0",
187-
]
188-
for fname in required_files:
211+
for fname in REQUIRED_LIBS:
189212
src_path = lib_src / fname
190213
if not src_path.exists():
191-
raise FileNotFoundError(f"{fname} not found in extracted LLVM")
214+
print(f"[libcxx] Warning: {fname} not found in extracted LLVM")
215+
continue
192216
shutil.copy(src_path, target_dir / fname)
193217

194-
# Create symlinks
195-
os.symlink("libc++.so.1.0", target_dir / "libc++.so.1")
196-
os.symlink("libc++.so.1", target_dir / "libc++.so")
197-
os.symlink("libc++abi.so.1.0", target_dir / "libc++abi.so.1")
198-
os.symlink("libc++abi.so.1", target_dir / "libc++abi.so")
218+
# Create symlinks for libc++/abi
219+
libcxx = target_dir / "libc++.so.1.0"
220+
libcxx_abi = target_dir / "libc++abi.so.1.0"
221+
if libcxx.exists():
222+
os.symlink("libc++.so.1.0", target_dir / "libc++.so.1")
223+
os.symlink("libc++.so.1", target_dir / "libc++.so")
224+
if libcxx_abi.exists():
225+
os.symlink("libc++abi.so.1.0", target_dir / "libc++abi.so.1")
226+
os.symlink("libc++abi.so.1", target_dir / "libc++abi.so")
199227

200228
print(f"[libcxx] Staged libc++ to {target_dir}")
201229

setup.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -471,19 +471,6 @@ def run(self):
471471
stage_libcxx,
472472
)
473473

474-
# libcxx setup
475-
prj_root = Path(__file__).parent.resolve()
476-
target_dir = (
477-
prj_root
478-
/ "executorch"
479-
/ "backends"
480-
/ "qualcomm"
481-
/ "sdk"
482-
/ f"libcxx-{LLVM_VERSION}"
483-
)
484-
485-
stage_libcxx(target_dir)
486-
487474
# qnn sdk setup
488475
print(
489476
"SDK_DIR: ",

0 commit comments

Comments
 (0)