Browse Source

Merge topic 'FindPkgConfig_Extend-PKG_CONFIG_PATH'

3df51470 FindPkgConfig: Extend PKG_CONFIG_PATH using CMake variables (#12926)
Brad King 11 years ago
parent
commit
41b82db685

+ 150 - 8
Modules/FindPkgConfig.cmake

@@ -99,9 +99,20 @@ 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)
+macro(_pkgconfig_parse_options _result _is_req _is_silent _no_cmake_path _no_cmake_environment_path)
   set(${_is_req} 0)
   set(${_is_silent} 0)
+  set(${_no_cmake_path} 0)
+  set(${_no_cmake_environment_path} 0)
+  if(DEFINED PKG_CONFIG_USE_CMAKE_PREFIX_PATH)
+    if(NOT PKG_CONFIG_USE_CMAKE_PREFIX_PATH)
+      set(${_no_cmake_path} 1)
+      set(${_no_cmake_environment_path} 1)
+    endif()
+  elseif(${CMAKE_MINIMUM_REQUIRED_VERSION} VERSION_LESS 3.1)
+    set(${_no_cmake_path} 1)
+    set(${_no_cmake_environment_path} 1)
+  endif()
 
   foreach(_pkg ${ARGN})
     if (_pkg STREQUAL "REQUIRED")
@@ -110,15 +121,23 @@ macro(_pkgconfig_parse_options _result _is_req _is_silent)
     if (_pkg STREQUAL "QUIET")
       set(${_is_silent} 1)
     endif ()
+    if (_pkg STREQUAL "NO_CMAKE_PATH")
+      set(${_no_cmake_path} 1)
+    endif()
+    if (_pkg STREQUAL "NO_CMAKE_ENVIRONMENT_PATH")
+      set(${_no_cmake_environment_path} 1)
+    endif()
   endforeach()
 
   set(${_result} ${ARGN})
   list(REMOVE_ITEM ${_result} "REQUIRED")
   list(REMOVE_ITEM ${_result} "QUIET")
+  list(REMOVE_ITEM ${_result} "NO_CMAKE_PATH")
+  list(REMOVE_ITEM ${_result} "NO_CMAKE_ENVIRONMENT_PATH")
 endmacro()
 
 ###
-macro(_pkg_check_modules_internal _is_required _is_silent _prefix)
+macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cmake_environment_path _prefix)
   _pkgconfig_unset(${_prefix}_FOUND)
   _pkgconfig_unset(${_prefix}_VERSION)
   _pkgconfig_unset(${_prefix}_PREFIX)
@@ -157,6 +176,95 @@ macro(_pkg_check_modules_internal _is_required _is_silent _prefix)
     set(_pkg_check_modules_packages)
     set(_pkg_check_modules_failed)
 
