1 /* Test file for mpfr_version.
2
3 Copyright 2004-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5
6 This file is part of the GNU MPFR Library.
7
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23 #include <errno.h>
24
25 #define MPFR_NEED_INTMAX_H
26 #include "mpfr-test.h"
27
28 /* Warning about the usage of printf/puts below:
29 *
30 * - If a macro expansion is used, it must not appear in the first
31 * argument of printf (format string), as we do not know whether
32 * the expanded string contains a '%' character.
33 *
34 * - If a #if preprocessor directive is used in an argument, parentheses
35 * must be put around the function name, in case this function is also
36 * implemented as a macro (#if does not work in macro arguments).
37 */
38
39 int
main(void)40 main (void)
41 {
42 mpfr_exp_t e;
43 int err = 0;
44
45 /* Test the GMP and MPFR versions. */
46 if (test_version ())
47 exit (1);
48
49 tests_start_mpfr ();
50
51 errno = 0;
52
53 /*********************** MPFR version and patches ************************/
54
55 /* The printf failure test was added because of an output issue under Wine,
56 * eventually not related to this output; this test is kept just in case...
57 * Details:
58 * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=914822
59 * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=914949
60 */
61 if (printf ("[tversion] MPFR %s\n", MPFR_VERSION_STRING) < 0)
62 {
63 perror ("tversion (first printf)");
64 err = 1;
65 }
66
67 if (strcmp (mpfr_get_patches (), "") != 0)
68 printf ("[tversion] MPFR patches: %s\n", mpfr_get_patches ());
69
70 /************************* Compiler information **************************/
71
72 /* TODO: We may want to output info for non-GNUC-compat compilers too. See:
73 * https://sourceforge.net/p/predef/wiki/Compilers/
74 * https://web.archive.org/web/20191011050717/http://nadeausoftware.com/articles/2012/10/c_c_tip_how_detect_compiler_name_and_version_using_compiler_predefined_macros
75 *
76 * For ICC, do not check the __ICC macro as it is obsolete and not always
77 * defined (in particular, on MS Windows).
78 */
79 #define COMP "[tversion] Compiler: "
80 #ifdef __INTEL_COMPILER
81 # ifdef __VERSION__
82 # define ICCV " [" __VERSION__ "]"
83 # else
84 # define ICCV ""
85 # endif
86 printf (COMP "ICC %d.%d.%d" ICCV "\n", __INTEL_COMPILER / 100,
87 __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE);
88 #elif defined(__TINYC__)
89 /* The format of __TINYC__ is not described, but libtcc.c defines it with
90 * sprintf(buffer, "%d", a*10000 + b*100 + c);
91 * tcc_define_symbol(s, "__TINYC__", buffer);
92 */
93 printf (COMP "TCC %d.%d.%d\n", (int) (__TINYC__ / 10000),
94 (int) ((__TINYC__ / 100) % 100), (int) (__TINYC__ % 100));
95 #elif (defined(__GNUC__) || defined(__clang__)) && defined(__VERSION__)
96 # ifdef __clang__
97 # define COMP2 COMP
98 # else
99 # define COMP2 COMP "GCC "
100 # endif
101 printf (COMP2 "%s\n", __VERSION__);
102 #endif
103
104 /************** More information about the C implementation **************/
105
106 /* The following macros are currently used by src/mpfr-cvers.h and/or
107 src/mpfr-impl.h; they may have an influcence on how MPFR is compiled. */
108
109 #if defined(__STDC__) || defined(__STDC_VERSION__)
110 (puts) ("[tversion] C standard: __STDC__ = "
111 #if defined(__STDC__)
112 MAKE_STR(__STDC__)
113 #else
114 "undef"
115 #endif
116 ", __STDC_VERSION__ = "
117 #if defined(__STDC_VERSION__)
118 MAKE_STR(__STDC_VERSION__)
119 #else
120 "undef"
121 #endif
122 );
123 #endif
124
125 #if defined(__GNUC__)
126 (puts) ("[tversion] __GNUC__ = " MAKE_STR(__GNUC__) ", __GNUC_MINOR__ = "
127 #if defined(__GNUC_MINOR__)
128 MAKE_STR(__GNUC_MINOR__)
129 #else
130 "undef"
131 #endif
132 #if defined(__STRICT_ANSI__)
133 ", __STRICT_ANSI__"
134 #endif
135 );
136 #endif
137
138 #if defined(__ICC) || defined(__INTEL_COMPILER)
139 (puts) ("[tversion] Intel compiler: __ICC = "
140 #if defined(__ICC)
141 MAKE_STR(__ICC)
142 #else
143 "undef"
144 #endif
145 ", __INTEL_COMPILER = "
146 #if defined(__INTEL_COMPILER)
147 MAKE_STR(__INTEL_COMPILER)
148 #else
149 "undef"
150 #endif
151 );
152 #endif
153
154 #if defined(_WIN32) || defined(_MSC_VER)
155 (puts) ("[tversion] MS Windows: _WIN32 = "
156 #if defined(_WIN32)
157 MAKE_STR(_WIN32)
158 #else
159 "undef"
160 #endif
161 ", _MSC_VER = "
162 #if defined(_MSC_VER)
163 MAKE_STR(_MSC_VER)
164 #else
165 "undef"
166 #endif
167 );
168 #endif
169
170 /* With MinGW64, both __MINGW32__ and __MINGW64__ seem to be defined,
171 but test both, just in case this will change in the future. Tested
172 with "x86_64-w64-mingw32-gcc -dM -E -xc /dev/null" under Debian. */
173 #if defined(__MINGW32__) || defined(__MINGW64__)
174 (puts) ("[tversion] MinGW"
175 #if defined(__MINGW64__)
176 "64"
177 #else
178 "32"
179 #endif
180 ": __USE_MINGW_ANSI_STDIO = "
181 #if defined(__USE_MINGW_ANSI_STDIO)
182 MAKE_STR(__USE_MINGW_ANSI_STDIO)
183 #else
184 "undef"
185 #endif
186 );
187 #endif
188
189 #if defined(__GLIBC__)
190 (puts) ("[tversion] __GLIBC__ = " MAKE_STR(__GLIBC__) ", __GLIBC_MINOR__ = "
191 #if defined(__GLIBC_MINOR__)
192 MAKE_STR(__GLIBC_MINOR__)
193 #else
194 "undef"
195 #endif
196 );
197 #endif
198
199 /******************* GMP version and build information *******************/
200
201 #ifdef __MPIR_VERSION
202 printf ("[tversion] MPIR: header %d.%d.%d, library %s\n",
203 __MPIR_VERSION, __MPIR_VERSION_MINOR, __MPIR_VERSION_PATCHLEVEL,
204 mpir_version);
205 #else
206 #ifdef MPFR_USE_MINI_GMP
207 printf ("[tversion] mini-gmp\n");
208 #else
209 printf ("[tversion] GMP: header %d.%d.%d, library %s\n",
210 __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, __GNU_MP_VERSION_PATCHLEVEL,
211 gmp_version);
212 #endif
213 #endif
214
215 #ifdef __GMP_CC
216 printf ("[tversion] __GMP_CC = \"%s\"\n", __GMP_CC);
217 #endif
218 #ifdef __GMP_CFLAGS
219 printf ("[tversion] __GMP_CFLAGS = \"%s\"\n", __GMP_CFLAGS);
220 #endif
221
222 /* The following output is also useful under Unix, where one should get:
223 WinDLL: __GMP_LIBGMP_DLL = 0, MPFR_WIN_THREAD_SAFE_DLL = undef
224 If this is not the case, something is probably broken. We cannot test
225 automatically as some MS Windows implementations may declare some Unix
226 (POSIX) compatibility; for instance, Cygwin32 defines __unix__ (but
227 Cygwin64 does not, probably because providing both MS Windows API and
228 POSIX API is not possible with a 64-bit ABI, since MS Windows is LLP64
229 and Unix is LP64).
230 MPFR_WIN_THREAD_SAFE_DLL is directly set up from __GMP_LIBGMP_DLL;
231 that is why it is output here. */
232 (puts) ("[tversion] WinDLL: __GMP_LIBGMP_DLL = "
233 #if defined(__GMP_LIBGMP_DLL)
234 MAKE_STR(__GMP_LIBGMP_DLL)
235 #else
236 "undef"
237 #endif
238 ", MPFR_WIN_THREAD_SAFE_DLL = "
239 #if defined(MPFR_WIN_THREAD_SAFE_DLL)
240 MAKE_STR(MPFR_WIN_THREAD_SAFE_DLL)
241 #else
242 "undef"
243 #endif
244 );
245
246 /********************* MPFR configuration parameters *********************/
247
248 /* The following code outputs configuration parameters, either set up
249 by the user or determined automatically (default values). */
250
251 if (
252 #ifdef MPFR_USE_THREAD_SAFE
253 !
254 #endif
255 mpfr_buildopt_tls_p ())
256 {
257 printf ("ERROR! mpfr_buildopt_tls_p() and macros"
258 " do not match!\n");
259 err = 1;
260 }
261
262 if (
263 #ifdef MPFR_WANT_FLOAT128
264 !
265 #endif
266 mpfr_buildopt_float128_p ())
267 {
268 printf ("ERROR! mpfr_buildopt_float128_p() and macros"
269 " do not match!\n");
270 err = 1;
271 }
272
273 if (
274 #ifdef MPFR_WANT_DECIMAL_FLOATS
275 !
276 #endif
277 mpfr_buildopt_decimal_p ())
278 {
279 printf ("ERROR! mpfr_buildopt_decimal_p() and macros"
280 " do not match!\n");
281 err = 1;
282 }
283
284 if (
285 #if defined(MPFR_HAVE_GMP_IMPL) || defined(WANT_GMP_INTERNALS)
286 !
287 #endif
288 mpfr_buildopt_gmpinternals_p ())
289 {
290 printf ("ERROR! mpfr_buildopt_gmpinternals_p() and macros"
291 " do not match!\n");
292 err = 1;
293 }
294
295 #if defined(MPFR_HAVE_GMP_IMPL)
296 (puts) ("[tversion] MPFR built with the GMP build (--with-gmp-build)");
297 #else
298 (printf) ("[tversion] MPFR_ALLOCA_MAX = %ld\n", (long) MPFR_ALLOCA_MAX);
299 #endif
300
301 if (
302 #ifdef MPFR_WANT_SHARED_CACHE
303 !
304 #endif
305 mpfr_buildopt_sharedcache_p ())
306 {
307 printf ("ERROR! mpfr_buildopt_sharedcache_p() and macros"
308 " do not match!\n");
309 err = 1;
310 }
311
312 (printf) ("[tversion] TLS = %s, float128 = %s, decimal = %s,"
313 " GMP internals = %s\n",
314 mpfr_buildopt_tls_p () ? "yes" : "no",
315 mpfr_buildopt_float128_p () ? "yes" : "no",
316 mpfr_buildopt_decimal_p () ? "yes"
317 #if defined(DECIMAL_BID_FORMAT)
318 " (BID)"
319 #elif defined(DECIMAL_DPD_FORMAT)
320 " (DPD)"
321 #endif
322 : "no",
323 mpfr_buildopt_gmpinternals_p () ? "yes" : "no");
324
325 #ifdef MPFR_THREAD_LOCK_METHOD
326 # define LOCK_METHOD " (lock method: " MPFR_THREAD_LOCK_METHOD ")"
327 #else
328 # define LOCK_METHOD ""
329 #endif
330
331 (printf) ("[tversion] Shared cache = %s\n",
332 mpfr_buildopt_sharedcache_p () ? "yes" LOCK_METHOD : "no");
333
334 (puts) ("[tversion] intmax_t = "
335 #if defined(_MPFR_H_HAVE_INTMAX_T)
336 "yes"
337 #else
338 "no"
339 #endif
340 ", printf = "
341 #if defined(HAVE_STDARG) && !defined(MPFR_USE_MINI_GMP)
342 "yes"
343 #else
344 "no"
345 #endif
346 ", IEEE floats = "
347 #if _MPFR_IEEE_FLOATS
348 "yes"
349 #else
350 "no"
351 #endif
352 );
353
354 (puts) ("[tversion] gmp_printf: hhd = "
355 #if defined(NPRINTF_HH)
356 "no"
357 #else
358 "yes"
359 #endif
360 ", lld = "
361 #if defined(NPRINTF_LL)
362 "no"
363 #else
364 "yes"
365 #endif
366 ", jd = "
367 #if defined(NPRINTF_J)
368 "no"
369 #else
370 "yes"
371 #endif
372 ", td = "
373 #if defined(NPRINTF_T)
374 "no"
375 #elif defined(PRINTF_T)
376 "yes"
377 #else
378 "?"
379 #endif
380 ", Ld = "
381 #if defined(NPRINTF_L)
382 "no"
383 #elif defined(PRINTF_L)
384 "yes"
385 #else
386 "?"
387 #endif
388 );
389
390 if (strcmp (mpfr_buildopt_tune_case (), MPFR_TUNE_CASE) != 0)
391 {
392 printf ("ERROR! mpfr_buildopt_tune_case() and MPFR_TUNE_CASE"
393 " do not match!\n %s\n %s\n",
394 mpfr_buildopt_tune_case (), MPFR_TUNE_CASE);
395 err = 1;
396 }
397 else
398 printf ("[tversion] MPFR tuning parameters from %s\n", MPFR_TUNE_CASE);
399
400 /**************************** ABI information ****************************/
401
402 (printf) ("[tversion] sizeof(long) = %ld, sizeof(mpfr_intmax_t) = %ld"
403 #if defined(_MPFR_H_HAVE_INTMAX_T)
404 ", sizeof(intmax_t) = %ld"
405 #endif
406 "\n", (long) sizeof(long), (long) sizeof(mpfr_intmax_t)
407 #if defined(_MPFR_H_HAVE_INTMAX_T)
408 , (long) sizeof(intmax_t)
409 #endif
410 );
411
412 if (mp_bits_per_limb != GMP_NUMB_BITS)
413 {
414 printf ("ERROR! mp_bits_per_limb != GMP_NUMB_BITS (%ld vs %ld)\n",
415 (long) mp_bits_per_limb, (long) GMP_NUMB_BITS);
416 err = 1;
417 }
418
419 printf ("[tversion] GMP_NUMB_BITS = %ld, sizeof(mp_limb_t) = %ld\n",
420 (long) GMP_NUMB_BITS, (long) sizeof(mp_limb_t));
421
422 /* Concerning the MPFR_LONG_WITHIN_LIMB and MPFR_INTMAX_WITHIN_LIMB macros,
423 if defined, code may be optimized to take these properties into account.
424 If not defined, MPFR should select portable code. So one should ideally
425 get either "y/y" or "n/n"; "n/y" is allowed, but "y/n" is forbidden.
426 Note: MPFR_LONG_WITHIN_LIMB should be defined by the configure script,
427 but may also be defined by the src/mpfr-impl.h header file. */
428 #define WITHIN_LIMB(T) \
429 (MPFR_LIMB_MAX >= (T) -1 ? \
430 ((WM) ? "y/y" : "n/y") : \
431 ((WM) ? (err = 1, "y/n (WRONG!)") : "n/n"))
432
433 (printf) ("[tversion] Within limb: long = %s"
434 #if defined(_MPFR_H_HAVE_INTMAX_T)
435 ", intmax_t = %s"
436 #endif
437 "\n"
438 #undef WM
439 #if defined(MPFR_LONG_WITHIN_LIMB)
440 # define WM 1
441 #else
442 # define WM 0
443 #endif
444 , WITHIN_LIMB (unsigned long)
445 #if defined(_MPFR_H_HAVE_INTMAX_T)
446 #undef WM
447 #if defined(MPFR_INTMAX_WITHIN_LIMB)
448 # define WM 1
449 #else
450 # define WM 0
451 #endif
452 , WITHIN_LIMB (uintmax_t)
453 #endif
454 );
455
456 printf ("[tversion] _MPFR_PREC_FORMAT = %ld, sizeof(mpfr_prec_t) = %ld\n",
457 (long) _MPFR_PREC_FORMAT, (long) sizeof(mpfr_prec_t));
458
459 printf ("[tversion] _MPFR_EXP_FORMAT = %ld, sizeof(mpfr_exp_t) = %ld\n",
460 (long) _MPFR_EXP_FORMAT, (long) sizeof(mpfr_exp_t));
461
462 printf ("[tversion] sizeof(mpfr_t) = %ld, sizeof(mpfr_ptr) = %ld\n",
463 (long) sizeof(mpfr_t), (long) sizeof(mpfr_ptr));
464
465 #define RANGE " range: [%" MPFR_EXP_FSPEC "d,%" MPFR_EXP_FSPEC "d]\n"
466
467 printf ("[tversion] Precision" RANGE,
468 (mpfr_eexp_t) MPFR_PREC_MIN, (mpfr_eexp_t) MPFR_PREC_MAX);
469
470 e = mpfr_get_emin_min ();
471 if (e != MPFR_EMIN_MIN)
472 {
473 printf ("ERROR! mpfr_get_emin_min != MPFR_EMIN_MIN (%"
474 MPFR_EXP_FSPEC "d vs %" MPFR_EXP_FSPEC "d)\n",
475 (mpfr_eexp_t) e, (mpfr_eexp_t) MPFR_EMIN_MIN);
476 err = 1;
477 }
478
479 e = mpfr_get_emax_max ();
480 if (e != MPFR_EMAX_MAX)
481 {
482 printf ("ERROR! mpfr_get_emax_max != MPFR_EMAX_MAX (%"
483 MPFR_EXP_FSPEC "d vs %" MPFR_EXP_FSPEC "d)\n",
484 (mpfr_eexp_t) e, (mpfr_eexp_t) MPFR_EMAX_MAX);
485 err = 1;
486 }
487
488 printf ("[tversion] Max exponent" RANGE,
489 (mpfr_eexp_t) MPFR_EMIN_MIN, (mpfr_eexp_t) MPFR_EMAX_MAX);
490
491 (puts) ("[tversion] Generic ABI code: "
492 #if defined(MPFR_GENERIC_ABI)
493 "yes"
494 #else
495 "no"
496 #endif
497 );
498
499 (puts) ("[tversion] Enable formally proven code: "
500 #if defined(MPFR_WANT_PROVEN_CODE)
501 "yes"
502 #else
503 "no"
504 #endif
505 );
506
507 /************************* Run-time information **************************/
508
509 if (locale != NULL)
510 printf ("[tversion] Locale: %s\n", locale);
511 /* The memory limit should not be changed for "make check".
512 The warning below signals a possible user mistake.
513 Do not use "%zu" because it is not available in C90;
514 the type mpfr_ueexp_t should be sufficiently large. */
515 if (tests_memory_limit != DEFAULT_MEMORY_LIMIT)
516 printf ("[tversion] Warning! Memory limit changed to %" MPFR_EXP_FSPEC
517 "u\n", (mpfr_ueexp_t) tests_memory_limit);
518
519 /*************************************************************************/
520
521 if (errno != 0)
522 {
523 perror ("tversion");
524 err = 1;
525 }
526
527 tests_end_mpfr ();
528
529 return err;
530 }
531