[cmake-developers] Volunteering to maintain a new module: FindGSL.cmake

Thompson, KT kgt at lanl.gov
Tue Dec 2 19:52:38 EST 2014


Brad,

Thank you very much for the constructive comments concerning my submitted FindGSL.cmake module.  I believe I have addressed nearly all of your concerns in the version shown below.  I have two comments that may be useful:

1. The command "add_library(GSL::gsl UNKOWN IMPORTED)" generates warnings on platforms that do not support shared libraries.  For example on the Cray XE6 (I think I also get this on BlueGene, but I didn't test it today):

   FindGSL.cmake:223 (add_library):
     ADD_LIBRARY called with MODULE option but the target platform does not
     support dynamic linking.  Building a STATIC library instead.  This may lead
     to problems.

I have added a query for the value of TARGET_SUPPORTS_SHARED_LIBS and will use the library type "STATIC" when this property is FALSE.

2. I understand the concerns with setting GSL_ROOT_DIR that you and Rolf raised.  Personally, I like using GSL_ROOT_DIR because it plays nicely with our use of modules (modules.sourceforge.net) or dotkit (computing.llnl.gov/?set=jobs&page=dotkit) and the revised FindGSL.cmake continues to use GSL_ROOT_DIR.  The decision to eliminate XXX_ROOT_DIR type variables from all cmake modules is beyond the scope of my submission and I will not comment further except to say that I could use CMAKE_PREFIX_PATH just as easily.

Again -- thank you for your help.

-kt

#.rst
# Find GSL
# --------
#
# Find the native GSL includes and libraries.
#
# The GNU Scientific Library (GSL) is a numerical library for C and C++
# programmers. It is free software under the GNU General Public License.
#
# === Imported Targets ===
#
# If GSL is found, this module defines the following :prop_tgt:`IMPORTED` targets
#
# ::
#
# ``GSL::gsl``        - The main GSL library.
# ``GSL::gslcblas``   - The CBLAS support library used by GSL.
#
# === Result Variables ===
#
# This module will set the following variables per language in your project:
#
# ::
#
#  GSL_FOUND          - True if GSL found on the local system
#  GSL_INCLUDE_DIRS   - Location of GSL header files.
#  GSL_LIBRARIES      - The GSL libraries.
#  GSL_VERSION        - The version of the discovered GSL install.
#  GSL_ROOT_DIR       - The top level directory of the discovered GSL 
#                       install (useful if GSL is not in a standard location)
#
# === Hints ===
#
# Set ``GSL_ROOT_DIR`` to a directory that contains a GSL installation.
#
# This script expects to find libraries at $GSL_ROOT_DIR/lib and the GSL headers
# at $GSL_ROOT_DIR/include/gsl.  The library directory may optionally provide
# Release and Debug folders.  For Unix-like systems, this script will use
# $GSL_ROOT_DIR/bin/gsl-config (if found) to aid in the discovery GSL.
#
# === Usage ===
#
# To use this module, simply call FindGSL from a CMakeLists.txt file, or run
# find_package(GSL), then run CMake. If you are happy with the auto-detected
# configuration for your language, then you're done.  If not, you have the
# option of manually specifying the ``GSL_ROOT_DIR``.
#
# This module may set the following variables depending on platform and type
# of GSL installation discovered.  These variables may optionally be set to
# help this module find the correct files.
#
# ::
#
# GSL_CLBAS_LIBRARY       - Location of the GSL CBLAS library.
# GSL_CBLAS_LIBRARY_DEBUG - Location of the debug GSL CBLAS library (if any).
# GSL_CONFIG              - Location of the ``gsl-config`` script (if any).
# GSL_LIBRARY             - Location of the GSL library.
# GSL_LIBRARY_DEBUG       - Location of the debug GSL library (if any).

#=============================================================================
# Copyright 2014 Kelly Thompson kgt at lanl.gov
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# License for more information.
# =============================================================================

# Include these modules to handle the QUIETLY and REQUIRED arguments. See
# http://www.cmake.org/cmake/help/v3.0/module/FindPackageHandleStandardArgs.html
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)

#=============================================================================
# If the user has provided ``GSL_ROOT_DIR``, use it!  Choose items found
# at this location over system locations.
if( EXISTS "$ENV{GSL_ROOT_DIR}" )
  file( TO_CMAKE_PATH "$ENV{GSL_ROOT_DIR}" GSL_ROOT_DIR )
  set( GSL_ROOT_DIR "${GSL_ROOT_DIR}" CACHE PATH "Prefix for GSL installation." )
