1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5FindGSL
6--------
7
8.. versionadded:: 3.2
9
10Find the native GNU Scientific Library (GSL) includes and libraries.
11
12The GNU Scientific Library (GSL) is a numerical library for C and C++
13programmers. It is free software under the GNU General Public
14License.
15
16Imported Targets
17^^^^^^^^^^^^^^^^
18
19If GSL is found, this module defines the following :prop_tgt:`IMPORTED`
20targets::
21
22 GSL::gsl      - The main GSL library.
23 GSL::gslcblas - The CBLAS support library used by GSL.
24
25Result Variables
26^^^^^^^^^^^^^^^^
27
28This module will set the following variables in your project::
29
30 GSL_FOUND          - True if GSL found on the local system
31 GSL_INCLUDE_DIRS   - Location of GSL header files.
32 GSL_LIBRARIES      - The GSL libraries.
33 GSL_VERSION        - The version of the discovered GSL install.
34
35Hints
36^^^^^
37
38Set ``GSL_ROOT_DIR`` to a directory that contains a GSL installation.
39
40This script expects to find libraries at ``$GSL_ROOT_DIR/lib`` and the GSL
41headers at ``$GSL_ROOT_DIR/include/gsl``.  The library directory may
42optionally provide Release and Debug folders. If available, the libraries
43named ``gsld``, ``gslblasd`` or ``cblasd`` are recognized as debug libraries.
44For Unix-like systems, this script will use ``$GSL_ROOT_DIR/bin/gsl-config``
45(if found) to aid in the discovery of GSL.
46
47Cache Variables
48^^^^^^^^^^^^^^^
49
50This module may set the following variables depending on platform and type
51of GSL installation discovered.  These variables may optionally be set to
52help this module find the correct files::
53
54 GSL_CBLAS_LIBRARY       - Location of the GSL CBLAS library.
55 GSL_CBLAS_LIBRARY_DEBUG - Location of the debug GSL CBLAS library (if any).
56 GSL_CONFIG_EXECUTABLE   - Location of the ``gsl-config`` script (if any).
57 GSL_LIBRARY             - Location of the GSL library.
58 GSL_LIBRARY_DEBUG       - Location of the debug GSL library (if any).
59
60#]=======================================================================]
61
62include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
63
64#=============================================================================
65# If the user has provided ``GSL_ROOT_DIR``, use it!  Choose items found
66# at this location over system locations.
67if( EXISTS "$ENV{GSL_ROOT_DIR}" )
68  file( TO_CMAKE_PATH "$ENV{GSL_ROOT_DIR}" GSL_ROOT_DIR )
69  set( GSL_ROOT_DIR "${GSL_ROOT_DIR}" CACHE PATH "Prefix for GSL installation." )
70endif()
71if( NOT EXISTS "${GSL_ROOT_DIR}" )
72  set( GSL_USE_PKGCONFIG ON )
73endif()
74
75#=============================================================================
76# As a first try, use the PkgConfig module.  This will work on many
77# *NIX systems.  See :module:`findpkgconfig`
78# This will return ``GSL_INCLUDEDIR`` and ``GSL_LIBDIR`` used below.
79if( GSL_USE_PKGCONFIG )
80  find_package(PkgConfig)
81  pkg_check_modules( GSL QUIET gsl )
82
83  if( EXISTS "${GSL_INCLUDEDIR}" )
84    get_filename_component( GSL_ROOT_DIR "${GSL_INCLUDEDIR}" DIRECTORY CACHE)
85  endif()
86endif()
87
88#=============================================================================
89# Set GSL_INCLUDE_DIRS and GSL_LIBRARIES. If we skipped the PkgConfig step, try
90# to find the libraries at $GSL_ROOT_DIR (if provided) or in standard system
91# locations.  These find_library and find_path calls will prefer custom
92# locations over standard locations (HINTS).  If the requested file is not found
93# at the HINTS location, standard system locations will be still be searched
94# (/usr/lib64 (Redhat), lib/i386-linux-gnu (Debian)).
95
96find_path( GSL_INCLUDE_DIR
97  NAMES gsl/gsl_sf.h
98  HINTS ${GSL_ROOT_DIR}/include ${GSL_INCLUDEDIR}
99)
100find_library( GSL_LIBRARY
101  NAMES gsl
102  HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
103  PATH_SUFFIXES Release Debug
104)
105find_library( GSL_CBLAS_LIBRARY
106  NAMES gslcblas cblas
107  HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
108  PATH_SUFFIXES Release Debug
109)
110# Do we also have debug versions?
111find_library( GSL_LIBRARY_DEBUG
112  NAMES gsld gsl
113  HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
114  PATH_SUFFIXES Debug
115)
116find_library( GSL_CBLAS_LIBRARY_DEBUG
117  NAMES gslcblasd cblasd gslcblas cblas
118  HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
119  PATH_SUFFIXES Debug
120)
121set( GSL_INCLUDE_DIRS ${GSL_INCLUDE_DIR} )
122set( GSL_LIBRARIES ${GSL_LIBRARY} ${GSL_CBLAS_LIBRARY} )
123
124# If we didn't use PkgConfig, try to find the version via gsl-config or by
125# reading gsl_version.h.
126if( NOT GSL_VERSION )
127  # 1. If gsl-config exists, query for the version.
128  find_program( GSL_CONFIG_EXECUTABLE
129    NAMES gsl-config
130    HINTS "${GSL_ROOT_DIR}/bin"
131    )
132  if( EXISTS "${GSL_CONFIG_EXECUTABLE}" )
133    execute_process(
134      COMMAND "${GSL_CONFIG_EXECUTABLE}" --version
135      OUTPUT_VARIABLE GSL_VERSION
136      OUTPUT_STRIP_TRAILING_WHITESPACE )
137  endif()
138
139  # 2. If gsl-config is not available, try looking in gsl/gsl_version.h
140  if( NOT GSL_VERSION AND EXISTS "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" )
141    file( STRINGS "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" gsl_version_h_contents REGEX "define GSL_VERSION" )
142    string( REGEX REPLACE ".*([0-9]\\.[0-9][0-9]?).*" "\\1" GSL_VERSION ${gsl_version_h_contents} )
143  endif()
144
145  # might also try scraping the directory name for a regex match "gsl-X.X"
146endif()
147
148#=============================================================================
149# handle the QUIETLY and REQUIRED arguments and set GSL_FOUND to TRUE if all
150# listed variables are TRUE
151find_package_handle_standard_args( GSL
152  FOUND_VAR
153    GSL_FOUND
154  REQUIRED_VARS
155    GSL_INCLUDE_DIR
156    GSL_LIBRARY
157    GSL_CBLAS_LIBRARY
158  VERSION_VAR
159    GSL_VERSION
160    )
161
162mark_as_advanced( GSL_ROOT_DIR GSL_VERSION GSL_LIBRARY GSL_INCLUDE_DIR
163  GSL_CBLAS_LIBRARY GSL_LIBRARY_DEBUG GSL_CBLAS_LIBRARY_DEBUG
164  GSL_USE_PKGCONFIG GSL_CONFIG )
165
166#=============================================================================
167# Register imported libraries:
168# 1. If we can find a Windows .dll file (or if we can find both Debug and
169#    Release libraries), we will set appropriate target properties for these.
170# 2. However, for most systems, we will only register the import location and
171#    include directory.
172
173# Look for dlls, or Release and Debug libraries.
174if(WIN32)
175  string( REPLACE ".lib" ".dll" GSL_LIBRARY_DLL       "${GSL_LIBRARY}" )
176  string( REPLACE ".lib" ".dll" GSL_CBLAS_LIBRARY_DLL "${GSL_CBLAS_LIBRARY}" )
177  string( REPLACE ".lib" ".dll" GSL_LIBRARY_DEBUG_DLL "${GSL_LIBRARY_DEBUG}" )
178  string( REPLACE ".lib" ".dll" GSL_CBLAS_LIBRARY_DEBUG_DLL "${GSL_CBLAS_LIBRARY_DEBUG}" )
179endif()
180
181if( GSL_FOUND AND NOT TARGET GSL::gsl )
182  if( EXISTS "${GSL_LIBRARY_DLL}" AND EXISTS "${GSL_CBLAS_LIBRARY_DLL}")
183
184    # Windows systems with dll libraries.
185    add_library( GSL::gsl      SHARED IMPORTED )
186    add_library( GSL::gslcblas SHARED IMPORTED )
187
188    # Windows with dlls, but only Release libraries.
189    set_target_properties( GSL::gslcblas PROPERTIES
190      IMPORTED_LOCATION_RELEASE         "${GSL_CBLAS_LIBRARY_DLL}"
191      IMPORTED_IMPLIB                   "${GSL_CBLAS_LIBRARY}"
192      INTERFACE_INCLUDE_DIRECTORIES     "${GSL_INCLUDE_DIRS}"
193      IMPORTED_CONFIGURATIONS           Release
194      IMPORTED_LINK_INTERFACE_LANGUAGES "C" )
195    set_target_properties( GSL::gsl PROPERTIES
196      IMPORTED_LOCATION_RELEASE         "${GSL_LIBRARY_DLL}"
197      IMPORTED_IMPLIB                   "${GSL_LIBRARY}"
198      INTERFACE_INCLUDE_DIRECTORIES     "${GSL_INCLUDE_DIRS}"
199      IMPORTED_CONFIGURATIONS           Release
200      IMPORTED_LINK_INTERFACE_LANGUAGES "C"
201      INTERFACE_LINK_LIBRARIES          GSL::gslcblas )
202
203    # If we have both Debug and Release libraries
204    if( EXISTS "${GSL_LIBRARY_DEBUG_DLL}" AND EXISTS "${GSL_CBLAS_LIBRARY_DEBUG_DLL}")
205      set_property( TARGET GSL::gslcblas APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug )
206      set_target_properties( GSL::gslcblas PROPERTIES
207        IMPORTED_LOCATION_DEBUG           "${GSL_CBLAS_LIBRARY_DEBUG_DLL}"
208        IMPORTED_IMPLIB_DEBUG             "${GSL_CBLAS_LIBRARY_DEBUG}" )
209      set_property( TARGET GSL::gsl APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug )
210      set_target_properties( GSL::gsl PROPERTIES
211        IMPORTED_LOCATION_DEBUG           "${GSL_LIBRARY_DEBUG_DLL}"
212        IMPORTED_IMPLIB_DEBUG             "${GSL_LIBRARY_DEBUG}" )
213    endif()
214
215  else()
216
217    # For all other environments (ones without dll libraries), create
218    # the imported library targets.
219    add_library( GSL::gsl      UNKNOWN IMPORTED )
220    add_library( GSL::gslcblas UNKNOWN IMPORTED )
221    set_target_properties( GSL::gslcblas PROPERTIES
222      IMPORTED_LOCATION                 "${GSL_CBLAS_LIBRARY}"
223      INTERFACE_INCLUDE_DIRECTORIES     "${GSL_INCLUDE_DIRS}"
224      IMPORTED_LINK_INTERFACE_LANGUAGES "C" )
225    set_target_properties( GSL::gsl PROPERTIES
226      IMPORTED_LOCATION                 "${GSL_LIBRARY}"
227      INTERFACE_INCLUDE_DIRECTORIES     "${GSL_INCLUDE_DIRS}"
228      IMPORTED_LINK_INTERFACE_LANGUAGES "C"
229      INTERFACE_LINK_LIBRARIES          GSL::gslcblas )
230  endif()
231endif()
232