Hi Paul, The module 'qsort_r' does not work at all on systems that don't have this function. For example, on AIX 7.1, with a gnulib testdir:
test-qsort_r.c: In function 'main': test-qsort_r.c:40:3: warning: implicit declaration of function 'qsort_r' [-Wimplicit-function-declaration] qsort_r (buf, sizeof buf - 1, 1, cmp, &forward); ^ gcc -mlong-double-64 -D_ALL_SOURCE -std=gnu11 -g -O2 -o test-qsort_r test-qsort_r.o ../gllib/libgnu.a -lm -lm -lm -lm -lm -lm -lm -lm -lm -lm ld: 0711-317 ERROR: Undefined symbol: .qsort_r ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information. collect2: error: ld returned 8 exit status make: 1254-004 The error code from the last command is 1. The problems are: 1) The gl_FUNC_QSORT_R macro finds that checking for qsort_r signature... GNU 2) The function does not get declared in gnulib's stdlib.h replacement. 3) It also is not included in libgnu.a (neither qsort.o nor qsort_r.o gets included in gl_LIBOBJS). Ad 1) Yes really it needs an AC_CHECK_FUNC call, because a program such as ============================================================================ #define __EXTENSIONS__ 1 #define _ALL_SOURCE 1 #define _DARWIN_C_SOURCE 1 #define _GNU_SOURCE 1 #include <stdlib.h> #define qsort_t any_nonexistent_name void qsort_r (void *, size_t, size_t, int (*) (void const *, void const *, void *), void *); void (*p) (void *, size_t, size_t, int (*) (void const *, void const *, void *), void *) = qsort_r; int main () { return 0; } ============================================================================ compiles and links perfectly fine. Ad 2) The idiom in stdlib.h is incomplete. You need to pick the complete one (e.g. copy&paste from the 'ptsname_r' declaration). Additionally: 4) The qsort_r function would not be warned about in GNULIB_POSIXCHECK mode. Here's a proposed fix. 2016-10-16 Bruno Haible <br...@clisp.org> qsort_r: Fix macrology for platforms that lack the function. * m4/stdlib_h.m4 (gl_STDLIB_H): Check for qsort_r. (gl_STDLIB_H_DEFAULTS): Initialize HAVE_QSORT_R. * modules/stdlib (Makefile.am): Substitute HAVE_QSORT_R. * lib/stdlib.in.h (qsort_r): Provide declaration if the function does not exist. * m4/qsort_r.m4 (gl_FUNC_QSORT_R): Use AC_CHECK_FUNCS to test whether the function exists. * modules/qsort_r: Add comments. diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index 70dc88d..db3253b 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -521,6 +521,9 @@ _GL_CXXALIASWARN (putenv); #endif #if @GNULIB_QSORT_R@ +/* Sort an array of NMEMB elements, starting at address BASE, each element + occupying SIZE bytes, in ascending order according to the comparison + function COMPARE. */ # if @REPLACE_QSORT_R@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef qsort_r @@ -535,12 +538,24 @@ _GL_CXXALIAS_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size, void *), void *arg)); # else +# if !@HAVE_QSORT_R@ +_GL_FUNCDECL_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size, + int (*compare) (void const *, void const *, + void *), + void *arg) _GL_ARG_NONNULL ((1, 4))); +# endif _GL_CXXALIAS_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size, int (*compare) (void const *, void const *, void *), void *arg)); # endif _GL_CXXALIASWARN (qsort_r); +#elif defined GNULIB_POSIXCHECK +# undef qsort_r +# if HAVE_RAW_DECL_QSORT_R +_GL_WARN_ON_USE (qsort_r, "qsort_r is not portable - " + "use gnulib module qsort_r for portability"); +# endif #endif diff --git a/m4/qsort_r.m4 b/m4/qsort_r.m4 index f3d2927..f1de7d4 100644 --- a/m4/qsort_r.m4 +++ b/m4/qsort_r.m4 @@ -14,35 +14,39 @@ AC_DEFUN([gl_FUNC_QSORT_R], AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) - AC_CACHE_CHECK([for qsort_r signature], [gl_cv_qsort_r_signature], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[#include <stdlib.h> - void qsort_r (void *, size_t, size_t, - int (*) (void const *, void const *, - void *), - void *); - void (*p) (void *, size_t, size_t, - int (*) (void const *, void const *, - void *), - void *) = qsort_r; - ]])], - [gl_cv_qsort_r_signature=GNU], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[#include <stdlib.h> - void qsort_r (void *, size_t, size_t, void *, - int (*) (void *, - void const *, - void const *)); - void (*p) (void *, size_t, size_t, void *, - int (*) (void *, void const *, - void const *)) = qsort_r; - ]])], - [gl_cv_qsort_r_signature=BSD], - [gl_cv_qsort_r_signature=no])])]) - - case $gl_cv_qsort_r_signature in - GNU) HAVE_QSORT_R=1;; - BSD) HAVE_QSORT_R=1 REPLACE_QSORT_R=1;; - *) HAVE_QSORT_R=0 REPLACE_QSORT_R=1;; - esac + AC_CHECK_FUNCS_ONCE([qsort_r]) + if test $ac_cv_func_qsort_r = yes; then + AC_CACHE_CHECK([for qsort_r signature], [gl_cv_qsort_r_signature], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include <stdlib.h> + void qsort_r (void *, size_t, size_t, + int (*) (void const *, void const *, + void *), + void *); + void (*p) (void *, size_t, size_t, + int (*) (void const *, void const *, + void *), + void *) = qsort_r; + ]])], + [gl_cv_qsort_r_signature=GNU], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include <stdlib.h> + void qsort_r (void *, size_t, size_t, void *, + int (*) (void *, + void const *, + void const *)); + void (*p) (void *, size_t, size_t, void *, + int (*) (void *, void const *, + void const *)) = qsort_r; + ]])], + [gl_cv_qsort_r_signature=BSD], + [gl_cv_qsort_r_signature=unknown])])]) + case $gl_cv_qsort_r_signature in + GNU) ;; + BSD) REPLACE_QSORT_R=1 ;; + unknown) HAVE_QSORT_R=0 REPLACE_QSORT_R=1 ;; + esac + else + HAVE_QSORT_R=0 + fi ]) diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4 index 19107c4..3999068 100644 --- a/m4/stdlib_h.m4 +++ b/m4/stdlib_h.m4 @@ -1,4 +1,4 @@ -# stdlib_h.m4 serial 42 +# stdlib_h.m4 serial 43 dnl Copyright (C) 2007-2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -21,7 +21,7 @@ AC_DEFUN([gl_STDLIB_H], #endif ]], [_Exit atoll canonicalize_file_name getloadavg getsubopt grantpt initstate initstate_r mkdtemp mkostemp mkostemps mkstemp mkstemps - posix_openpt ptsname ptsname_r random random_r realpath rpmatch + posix_openpt ptsname ptsname_r qsort_r random random_r realpath rpmatch secure_getenv setenv setstate setstate_r srandom srandom_r strtod strtoll strtoull unlockpt unsetenv]) ]) @@ -85,6 +85,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], HAVE_POSIX_OPENPT=1; AC_SUBST([HAVE_POSIX_OPENPT]) HAVE_PTSNAME=1; AC_SUBST([HAVE_PTSNAME]) HAVE_PTSNAME_R=1; AC_SUBST([HAVE_PTSNAME_R]) + HAVE_QSORT_R=1; AC_SUBST([HAVE_QSORT_R]) HAVE_RANDOM=1; AC_SUBST([HAVE_RANDOM]) HAVE_RANDOM_H=1; AC_SUBST([HAVE_RANDOM_H]) HAVE_RANDOM_R=1; AC_SUBST([HAVE_RANDOM_R]) diff --git a/modules/qsort_r b/modules/qsort_r index 52b57c0..6772edc 100644 --- a/modules/qsort_r +++ b/modules/qsort_r @@ -13,8 +13,10 @@ stdlib configure.ac: gl_FUNC_QSORT_R if test $HAVE_QSORT_R = 0; then + # The function is missing from the system or has an unknown signature. AC_LIBOBJ([qsort]) elif test $REPLACE_QSORT_R = 1; then + # The function exists, but it has the BSD signature. AC_LIBOBJ([qsort_r]) fi gl_STDLIB_MODULE_INDICATOR([qsort_r]) diff --git a/modules/stdlib b/modules/stdlib index cbc5b01..27b1caa 100644 --- a/modules/stdlib +++ b/modules/stdlib @@ -79,6 +79,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's|@''HAVE_POSIX_OPENPT''@|$(HAVE_POSIX_OPENPT)|g' \ -e 's|@''HAVE_PTSNAME''@|$(HAVE_PTSNAME)|g' \ -e 's|@''HAVE_PTSNAME_R''@|$(HAVE_PTSNAME_R)|g' \ + -e 's|@''HAVE_QSORT_R''@|$(HAVE_QSORT_R)|g' \ -e 's|@''HAVE_RANDOM''@|$(HAVE_RANDOM)|g' \ -e 's|@''HAVE_RANDOM_H''@|$(HAVE_RANDOM_H)|g' \ -e 's|@''HAVE_RANDOM_R''@|$(HAVE_RANDOM_R)|g' \