It has always nagged me that the FindPkgConfig module requires people to use 
link_directories(). Now I created a new optional mode for pkg_check_modules() 
and pkg_search_modules() which will search the absolute paths of the libraries 
that are returned by pkg-config, and create an imported target from that 
information that also contains defines and include directories. It restricts 
searching to the directories returned by pkg-config, if none are given the 
normal search rules are used. I have manually tested this and it seems to 
work. Please have a look and tell me if I have missed something before I put 
this into next.

Greetings,

Eike

From 352e6b2733995dc121fe5d80d1183fe372522124 Mon Sep 17 00:00:00 2001
From: Rolf Eike Beer <e...@sf-mail.de>
Date: Wed, 11 May 2016 23:45:26 +0200
Subject: [PATCH] FindPkgConfig: optionally create imported target for the
 found libraries

---
 Modules/FindPkgConfig.cmake | 81 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 74 insertions(+), 7 deletions(-)

diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
index 447c526..fd71a7a 100644
--- a/Modules/FindPkgConfig.cmake
+++ b/Modules/FindPkgConfig.cmake
@@ -16,6 +16,7 @@
 # Copyright 2006-2014 Kitware, Inc.
 # Copyright 2014      Christoph GrĂ¼ninger <f...@grueninger.de>
 # Copyright 2006      Enrico Scholz <enrico.sch...@informatik.tu-chemnitz.de>
+# Copyright 2016      Rolf Eike Beer <e...@sf-mail.de>
 #
 # Distributed under the OSI-approved BSD License (the "License");
 # see accompanying file Copyright.txt for details.
@@ -119,11 +120,12 @@ macro(_pkgconfig_invoke_dyn _pkglist _prefix _varname 
cleanup_regexp)
 endmacro()
 
 # Splits given arguments into options and a package list
-macro(_pkgconfig_parse_options _result _is_req _is_silent _no_cmake_path 
_no_cmake_environment_path)
+macro(_pkgconfig_parse_options _result _is_req _is_silent _no_cmake_path 
_no_cmake_environment_path _imp_target)
   set(${_is_req} 0)
   set(${_is_silent} 0)
   set(${_no_cmake_path} 0)
   set(${_no_cmake_environment_path} 0)
+  set(${_imp_target} 0)
   if(DEFINED PKG_CONFIG_USE_CMAKE_PREFIX_PATH)
     if(NOT PKG_CONFIG_USE_CMAKE_PREFIX_PATH)
       set(${_no_cmake_path} 1)
