Commit 0c8ff50fe5446c1e5f2c0bbfdd49881d45fb8253

Patrick Steinhardt 2018-04-27T10:38:49

cmake: resolve libraries found by pkg-config Libraries found by CMake modules are usually handled with their full path. This makes linking against those libraries a lot more robust when it comes to libraries in non-standard locations, as otherwise we might mix up libraries from different locations when link directories are given. One excemption are libraries found by PKG_CHECK_MODULES. Instead of returning libraries with their complete path, it will return the variable names as well as a set of link directories. In case where multiple sets of the same library are installed in different locations, this can lead the compiler to link against the wrong libraries in the end, when link directories of other dependencies are added. To fix this shortcoming, we need to manually resolve library paths returned by CMake against their respective library directories. This is an easy task to do with `FIND_LIBRARY`.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2ca5354..7c15902 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,7 +29,7 @@ INCLUDE(CheckFunctionExists)
 INCLUDE(CheckSymbolExists)
 INCLUDE(CheckStructHasMember)
 INCLUDE(AddCFlagIfSupported)
-INCLUDE(FindPkgConfig)
+INCLUDE(FindPkgLibraries)
 INCLUDE(FindThreads)
 INCLUDE(FindStatNsec)
 INCLUDE(IdeSplitSources)
diff --git a/cmake/Modules/FindPkgLibraries.cmake b/cmake/Modules/FindPkgLibraries.cmake
new file mode 100644
index 0000000..49311c3
--- /dev/null
+++ b/cmake/Modules/FindPkgLibraries.cmake
@@ -0,0 +1,28 @@
+INCLUDE(FindPkgConfig)
+
+# This function will find and set up a pkg-config based module.
+# If a pc-file was found, it will resolve library paths to
+# absolute paths. Furthermore, the function will automatically
+# fall back to use static libraries in case no dynamic libraries
+# were found.
+FUNCTION(FIND_PKGLIBRARIES prefix package)
+	PKG_CHECK_MODULES(${prefix} ${package})
+	IF(NOT ${prefix}_FOUND)
+		RETURN()
+	ENDIF()
+
+	FOREACH(LIBRARY ${${prefix}_LIBRARIES})
+		FIND_LIBRARY(${LIBRARY}_RESOLVED ${LIBRARY} PATHS ${${prefix}_LIBRARY_DIRS})
+		IF(${${LIBRARY}_RESOLVED} STREQUAL "${LIBRARY}_RESOLVED-NOTFOUND")
+			MESSAGE(FATAL_ERROR "could not resolve ${LIBRARY}")
+		ENDIF()
+		LIST(APPEND RESOLVED_LIBRARIES ${${LIBRARY}_RESOLVED})
+	ENDFOREACH(LIBRARY)
+
+	SET(${prefix}_FOUND 1 PARENT_SCOPE)
+	SET(${prefix}_LIBRARIES ${RESOLVED_LIBRARIES} PARENT_SCOPE)
+	SET(${prefix}_INCLUDE_DIRS ${${prefix}_INCLUDE_DIRS} PARENT_SCOPE)
+	SET(${prefix}_LDFLAGS ${${prefix}_LDFLAGS} PARENT_SCOPE)
+
+	MESSAGE(STATUS "  Resolved libraries: ${RESOLVED_LIBRARIES}")
+ENDFUNCTION()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b03b96a..cfbf22c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -119,9 +119,8 @@ IF (WIN32 AND WINHTTP)
 	LIST(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32")
 ELSE ()
 	IF (CURL)
-		PKG_CHECK_MODULES(CURL libcurl)
+		FIND_PKGLIBRARIES(CURL libcurl)
 	ENDIF ()
-
 	IF (CURL_FOUND)
 		SET(GIT_CURL 1)
 		LIST(APPEND LIBGIT2_INCLUDES ${CURL_INCLUDE_DIRS})
@@ -282,7 +281,7 @@ ENDIF()
 
 # Optional external dependency: libssh2
 IF (USE_SSH)
-	PKG_CHECK_MODULES(LIBSSH2 libssh2)
+	FIND_PKGLIBRARIES(LIBSSH2 libssh2)
 ENDIF()
 IF (LIBSSH2_FOUND)
 	SET(GIT_SSH 1)
@@ -290,7 +289,6 @@ IF (LIBSSH2_FOUND)
 	LIST(APPEND LIBGIT2_LIBS ${LIBSSH2_LIBRARIES})
 	LIST(APPEND LIBGIT2_LIBDIRS ${LIBSSH2_LIBRARY_DIRS})
 	LIST(APPEND LIBGIT2_PC_LIBS ${LIBSSH2_LDFLAGS})
-	#SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} ${LIBSSH2_LDFLAGS}")
 
 	CHECK_LIBRARY_EXISTS("${LIBSSH2_LIBRARIES}" libssh2_userauth_publickey_frommemory "${LIBSSH2_LIBRARY_DIRS}" HAVE_LIBSSH2_MEMORY_CREDENTIALS)
 	IF (HAVE_LIBSSH2_MEMORY_CREDENTIALS)