1414import os
1515from collections .abc import Sequence
1616from dataclasses import dataclass
17+ from pathlib import PurePath
1718from typing import Protocol , cast
1819
1920from cuda .pathfinder ._dynamic_libs .lib_descriptor import LibDescriptor
2021from cuda .pathfinder ._dynamic_libs .supported_nvidia_libs import is_suppressed_dll_file
2122from cuda .pathfinder ._utils .find_sub_dirs import find_sub_dirs_all_sitepackages
2223from cuda .pathfinder ._utils .platform_aware import IS_WINDOWS
24+ from cuda .pathfinder ._utils .windows_arch import windows_pe_matches_arch , windows_python_arch
2325
2426
2527def _no_such_file_in_sub_dirs (
@@ -41,7 +43,7 @@ def _find_so_in_rel_dirs(
4143 sub_dirs_searched : list [tuple [str , ...]] = []
4244 file_wild = so_basename + "*"
4345 for rel_dir in rel_dirs :
44- sub_dir = tuple (rel_dir . split ( os . path . sep ))
46+ sub_dir = PurePath (rel_dir ). parts
4547 for abs_dir in find_sub_dirs_all_sitepackages (sub_dir ):
4648 # Exact unversioned match first; fall back to versioned names because some
4749 # distros only ship lib<name>.so.<major> (e.g. conda libcupti). Only one match
@@ -61,12 +63,15 @@ def _find_so_in_rel_dirs(
6163 return None
6264
6365
64- def _find_dll_under_dir (dirpath : str , file_wild : str ) -> str | None :
66+ def _find_dll_under_dir (dirpath : str , file_wild : str , target_arch : str | None = None ) -> str | None :
6567 for path in sorted (glob .glob (os .path .join (dirpath , file_wild ))):
6668 if not os .path .isfile (path ):
6769 continue
68- if not is_suppressed_dll_file (os .path .basename (path )):
69- return path
70+ if is_suppressed_dll_file (os .path .basename (path )):
71+ continue
72+ if target_arch is not None and not windows_pe_matches_arch (path , target_arch ):
73+ continue
74+ return path
7075 return None
7176
7277
@@ -78,7 +83,7 @@ def _find_dll_in_rel_dirs(
7883) -> str | None :
7984 sub_dirs_searched : list [tuple [str , ...]] = []
8085 for rel_dir in rel_dirs :
81- sub_dir = tuple (rel_dir . split ( os . path . sep ))
86+ sub_dir = PurePath (rel_dir ). parts
8287 for abs_dir in find_sub_dirs_all_sitepackages (sub_dir ):
8388 dll_name = _find_dll_under_dir (abs_dir , lib_searched_for )
8489 if dll_name is not None :
@@ -109,7 +114,7 @@ def find_in_site_packages(
109114 def find_in_lib_dir (
110115 self ,
111116 lib_dir : str ,
112- libname : str ,
117+ desc : LibDescriptor ,
113118 lib_searched_for : str ,
114119 error_messages : list [str ],
115120 attachments : list [str ],
@@ -142,7 +147,7 @@ def find_in_site_packages(
142147 def find_in_lib_dir (
143148 self ,
144149 lib_dir : str ,
145- _libname : str ,
150+ _desc : LibDescriptor ,
146151 lib_searched_for : str ,
147152 error_messages : list [str ],
148153 attachments : list [str ],
@@ -173,17 +178,19 @@ def find_in_lib_dir(
173178
174179@dataclass (frozen = True , slots = True )
175180class WindowsSearchPlatform :
181+ target_arch : str
182+
176183 def lib_searched_for (self , libname : str ) -> str :
177184 return f"{ libname } *.dll"
178185
179186 def site_packages_rel_dirs (self , desc : LibDescriptor ) -> tuple [str , ...]:
180- return cast (tuple [str , ...], desc .site_packages_windows )
187+ return cast (tuple [str , ...], desc .site_packages_windows . for_arch ( self . target_arch ) )
181188
182189 def conda_anchor_point (self , conda_prefix : str ) -> str :
183190 return os .path .join (conda_prefix , "Library" )
184191
185192 def anchor_rel_dirs (self , desc : LibDescriptor ) -> tuple [str , ...]:
186- return cast (tuple [str , ...], desc .anchor_rel_dirs_windows )
193+ return cast (tuple [str , ...], desc .anchor_rel_dirs_windows . for_arch ( self . target_arch ) )
187194
188195 def find_in_site_packages (
189196 self ,
@@ -197,16 +204,20 @@ def find_in_site_packages(
197204 def find_in_lib_dir (
198205 self ,
199206 lib_dir : str ,
200- libname : str ,
207+ desc : LibDescriptor ,
201208 _lib_searched_for : str ,
202209 error_messages : list [str ],
203210 attachments : list [str ],
204211 ) -> str | None :
205- file_wild = libname + "*.dll"
206- dll_name = _find_dll_under_dir (lib_dir , file_wild )
212+ file_wild = desc .name + "*.dll"
213+ target_arch = self .target_arch if desc .requires_windows_binary_arch_check else None
214+ dll_name = _find_dll_under_dir (lib_dir , file_wild , target_arch )
207215 if dll_name is not None :
208216 return dll_name
209- error_messages .append (f"No such file: { file_wild } " )
217+ if target_arch is None :
218+ error_messages .append (f"No such file: { file_wild } " )
219+ else :
220+ error_messages .append (f"No { target_arch } -compatible PE file: { file_wild } " )
210221 attachments .append (f' listdir("{ lib_dir } "):' )
211222 if not os .path .isdir (lib_dir ):
212223 attachments .append (" DIRECTORY DOES NOT EXIST" )
@@ -216,4 +227,10 @@ def find_in_lib_dir(
216227 return None
217228
218229
219- PLATFORM : SearchPlatform = WindowsSearchPlatform () if IS_WINDOWS else LinuxSearchPlatform ()
230+ def _platform_for_current_system () -> SearchPlatform :
231+ if IS_WINDOWS :
232+ return WindowsSearchPlatform (target_arch = windows_python_arch ())
233+ return LinuxSearchPlatform ()
234+
235+
236+ PLATFORM = _platform_for_current_system ()
0 commit comments