From f7e092fa296249cbec57d4fc19f6bb3057fb674c Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 3 Oct 2005 14:44:27 -0400
Subject: [PATCH] ENH: Converting FundamentalType try-compiles into a single
 try-run.  All the information about the existence, size, and signedness of
 types can be determined in one program thanks to limits.h.

---
 CMakeLists.txt            | 84 ++++++++++++++++++++++---------------
 kwsysPlatformCxxTests.cxx | 87 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+), 34 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b4b7a18..f6aaa90 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -254,20 +254,56 @@ IF(UNIX)
 ENDIF(UNIX)
 
 IF(KWSYS_USE_FundamentalType)
-  # Determine type sizes.
-  INCLUDE(CheckTypeSize)
-  CHECK_TYPE_SIZE("char"      KWSYS_SIZEOF_CHAR)
-  CHECK_TYPE_SIZE("short"     KWSYS_SIZEOF_SHORT)
-  CHECK_TYPE_SIZE("int"       KWSYS_SIZEOF_INT)
-  CHECK_TYPE_SIZE("long"      KWSYS_SIZEOF_LONG)
-  CHECK_TYPE_SIZE("long long" KWSYS_SIZEOF_LONG_LONG)
-  CHECK_TYPE_SIZE("__int64"   KWSYS_SIZEOF___INT64)
-  IF(NOT KWSYS_SIZEOF_LONG_LONG)
-    SET(KWSYS_SIZEOF_LONG_LONG 0)
-  ENDIF(NOT KWSYS_SIZEOF_LONG_LONG)
-  IF(NOT KWSYS_SIZEOF___INT64)
-    SET(KWSYS_SIZEOF___INT64 0)
-  ENDIF(NOT KWSYS_SIZEOF___INT64)
+  # Load fundamental type information generated by the below try-run.
+  IF(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/FundamentalTypeInfo.cmake)
+    # The file already exists.  Load it now.
+    INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/FundamentalTypeInfo.cmake)
+  ELSE(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/FundamentalTypeInfo.cmake)
+    # The file does not exist.  Try to generate it.  All the type
+    # information can be detected by a single try-run because the
+    # available types can be determined at compile time.  This
+    # significantly reduces the number of try-compiles and try-runs needed
+    # to collect this information.
+    MESSAGE(STATUS "Checking C++ fundamental types")
+
+    # Pass the output directory in KWSYS_CXX_TYPE_INFO_DIR as a cache
+    # entry to work-around some CMake parsing problems when there are
+    # spaces in the path (for CMake 2.2.1 and lower).  Do not quote
+    # the definition for VS 7 or 8 to work-around a CMake 2.2.1 and
+    # lower generator bug.
+    SET(DOLLAR "$")
+    IF(CMAKE_GENERATOR MATCHES "Visual Studio [78]")
+      SET(QUOTE "")
+    ELSE(CMAKE_GENERATOR MATCHES "Visual Studio [78]")
+      SET(QUOTE "\"")
+    ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio [78]")
+    TRY_RUN(KWSYS_CXX_TYPE_INFO KWSYS_CXX_TYPE_INFO_COMPILED
+      ${CMAKE_CURRENT_BINARY_DIR}
+      ${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformCxxTests.cxx
+      CMAKE_FLAGS
+      "-DKWSYS_CXX_TYPE_INFO_DIR:STRING=${CMAKE_CURRENT_BINARY_DIR}"
+      COMPILE_DEFINITIONS
+      -DTEST_KWSYS_CXX_TYPE_INFO
+      "-DKWSYS_CXX_TYPE_INFO_FILE=${QUOTE}${DOLLAR}{KWSYS_CXX_TYPE_INFO_DIR}/FundamentalTypeInfo.cmake${QUOTE}"
+      OUTPUT_VARIABLE OUTPUT
+      )
+
+    # Check if the file now exists.
+    IF(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/FundamentalTypeInfo.cmake)
+      # The file exists.  Report success and load it.
+      MESSAGE(STATUS "Checking C++ fundamental types -- success")
+      FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeOutput.log
+        "Checking C++ fundamental types compiled with the following output:\n${OUTPUT}\n\n")
+      INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/FundamentalTypeInfo.cmake)
+    ELSE(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/FundamentalTypeInfo.cmake)
+      # The file does not exist.  Report failure.
+      MESSAGE(STATUS "Checking C++ fundamental types -- failure")
+      FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeError.log
+        "Checking C++ fundamental types failed to compile with the following output:\n${OUTPUT}\n\n")
+      MESSAGE(FATAL_ERROR "Checking C++ fundamental type information failed.  "
+        "Check \"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeError.log\" for more information.")
+    ENDIF(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/FundamentalTypeInfo.cmake)
+  ENDIF(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/FundamentalTypeInfo.cmake)
 
   # Check uniqueness of types.
   IF(KWSYS_SIZEOF___INT64)
@@ -303,26 +339,6 @@ IF(KWSYS_USE_FundamentalType)
   ELSE(KWSYS_USE___INT64)
     SET(KWSYS_CAN_CONVERT_UI64_TO_DOUBLE 1)
   ENDIF(KWSYS_USE___INT64)