@@ -147,6 +149,9 @@ macro(_pkgconfig_parse_options _result _is_req _is_silent 
_no_cmake_path _no_cma
     if (_pkg STREQUAL "NO_CMAKE_ENVIRONMENT_PATH")
       set(${_no_cmake_environment_path} 1)
     endif()
+    if (_pkg STREQUAL "IMPORTED_TARGET")
+      set(${_imp_target} 1)
+    endif()
   endforeach()
 
   set(${_result} ${ARGN})
@@ -154,6 +159,7 @@ macro(_pkgconfig_parse_options _result _is_req _is_silent 
_no_cmake_path _no_cma
   list(REMOVE_ITEM ${_result} "QUIET")
   list(REMOVE_ITEM ${_result} "NO_CMAKE_PATH")
   list(REMOVE_ITEM ${_result} "NO_CMAKE_ENVIRONMENT_PATH")
+  list(REMOVE_ITEM ${_result} "IMPORTED_TARGET")
 endmacro()
 
 # Add the content of a variable or an environment variable to a list of
@@ -181,8 +187,60 @@ function(_pkgconfig_add_extra_path _extra_paths_var _var)
   set(${_extra_paths_var} ${${_extra_paths_var}} PARENT_SCOPE)
 endfunction()
 
+# scan the LDFLAGS returned by pkg-config for library directories and
+# libraries, figure out the absolute paths of that libraries in the
+# given directories, and create an imported target from them
+function(_pkg_create_imp_target _prefix _no_cmake_path 
_no_cmake_environment_path)
+  unset(_libs)
+  unset(_find_opts)
+
+  # set the options that are used as long as the .pc file does not provide a 
library
+  # path to look into
+  if(_no_cmake_path)
+    set(_find_opts "NO_CMAKE_PATH")
+  endif()
+  if(_no_cmake_environment_path)
+    set(_find_opts "${_find_opts} NO_CMAKE_ENVIRONMENT_PATH")
+  endif()
+
+  foreach (flag IN LISTS ${_prefix}_LDFLAGS)
+    if (flag MATCHES "^-L(.*)")
+      # only look into the given paths from now on
+      set(_find_opts "HINTS ${${CMAKE_MATCH_1}} NO_DEFAULT_PATH")
+      continue()
+    endif()
+    if (flag MATCHES "^-l(.*)")
+      set(_pkg_search "${CMAKE_MATCH_1}")
+    else()
+      continue()
+    endif()
+
+    find_library(${_prefix}-${CMAKE_MATCH_1}
+                 NAMES ${CMAKE_MATCH_1}
+                 ${_find_opts})
+    list(APPEND _libs "${${_prefix}-${CMAKE_MATCH_1}}")
+  endforeach()
+
+  # only create the target if it is linkable, i.e. no executables
+  if (NOT TARGET PkgConfig::${_prefix}
+      AND ( ${_prefix}_INCLUDE_DIRS OR _libs OR ${_prefix}_CFLAGS_OTHER ))
+    add_library(PkgConfig::${_prefix} INTERFACE IMPORTED)
+    if(${_prefix}_INCLUDE_DIRS)
+      set_target_properties(PkgConfig::${_prefix} PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${${_prefix}_INCLUDE_DIRS}")
+    endif()
+    if(_libs)
+      set_target_properties(PkgConfig::${_prefix} PROPERTIES
+        INTERFACE_LINK_LIBRARIES "${_libs}")
+    endif()
+    if(${_prefix}_CFLAGS_OTHER)
+      set_property(TARGET PkgConfig::${_prefix} PROPERTY 
INTERFACE_COMPILE_OPTIONS "${${_prefix}_CFLAGS_OTHER}")
+    endif()
+  endif()
+endfunction()
+
 ###
-macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path 
_no_cmake_environment_path _prefix)
+macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path 
_no_cmake_environment_path _imp_target _prefix)
   _pkgconfig_unset(${_prefix}_FOUND)
   _pkgconfig_unset(${_prefix}_VERSION)
   _pkgconfig_unset(${_prefix}_PREFIX)
@@ -383,7 +441,7 @@ macro(_pkg_check_modules_internal _is_required _is_silent 
_no_cmake_path _no_cma
         pkg_get_variable("${_pkg_check_prefix}_INCLUDEDIR" 
${_pkg_check_modules_pkg} "includedir")
         pkg_get_variable("${_pkg_check_prefix}_LIBDIR" 
${_pkg_check_modules_pkg} "libdir")
         foreach (variable IN ITEMS PREFIX INCLUDEDIR LIBDIR)
-          _pkgconfig_set("${_pkg_check_prefix}_${variable}" 
"${${_pkg_check_prefix}_${variable}}")
+          _pkgconfig_set("${_pkg_check_modules_pkg}_${variable}" 
"${${_pkg_check_modules_pkg}_${variable}}")
         endforeach ()
 
         if (NOT ${_is_silent})
@@ -400,6 +458,10 @@ macro(_pkg_check_modules_internal _is_required _is_silent 
_no_cmake_path _no_cma
       _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" 
INCLUDE_DIRS        "(^| )-I" --cflags-only-I )
       _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" 
CFLAGS              ""        --cflags )
       _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" 
CFLAGS_OTHER        ""        --cflags-only-other )
+
+      if (_imp_target)
+        _pkg_create_imp_target("${_prefix}" _no_cmake_path 
_no_cmake_environment_path)
+      endif()
     endif()
 
     if(NOT "${_extra_paths}" STREQUAL "")