+    set(_extra_paths)
+
+    if(NOT _no_cmake_path)
+      if(NOT "${CMAKE_PREFIX_PATH}" STREQUAL "")
+        list(APPEND _extra_paths ${CMAKE_PREFIX_PATH})
+      endif()
+      if(NOT "${CMAKE_FRAMEWORK_PATH}" STREQUAL "")
+        list(APPEND _extra_paths ${CMAKE_FRAMEWORK_PATH})
+      endif()
+      if(NOT "${CMAKE_APPBUNDLE_PATH}" STREQUAL "")
+        list(APPEND _extra_paths ${CMAKE_FRAMEWORK_PATH})
+      endif()
+    endif()
+
+    if(NOT _no_cmake_environment_path)
+      if(NOT "$ENV{CMAKE_PREFIX_PATH}" STREQUAL "")
+        file(TO_CMAKE_PATH "$ENV{CMAKE_PREFIX_PATH}" _path)
+        list(APPEND _extra_paths ${_path})
+        unset(_path)
+      endif()
+      if(NOT "$ENV{CMAKE_FRAMEWORK_PATH}" STREQUAL "")
+        file(TO_CMAKE_PATH "$ENV{CMAKE_FRAMEWORK_PATH}" _path)
+        list(APPEND _extra_paths ${_path})
+        unset(_path)
+      endif()
+      if(NOT "$ENV{CMAKE_APPBUNDLE_PATH}" STREQUAL "")
+        file(TO_CMAKE_PATH "$ENV{CMAKE_APPBUNDLE_PATH}" _path)
+        list(APPEND _extra_paths ${_path})
+        unset(_path)
+      endif()
+    endif()
+
+    if(NOT "${_extra_paths}" STREQUAL "")
+      # Save the PKG_CONFIG_PATH environment variable, and add paths
+      # from the CMAKE_PREFIX_PATH variables
+      set(_pkgconfig_path_old $ENV{PKG_CONFIG_PATH})
+      set(_pkgconfig_path ${_pkgconfig_path_old})
+      if(NOT "${_pkgconfig_path}" STREQUAL "")
+        file(TO_CMAKE_PATH "${_pkgconfig_path}" _pkgconfig_path)
+      endif()
+
+      # Create a list of the possible pkgconfig subfolder (depending on
+      # the system
+      set(_lib_dirs)
+      if(NOT DEFINED CMAKE_SYSTEM_NAME
+          OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
+              AND NOT CMAKE_CROSSCOMPILING))
+        if(EXISTS "/etc/debian_version") # is this a debian system ?
+          if(CMAKE_LIBRARY_ARCHITECTURE)
+            list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig")
+          endif()
+        else()
+          # not debian, chech the FIND_LIBRARY_USE_LIB64_PATHS property
+          get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
+          if(uselib64)
+            list(APPEND _lib_dirs "lib64/pkgconfig")
+          endif()
+        endif()
+      endif()
+      list(APPEND _lib_dirs "lib/pkgconfig")
+
+      # Check if directories exist and eventually append them to the
+      # pkgconfig path list
+      foreach(_prefix_dir ${_extra_paths})
+        foreach(_lib_dir ${_lib_dirs})
+          if(EXISTS "${_prefix_dir}/${_lib_dir}")
+            list(APPEND _pkgconfig_path "${_prefix_dir}/${_lib_dir}")
+            list(REMOVE_DUPLICATES _pkgconfig_path)
+          endif()
+        endforeach()
+      endforeach()
+
+      # Prepare and set the environment variable
+      if(NOT "${_pkgconfig_path}" STREQUAL "")
+        # remove empty values from the list
+        list(REMOVE_ITEM _pkgconfig_path "")
+        file(TO_NATIVE_PATH "${_pkgconfig_path}" _pkgconfig_path)
+        if(UNIX)
+          string(REPLACE ";" ":" _pkgconfig_path "${_pkgconfig_path}")
+          string(REPLACE "\\ " " " _pkgconfig_path "${_pkgconfig_path}")
+        endif()
+        set(ENV{PKG_CONFIG_PATH} ${_pkgconfig_path})
+      endif()
+
+      # Unset variables
+      unset(_lib_dirs)
+      unset(_pkgconfig_path)
+    endif()
+
     # iterate through module list and check whether they exist and match the required version
     foreach (_pkg_check_modules_pkg ${_pkg_check_modules_list})
       set(_pkg_check_modules_exist_query)
@@ -260,6 +368,14 @@ macro(_pkg_check_modules_internal _is_required _is_silent _prefix)
       _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" CFLAGS              ""        --cflags )
       _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" CFLAGS_OTHER        ""        --cflags-only-other )
     endif()
+
+    if(NOT "${_extra_paths}" STREQUAL "")
+      # Restore the environment variable
+      set(ENV{PKG_CONFIG_PATH} ${_pkgconfig_path})
+    endif()
+
+    unset(_extra_paths)
+    unset(_pkgconfig_path_old)
   else()
     if (${_is_required})
       message(SEND_ERROR "pkg-config tool not found")
@@ -276,13 +392,25 @@ endmacro()
 
  Checks for all the given modules. ::
 
-    pkg_check_modules(<PREFIX> [REQUIRED] [QUIET] <MODULE> [<MODULE>]*)
+    pkg_check_modules(<PREFIX> [REQUIRED] [QUIET]
+                      [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH]
+                      <MODULE> [<MODULE>]*)
+
 
  When the ``REQUIRED`` argument was set, macros will fail with an error
  when module(s) could not be found.
 
  When the ``QUIET`` argument is set, no status messages will be printed.
 
