Skip to content

Commit 44e3032

Browse files
committed
Add availability checks for MKL and OpenBLAS similar to AppleAccelerate
This commit adds runtime availability checks for MKL and OpenBLAS libraries to ensure proper error handling when the libraries are not available. The implementation follows the same pattern as AppleAccelerateLU: - Added __mkl_isavailable() function to check MKL library availability - Added __openblas_isavailable() function to check OpenBLAS library availability - Added error checks in all getrf!, getrs!, and solve! functions - Uses Libdl to check for library symbols at runtime This ensures that calls properly compile out when the binaries are missing and provides clear error messages when the libraries are not available. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 2ff3977 commit 44e3032

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

src/mkl.jl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Libdl
2+
13
"""
24
```julia
35
MKLLUFactorization()
@@ -8,11 +10,38 @@ to avoid allocations and does not require libblastrampoline.
810
"""
911
struct MKLLUFactorization <: AbstractFactorization end
1012

13+
# Check if MKL is available and can be loaded
14+
function __mkl_isavailable()
15+
if !@isdefined(MKL_jll)
16+
return false
17+
end
18+
if !MKL_jll.is_available()
19+
return false
20+
end
21+
# Try to load the library and check for required symbols
22+
try
23+
mkl_hdl = Libdl.dlopen(MKL_jll.libmkl_rt)
24+
if mkl_hdl == C_NULL
25+
return false
26+
end
27+
# Check for a required symbol
28+
if Libdl.dlsym_e(mkl_hdl, "dgetrf_") == C_NULL
29+
Libdl.dlclose(mkl_hdl)
30+
return false
31+
end
32+
Libdl.dlclose(mkl_hdl)
33+
return true
34+
catch
35+
return false
36+
end
37+
end
1138

1239
function getrf!(A::AbstractMatrix{<:ComplexF64};
1340
ipiv = similar(A, BlasInt, min(size(A, 1), size(A, 2))),
1441
info = Ref{BlasInt}(),
1542
check = false)
43+
__mkl_isavailable() ||
44+
error("Error, MKL binary is missing but solve is being called. Report this issue")
1645
require_one_based_indexing(A)
1746
check && chkfinite(A)
1847
chkstride1(A)
@@ -33,6 +62,8 @@ function getrf!(A::AbstractMatrix{<:ComplexF32};
3362
ipiv = similar(A, BlasInt, min(size(A, 1), size(A, 2))),
3463
info = Ref{BlasInt}(),
3564
check = false)
65+
__mkl_isavailable() ||
66+
error("Error, MKL binary is missing but solve is being called. Report this issue")
3667
require_one_based_indexing(A)
3768
check && chkfinite(A)
3869
chkstride1(A)
@@ -53,6 +84,8 @@ function getrf!(A::AbstractMatrix{<:Float64};
5384
ipiv = similar(A, BlasInt, min(size(A, 1), size(A, 2))),
5485
info = Ref{BlasInt}(),
5586
check = false)
87+
__mkl_isavailable() ||
88+
error("Error, MKL binary is missing but solve is being called. Report this issue")
5689
require_one_based_indexing(A)
5790
check && chkfinite(A)
5891
chkstride1(A)
@@ -73,6 +106,8 @@ function getrf!(A::AbstractMatrix{<:Float32};
73106
ipiv = similar(A, BlasInt, min(size(A, 1), size(A, 2))),
74107
info = Ref{BlasInt}(),
75108
check = false)
109+
__mkl_isavailable() ||
110+
error("Error, MKL binary is missing but solve is being called. Report this issue")
76111
require_one_based_indexing(A)
77112
check && chkfinite(A)
78113
chkstride1(A)
@@ -94,6 +129,8 @@ function getrs!(trans::AbstractChar,
94129
ipiv::AbstractVector{BlasInt},
95130
B::AbstractVecOrMat{<:ComplexF64};
96131
info = Ref{BlasInt}())
132+
__mkl_isavailable() ||
133+
error("Error, MKL binary is missing but solve is being called. Report this issue")
97134
require_one_based_indexing(A, ipiv, B)
98135
LinearAlgebra.LAPACK.chktrans(trans)
99136
chkstride1(A, B, ipiv)
@@ -119,6 +156,8 @@ function getrs!(trans::AbstractChar,
119156
ipiv::AbstractVector{BlasInt},
120157
B::AbstractVecOrMat{<:ComplexF32};
121158
info = Ref{BlasInt}())
159+
__mkl_isavailable() ||
160+
error("Error, MKL binary is missing but solve is being called. Report this issue")
122161
require_one_based_indexing(A, ipiv, B)
123162
LinearAlgebra.LAPACK.chktrans(trans)
124163
chkstride1(A, B, ipiv)
@@ -144,6 +183,8 @@ function getrs!(trans::AbstractChar,
144183
ipiv::AbstractVector{BlasInt},
145184
B::AbstractVecOrMat{<:Float64};
146185
info = Ref{BlasInt}())
186+
__mkl_isavailable() ||
187+
error("Error, MKL binary is missing but solve is being called. Report this issue")
147188
require_one_based_indexing(A, ipiv, B)
148189
LinearAlgebra.LAPACK.chktrans(trans)
149190
chkstride1(A, B, ipiv)
@@ -169,6 +210,8 @@ function getrs!(trans::AbstractChar,
169210
ipiv::AbstractVector{BlasInt},
170211
B::AbstractVecOrMat{<:Float32};
171212
info = Ref{BlasInt}())
213+
__mkl_isavailable() ||
214+
error("Error, MKL binary is missing but solve is being called. Report this issue")
172215
require_one_based_indexing(A, ipiv, B)
173216
LinearAlgebra.LAPACK.chktrans(trans)
174217
chkstride1(A, B, ipiv)
@@ -213,6 +256,8 @@ end
213256