endif()
if( NOT EXISTS "${GSL_ROOT_DIR}" )
  set( GSL_USE_PKGCONFIG ON )
endif()

#=============================================================================
# As a first try, use the PkgConfig module.  This will work on many
# *NIX systems.  See :module:`findpkgconfig`
# This will return ``GSL_INCLUDEDIR`` and ``GSL_LIBDIR`` used below.
if( GSL_USE_PKGCONFIG )
  find_package(PkgConfig)
  pkg_check_modules( GSL QUIET gsl )

  if( EXISTS "${GSL_INCLUDEDIR}" )
    get_filename_component( GSL_ROOT_DIR "${GSL_INCLUDEDIR}" DIRECTORY CACHE)
  endif() 
endif()

#=============================================================================
# Set GSL_INCLUDE_DIRS and GSL_LIBRARIES. If we skipped the PkgConfig step, try
# to find the libraries at $GSL_ROOT_DIR (if provided) or in standard system
# locations.  These find_library and find_path calls will prefer custom
# locations over standard locations (HINTS).  If the requested file is not found
# at the HINTS location, standard system locations will be still be searched
# (/usr/lib64 (Redhat), lib/i386-linux-gnu (Debian)).
  
find_path( GSL_INCLUDE_DIRS 
  NAMES gsl/gsl_sf.h
  HINTS ${GSL_ROOT_DIR}/include ${GSL_INCLUDEDIR}
)
find_library( GSL_LIBRARY
  NAMES gsl 
  HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
  PATH_SUFFIXES Release Debug
)
find_library( GSL_CBLAS_LIBRARY
  NAMES gslcblas cblas
  HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
  PATH_SUFFIXES Release Debug
)
# Do we also have debug versions?
find_library( GSL_LIBRARY_DEBUG
  NAMES gsl 
  HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
  PATH_SUFFIXES Debug
)
find_library( GSL_CBLAS_LIBRARY_DEBUG
  NAMES gslcblas cblas
  HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
  PATH_SUFFIXES Debug
)
set( GSL_LIBRARIES ${GSL_LIBRARY};${GSL_CBLAS_LIBRARY} CACHE PATH "GSL libraries." )

# If we didn't use PkgConfig, try to find the version via gsl-config or by
# reading gsl_version.h.
if( NOT GSL_VERSION )
  # 1. If gsl-config exists, query for the version.
  find_program( GSL_CONFIG
    NAMES gsl-config
    HINTS "${GSL_ROOT_DIR}/bin"
    )
  if( EXISTS "${GSL_CONFIG}" )
    execute_process(
      COMMAND         "${GSL_CONFIG}" --version
      OUTPUT_VARIABLE GSL_VERSION
      OUTPUT_STRIP_TRAILING_WHITESPACE )
  endif()
  
  # 2. If gsl-config is not available, try looking in gsl/gsl_version.h
  if( NOT GSL_VERSION AND EXISTS "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" )
    file( STRINGS "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" gsl_version_h_contents )
    foreach( entry ${gsl_version_h_contents} )
      if( ${entry} MATCHES "define GSL_VERSION")
         string( REGEX REPLACE ".*([0-9].[0-9][0-9]).*" "\\1" GSL_VERSION ${entry} )
      endif()
    endforeach()    
  endif()
  
  # might also try scraping the directory name for a regex match "gsl-X.X"
endif()

#=============================================================================
# handle the QUIETLY and REQUIRED arguments and set GSL_FOUND to TRUE if all
# listed variables are TRUE
find_package_handle_standard_args( GSL
  FOUND_VAR
    GSL_FOUND
  REQUIRED_VARS 
    GSL_INCLUDE_DIRS 
    GSL_LIBRARIES
    GSL_ROOT_DIR
  VERSION_VAR
    GSL_VERSION
  )
mark_as_advanced( GSL_LIBRARIES GSL_INCLUDE_DIRS GSL_ROOT_DIR GSL_VERSION 
  GSL_LIBRARY GSL_CBLAS_LIBRARY GSL_LIBRARY_DEBUG GSL_CBLAS_LIBRARY_DEBUG 
  GSL_USE_PKGCONFIG GSL_CONFIG )

#=============================================================================
# Register imported libraries:
# 1. If we can find a Windows .dll file (or if we can find both Debug and 
#    Release libraries), we will set appropriate target properties for these.  
# 2. However, for most systems, we will only register the import location and 
#    include directory.

