Add support for glog exported CMake target.

- The latest version of glog supports building with CMake, in which case
  it exports itself via CMake as a target that contains important meta
  information such as Windows-specific compilation definitions.
- This patch updates FindGlog.cmake such that it can optionally use
  an exported glog target if one exists, if not it will fall back to
  the current approach whereby the glog components are found manually.
  This behaviour (and the implementation) is very similar to that of
  FindGflags.cmake.

Change-Id: Idfb5f49c1b457707029bff52068f58237c0e285d
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ed1425a..97a1726 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -380,13 +380,12 @@
   # Don't search with REQUIRED so that configuration continues if not found and
   # we can output an error messages explaining MINIGLOG option.
   find_package(Glog)
-  if (GLOG_FOUND)
-    message("-- Found Google Log header in: ${GLOG_INCLUDE_DIRS}")
-  else (GLOG_FOUND)
-    message(FATAL_ERROR "Can't find Google Log. Please set GLOG_INCLUDE_DIR & "
+  if (NOT GLOG_FOUND)
+    message(FATAL_ERROR "Can't find Google Log (glog). Please set either: "
+      "glog_DIR (newer CMake built versions of glog) or GLOG_INCLUDE_DIR & "
       "GLOG_LIBRARY or enable MINIGLOG option to use minimal glog "
       "implementation.")
-  endif (GLOG_FOUND)
+  endif(NOT GLOG_FOUND)
 endif (MINIGLOG)
 
 if (NOT SCHUR_SPECIALIZATIONS)
diff --git a/cmake/FindGlog.cmake b/cmake/FindGlog.cmake
index 3057b31..3a6f796 100644
--- a/cmake/FindGlog.cmake
+++ b/cmake/FindGlog.cmake
@@ -39,6 +39,16 @@
 #
 # The following variables control the behaviour of this module:
 #
+# GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION: TRUE/FALSE, iff TRUE then
+#                           then prefer using an exported CMake configuration
+#                           generated by glog > 0.3.4 over searching for the
+#                           glog components manually.  Otherwise (FALSE)
+#                           ignore any exported glog CMake configurations and
+#                           always perform a manual search for the components.
+#                           Default: TRUE iff user does not define this variable
+#                           before we are called, and does NOT specify either
+#                           GLOG_INCLUDE_DIR_HINTS or GLOG_LIBRARY_DIR_HINTS
+#                           otherwise FALSE.
 # GLOG_INCLUDE_DIR_HINTS: List of additional directories in which to
 #                         search for glog includes, e.g: /timbuktu/include.
 # GLOG_LIBRARY_DIR_HINTS: List of additional directories in which to
@@ -63,9 +73,9 @@
 # Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
 # FindGlog was invoked.
 macro(GLOG_RESET_FIND_LIBRARY_PREFIX)
-  if (MSVC)
+  if (MSVC AND CALLERS_CMAKE_FIND_LIBRARY_PREFIXES)
     set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
-  endif (MSVC)
+  endif()
 endmacro(GLOG_RESET_FIND_LIBRARY_PREFIX)
 
 # Called if we failed to find glog or any of it's required dependencies,
@@ -96,98 +106,188 @@
   return()
 endmacro(GLOG_REPORT_NOT_FOUND)
 
-# Handle possible presence of lib prefix for libraries on MSVC, see
-# also GLOG_RESET_FIND_LIBRARY_PREFIX().
-if (MSVC)
-  # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
-  # s/t we can set it back before returning.
-  set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
-  # The empty string in this list is important, it represents the case when
-  # the libraries have no prefix (shared libraries / DLLs).
-  set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
-endif (MSVC)
+# -----------------------------------------------------------------
+# By default, if the user has expressed no preference for using an exported
+# glog CMake configuration over performing a search for the installed
+# components, and has not specified any hints for the search locations, then
+# prefer a glog exported configuration if available.
+if (NOT DEFINED GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION
+    AND NOT GLOG_INCLUDE_DIR_HINTS
+    AND NOT GLOG_LIBRARY_DIR_HINTS)
+  message(STATUS "No preference for use of exported glog CMake configuration "
+    "set, and no hints for include/library directories provided. "
+    "Defaulting to preferring an installed/exported glog CMake configuration "
+    "if available.")
+  set(GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION TRUE)
+endif()
 
-# Search user-installed locations first, so that we prefer user installs
-# to system installs where both exist.
-list(APPEND GLOG_CHECK_INCLUDE_DIRS
-  /usr/local/include
-  /usr/local/homebrew/include # Mac OS X
-  /opt/local/var/macports/software # Mac OS X.
-  /opt/local/include
-  /usr/include)
-# Windows (for C:/Program Files prefix).
-list(APPEND GLOG_CHECK_PATH_SUFFIXES
-  glog/include
-  glog/Include
-  Glog/include
-  Glog/Include)
+if (GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION)
+  # Try to find an exported CMake configuration for glog, as generated by
+  # glog versions > 0.3.4
+  #
+  # We search twice, s/t we can invert the ordering of precedence used by
+  # find_package() for exported package build directories, and installed
+  # packages (found via CMAKE_SYSTEM_PREFIX_PATH), listed as items 6) and 7)
+  # respectively in [1].
+  #
+  # By default, exported build directories are (in theory) detected first, and
+  # this is usually the case on Windows.  However, on OS X & Linux, the install
+  # path (/usr/local) is typically present in the PATH environment variable
+  # which is checked in item 4) in [1] (i.e. before both of the above, unless
+  # NO_SYSTEM_ENVIRONMENT_PATH is passed).  As such on those OSs installed
+  # packages are usually detected in preference to exported package build
+  # directories.
+  #
+  # To ensure a more consistent response across all OSs, and as users usually
+  # want to prefer an installed version of a package over a locally built one
+  # where both exist (esp. as the exported build directory might be removed
+  # after installation), we first search with NO_CMAKE_PACKAGE_REGISTRY which
+  # means any build directories exported by the user are ignored, and thus
+  # installed directories are preferred.  If this fails to find the package
+  # we then research again, but without NO_CMAKE_PACKAGE_REGISTRY, so any
+  # exported build directories will now be detected.
+  #
+  # To prevent confusion on Windows, we also pass NO_CMAKE_BUILDS_PATH (which
+  # is item 5) in [1]), to not preferentially use projects that were built
+  # recently with the CMake GUI to ensure that we always prefer an installed
+  # version if available.
+  #
+  # [1] http://www.cmake.org/cmake/help/v2.8.11/cmake.html#command:find_package
+  find_package(glog QUIET
+                    NO_MODULE
+                    NO_CMAKE_PACKAGE_REGISTRY
+                    NO_CMAKE_BUILDS_PATH)
+  if (glog_FOUND)
+    message(STATUS "Found installed version of glog: ${glog_DIR}")
+  else()
+    # Failed to find an installed version of glog, repeat search allowing
+    # exported build directories.
+    message(STATUS "Failed to find installed glog CMake configuration, "
+      "searching for glog build directories exported with CMake.")
+    # Again pass NO_CMAKE_BUILDS_PATH, as we know that glog is exported and
+    # do not want to treat projects built with the CMake GUI preferentially.
+    find_package(glog QUIET
+                      NO_MODULE
+                      NO_CMAKE_BUILDS_PATH)
+    if (glog_FOUND)
+      message(STATUS "Found exported glog build directory: ${glog_DIR}")
+    endif(glog_FOUND)
+  endif(glog_FOUND)
 
-list(APPEND GLOG_CHECK_LIBRARY_DIRS
-  /usr/local/lib
-  /usr/local/homebrew/lib # Mac OS X.
-  /opt/local/lib
-  /usr/lib)
-# Windows (for C:/Program Files prefix).
-list(APPEND GLOG_CHECK_LIBRARY_SUFFIXES
-  glog/lib
-  glog/Lib
-  Glog/lib
-  Glog/Lib)
+  set(FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION ${glog_FOUND})
 
-# Search supplied hint directories first if supplied.
-find_path(GLOG_INCLUDE_DIR
-  NAMES glog/logging.h
-  PATHS ${GLOG_INCLUDE_DIR_HINTS}
-  ${GLOG_CHECK_INCLUDE_DIRS}
-  PATH_SUFFIXES ${GLOG_CHECK_PATH_SUFFIXES})
-if (NOT GLOG_INCLUDE_DIR OR
+  if (FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
+    message(STATUS "Detected glog version: ${glog_VERSION}")
+    set(GLOG_FOUND ${glog_FOUND})
+    # glog wraps the include directories into the exported glog::glog target.
+    set(GLOG_INCLUDE_DIR "")
+    set(GLOG_LIBRARY glog::glog)
+  else (FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
+    message(STATUS "Failed to find an installed/exported CMake configuration "
+      "for glog, will perform search for installed glog components.")
+  endif (FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
+endif(GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION)
+
+if (NOT GLOG_FOUND)
+  # Either failed to find an exported glog CMake configuration, or user
+  # told us not to use one.  Perform a manual search for all glog components.
+
+  # Handle possible presence of lib prefix for libraries on MSVC, see
+  # also GLOG_RESET_FIND_LIBRARY_PREFIX().
+  if (MSVC)
+    # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
+    # s/t we can set it back before returning.
+    set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
+    # The empty string in this list is important, it represents the case when
+    # the libraries have no prefix (shared libraries / DLLs).
+    set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
+  endif (MSVC)
+
+  # Search user-installed locations first, so that we prefer user installs
+  # to system installs where both exist.
+  list(APPEND GLOG_CHECK_INCLUDE_DIRS
+    /usr/local/include
+    /usr/local/homebrew/include # Mac OS X
+    /opt/local/var/macports/software # Mac OS X.
+    /opt/local/include
+    /usr/include)
+  # Windows (for C:/Program Files prefix).
+  list(APPEND GLOG_CHECK_PATH_SUFFIXES
+    glog/include
+    glog/Include
+    Glog/include
+    Glog/Include)
+
+  list(APPEND GLOG_CHECK_LIBRARY_DIRS
+    /usr/local/lib
+    /usr/local/homebrew/lib # Mac OS X.
+    /opt/local/lib
+    /usr/lib)
+  # Windows (for C:/Program Files prefix).
+  list(APPEND GLOG_CHECK_LIBRARY_SUFFIXES
+    glog/lib
+    glog/Lib
+    Glog/lib
+    Glog/Lib)
+
+  # Search supplied hint directories first if supplied.
+  find_path(GLOG_INCLUDE_DIR
+    NAMES glog/logging.h
+    PATHS ${GLOG_INCLUDE_DIR_HINTS}
+    ${GLOG_CHECK_INCLUDE_DIRS}
+    PATH_SUFFIXES ${GLOG_CHECK_PATH_SUFFIXES})
+  if (NOT GLOG_INCLUDE_DIR OR
+      NOT EXISTS ${GLOG_INCLUDE_DIR})
+    glog_report_not_found(
+      "Could not find glog include directory, set GLOG_INCLUDE_DIR "
+      "to directory containing glog/logging.h")
+  endif (NOT GLOG_INCLUDE_DIR OR
     NOT EXISTS ${GLOG_INCLUDE_DIR})
-  glog_report_not_found(
-    "Could not find glog include directory, set GLOG_INCLUDE_DIR "
-    "to directory containing glog/logging.h")
-endif (NOT GLOG_INCLUDE_DIR OR
-       NOT EXISTS ${GLOG_INCLUDE_DIR})
 
-find_library(GLOG_LIBRARY NAMES glog
-  PATHS ${GLOG_LIBRARY_DIR_HINTS}
-  ${GLOG_CHECK_LIBRARY_DIRS}
-  PATH_SUFFIXES ${GLOG_CHECK_LIBRARY_SUFFIXES})
-if (NOT GLOG_LIBRARY OR
+  find_library(GLOG_LIBRARY NAMES glog
+    PATHS ${GLOG_LIBRARY_DIR_HINTS}
+    ${GLOG_CHECK_LIBRARY_DIRS}
+    PATH_SUFFIXES ${GLOG_CHECK_LIBRARY_SUFFIXES})
+  if (NOT GLOG_LIBRARY OR
+      NOT EXISTS ${GLOG_LIBRARY})
+    glog_report_not_found(
+      "Could not find glog library, set GLOG_LIBRARY "
+      "to full path to libglog.")
+  endif (NOT GLOG_LIBRARY OR
     NOT EXISTS ${GLOG_LIBRARY})
-  glog_report_not_found(
-    "Could not find glog library, set GLOG_LIBRARY "
-    "to full path to libglog.")
-endif (NOT GLOG_LIBRARY OR
-       NOT EXISTS ${GLOG_LIBRARY})
 
-# Mark internally as found, then verify. GLOG_REPORT_NOT_FOUND() unsets
-# if called.
-set(GLOG_FOUND TRUE)
+  # Mark internally as found, then verify. GLOG_REPORT_NOT_FOUND() unsets
+  # if called.
+  set(GLOG_FOUND TRUE)
 
-# Glog does not seem to provide any record of the version in its
-# source tree, thus cannot extract version.
+  # Glog does not seem to provide any record of the version in its
+  # source tree, thus cannot extract version.
 
-# Catch case when caller has set GLOG_INCLUDE_DIR in the cache / GUI and
-# thus FIND_[PATH/LIBRARY] are not called, but specified locations are
-# invalid, otherwise we would report the library as found.
-if (GLOG_INCLUDE_DIR AND
+  # Catch case when caller has set GLOG_INCLUDE_DIR in the cache / GUI and
+  # thus FIND_[PATH/LIBRARY] are not called, but specified locations are
+  # invalid, otherwise we would report the library as found.
+  if (GLOG_INCLUDE_DIR AND
+      NOT EXISTS ${GLOG_INCLUDE_DIR}/glog/logging.h)
+    glog_report_not_found(
+      "Caller defined GLOG_INCLUDE_DIR:"
+      " ${GLOG_INCLUDE_DIR} does not contain glog/logging.h header.")
+  endif (GLOG_INCLUDE_DIR AND
     NOT EXISTS ${GLOG_INCLUDE_DIR}/glog/logging.h)
-  glog_report_not_found(
-    "Caller defined GLOG_INCLUDE_DIR:"
-    " ${GLOG_INCLUDE_DIR} does not contain glog/logging.h header.")
-endif (GLOG_INCLUDE_DIR AND
-       NOT EXISTS ${GLOG_INCLUDE_DIR}/glog/logging.h)
-# TODO: This regex for glog library is pretty primitive, we use lowercase
-#       for comparison to handle Windows using CamelCase library names, could
-#       this check be better?
-string(TOLOWER "${GLOG_LIBRARY}" LOWERCASE_GLOG_LIBRARY)
-if (GLOG_LIBRARY AND
+  # TODO: This regex for glog library is pretty primitive, we use lowercase
+  #       for comparison to handle Windows using CamelCase library names, could
+  #       this check be better?
+  string(TOLOWER "${GLOG_LIBRARY}" LOWERCASE_GLOG_LIBRARY)
+  if (GLOG_LIBRARY AND
+      NOT "${LOWERCASE_GLOG_LIBRARY}" MATCHES ".*glog[^/]*")
+    glog_report_not_found(
+      "Caller defined GLOG_LIBRARY: "
+      "${GLOG_LIBRARY} does not match glog.")
+  endif (GLOG_LIBRARY AND
     NOT "${LOWERCASE_GLOG_LIBRARY}" MATCHES ".*glog[^/]*")
-  glog_report_not_found(
-    "Caller defined GLOG_LIBRARY: "
-    "${GLOG_LIBRARY} does not match glog.")
-endif (GLOG_LIBRARY AND
-       NOT "${LOWERCASE_GLOG_LIBRARY}" MATCHES ".*glog[^/]*")
+
+  glog_reset_find_library_prefix()
+
+endif(NOT GLOG_FOUND)
 
 # Set standard CMake FindPackage variables if found.
 if (GLOG_FOUND)
@@ -195,16 +295,25 @@
   set(GLOG_LIBRARIES ${GLOG_LIBRARY})
 endif (GLOG_FOUND)
 
-glog_reset_find_library_prefix()
+# If we are using an exported CMake glog target, the include directories are
+# wrapped into the target itself, and do not have to be (and are not)
+# separately specified.  In which case, we should not add GLOG_INCLUDE_DIRS
+# to the list of required variables in order that glog be reported as found.
+if (FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
+  set(GLOG_REQUIRED_VARIABLES GLOG_LIBRARIES)
+else()
+  set(GLOG_REQUIRED_VARIABLES GLOG_INCLUDE_DIRS GLOG_LIBRARIES)
+endif()
 
 # Handle REQUIRED / QUIET optional arguments.
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Glog DEFAULT_MSG
-  GLOG_INCLUDE_DIRS GLOG_LIBRARIES)
+  ${GLOG_REQUIRED_VARIABLES})
 
 # Only mark internal variables as advanced if we found glog, otherwise
 # leave them visible in the standard GUI for the user to set manually.
 if (GLOG_FOUND)
   mark_as_advanced(FORCE GLOG_INCLUDE_DIR
-                         GLOG_LIBRARY)
+                         GLOG_LIBRARY
+                         glog_DIR) # Autogenerated by find_package(glog)
 endif (GLOG_FOUND)