+ By default, if :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` is 3.1 or
+ later, or if :variable:`PKG_CONFIG_USE_CMAKE_PREFIX_PATH` is set, the
+ :variable:`CMAKE_PREFIX_PATH`, :variable:`CMAKE_FRAMEWORK_PATH`, and
+ :variable:`CMAKE_APPBUNDLE_PATH` cache and environment variables will
+ be added to ``pkg-config`` search path.
+ The ``NO_CMAKE_PATH`` and ``NO_CMAKE_ENVIRONMENT_PATH`` arguments
+ disable this behavior for the cache variables and the environment
+ variables, respectively.
+
  It sets the following variables: ::
 
     PKG_CONFIG_FOUND          ... if pkg-config executable was found
@@ -362,8 +490,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 "${_module0}" ${ARGN})
-    _pkg_check_modules_internal("${_pkg_is_required}" "${_pkg_is_silent}" "${_prefix}" ${_pkg_modules})
+    _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_set(__pkg_config_checked_${_prefix} ${PKG_CONFIG_VERSION})
   endif()
@@ -376,7 +504,9 @@ endmacro()
  Same as :command:`pkg_check_modules`, but instead it checks for given
  modules and uses the first working one. ::
 
-    pkg_search_module(<PREFIX> [REQUIRED] [QUIET] <MODULE> [<MODULE>]*)
+    pkg_search_module(<PREFIX> [REQUIRED] [QUIET]
+                      [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH]
+                      <MODULE> [<MODULE>]*)
 
  Examples
 
@@ -388,7 +518,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 "${_module0}" ${ARGN})
+    _pkgconfig_parse_options(_pkg_modules_alt _pkg_is_required _pkg_is_silent _no_cmake_path _no_cmake_environment_path "${_module0}" ${ARGN})
 
     if (NOT ${_pkg_is_silent})
       message(STATUS "checking for one of the modules '${_pkg_modules_alt}'")
@@ -397,7 +527,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 "${_prefix}" "${_pkg_alt}")
+        _pkg_check_modules_internal(0 1 ${_no_cmake_path} ${_no_cmake_environment_path} "${_prefix}" "${_pkg_alt}")
       endif()
 
       if (${_prefix}_FOUND)
@@ -420,6 +550,18 @@ endmacro()
 .. variable:: PKG_CONFIG_EXECUTABLE
 
  Path to the pkg-config executable.
+
+
+.. variable:: PKG_CONFIG_USE_CMAKE_PREFIX_PATH
+
+ Whether :command:`pkg_check_modules` and :command:`pkg_search_module`
+ should add the paths in :variable:`CMAKE_PREFIX_PATH`,
+ :variable:`CMAKE_FRAMEWORK_PATH`, and :variable:`CMAKE_APPBUNDLE_PATH`
+ cache and environment variables to ``pkg-config`` search path.
+
+ If this variable is not set, this behavior is enabled by default if
+ :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` is 3.1 or later, disabled
+ otherwise.
 #]========================================]
 
 

+ 5 - 0
Tests/RunCMake/CMakeLists.txt

@@ -107,6 +107,11 @@ if (QT4_FOUND)
   add_RunCMake_test(ObsoleteQtMacros)
 endif()
 
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+  add_RunCMake_test(FindPkgConfig)
+endif()
+
 if("${CMAKE_GENERATOR}" MATCHES "Visual Studio [^6]")
   add_RunCMake_test(include_external_msproject)
   add_RunCMake_test(SolutionGlobalSections)

+ 3 - 0
Tests/RunCMake/FindPkgConfig/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.11)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 51 - 0
Tests/RunCMake/FindPkgConfig/FindPkgConfig_PKGCONFIG_PATH.cmake