214257
function SciMLBase.solve!(cache::LinearCache, alg::MKLLUFactorization;
215258
kwargs...)
259+
__mkl_isavailable() ||
260+
error("Error, MKL binary is missing but solve is being called. Report this issue")
216261
A = cache.A
217262
A = convert(AbstractMatrix, A)
218263
if cache.isfresh
@@ -266,6 +311,8 @@ end
266311

267312
function SciMLBase.solve!(cache::LinearCache, alg::MKL32MixedLUFactorization;
268313
kwargs...)
314+
__mkl_isavailable() ||
315+
error("Error, MKL binary is missing but solve is being called. Report this issue")
269316
A = cache.A
270317
A = convert(AbstractMatrix, A)
271318

src/openblas.jl

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Libdl
2+
13
"""
24
```julia
35
OpenBLASLUFactorization()
@@ -33,12 +35,38 @@ sol = solve(prob, OpenBLASLUFactorization())
3335
"""
3436
struct OpenBLASLUFactorization <: AbstractFactorization end
3537

36-
# OpenBLAS methods - OpenBLAS_jll is always available as a standard library
38+
# Check if OpenBLAS is available and can be loaded
39+
function __openblas_isavailable()
40+
if !@isdefined(OpenBLAS_jll)
41+
return false
42+
end
43+
if !OpenBLAS_jll.is_available()
44+
return false
45+
end
46+
# Try to load the library and check for required symbols
47+
try
48+
openblas_hdl = Libdl.dlopen(OpenBLAS_jll.libopenblas)
49+
if openblas_hdl == C_NULL
50+
return false
51+
end
52+
# Check for a required symbol
53+
if Libdl.dlsym_e(openblas_hdl, "dgetrf_") == C_NULL
54+
Libdl.dlclose(openblas_hdl)
55+
return false
56+
end
57+
Libdl.dlclose(openblas_hdl)
58+
return true
59+
catch
60+
return false
61+
end
62+
end
3763