-
-  # Check signedness of "char" type.
-  IF("KWSYS_CHAR_IS_SIGNED" MATCHES "^KWSYS_CHAR_IS_SIGNED$")
-    MESSAGE(STATUS "Checking signedness of char")
-    TRY_RUN(KWSYS_CHAR_IS_SIGNED KWSYS_CHAR_IS_SIGNED_COMPILED
-      ${CMAKE_CURRENT_BINARY_DIR}
-      ${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformCxxTests.cxx
-      COMPILE_DEFINITIONS -DTEST_KWSYS_CHAR_IS_SIGNED)
-    IF(KWSYS_CHAR_IS_SIGNED_COMPILED)
-      IF(KWSYS_CHAR_IS_SIGNED)
-        MESSAGE(STATUS "Checking signedness of char -- signed")
-        SET(KWSYS_CHAR_IS_SIGNED 1 CACHE INTERNAL "Whether char is signed.")
-      ELSE(KWSYS_CHAR_IS_SIGNED)
-        MESSAGE(STATUS "Checking signedness of char -- unsigned")
-        SET(KWSYS_CHAR_IS_SIGNED 0 CACHE INTERNAL "Whether char is signed.")
-      ENDIF(KWSYS_CHAR_IS_SIGNED)
-    ELSE(KWSYS_CHAR_IS_SIGNED_COMPILED)
-      MESSAGE(FATAL_ERROR "Checking signedness of char -- failed")
-    ENDIF(KWSYS_CHAR_IS_SIGNED_COMPILED)
-  ENDIF("KWSYS_CHAR_IS_SIGNED" MATCHES "^KWSYS_CHAR_IS_SIGNED$")
 ENDIF(KWSYS_USE_FundamentalType)
 
 IF(KWSYS_NAMESPACE MATCHES "^kwsys$")
diff --git a/kwsysPlatformCxxTests.cxx b/kwsysPlatformCxxTests.cxx
index 4187bcc..77e0d1c 100644
--- a/kwsysPlatformCxxTests.cxx
+++ b/kwsysPlatformCxxTests.cxx
@@ -265,3 +265,90 @@ int main()
   return (*reinterpret_cast<char*>(&uc) < 0)?1:0;
 }
 #endif
+
+#ifdef TEST_KWSYS_CXX_TYPE_INFO
+/* Collect fundamental type information and save it to a CMake script.  */
+
+/* Include limits.h to get macros indicating long long and __int64.
+   Note that certain compilers need special macros to define these
+   macros in limits.h.  */
+#if defined(_MSC_VER) && !defined(_MSC_EXTENSIONS)
+# define _MSC_EXTENSIONS
+#endif
+#if defined(__GNUC__) && __GNUC__ < 3
+# define _GNU_SOURCE
+#endif
+#include <limits.h>
+
+#include <stdio.h>
+#include <string.h>
+
+/* Due to shell differences and limitations of ADD_DEFINITIONS the
+   KWSYS_CXX_TYPE_INFO_FILE macro will sometimes have double quotes
+   and sometimes not.  This macro will make sure the value is treated
+   as a double-quoted string.  */
+#define TO_STRING(x) TO_STRING0(x)
+#define TO_STRING0(x) TO_STRING1(x)
+#define TO_STRING1(x) #x
+
+void f() {}
+
+int main()
+{
+  /* Construct the output file name.  Some preprocessors will add an
+     extra level of double quotes, so strip them.  */
+  char fbuf[] = TO_STRING(KWSYS_CXX_TYPE_INFO_FILE);
+  char* fname = fbuf;
+  if(fname[0] == '"')
+    {
+    ++fname;
+    int len = static_cast<int>(strlen(fname));
+    if(len > 0 && fname[len-1] == '"')
+      {
+      fname[len-1] = 0;
+      }
+    }
+
+  /* Try to open the output file.  */
+  if(FILE* fout = fopen(fname, "w"))
+    {
+    /* Set the size of standard types.  */
+    fprintf(fout, "SET(KWSYS_SIZEOF_CHAR %d)\n", static_cast<int>(sizeof(char)));
+    fprintf(fout, "SET(KWSYS_SIZEOF_SHORT %d)\n", static_cast<int>(sizeof(short)));
+    fprintf(fout, "SET(KWSYS_SIZEOF_INT %d)\n", static_cast<int>(sizeof(int)));
+    fprintf(fout, "SET(KWSYS_SIZEOF_LONG %d)\n", static_cast<int>(sizeof(long)));
+
+    /* Set the size of some non-standard but common types.  */
+    /* Check for a limits.h macro for long long to see if the type exists.  */
+#if defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX)
+    fprintf(fout, "SET(KWSYS_SIZEOF_LONG_LONG %d)\n", static_cast<int>(sizeof(long long)));
+#else
+    fprintf(fout, "SET(KWSYS_SIZEOF_LONG_LONG 0) # No long long available.\n");
+#endif
+    /* Check for a limits.h macro for __int64 to see if the type exists.  */
+#if defined(_I64_MIN)
+    fprintf(fout, "SET(KWSYS_SIZEOF___INT64 %d)\n", static_cast<int>(sizeof(__int64)));
+#else
+    fprintf(fout, "SET(KWSYS_SIZEOF___INT64 0) # No __int64 available.\n");
+#endif
+
+    /* Set the size of some pointer types.  */
+    fprintf(fout, "SET(KWSYS_SIZEOF_PDATA %d)\n", static_cast<int>(sizeof(void*)));
+    fprintf(fout, "SET(KWSYS_SIZEOF_PFUNC %d)\n", static_cast<int>(sizeof(&f)));
+
+    /* Set whether the native type "char" is signed or unsigned.  */
+    unsigned char uc = 255;
+    fprintf(fout, "SET(KWSYS_CHAR_IS_SIGNED %d)\n",
+            (*reinterpret_cast<char*>(&uc) < 0)?1:0);
+
+    fclose(fout);
+    return 0;
+    }
+  else
+    {
+    fprintf(stderr, "Failed to write fundamental type info to \"%s\".\n",
+            fname);
+    return 1;
+    }
+}
+#endif
-- 
GitLab