From 41c4a0869d68d894cbe74a63612df75fd1e93bdf Mon Sep 17 00:00:00 2001
From: Michael Orlitzky <michael@orlitzky.com>
Date: Mon, 19 Apr 2021 16:56:54 -0400
Subject: [PATCH 1/1] CMake/FindGMP.cmake: compile a test program to check the
 gmp version.

The existing GMP version check consists of grepping the contents of
the gmp.h header to parse out a few constants. This test fails, at
least, on Gentoo, where the usual header file is a wrapper that
includes the true header to allow for simultaneous 32/64-bit
support.

This commit updates FindGMP to compile a test program against gmp.h
that compares version constants using the C preprocessor. If GMP is
too old, the test program will fail to compile and CMake will know.
---
 CMake/FindGMP.cmake | 91 +++++++++++++++++++++++----------------------
 1 file changed, 47 insertions(+), 44 deletions(-)

diff --git a/CMake/FindGMP.cmake b/CMake/FindGMP.cmake
index ce4df70f5..951151274 100644
--- a/CMake/FindGMP.cmake
+++ b/CMake/FindGMP.cmake
@@ -2,28 +2,23 @@
 # https://gmplib.org/
 #
 # This module supports requiring a minimum version, e.g. you can do
-#   find_package(GMP 6.0.0)
-# to require version 6.0.0 to newer of GMP.
+#   find_package(GMP 6.2.1)
+# to require version 6.2.1 to newer of GMP.
 #
 # Once done this will define
 #
 #  GMP_FOUND - system has GMP lib with correct version
 #  GMP_INCLUDE_DIRS - the GMP include directory
 #  GMP_LIBRARIES - the GMP library
-#  GMP_VERSION - GMP version
 #
-# Copyright (c) 2016 Jack Poulson, <jack.poulson@gmail.com>
-# Redistribution and use is allowed according to the terms of the BSD license.
 
-find_path(GMP_INCLUDE_DIRS NAMES gmp.h PATHS $ENV{GMPDIR} ${INCLUDE_INSTALL_DIR})
-
-# Set GMP_FIND_VERSION to 5.1.0 if no minimum version is specified
+# Set GMP_FIND_VERSION to 6.0.0 if no minimum version is specified
 if(NOT GMP_FIND_VERSION)
   if(NOT GMP_FIND_VERSION_MAJOR)
-    set(GMP_FIND_VERSION_MAJOR 5)
+    set(GMP_FIND_VERSION_MAJOR 6)
   endif()
   if(NOT GMP_FIND_VERSION_MINOR)
-    set(GMP_FIND_VERSION_MINOR 1)
+    set(GMP_FIND_VERSION_MINOR 0)
   endif()
   if(NOT GMP_FIND_VERSION_PATCH)
     set(GMP_FIND_VERSION_PATCH 0)
@@ -32,43 +27,51 @@ if(NOT GMP_FIND_VERSION)
     "${GMP_FIND_VERSION_MAJOR}.${GMP_FIND_VERSION_MINOR}.${GMP_FIND_VERSION_PATCH}")
 endif()
 
