diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake index b0ceb2b24..812bb922f 100644 --- a/Modules/FindPkgConfig.cmake +++ b/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( [REQUIRED] [QUIET] []*) + pkg_check_modules( [REQUIRED] [QUIET] + [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] + []*) + 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( [REQUIRED] [QUIET] []*) + pkg_search_module( [REQUIRED] [QUIET] + [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] + []*) 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. #]========================================] diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 499d12b38..f9d590a06 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/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) diff --git a/Tests/RunCMake/FindPkgConfig/CMakeLists.txt b/Tests/RunCMake/FindPkgConfig/CMakeLists.txt new file mode 100644 index 000000000..72abfc809 --- /dev/null +++ b/Tests/RunCMake/FindPkgConfig/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.11) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_PKGCONFIG_PATH.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_PKGCONFIG_PATH.cmake new file mode 100644 index 000000000..5f9913f79 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake new file mode 100644 index 000000000..ad77ad06e --- /dev/null +++ b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake @@ -0,0 +1,3 @@ +include(RunCMake) + +run_cmake(FindPkgConfig_PKGCONFIG_PATH) diff --git a/Tests/RunCMake/FindPkgConfig/dummy-pkg-config.bat b/Tests/RunCMake/FindPkgConfig/dummy-pkg-config.bat new file mode 100755 index 000000000..b2096edc6 --- /dev/null +++ b/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 diff --git a/Tests/RunCMake/FindPkgConfig/dummy-pkg-config.sh b/Tests/RunCMake/FindPkgConfig/dummy-pkg-config.sh new file mode 100755 index 000000000..e62bb749b --- /dev/null +++ b/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 diff --git a/Tests/RunCMake/FindPkgConfig/pc-bar/lib/i386-linux-gnu/pkgconfig/.placeholder b/Tests/RunCMake/FindPkgConfig/pc-bar/lib/i386-linux-gnu/pkgconfig/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/RunCMake/FindPkgConfig/pc-bar/lib/pkgconfig/.placeholder b/Tests/RunCMake/FindPkgConfig/pc-bar/lib/pkgconfig/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/RunCMake/FindPkgConfig/pc-bar/lib/x86_64-linux-gnu/pkgconfig/.placeholder b/Tests/RunCMake/FindPkgConfig/pc-bar/lib/x86_64-linux-gnu/pkgconfig/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/RunCMake/FindPkgConfig/pc-bar/lib64/pkgconfig/.placeholder b/Tests/RunCMake/FindPkgConfig/pc-bar/lib64/pkgconfig/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/RunCMake/FindPkgConfig/pc-foo/lib/i386-linux-gnu/pkgconfig/.placeholder b/Tests/RunCMake/FindPkgConfig/pc-foo/lib/i386-linux-gnu/pkgconfig/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/RunCMake/FindPkgConfig/pc-foo/lib/pkgconfig/.placeholder b/Tests/RunCMake/FindPkgConfig/pc-foo/lib/pkgconfig/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/RunCMake/FindPkgConfig/pc-foo/lib/x86_64-linux-gnu/pkgconfig/.placeholder b/Tests/RunCMake/FindPkgConfig/pc-foo/lib/x86_64-linux-gnu/pkgconfig/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/RunCMake/FindPkgConfig/pc-foo/lib64/pkgconfig/.placeholder b/Tests/RunCMake/FindPkgConfig/pc-foo/lib64/pkgconfig/.placeholder new file mode 100644 index 000000000..e69de29bb