7
7
import tarfile
8
8
import tempfile
9
9
import urllib .request
10
+ import zipfile
10
11
from typing import Optional
11
12
13
+ from tqdm import tqdm
14
+
12
15
SDK_DIR = pathlib .Path (__file__ ).parent .parent / "sdk" / "qnn"
13
16
PKG_ROOT = pathlib .Path (__file__ ).parent
14
17
@@ -110,63 +113,90 @@ def _extract_zip(archive_path, content_dir, target_dir):
110
113
print (f"Extracting { archive_path } to { target_dir } " )
111
114
print (f"Looking for content in subdirectory: { content_dir } " )
112
115
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 )
116
117
117
118
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 )]
141
121
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
142
126
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 )
148
137
149
138
150
- def stage_libcxx ( target_dir : pathlib .Path ):
139
+ def _extract_tar ( archive_path : pathlib . Path , prefix : str , target_dir : pathlib .Path ):
151
140
"""
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.
155
147
"""
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."""
156
189
target_dir .mkdir (parents = True , exist_ok = True )
157
190
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" )
162
194
return
163
195
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"
166
196
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
168
198
169
- # Download if not already exists
199
+ # Download tarball if missing
170
200
if not temp_tar .exists ():
171
201
print (f"[libcxx] Downloading { LLVM_URL } " )
172
202
urllib .request .urlretrieve (LLVM_URL , temp_tar )
@@ -176,26 +206,24 @@ def stage_libcxx(target_dir: pathlib.Path):
176
206
with tarfile .open (temp_tar , "r:xz" ) as tar :
177
207
tar .extractall (temp_extract .parent )
178
208
179
- # Copy only the required .so files
209
+ # Copy required .so files
180
210
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 :
189
212
src_path = lib_src / fname
190
213
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
192
216
shutil .copy (src_path , target_dir / fname )
193
217
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" )
199
227
200
228
print (f"[libcxx] Staged libc++ to { target_dir } " )
201
229
0 commit comments