3864
function openblas_getrf!(A::AbstractMatrix{<:ComplexF64};
3965
ipiv = similar(A, BlasInt, min(size(A, 1), size(A, 2))),
4066
info = Ref{BlasInt}(),
4167
check = false)
68+
__openblas_isavailable() ||
69+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
4270
require_one_based_indexing(A)
4371
check && chkfinite(A)
4472
chkstride1(A)
@@ -59,6 +87,8 @@ function openblas_getrf!(A::AbstractMatrix{<:ComplexF32};
5987
ipiv = similar(A, BlasInt, min(size(A, 1), size(A, 2))),
6088
info = Ref{BlasInt}(),
6189
check = false)
90+
__openblas_isavailable() ||
91+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
6292
require_one_based_indexing(A)
6393
check && chkfinite(A)
6494
chkstride1(A)
@@ -79,6 +109,8 @@ function openblas_getrf!(A::AbstractMatrix{<:Float64};
79109
ipiv = similar(A, BlasInt, min(size(A, 1), size(A, 2))),
80110
info = Ref{BlasInt}(),
81111
check = false)
112+
__openblas_isavailable() ||
113+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
82114
require_one_based_indexing(A)
83115
check && chkfinite(A)
84116
chkstride1(A)
@@ -99,6 +131,8 @@ function openblas_getrf!(A::AbstractMatrix{<:Float32};
99131
ipiv = similar(A, BlasInt, min(size(A, 1), size(A, 2))),
100132
info = Ref{BlasInt}(),
101133
check = false)
134+
__openblas_isavailable() ||
135+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
102136
require_one_based_indexing(A)
103137
check && chkfinite(A)
104138
chkstride1(A)
@@ -120,6 +154,8 @@ function openblas_getrs!(trans::AbstractChar,
120154
ipiv::AbstractVector{BlasInt},
121155
B::AbstractVecOrMat{<:ComplexF64};
122156
info = Ref{BlasInt}())
157+
__openblas_isavailable() ||
158+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
123159
require_one_based_indexing(A, ipiv, B)
124160
LinearAlgebra.LAPACK.chktrans(trans)
125161
chkstride1(A, B, ipiv)
@@ -145,6 +181,8 @@ function openblas_getrs!(trans::AbstractChar,
145181
ipiv::AbstractVector{BlasInt},
146182
B::AbstractVecOrMat{<:ComplexF32};
147183
info = Ref{BlasInt}())
184+
__openblas_isavailable() ||
185+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
148186
require_one_based_indexing(A, ipiv, B)
149187
LinearAlgebra.LAPACK.chktrans(trans)
150188
chkstride1(A, B, ipiv)
@@ -170,6 +208,8 @@ function openblas_getrs!(trans::AbstractChar,
170208
ipiv::AbstractVector{BlasInt},
171209
B::AbstractVecOrMat{<:Float64};
172210
info = Ref{BlasInt}())
211+
__openblas_isavailable() ||
212+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
173213
require_one_based_indexing(A, ipiv, B)
174214
LinearAlgebra.LAPACK.chktrans(trans)
175215
chkstride1(A, B, ipiv)
@@ -195,6 +235,8 @@ function openblas_getrs!(trans::AbstractChar,
195235
ipiv::AbstractVector{BlasInt},
196236
B::AbstractVecOrMat{<:Float32};
197237
info = Ref{BlasInt}())
238+
__openblas_isavailable() ||
239+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
198240
require_one_based_indexing(A, ipiv, B)
199241
LinearAlgebra.LAPACK.chktrans(trans)
200242
chkstride1(A, B, ipiv)
@@ -239,6 +281,8 @@ end
239281

240282
function SciMLBase.solve!(cache::LinearCache, alg::OpenBLASLUFactorization;
241283
kwargs...)
284+
__openblas_isavailable() ||
285+
error("Error, OpenBLAS binary is missing but solve is being called. Report this issue")
242286
A = cache.A
243287
A = convert(AbstractMatrix, A)
244288
if cache.isfresh

0 commit comments

Comments
 (0)