Skip to content

Commit 4410a6b

Browse files
committed
Include conda Library bin and lib paths to default blas ldflags search dirs
1 parent 91d3b7c commit 4410a6b

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

pytensor/link/c/cmodule.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -2744,7 +2744,9 @@ def get_cxx_library_dirs():
27442744
[pathlib.Path(p).resolve() for p in line[len("libraries: =") :].split(":")]
27452745
for line in stdout.decode(sys.stdout.encoding).splitlines()
27462746
if line.startswith("libraries: =")
2747-
][0]
2747+
]
2748+
if len(maybe_lib_dirs) > 0:
2749+
maybe_lib_dirs = maybe_lib_dirs[0]
27482750
return [str(d) for d in maybe_lib_dirs if d.exists() and d.is_dir()]
27492751

27502752
def check_libs(
@@ -2793,6 +2795,14 @@ def check_libs(
27932795

27942796
cxx_library_dirs = get_cxx_library_dirs()
27952797
searched_library_dirs = cxx_library_dirs + _std_lib_dirs
2798+
print(sys.platform, sys.prefix)
2799+
if sys.platform == "win32":
2800+
# Conda on Windows saves MKL libraries under CONDA_PREFIX\Library\bin
2801+
# From the conda manual (https://docs.conda.io/projects/conda-build/en/stable/user-guide/environment-variables.html)
2802+
# it seems like conda could also save some libraries into the CONDA_PREFIX\Library\lib
2803+
# directory. We will include both in our searched library dirs
2804+
searched_library_dirs.append(os.path.join(sys.prefix, "Library", "bin"))
2805+
searched_library_dirs.append(os.path.join(sys.prefix, "Library", "lib"))
27962806
all_libs = [
27972807
l
27982808
for path in [

tests/link/c/test_cmodule.py

+45
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,51 @@ def test_default_blas_ldflags_no_cxx():
260260
assert default_blas_ldflags() == ""
261261

262262

263+
@pytest.fixture()
264+
def windows_conda_libs(blas_libs):
265+
libtemplate = "{lib}.dll"
266+
libraries = []
267+
with tempfile.TemporaryDirectory() as d:
268+
subdir = os.path.join(d, "Library", "bin")
269+
os.makedirs(subdir, exist_ok=True)
270+
flags = f'-L"{subdir}"'
271+
for lib in blas_libs:
272+
lib_path = os.path.join(subdir, libtemplate.format(lib=lib))
273+
with open(lib_path, "wb") as f:
274+
f.write(b"1")
275+
libraries.append(lib_path)
276+
flags += f" -l{lib}"
277+
if "gomp" in blas_libs and "mkl_gnu_thread" not in blas_libs:
278+
flags += " -fopenmp"
279+
if len(blas_libs) == 0:
280+
flags = ""
281+
yield d, flags
282+
283+
284+
@patch("pytensor.link.c.cmodule.std_lib_dirs", return_value=[])
285+
@patch("pytensor.link.c.cmodule.check_mkl_openmp", return_value=None)
286+
def test_default_blas_ldflags_conda_windows(
287+
mock_std_lib_dirs, mock_check_mkl_openmp, windows_conda_libs
288+
):
289+
mock_sys_prefix, expected_blas_ldflags = windows_conda_libs
290+
mock_process = MagicMock()
291+
mock_process.communicate = lambda *args, **kwargs: (b"", b"")
292+
mock_process.returncode = 0
293+
with patch("sys.platform", "win32"):
294+
with patch("sys.prefix", mock_sys_prefix):
295+
with patch(
296+
"pytensor.link.c.cmodule.subprocess_Popen", return_value=mock_process
297+
):
298+
with patch.object(
299+
pytensor.link.c.cmodule.GCC_compiler,
300+
"try_compile_tmp",
301+
return_value=(True, True),
302+
):
303+
assert set(default_blas_ldflags().split(" ")) == set(
304+
expected_blas_ldflags.split(" ")
305+
)
306+
307+
263308
@patch(
264309
"os.listdir", return_value=["mkl_core.1.dll", "mkl_rt.1.0.dll", "mkl_rt.1.1.lib"]
265310
)

0 commit comments

Comments
 (0)