-if(GMP_INCLUDE_DIRS)
-  # Since the GMP version macros may be in a file included by gmp.h of the form
-  # gmp-.*[_]?.*.h (e.g., gmp-x86_64.h), we search each of them.
-  file(GLOB GMP_HEADERS "${GMP_INCLUDE_DIRS}/gmp.h" "${GMP_INCLUDE_DIRS}/gmp-*.h"
-	  "${GMP_INCLUDE_DIRS}/x86*/gmp.h")
-  foreach(gmp_header_filename ${GMP_HEADERS})
-    file(READ "${gmp_header_filename}" _gmp_version_header)
-    string(REGEX MATCH
-      "define[ \t]+__GNU_MP_VERSION[ \t]+([0-9]+)" _gmp_major_version_match
-      "${_gmp_version_header}")
-    if(_gmp_major_version_match)
-      set(GMP_MAJOR_VERSION "${CMAKE_MATCH_1}")
-      string(REGEX MATCH "define[ \t]+__GNU_MP_VERSION_MINOR[ \t]+([0-9]+)"
-        _gmp_minor_version_match "${_gmp_version_header}")
-      set(GMP_MINOR_VERSION "${CMAKE_MATCH_1}")
-      string(REGEX MATCH "define[ \t]+__GNU_MP_VERSION_PATCHLEVEL[ \t]+([0-9]+)"
-        _gmp_patchlevel_version_match "${_gmp_version_header}")
-      set(GMP_PATCHLEVEL_VERSION "${CMAKE_MATCH_1}")
-      set(GMP_VERSION
-        ${GMP_MAJOR_VERSION}.${GMP_MINOR_VERSION}.${GMP_PATCHLEVEL_VERSION})
-    endif()
-  endforeach()
+find_path(GMP_INCLUDE_DIRS
+          NAMES gmp.h
+          PATHS $ENV{GMPDIR} ${INCLUDE_INSTALL_DIR})
 
-  # Check whether found version exists and exceeds the minimum requirement
-  if(NOT GMP_VERSION)
-    set(GMP_VERSION_OK FALSE)
-    message(STATUS "GMP version was not detected")
-  elseif(${GMP_VERSION} VERSION_LESS ${GMP_FIND_VERSION})
-    set(GMP_VERSION_OK FALSE)
-    message(STATUS "GMP version ${GMP_VERSION} found in ${GMP_INCLUDE_DIRS}, "
-                   "but at least version ${GMP_FIND_VERSION} is required")
-  else()
-    set(GMP_VERSION_OK TRUE)
-  endif()
+find_library(GMP_LIBRARIES
+             gmp
+             PATHS $ENV{GMPDIR} ${LIB_INSTALL_DIR})
+
+if(GMP_INCLUDE_DIRS AND GMP_LIBRARIES)
+
+  # This program will fail to compile if GMP is too old.
+  # We prefer to perform this "test" at compile-time to
+  # avoid problems with e.g. try_run() during cross-compilation.
+  file(WRITE ${PROJECT_BINARY_DIR}/gmp-version-check.c ""
+  "#include <gmp.h>\n"
+  "\n"
+  "#define GMP_FIND_VERSION_MAJOR ${GMP_FIND_VERSION_MAJOR}\n"
+  "#define GMP_FIND_VERSION_MINOR ${GMP_FIND_VERSION_MINOR}\n"
+  "#define GMP_FIND_VERSION_PATCH ${GMP_FIND_VERSION_PATCH}\n"
+  "\n"
+  "#if __GNU_MP_VERSION < GMP_FIND_VERSION_MAJOR\n"
+  "#error insufficient GMP major version\n"
+  "#elif __GNU_MP_VERSION == GMP_FIND_VERSION_MAJOR\n"
+  "#if __GNU_MP_VERSION_MINOR < GMP_FIND_VERSION_MINOR\n"
+  "#error insufficient GMP minor version\n"
+  "#elif __GNU_MP_VERSION_MINOR == GMP_FIND_VERSION_MINOR\n"
+  "#if __GNU_MP_VERSION_PATCH < GMP_FIND_VERSION_PATCH\n"
+  "#error insufficient GMP patch version\n"
+  "#endif\n"
+  "#endif\n"
+  "#endif\n"
+  "\n"
+  "int main(int argc, char** argv) { return 0; }\n")
+
+  # Try to compile the test program above with the appropriate version
+  # strings substituted in.
+  try_compile(GMP_VERSION_OK
+          "${PROJECT_BINARY_DIR}"
+          "${PROJECT_BINARY_DIR}/gmp-version-check.c"
+          CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${GMP_INCLUDE_DIRS}")
 endif()
 
-find_library(GMP_LIBRARIES gmp PATHS $ENV{GMPDIR} ${LIB_INSTALL_DIR})
+if(NOT GMP_VERSION_OK)
+  message(STATUS "No sufficient GMP version detected")
+endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(GMP DEFAULT_MSG
-- 
2.26.3

