Add thread dependency & fix namespace detection on Windows for gflags.

- Add missing gflags threading dependency.
- Also add optional gflags Shlwapi dependency on Windows.
- Add check_cxx_source_compiles() with CMAKE_BUILD_TYPE to fix
  namespace test builds on Windows with NMake generators.
- Add namespace regex on gflags.h when check_cxx_source_compiles()
  fails on Windows using Visual Studio generator.

Change-Id: I6570c566e5a29c665d621a54935c16d16bac7117
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ef881df..9b7c29a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -424,7 +424,8 @@
   # made search variables visible in GUI for user to set, but then user disables
   # GFLAGS instead of setting them.
   MARK_AS_ADVANCED(FORCE GFLAGS_INCLUDE_DIR
-                         GFLAGS_LIBRARY)
+                         GFLAGS_LIBRARY
+                         GFLAGS_NAMESPACE)
 ENDIF (GFLAGS)
 
 # MiniGLog.
diff --git a/cmake/FindGflags.cmake b/cmake/FindGflags.cmake
index 5d89bb0..99d461e 100644
--- a/cmake/FindGflags.cmake
+++ b/cmake/FindGflags.cmake
@@ -72,11 +72,16 @@
   UNSET(GFLAGS_FOUND)
   UNSET(GFLAGS_INCLUDE_DIRS)
   UNSET(GFLAGS_LIBRARIES)
-  UNSET(GFLAGS_NAMESPACE)
+  # Do not use unset, as we want to keep GFLAGS_NAMESPACE in the cache,
+  # but simply clear its value.
+  SET(GFLAGS_NAMESPACE "" CACHE STRING
+    "gflags namespace (google or gflags)" FORCE)
+
   # Make results of search visible in the CMake GUI if gflags has not
   # been found so that user does not have to toggle to advanced view.
   MARK_AS_ADVANCED(CLEAR GFLAGS_INCLUDE_DIR
-                         GFLAGS_LIBRARY)
+                         GFLAGS_LIBRARY
+                         GFLAGS_NAMESPACE)
   # Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
   # use the camelcase library name, not uppercase.
   IF (Gflags_FIND_QUIETLY)
@@ -90,6 +95,88 @@
   ENDIF ()
 ENDMACRO(GFLAGS_REPORT_NOT_FOUND)
 