@@ -0,0 +1,51 @@
+# Needed for CMAKE_SYSTEM_NAME, CMAKE_LIBRARY_ARCHITECTURE and FIND_LIBRARY_USE_LIB64_PATHS
+enable_language(C)
+
+# Prepare environment and variables
+set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH TRUE)
+set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/pc-foo")
+if(WIN32)
+    set(PKG_CONFIG_EXECUTABLE "${CMAKE_CURRENT_SOURCE_DIR}\\dummy-pkg-config.bat")
+    set(ENV{CMAKE_PREFIX_PATH} "${CMAKE_CURRENT_SOURCE_DIR}\\pc-bar;X:\\this\\directory\\should\\not\\exist\\in\\the\\filesystem")
+    set(ENV{PKG_CONFIG_PATH} "C:\\baz")
+else()
+    set(PKG_CONFIG_EXECUTABLE "${CMAKE_CURRENT_SOURCE_DIR}/dummy-pkg-config.sh")
+    set(ENV{CMAKE_PREFIX_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/pc-bar:/this/directory/should/not/exist/in/the/filesystem")
+    set(ENV{PKG_CONFIG_PATH} "/baz")
+endif()
+
+
+find_package(PkgConfig)
+
+
+if(NOT DEFINED CMAKE_SYSTEM_NAME
+    OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
+    AND NOT CMAKE_CROSSCOMPILING))
+  if(EXISTS "/etc/debian_version") # is this a debian system ?
+    if(CMAKE_LIBRARY_ARCHITECTURE MATCHES "^(i386-linux-gnu|x86_64-linux-gnu)$")
+      # Cannot create directories for all the existing architectures...
+      set(expected_path "/baz:${CMAKE_CURRENT_SOURCE_DIR}/pc-foo/lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig:${CMAKE_CURRENT_SOURCE_DIR}/pc-foo/lib/pkgconfig:${CMAKE_CURRENT_SOURCE_DIR}/pc-bar/lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig:${CMAKE_CURRENT_SOURCE_DIR}/pc-bar/lib/pkgconfig")
+    else()
+      set(expected_path "/baz:${CMAKE_CURRENT_SOURCE_DIR}/pc-foo/lib/pkgconfig:${CMAKE_CURRENT_SOURCE_DIR}/pc-bar/lib/pkgconfig")
+    endif()
+  else()
+    # not debian, chech the FIND_LIBRARY_USE_LIB64_PATHS property
+    get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
+    if(uselib64)
+      set(expected_path "/baz:${CMAKE_CURRENT_SOURCE_DIR}/pc-foo/lib64/pkgconfig:${CMAKE_CURRENT_SOURCE_DIR}/pc-foo/lib/pkgconfig:${CMAKE_CURRENT_SOURCE_DIR}/pc-bar/lib64/pkgconfig:${CMAKE_CURRENT_SOURCE_DIR}/pc-bar/lib/pkgconfig")
+    endif()
+  endif()
+else()
+  if(WIN32)
+    set(expected_path "C:\\baz;${CMAKE_CURRENT_SOURCE_DIR}\\pc-foo\\lib\\pkgconfig;${CMAKE_CURRENT_SOURCE_DIR}\\pc-bar\\lib\\pkgconfig")
+  else()
+    set(expected_path "/baz:${CMAKE_CURRENT_SOURCE_DIR}/pc-foo/lib/pkgconfig:${CMAKE_CURRENT_SOURCE_DIR}/pc-bar/lib/pkgconfig")
+  endif()
+endif()
+
+
+pkg_check_modules (FOO "${expected_path}")
+
+if(NOT "FOO_FOUND")
+  message(FATAL_ERROR "Expected PKG_CONFIG_PATH: \"${expected_path}\".")
+endif()

+ 3 - 0
Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake

@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(FindPkgConfig_PKGCONFIG_PATH)

+ 16 - 0
Tests/RunCMake/FindPkgConfig/dummy-pkg-config.bat

@@ -0,0 +1,16 @@
+@ECHO OFF
+IF "%1"=="" (
+  EXIT /B 255
+)
+IF "%1"=="--version" (
+  ECHO 0.0-cmake-dummy
+  EXIT /B 0
+)
+
+IF "%1"=="--exists" (
+  SHIFT
+  IF NOT "%*"=="%PKG_CONFIG_PATH%" (
+    EXIT /B 1
+  )
+)
+EXIT /B 0

+ 20 - 0
Tests/RunCMake/FindPkgConfig/dummy-pkg-config.sh

@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# This is a replacement for pkg-config that compares the string passed
+# to the --exists argument with the PKG_CONFIG_PATH environment variable
+# and returns 1 if they are different.
+
+case $1 in
+  --version)
+    echo "0.0-cmake-dummy"
+    ;;
+  --exists)
+    shift
+    echo "$@"
+    echo "${PKG_CONFIG_PATH}"
+    [ "$@" = "${PKG_CONFIG_PATH}" ] || exit 1
+    ;;
+  *)
+    exit 255
+    ;;
+esac

+ 0 - 0
Tests/RunCMake/FindPkgConfig/pc-bar/lib/i386-linux-gnu/pkgconfig/.placeholder


+ 0 - 0
Tests/RunCMake/FindPkgConfig/pc-bar/lib/pkgconfig/.placeholder


+ 0 - 0
Tests/RunCMake/FindPkgConfig/pc-bar/lib/x86_64-linux-gnu/pkgconfig/.placeholder


+ 0 - 0
Tests/RunCMake/FindPkgConfig/pc-bar/lib64/pkgconfig/.placeholder


+ 0 - 0
Tests/RunCMake/FindPkgConfig/pc-foo/lib/i386-linux-gnu/pkgconfig/.placeholder


+ 0 - 0
Tests/RunCMake/FindPkgConfig/pc-foo/lib/pkgconfig/.placeholder


+ 0 - 0
Tests/RunCMake/FindPkgConfig/pc-foo/lib/x86_64-linux-gnu/pkgconfig/.placeholder


+ 0 - 0
Tests/RunCMake/FindPkgConfig/pc-foo/lib64/pkgconfig/.placeholder