@@ -427,6 +489,7 @@ endmacro()
 
     pkg_check_modules(<PREFIX> [REQUIRED] [QUIET]
                       [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH]
+                      [IMPORTED_TARGET]
                       <MODULE> [<MODULE>]*)
 
 
@@ -443,6 +506,9 @@ endmacro()
  The ``NO_CMAKE_PATH`` and ``NO_CMAKE_ENVIRONMENT_PATH`` arguments
  disable this behavior for the cache variables and the environment
  variables, respectively.
+ The ``IMPORTED_TARGET`` argument will create an imported target named
+ PkgConfig::<PREFIX>> that can be passed directly as an argument to
+ :command:`target_link_libraries`.
 
  It sets the following variables: ::
 
@@ -524,8 +590,8 @@ endmacro()
 macro(pkg_check_modules _prefix _module0)
   # check cached value
   if (NOT DEFINED __pkg_config_checked_${_prefix} OR 
__pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION} OR NOT 
${_prefix}_FOUND)
-    _pkgconfig_parse_options   (_pkg_modules _pkg_is_required _pkg_is_silent 
_no_cmake_path _no_cmake_environment_path "${_module0}" ${ARGN})
-    _pkg_check_modules_internal("${_pkg_is_required}" "${_pkg_is_silent}" 
${_no_cmake_path} ${_no_cmake_environment_path} "${_prefix}" ${_pkg_modules})
+    _pkgconfig_parse_options   (_pkg_modules _pkg_is_required _pkg_is_silent 
_no_cmake_path _no_cmake_environment_path _imp_target "${_module0}" ${ARGN})
+    _pkg_check_modules_internal("${_pkg_is_required}" "${_pkg_is_silent}" 
${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} "${_prefix}" 
${_pkg_modules})
 
     _pkgconfig_set(__pkg_config_checked_${_prefix} ${PKG_CONFIG_VERSION})
   endif()
@@ -540,6 +606,7 @@ endmacro()
 
     pkg_search_module(<PREFIX> [REQUIRED] [QUIET]
                       [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH]
+                      [IMPORTED_TARGET]
                       <MODULE> [<MODULE>]*)
 
  Examples
@@ -552,7 +619,7 @@ macro(pkg_search_module _prefix _module0)
   # check cached value
   if (NOT DEFINED __pkg_config_checked_${_prefix} OR 
__pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION} OR NOT 
${_prefix}_FOUND)
     set(_pkg_modules_found 0)
-    _pkgconfig_parse_options(_pkg_modules_alt _pkg_is_required _pkg_is_silent 
_no_cmake_path _no_cmake_environment_path "${_module0}" ${ARGN})
+    _pkgconfig_parse_options(_pkg_modules_alt _pkg_is_required _pkg_is_silent 
_no_cmake_path _no_cmake_environment_path _imp_target "${_module0}" ${ARGN})
 
     if (NOT ${_pkg_is_silent})
       message(STATUS "Checking for one of the modules '${_pkg_modules_alt}'")
@@ -561,7 +628,7 @@ macro(pkg_search_module _prefix _module0)
     # iterate through all modules and stop at the first working one.
     foreach(_pkg_alt ${_pkg_modules_alt})
       if(NOT _pkg_modules_found)
-        _pkg_check_modules_internal(0 1 ${_no_cmake_path} 
${_no_cmake_environment_path} "${_prefix}" "${_pkg_alt}")
+        _pkg_check_modules_internal(0 1 ${_no_cmake_path} 
${_no_cmake_environment_path} ${_imp_target} "${_prefix}" "${_pkg_alt}")
       endif()
 
       if (${_prefix}_FOUND)
-- 
1.8.4.5

Attachment: signature.asc
Description: This is a digitally signed message part.

-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers

Reply via email to