+# A cut down version of CMake's check_cxx_source_compiles() macro, which
+# supports specification of the CMAKE_BUILD_TYPE with which the test should
+# be compiled (but not REGEX matching of the output).  This is important
+# on Windows, for at least the NMake generator, which otherwise chooses
+# Debug, when the gflags library will typically be compiled in Release, and
+# MSVC will then fail to build, thus making all check_cxx_source_compiles()
+# tests fail.
+#
+# As per the CMake check_cxx_source_compiles() macro, we assume the following
+# variables can be set before this is invoked:
+#
+#    CMAKE_REQUIRED_FLAGS - String of compile command line flags.
+#    CMAKE_REQUIRED_DEFINITIONS - List of macros to define (-DFOO=bar).
+#    CMAKE_REQUIRED_INCLUDES - List of include directories.
+#    CMAKE_REQUIRED_LIBRARIES - List of libraries to link.
+#
+# This macro is a derivative of the CMake check_cxx_source_compiles() macro
+# distributed under the BSD License, Copyright 2005-2009 Kitware, Inc.
+MACRO(CHECK_CXX_SOURCE_COMPILES_WITH_BUILD_TYPE
+    SOURCE BUILD_TYPE VAR)
+  # Do not rerun test if output variable has an assigned value, ie is not
+  # an empty string.
+  IF ("${VAR}" MATCHES "^${VAR}$")
+    # Verify that the BUILD_TYPE is sane.
+    IF (NOT "${BUILD_TYPE}" STREQUAL "Release" AND
+        NOT "${BUILD_TYPE}" STREQUAL "Debug" AND
+        NOT "${BUILD_TYPE}" STREQUAL "RelWithDebInfo" AND
+        NOT "${BUILD_TYPE}" STREQUAL "MinSizeRel" AND
+        NOT "${BUILD_TYPE}" STREQUAL "")
+      MESSAGE(FATAL_ERROR "Invalid BUILD_TYPE: ${BUILD_TYPE}, is not a "
+        "valid CMAKE_BUILD_TYPE option.")
+    ENDIF()
+
+    SET(MACRO_CHECK_FUNCTION_DEFINITIONS
+      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
+
+    SET(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES)
+    IF (CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES
+        LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+    ENDIF()
+
+    SET(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES)
+    IF (CMAKE_REQUIRED_INCLUDES)
+      SET(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES
+        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+    ENDIF()
+
+    FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx"
+      "${SOURCE}\n")
+
+    MESSAGE(STATUS "Performing Test ${VAR}")
+    # Pass the CMAKE_BUILD_TYPE to the CMake test project created to execute
+    # the test (main difference over CMake's check_cxx_source_compiles() macro).
+    TRY_COMPILE(${VAR}
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      ${CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES}
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+      "-DCMAKE_BUILD_TYPE:STRING=${BUILD_TYPE}"
+      "${CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES}"
+      OUTPUT_VARIABLE OUTPUT)
+
+    IF (${VAR})
+      MESSAGE(STATUS "Performing Test ${VAR} - Success")
+      SET(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "Performing C++ SOURCE FILE Test ${VAR} succeded with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${SOURCE}\n")
+    ELSE()
+      MESSAGE(STATUS "Performing Test ${VAR} - Failed")
+      SET(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "Performing C++ SOURCE FILE Test ${VAR} failed with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${SOURCE}\n")
+    ENDIF()
+  ENDIF()
+ENDMACRO()
+
 # Search user-installed locations first, so that we prefer user installs
 # to system installs where both exist.
 #
@@ -130,53 +217,156 @@
 ENDIF (NOT GFLAGS_LIBRARY OR
        NOT EXISTS ${GFLAGS_LIBRARY})
 
+# gflags typically requires a threading library (which is OS dependent), note
+# that this defines the CMAKE_THREAD_LIBS_INIT variable.  If we are able to
+# detect threads, we assume that gflags requires it.
+FIND_PACKAGE(Threads QUIET)
+SET(GFLAGS_LINK_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+# On Windows, the Shlwapi library is used by gflags if available.
+IF (MSVC)
+  INCLUDE(CheckIncludeFileCXX)
+  CHECK_INCLUDE_FILE_CXX("shlwapi.h" HAVE_SHLWAPI)
+  IF (HAVE_SHLWAPI)
+    LIST(APPEND GFLAGS_LINK_LIBRARIES shlwapi.lib)
+  ENDIF(HAVE_SHLWAPI)
+ENDIF (MSVC)
+
 # Mark internally as found, then verify. GFLAGS_REPORT_NOT_FOUND() unsets
 # if called.
 SET(GFLAGS_FOUND TRUE)
 
 # Identify what namespace gflags was built with.
-IF (GFLAGS_INCLUDE_DIR)
-  # First try the (older) google namespace.
-  INCLUDE(CheckCXXSourceCompiles)
-  # Setup include path & link library for gflags for CHECK_CXX_SOURCE_COMPILES
-  SET(CMAKE_REQUIRED_INCLUDES ${GFLAGS_INCLUDE_DIR})
-  SET(CMAKE_REQUIRED_LIBRARIES ${GFLAGS_LIBRARY})
-  CHECK_CXX_SOURCE_COMPILES(
-    "#include <gflags/gflags.h>
+IF (GFLAGS_INCLUDE_DIR AND NOT GFLAGS_NAMESPACE)
+  # To handle Windows peculiarities / CMake bugs on MSVC we try two approaches
+  # to detect the gflags namespace:
+  #
+  # 1) Try to use a custom version of check_cxx_source_compiles():
+  #    check_cxx_source_compiles_with_build_type(),
+  #    to compile a trivial program with the two choices for the gflags
+  #    namespace.
+  #
+  #    This works on all OSs except Windows.  On Windows, if using NMake
+  #    generator the previous method also works, if using Visual Studio, it does
+  #    not, because our explicit instruction regarding the CMAKE_BUILD_TYPE is
+  #    ignored by msbuild.  This breaks detection because MSVC requires that the
+  #    build type of the test project used by check_cxx_source_compiles() match
+  #    that of gflags.  However, msbuild forces the test project to use Debug,
+  #    but gflags will be built in Release.
+  #
+  # 2) [In the event 1) fails] Use regex on the gflags.h header file to try to
+  #    determine the gflags namespace.  Whilst this is less robust than 1),
+  #    it does avoid any interaction with msbuild.
+
+  # On Windows, it is required that the build type of the test app match that
+  # of gflags, as CMAKE_BUILD_TYPE may not be defined when this is called, we
+  # try each in turn.
+  LIST(APPEND TEST_BUILD_TYPES Release Debug)
+  FOREACH(BUILD_TYPE ${TEST_BUILD_TYPES})
+    STRING(TOUPPER "${BUILD_TYPE}" BUILD_TYPE_UPPERCASE)
+    # Setup include path & link library for gflags for CHECK_CXX_SOURCE_COMPILES.
+    SET(CMAKE_REQUIRED_INCLUDES ${GFLAGS_INCLUDE_DIR})
+    SET(CMAKE_REQUIRED_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES})
+    # First try the (older) google namespace.  Note that the output variable
+    # MUST be unique to the build type as otherwise the test is not repeated as
+    # it is assumed to have already been performed.
+    CHECK_CXX_SOURCE_COMPILES_WITH_BUILD_TYPE(
+      "#include <gflags/gflags.h>
      int main(int argc, char * argv[]) {
        google::ParseCommandLineFlags(&argc, &argv, true);
        return 0;
      }"
-     GFLAGS_IN_GOOGLE_NAMESPACE)
-  IF (GFLAGS_IN_GOOGLE_NAMESPACE)
-    SET(GFLAGS_NAMESPACE google)
-  ELSE (GFLAGS_IN_GOOGLE_NAMESPACE)
-    # Try (newer) gflags namespace instead.
-    #
-    # Setup include path & link library for gflags for CHECK_CXX_SOURCE_COMPILES
-    SET(CMAKE_REQUIRED_INCLUDES ${GFLAGS_INCLUDE_DIR})
-    SET(CMAKE_REQUIRED_LIBRARIES ${GFLAGS_LIBRARY})
-    CHECK_CXX_SOURCE_COMPILES(
-      "#include <gflags/gflags.h>
+     ${BUILD_TYPE}
+     GFLAGS_IN_GOOGLE_NAMESPACE_${BUILD_TYPE_UPPERCASE})
+   IF (GFLAGS_IN_GOOGLE_NAMESPACE_${BUILD_TYPE_UPPERCASE})
+     SET(GFLAGS_NAMESPACE google)
+     BREAK()
+   ELSE (GFLAGS_IN_GOOGLE_NAMESPACE_${BUILD_TYPE_UPPERCASE})
+     # Try (newer) gflags namespace instead.  Note that the output variable
+     # MUST be unique to the build type as otherwise the test is not repeated as
+     # it is assumed to have already been performed.
+     SET(CMAKE_REQUIRED_INCLUDES ${GFLAGS_INCLUDE_DIR})
+     SET(CMAKE_REQUIRED_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES})
+     CHECK_CXX_SOURCE_COMPILES_WITH_BUILD_TYPE(
+       "#include <gflags/gflags.h>
        int main(int argc, char * argv[]) {
          gflags::ParseCommandLineFlags(&argc, &argv, true);
          return 0;
        }"
-       GFLAGS_IN_GFLAGS_NAMESPACE)
-    IF (GFLAGS_IN_GFLAGS_NAMESPACE)
-      SET(GFLAGS_NAMESPACE gflags)
-    ENDIF (GFLAGS_IN_GFLAGS_NAMESPACE)
-  ENDIF (GFLAGS_IN_GOOGLE_NAMESPACE)
+       ${BUILD_TYPE}
+       GFLAGS_IN_GFLAGS_NAMESPACE_${BUILD_TYPE_UPPERCASE})
+     IF (GFLAGS_IN_GFLAGS_NAMESPACE_${BUILD_TYPE_UPPERCASE})
+       SET(GFLAGS_NAMESPACE gflags)
+       BREAK()
+     ENDIF (GFLAGS_IN_GFLAGS_NAMESPACE_${BUILD_TYPE_UPPERCASE})
+   ENDIF (GFLAGS_IN_GOOGLE_NAMESPACE_${BUILD_TYPE_UPPERCASE})
+ ENDFOREACH()
 
-  IF (NOT GFLAGS_NAMESPACE)
-    GFLAGS_REPORT_NOT_FOUND(
-      "Failed to determine gflags namespace, it is not google or gflags.")
-  ENDIF (NOT GFLAGS_NAMESPACE)
-ENDIF (GFLAGS_INCLUDE_DIR)
+ IF (NOT GFLAGS_NAMESPACE)
+   # Failed to determine gflags namespace using
+   # check_cxx_source_compiles_with_build_type() method, try and obtain it
+   # using regex on the gflags header instead.
+   MESSAGE(STATUS "Failed to find gflags namespace using using "
+     "check_cxx_source_compiles(), trying namespace regex instead, "
+     "this is expected on Windows.")
+   # Scan gflags.h to identify what namespace gflags was built with.
+   SET(GFLAGS_HEADER_FILE ${GFLAGS_INCLUDE_DIR}/gflags/gflags.h)
+   IF (NOT EXISTS ${GFLAGS_HEADER_FILE})
+     GFLAGS_REPORT_NOT_FOUND(
+       "Could not find file: ${GFLAGS_HEADER_FILE} "
+       "containing namespace information in gflags install located at: "
+       "${GFLAGS_INCLUDE_DIR}.")
+   ELSE (NOT EXISTS ${GFLAGS_HEADER_FILE})
+     FILE(READ ${GFLAGS_HEADER_FILE} GFLAGS_HEADER_FILE_CONTENTS)
+
+     STRING(REGEX MATCH "namespace [A-Za-z]+"
+       GFLAGS_NAMESPACE "${GFLAGS_HEADER_FILE_CONTENTS}")
+     STRING(REGEX REPLACE "namespace ([A-Za-z]+)" "\\1"
+       GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}")
+
+     IF (NOT GFLAGS_NAMESPACE)
+      GFLAGS_REPORT_NOT_FOUND(
+        "Failed to extract gflags namespace from header file: "
+        "${GFLAGS_HEADER_FILE}.")
+     ENDIF (NOT GFLAGS_NAMESPACE)
+
+     # Verify that the namespace is either google or gflags.  Strictly
+     # speaking the users can specify something else when building gflags,
+     # but doing so would cause so many compatibility issues, that they should
+     # not have done, so any mismatch is almost certainly a regex failure.
+     IF (NOT GFLAGS_NAMESPACE STREQUAL "google" AND
+         NOT GFLAGS_NAMESPACE STREQUAL "gflags")
+       GFLAGS_REPORT_NOT_FOUND(
+         "Failed to extract valid gflags namespace from header file: "
+         "${GFLAGS_HEADER_FILE}, result: ${GFLAGS_NAMESPACE} is not "
+         "google or gflags.")
+     ENDIF()
+   ENDIF (NOT EXISTS ${GFLAGS_HEADER_FILE})
+ ENDIF (NOT GFLAGS_NAMESPACE)
+
+ IF (NOT GFLAGS_NAMESPACE)
+   GFLAGS_REPORT_NOT_FOUND(
+     "Failed to determine gflags namespace either by "
+     "check_cxx_source_compiles(), or namespace regex.")
+ ENDIF (NOT GFLAGS_NAMESPACE)
+ENDIF (GFLAGS_INCLUDE_DIR AND NOT GFLAGS_NAMESPACE)
+
+# Make the GFLAGS_NAMESPACE a cache variable s/t the user can view it, and could
+# overwrite it in the CMake GUI.
+SET(GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}" CACHE STRING
+  "gflags namespace (google or gflags)" FORCE)
 
 # gflags does not seem to provide any record of the version in its
 # source tree, thus cannot extract version.
 
+# Catch case when caller has set GFLAGS_NAMESPACE in the cache / GUI
+# with an invalid value.
+IF (GFLAGS_NAMESPACE AND
+    NOT GFLAGS_NAMESPACE STREQUAL "google" AND
+    NOT GFLAGS_NAMESPACE STREQUAL "gflags")
+  GFLAGS_REPORT_NOT_FOUND(
+    "Caller defined GFLAGS_NAMESPACE:"
+    " ${GFLAGS_NAMESPACE} is not valid, not google or gflags.")
+ENDIF ()
 # Catch case when caller has set GFLAGS_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.
@@ -202,7 +392,7 @@
 # Set standard CMake FindPackage variables if found.
 IF (GFLAGS_FOUND)
   SET(GFLAGS_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIR})
-  SET(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY})
+  SET(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES})
 ENDIF (GFLAGS_FOUND)
 
 # Handle REQUIRED / QUIET optional arguments.