Skip to content

Commit 7da8670

Browse files
authored
Merge branch 'master' into sparse_sym
2 parents 485462c + 843ffb0 commit 7da8670

13 files changed

Lines changed: 433 additions & 36 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## Unreleased
2+
3+
Changes to the existing build system
4+
- Fixed absolute paths in generated pkg-config file for external BLAS/LAPACK
5+
[#1109](https://github.com/fortran-lang/stdlib/issues/1109)
6+
17
# Version 0.8.1
28

39
Full release notes available at [v0.8.1] tag.

config/export_pc.cmake

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ function(resolve_pc_libs out_var root_target)
55
set(_result "")
66
set(_visited "")
77

8+
# List of imported targets to skip (handled separately for pkg-config)
9+
set(_skip_targets "BLAS::BLAS" "LAPACK::LAPACK")
10+
811
function(_resolve target)
912
# Prevent infinite recursion
1013
if(target IN_LIST _visited)
@@ -13,6 +16,12 @@ function(resolve_pc_libs out_var root_target)
1316
list(APPEND _visited "${target}")
1417
set(_visited "${_visited}" PARENT_SCOPE)
1518

19+
# Skip BLAS/LAPACK imported targets — they will be handled
20+
# separately via Requires.private / Libs.private
21+
if(target IN_LIST _skip_targets)
22+
return()
23+
endif()
24+
1625
if(TARGET "${target}")
1726
# Recurse into PUBLIC/INTERFACE deps first
1827
get_target_property(deps "${target}" INTERFACE_LINK_LIBRARIES)
@@ -50,10 +59,151 @@ function(resolve_pc_libs out_var root_target)
5059
set(${out_var} "${_result}" PARENT_SCOPE)
5160
endfunction()
5261

62+
# Convert absolute library paths to -l flags
63+
# e.g. /usr/lib/libopenblas.so -> -lopenblas
64+
# /usr/lib/libopenblas.so.0.3 -> -lopenblas
65+
# /usr/lib/libopenblas.dll.a -> -lopenblas
66+
function(libs_to_linker_flags out_var libs)
67+
set(_flags "")
68+
foreach(lib IN LISTS libs)
69+
if(IS_ABSOLUTE "${lib}")
70+
# Extract the full filename, then strip everything from the first dot
71+
# onwards. Using NAME_WE would only strip the last extension, which
72+
# breaks for versioned libraries (e.g. libopenblas.so.0.3 -> libopenblas.so.0).
73+
get_filename_component(_name "${lib}" NAME)
74+
string(REGEX REPLACE "\\..*$" "" _name "${_name}")
75+
# Strip leading "lib" prefix if present
76+
string(REGEX REPLACE "^lib" "" _name "${_name}")
77+
list(APPEND _flags "-l${_name}")
78+
else()
79+
# Already a flag like -lopenblas or -lm
80+
list(APPEND _flags "${lib}")
81+
endif()
82+
endforeach()
83+
list(REMOVE_DUPLICATES _flags)
84+
set(${out_var} "${_flags}" PARENT_SCOPE)
85+
endfunction()
86+
5387
resolve_pc_libs(PC_LIBS ${PROJECT_NAME})
5488

5589
string(REPLACE ";" " " PC_CONTENT "${PC_LIBS}")
5690

91+
# --- Handle BLAS/LAPACK for pkg-config ---
92+
# Use Requires.private when a vendor .pc file exists,
93+
# otherwise fall back to Libs.private with -l flags.
94+
set(PC_REQUIRES_PRIVATE "")
95+
set(PC_LIBS_PRIVATE "")
96+
97+
if(BLAS_FOUND OR LAPACK_FOUND)
98+
find_package(PkgConfig QUIET)
99+
100+
# Known pkg-config names for common BLAS/LAPACK vendors.
101+
# We try the most specific names first, then fall back to generic ones.
102+
set(_blas_pc_names
103+
openblas # OpenBLAS
104+
blas-openblas # Debian/Ubuntu OpenBLAS
105+
mkl-dynamic-lp64-seq # Intel MKL (dynamic, LP64, sequential)
106+
mkl-dynamic-ilp64-seq # Intel MKL (dynamic, ILP64, sequential)
107+
mkl-dynamic-lp64-iomp # Intel MKL (dynamic, LP64, OpenMP)
108+
mkl-dynamic-ilp64-iomp # Intel MKL (dynamic, ILP64, OpenMP)
109+
mkl-static-lp64-seq # Intel MKL (static, LP64, sequential)
110+
mkl-static-ilp64-seq # Intel MKL (static, ILP64, sequential)
111+
blas # Generic BLAS
112+
blas-netlib # Netlib BLAS
113+
)
114+
set(_lapack_pc_names
115+
lapack # Generic LAPACK
116+
lapack-netlib # Netlib LAPACK
117+
)
118+
119+
# BLAS packages that are known to also provide LAPACK
120+
set(_blas_includes_lapack_list
121+
openblas
122+
blas-openblas
123+
mkl-dynamic-lp64-seq
124+
mkl-dynamic-ilp64-seq
125+
mkl-dynamic-lp64-iomp
126+
mkl-dynamic-ilp64-iomp
127+
mkl-static-lp64-seq
128+
mkl-static-ilp64-seq
129+
)
130+
131+
set(_blas_pc_found FALSE)
132+
set(_blas_includes_lapack FALSE)
133+
set(_lapack_pc_found FALSE)
134+
135+
if(PKG_CONFIG_FOUND)
136+
# --- Detect BLAS pkg-config package ---
137+
if(BLAS_FOUND)
138+
foreach(_pkg IN LISTS _blas_pc_names)
139+
pkg_check_modules(_BLAS_PC_${_pkg} QUIET "${_pkg}")
140+
if(_BLAS_PC_${_pkg}_FOUND)
141+
list(APPEND PC_REQUIRES_PRIVATE "${_pkg}")
142+
set(_blas_pc_found TRUE)
143+
if(_pkg IN_LIST _blas_includes_lapack_list)
144+
set(_blas_includes_lapack TRUE)
145+
endif()
146+
message(STATUS "pkg-config: using '${_pkg}' for BLAS")
147+
break()
148+
endif()
149+
endforeach()
150+
endif()
151+
152+
# --- Detect LAPACK pkg-config package ---
153+
# Skip separate LAPACK detection if the BLAS package already includes LAPACK
154+
# (e.g. OpenBLAS, MKL). Standalone BLAS packages like netlib still need this.
155+
if(LAPACK_FOUND AND NOT _blas_includes_lapack)
156+
foreach(_pkg IN LISTS _lapack_pc_names)
157+
pkg_check_modules(_LAPACK_PC_${_pkg} QUIET "${_pkg}")
158+
if(_LAPACK_PC_${_pkg}_FOUND)
159+
list(APPEND PC_REQUIRES_PRIVATE "${_pkg}")
160+
set(_lapack_pc_found TRUE)
161+
message(STATUS "pkg-config: using '${_pkg}' for LAPACK")
162+
break()
163+
endif()
164+
endforeach()
165+
endif()
166+
endif()
167+
168+
# --- Fallback: convert absolute paths to -l flags ---
169+
if(BLAS_FOUND AND NOT _blas_pc_found)
170+
libs_to_linker_flags(_blas_flags "${BLAS_LIBRARIES}")
171+
list(APPEND PC_LIBS_PRIVATE ${_blas_flags})
172+
message(STATUS "pkg-config: no .pc file found for BLAS, using linker flags: ${_blas_flags}")
173+
endif()
174+
175+
if(LAPACK_FOUND AND NOT _lapack_pc_found AND NOT _blas_includes_lapack)
176+
libs_to_linker_flags(_lapack_flags "${LAPACK_LIBRARIES}")
177+
list(APPEND PC_LIBS_PRIVATE ${_lapack_flags})
178+
message(STATUS "pkg-config: no .pc file found for LAPACK, using linker flags: ${_lapack_flags}")
179+
endif()
180+
endif()
181+
182+
# Flatten lists to space-separated strings
183+
string(REPLACE ";" " " PC_REQUIRES_PRIVATE "${PC_REQUIRES_PRIVATE}")
184+
string(REPLACE ";" " " PC_LIBS_PRIVATE "${PC_LIBS_PRIVATE}")
185+
186+
# Handle absolute vs relative install paths for libdir
187+
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
188+
set(PC_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
189+
else()
190+
set(PC_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
191+
endif()
192+
193+
# Handle absolute vs relative install paths for includedir
194+
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
195+
set(PC_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
196+
else()
197+
set(PC_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
198+
endif()
199+
200+
# Handle absolute vs relative install paths for moduledir
201+
if(IS_ABSOLUTE "${CMAKE_INSTALL_MODULEDIR}")
202+
set(PC_MODULEDIR "${CMAKE_INSTALL_MODULEDIR}")
203+
else()
204+
set(PC_MODULEDIR "\${prefix}/${CMAKE_INSTALL_MODULEDIR}")
205+
endif()
206+
57207
configure_file(
58208
"${CMAKE_CURRENT_SOURCE_DIR}/config/template.pc"
59209
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
@@ -64,4 +214,3 @@ install(
64214
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
65215
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
66216
)
67-

config/template.pc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
prefix=@CMAKE_INSTALL_PREFIX@
2-
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
3-
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
4-
moduledir=${prefix}/@CMAKE_INSTALL_MODULEDIR@
2+
libdir=@PC_LIBDIR@
3+
includedir=@PC_INCLUDEDIR@
4+
moduledir=@PC_MODULEDIR@
55

66
Name: @PROJECT_NAME@
77
Description: @PROJECT_DESCRIPTION@
88
Version: @PROJECT_VERSION@
9-
Libs: -L${libdir} @PC_CONTENT@
9+
Requires.private: @PC_REQUIRES_PRIVATE@
1010
Cflags: -I${includedir} -I${moduledir}
11+
Libs: -L${libdir} @PC_CONTENT@
12+
Libs.private: @PC_LIBS_PRIVATE@

doc/specs/stdlib_sparse.md

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ If the `diagonal` array has not been previously allocated, the `diag` subroutine
338338

339339
### Syntax
340340

341-
`call ` [[stdlib_sparse_conversion(module):csr2sellc(interface)]] `(csr,ell[,num_nz_rows])`
341+
`call ` [[stdlib_sparse_conversion(module):csr2ell(interface)]] `(csr,ell[,num_nz_rows])`
342342

343343
### Arguments
344344

@@ -361,4 +361,39 @@ If the `diagonal` array has not been previously allocated, the `diag` subroutine
361361
### Example
362362
```fortran
363363
{!example/linalg/example_sparse_spmv.f90!}
364-
```
364+
```
365+
366+
<!-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -->
367+
## Operator overloading (`+`, `-`, `*`, `/`) {#operators}
368+
369+
### Status
370+
371+
Experimental
372+
373+
### Description
374+
375+
The definition of all standard arithmetic operators have been overloaded to be applicable for the matrix types defined by `stdlib_sparse`. The operators have been overloaded to support the following tuple combinations of the left-hand-side of the operation: same type and kind matrix-matrix, matrix-scalar and scalar-matrix.
376+
377+
### Syntax
378+
379+
- Matrix-matrix operators :
380+
381+
`C = A + B`
382+
383+
`C = A - B`
384+
385+
`C = A * B`
386+
387+
`C = A / B`
388+
389+
- Matrix scalar operators :
390+
391+
`B = A + alpha` or `B = alpha + A`
392+
393+
`B = A - alpha` or `B = alpha - A`
394+
395+
`B = A * alpha` or `B = alpha * A`
396+
397+
`B = A / alpha` or `B = alpha / A`
398+
399+
*Note*: scalar addition and subtraction operators perform element-wise operations only on the stored (non-zero) values, not on the full mathematical matrix. Meaning, the sparsity pattern is preserved.

src/linalg/stdlib_linalg.fypp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -876,8 +876,7 @@ module stdlib_linalg
876876
!! This interface provides methods for computing the determinant of a matrix.
877877
!! Supported data types include `real` and `complex`.
878878
!!
879-
!!@note The provided functions are intended for square matrices only.
880-
!!@note BLAS/LAPACK backends do not currently support extended precision (``xdp``).
879+
!!@note The provided functions are intended for square matrices only.
881880
!!
882881
!!### Example
883882
!!
@@ -898,10 +897,8 @@ module stdlib_linalg
898897
!!```
899898
!!
900899
#:for rk,rt in RC_KINDS_TYPES
901-
#:if rk!="xdp"
902900
module procedure stdlib_linalg_${rt[0]}$${rk}$determinant
903901
module procedure stdlib_linalg_pure_${rt[0]}$${rk}$determinant
904-
#:endif
905902
#:endfor
906903
end interface det
907904

@@ -920,7 +917,6 @@ module stdlib_linalg
920917
!! Supported data types include real and complex.
921918
!!
922919
!!@note The provided functions are intended for square matrices.
923-
!!@note BLAS/LAPACK backends do not currently support extended precision (``xdp``).
924920
!!
925921
!!### Example
926922
!!
@@ -935,15 +931,12 @@ module stdlib_linalg
935931
!!```
936932
!
937933
#:for rk,rt in RC_KINDS_TYPES
938-
#:if rk!="xdp"
939934
module procedure stdlib_linalg_pure_${rt[0]}$${rk}$determinant
940-
#:endif
941935
#:endfor
942936
end interface operator(.det.)
943937

944938
interface
945939
#:for rk,rt in RC_KINDS_TYPES
946-
#:if rk!="xdp"
947940
module function stdlib_linalg_${rt[0]}$${rk}$determinant(a,overwrite_a,err) result(det)
948941
!> Input matrix a[m,n]
949942
${rt}$, intent(inout), target :: a(:,:)
@@ -960,7 +953,6 @@ module stdlib_linalg
960953
!> Matrix determinant
961954
${rt}$ :: det
962955
end function stdlib_linalg_pure_${rt[0]}$${rk}$determinant
963-
#:endif
964956
#:endfor
965957
end interface
966958

@@ -1216,7 +1208,6 @@ module stdlib_linalg
12161208
!! Preallocated space for both eigenvalues `lambda` and the eigenvector matrices must be user-provided.
12171209
!!
12181210
!!@note The solution is based on LAPACK's general eigenproblem solvers `*GEEV`.
1219-
!!@note BLAS/LAPACK backends do not currently support extended precision (``xdp``).
12201211
!!
12211212
#:for rk,rt,ri in RC_KINDS_TYPES
12221213
#:for ep,ei in EIG_PROBLEM_LIST
@@ -1294,7 +1285,6 @@ module stdlib_linalg
12941285
!! as an optional `type(linalg_state_type)` output flag.
12951286
!!
12961287
!!@note The solution is based on LAPACK's general eigenproblem solvers `*GEEV`.
1297-
!!@note BLAS/LAPACK backends do not currently support extended precision (``xdp``).
12981288
!!
12991289
#:for rk,rt,ri in RC_KINDS_TYPES
13001290
#:for ep,ei in EIG_PROBLEM_LIST
@@ -1349,7 +1339,6 @@ module stdlib_linalg
13491339
!! Preallocated space for both eigenvalues `lambda` and the eigenvector matrix must be user-provided.
13501340
!!
13511341
!!@note The solution is based on LAPACK's eigenproblem solvers `*SYEV`/`*HEEV`.
1352-
!!@note BLAS/LAPACK backends do not currently support extended precision (``xdp``).
13531342
!!
13541343
#:for rk,rt,ri in RC_KINDS_TYPES
13551344
module subroutine stdlib_linalg_eigh_${ri}$(a,lambda,vectors,upper_a,overwrite_a,err)
@@ -1392,7 +1381,6 @@ module stdlib_linalg
13921381
!! as an optional `type(linalg_state_type)` output flag.
13931382
!!
13941383
!!@note The solution is based on LAPACK's eigenproblem solvers `*SYEV`/`*HEEV`.
1395-
!!@note BLAS/LAPACK backends do not currently support extended precision (``xdp``).
13961384
!!
13971385
#:for rk,rt,ri in RC_KINDS_TYPES
13981386
module function stdlib_linalg_eigvalsh_${ri}$(a,upper_a,err) result(lambda)

src/linalg/stdlib_linalg_determinant.fypp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ submodule (stdlib_linalg) stdlib_linalg_determinant
1313

1414
contains
1515

16-
! BLAS/LAPACK backends do not currently support xdp
1716
#:for rk,rt in RC_KINDS_TYPES
18-
#:if rk!="xdp"
1917
pure module function stdlib_linalg_pure_${rt[0]}$${rk}$determinant(a) result(det)
2018
!!### Summary
2119
!! Compute determinant of a real square matrix (pure interface).
@@ -233,7 +231,6 @@ submodule (stdlib_linalg) stdlib_linalg_determinant
233231

234232
end function stdlib_linalg_${rt[0]}$${rk}$determinant
235233

236-
#:endif
237234
#:endfor
238235

239236
end submodule stdlib_linalg_determinant

src/sparse/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ set(sparse_fppFiles
22
stdlib_sparse_constants.fypp
33
stdlib_sparse_conversion.fypp
44
stdlib_sparse_kinds.fypp
5+
stdlib_sparse_operators.fypp
56
stdlib_sparse_spmv.fypp
67
)
78

0 commit comments

Comments
 (0)