Subject: bug#10519: guile and (mini-)gmp

From: [email-masked] (Niels Möller)
Date: Mon, 23 Jul 2012 01:17:51 +0200

[email-masked] (Ludovic Courtès) writes:

> Reviving the discussion, as we’ve been discussing this at the GHM, and
> some people would really like to see it happen.  :-)

Great! Any summary of the discussion, for those of us who couldn't make
it there?

> [email-masked] (Niels Möller) skribis:
>
>> To try that out, I'm working with a slightly patched guile:
>
> Do you still have the patch around?

I'm attaching a patch from I tree I have around, without reading it
carefully. I'm not sure this is the latest version I worked with. Maybe
it's of some use.

>> 1. The header file libguile.h. As far as I understand, this is a public
>>    header file and it's use of <gmp.h> means that the public guile ABI
>>    depends on gmp.
>
> The problem is that there’s a public API dealing with mpz_t:

Exactly. To me, that seems like a potentially hairy problem to get
right.

>   SCM_API void scm_to_mpz (SCM x, mpz_t rop);
>   SCM_API SCM  scm_from_mpz (mpz_t rop);
>
> So, when mini-gmp is used, a <gmp.h> header should be installed as well,
> say under <libguile/mini-gmp.h>.  WDYT?

Maybe it would make sense with a level of indirection. User's could
include libguile/bignum.h, which would in turn include either mini-gmp.h
or the real gmp.h, depending on how guile was configured. Users may also
need some way of figuring out if they need to link with -lgmp or not.

>> Since mini-gmp is not binary compatible,
>
> I don’t think there’s a problem, because only mpz_t objects appear in
> the API, and they’re pointers.

mpz_t is a typedef, which is a single element array of a semi-internal
struct. So when you declare

  mpz_t x;

you are really declaring a struct, not a pointer (and then the array
type automatically "decays" to a pointer when passed as a function
argument).

But it's likely that mini-gmp will use the same size of that struct. And
even the same layout. I think the main ABI incompatibilities are that

1. symbol names, as seen by the linker, are different. With gmp, mpz_foo
   is a name mangling #define, and the real name is ___gmpz_foo.
   mini-gmp doesn't do that.

2. mp_limb_t may be of different size: With mini-gmp, it's always
   unsigned long, with gmp it's unsigned long long on some platforms
   (notably 64-bit windows, I think).

Hmm, or if you're saying that the use of mpz_t in guile's public API is
pointers only, that that might make things a little simpler. But things
will still break badly if the user's code is linked with gmp and guile
uses mini-gmp, or vice versa.

>> 4. mini-gmp has no mp_set_memory_functions.

That's added now, with the subtle difference that mini-gmp doesn't pass
a valid size for the old_size argument for the free and realloc
functions. I don't think guile depends on that feature.

Please also note that the most recent version of mini-gmp is now the one
included in the main gmp repo.

diff --git a/configure.ac b/configure.ac
index a32ff4b..089dfbe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -146,6 +146,10 @@ AC_ARG_ENABLE(regex,
   [  --disable-regex         omit regular expression interfaces],,
   enable_regex=yes)
 
+AC_ARG_ENABLE(gmp,
+  [  --disable-gmp	     omit high performance bignums],,
+  enable_gmp=yes)
+
 AC_ARG_ENABLE([deprecated],
   AS_HELP_STRING([--disable-deprecated],[omit deprecated features]))
 
@@ -869,15 +873,20 @@ fi
 AC_CACHE_SAVE
 
 dnl GMP tests
+if test "x$enable_gmp" != xno ; then
 AC_LIB_HAVE_LINKFLAGS([gmp],
   [],
   [#include <gmp.h>],
   [mpz_import (0, 0, 0, 0, 0, 0, 0);])
 
 if test "x$HAVE_LIBGMP" != "xyes"; then
-  AC_MSG_ERROR([GNU MP 4.1 or greater not found, see README])
+  AC_MSG_NOTICE([GNU MP 4.1 or greater not found, see README])
+  enable_gmp=no
+fi
+fi
+if test "x$enable_gmp" = xno ; then
+  AC_LIBOBJ([mini-gmp])
 fi
-
 dnl GNU libunistring is checked for by Gnulib's `libunistring' module.
 if test "x$LTLIBUNISTRING" = "x"; then
   AC_MSG_ERROR([GNU libunistring is required, please install it.])
@@ -1253,7 +1262,7 @@ main (int argc, char **argv)
 # Boehm's GC library
 #
 #--------------------------------------------------------------------
-PKG_CHECK_MODULES([BDW_GC], [bdw-gc])
+# PKG_CHECK_MODULES([BDW_GC], [bdw-gc])
 
 save_LIBS="$LIBS"
 LIBS="$BDW_GC_LIBS $LIBS"
diff --git a/libguile.h b/libguile.h
index 7ac98a5..457dd66 100644
--- a/libguile.h
+++ b/libguile.h
@@ -22,8 +22,11 @@
 
 /* This needs to be included outside of the extern "C" block.
  */
+#if HAVE_LIBGMP
 #include <gmp.h>
-
+#else
+#include "libguile/mini-gmp.h"
+#endif
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/libguile/bytevectors.c b/libguile/bytevectors.c
index 811e8d8..240e457 100644
--- a/libguile/bytevectors.c
+++ b/libguile/bytevectors.c
@@ -24,7 +24,11 @@
 #include <alloca.h>
 #include <assert.h>
 
+#if HAVE_LIBGMP
 #include <gmp.h>
+#else
+#include "mini-gmp.h"
+#endif
 
 #include "libguile/_scm.h"
 #include "libguile/extensions.h"
diff --git a/libguile/init.c b/libguile/init.c
index 35ab856..bb79422 100644
--- a/libguile/init.c
+++ b/libguile/init.c
@@ -29,7 +29,11 @@
 #include <stdio.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#if HAVE_LIBGMP
 #include <gmp.h>
+#else
+#include "mini-gmp.h"
+#endif
 
 #include "libguile/_scm.h"
 
diff --git a/libguile/numbers.h b/libguile/numbers.h
index b7bcfe4..166f222 100644
--- a/libguile/numbers.h
+++ b/libguile/numbers.h
@@ -22,9 +22,11 @@
  */
 
 
-
+#ifdef HAVE_LIBGMP
 #include <gmp.h>
-
+#else
+#include "mini-gmp.h"
+#endif
 #include "libguile/__scm.h"
 #include "libguile/print.h"
 
diff --git a/libguile/random.c b/libguile/random.c
index 8bc0d87..c216245 100644
--- a/libguile/random.c
+++ b/libguile/random.c
@@ -25,7 +25,11 @@
 
 #include "libguile/_scm.h"
 
+#if HAVE_LIBGMP
 #include <gmp.h>
+#else
+#include "mini-gmp.h"
+#endif
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
diff --git a/libguile/socket.c b/libguile/socket.c
index d085d33..5ec20a2 100644
--- a/libguile/socket.c
+++ b/libguile/socket.c
@@ -25,7 +25,11 @@
 #endif
 
 #include <errno.h>
+#if HAVE_LIBGMP
 #include <gmp.h>
+#else
+#include "mini-gmp.h"
+#endif
 
 #include "libguile/_scm.h"
 #include "libguile/arrays.h"

Regards,
/Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.