# Look for dlls, or Release and Debug libraries.
if(WIN32)
  string( REPLACE ".lib" ".dll" GSL_LIBRARY_DLL       "${GSL_LIBRARY}" )
  string( REPLACE ".lib" ".dll" GSL_CBLAS_LIBRARY_DLL "${GSL_CBLAS_LIBRARY}" )
  string( REPLACE ".lib" ".dll" GSL_LIBRARY_DEBUG_DLL "${GSL_LIBRARY_DEBUG}" )
  string( REPLACE ".lib" ".dll" GSL_CBLAS_LIBRARY_DEBUG_DLL "${GSL_CBLAS_LIBRARY_DEBUG}" )
endif()

if( GSL_FOUND )
  if( EXISTS "${GSL_LIBRARY_DLL}" AND EXISTS "${GSL_CBLAS_LIBRARY_DLL}")
    # Windows systems with dll libraries.
    add_library( GSL::gsl      SHARED IMPORTED )
    add_library( GSL::gslcblas SHARED IMPORTED )
    
    # Windows with dlls, but only Release libraries.
    set_target_properties( GSL::gslcblas PROPERTIES
      IMPORTED_LOCATION                 "${GSL_CBLAS_LIBRARY_DLL}"
      IMPORTED_IMPLIB                   "${GSL_CBLAS_LIBRARY}"
      INTERFACE_INCLUDE_DIRECTORIES     "${GSL_INCLUDE_DIRS}"
      IMPORTED_LINK_INTERFACE_LANGUAGES "C" )
    set_target_properties( GSL::gsl PROPERTIES
      IMPORTED_LOCATION                 "${GSL_LIBRARY_DLL}"
      IMPORTED_IMPLIB                   "${GSL_LIBRARY}"
      INTERFACE_INCLUDE_DIRECTORIES     "${GSL_INCLUDE_DIRS}" 
      IMPORTED_LINK_INTERFACE_LANGUAGES "C"
      INTERFACE_LINK_LIBRARIES          GSL::gslcblas )
     
    # If we have both Debug and Release libraries
    if( EXISTS "${GSL_LIBRARY_DEBUG_DLL}" AND EXISTS "${GSL_CBLAS_LIBRARY_DEBUG_DLL}")
      set_target_properties( GSL::gslcblas PROPERTIES
        IMPORTED_LOCATION_DEBUG           "${GSL_CBLAS_LIBRARY_DEBUG_DLL}"
        IMPORTED_IMPLIB_DEBUG             "${GSL_CBLAS_LIBRARY_DEBUG}" )
      set_target_properties( GSL::gsl PROPERTIES
        IMPORTED_LOCATION_DEBUG           "${GSL_LIBRARY_DEBUG_DLL}"
        IMPORTED_IMPLIB_DEBUG             "${GSL_LIBRARY_DEBUG}" )
    endif()

  else()

    # If this platform doesn't support shared libraries (i.e.: Cray XE6 or Blue
    # Gene) suppress the CMake warning of the form:
    #     "ADD_LIBRARY called with MODULE option but the target platform
    #     does not support dynamic linking.  Building a STATIC library
    #     instead.  This may lead to problems."
    # by setting the library type to STATIC instead of UNKNOWN
    get_property( os_supports_shared GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS )
    if( ${os_supports_shared} )
      set( library_type UNKNOWN )
    else()
      set( library_type STATIC )
    endif()

    # Create the imported library targets
    add_library( GSL::gsl      ${library_type} IMPORTED )
    add_library( GSL::gslcblas ${library_type} IMPORTED )
    set_target_properties( GSL::gslcblas PROPERTIES
      IMPORTED_LOCATION                 "${GSL_CBLAS_LIBRARY}"
      INTERFACE_INCLUDE_DIRECTORIES     "${GSL_INCLUDE_DIRS}"
      IMPORTED_LINK_INTERFACE_LANGUAGES "C" )
    set_target_properties( GSL::gsl PROPERTIES
      IMPORTED_LOCATION                 "${GSL_LIBRARY}"
      INTERFACE_INCLUDE_DIRECTORIES     "${GSL_INCLUDE_DIRS}" 
      IMPORTED_LINK_INTERFACE_LANGUAGES "C"
      INTERFACE_LINK_LIBRARIES          GSL::gslcblas )
  endif()
endif()

#=============================================================================
# References:
# - http://www.cmake.org/cmake/help/git-master/manual/cmake-developer.7.html#modules





More information about the cmake-developers mailing list