This patch removes the need to link with -lpthread on several platforms, by using the "weak symbols" trick from lock.h. With this, the only platform on which setlocale-null requires -lpthread is AIX.
2019-12-16 Bruno Haible <br...@clisp.org> setlocale-null: Remove need for -lpthread on musl libc, *BSD, Haiku. Reported by Arnold Robbins <arn...@skeeve.com>. * lib/setlocale_null.c (c11_threads_in_use, pthread_in_use): New macros, copied from lib/glthread/lock.h. (pthread_mutex_lock, pthread_mutex_unlock): Mark as weak. (setlocale_null_with_lock): If pthread_in_use() is false, use setlocale_null_unlocked directly. * m4/threadlib.m4 (gl_WEAK_SYMBOLS): New macro, extracted from gl_THREADLIB_BODY. Define HAVE_WEAK_SYMBOLS. (gl_THREADLIB_BODY): Invoke gl_WEAK_SYMBOLS. * m4/setlocale_null.m4 (gl_FUNC_SETLOCALE_NULL): Invoke gl_WEAK_SYMBOLS. Set LIB_SETLOCALE_NULL to empty if weak symbols are supported. * m4/duplocale.m4 (gl_FUNC_DUPLOCALE): Add comment. diff --git a/lib/setlocale_null.c b/lib/setlocale_null.c index b0506b9..350eca7 100644 --- a/lib/setlocale_null.c +++ b/lib/setlocale_null.c @@ -30,12 +30,25 @@ #if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) # if defined _WIN32 && !defined __CYGWIN__ + # define WIN32_LEAN_AND_MEAN /* avoid including junk */ # include <windows.h> + # elif HAVE_PTHREAD_API + # include <pthread.h> +# if HAVE_THREADS_H && HAVE_WEAK_SYMBOLS +# include <threads.h> +# pragma weak thrd_exit +# define c11_threads_in_use() (thrd_exit != NULL) +# else +# define c11_threads_in_use() 0 +# endif + # elif HAVE_THREADS_H + # include <threads.h> + # endif #endif @@ -100,7 +113,7 @@ setlocale_null_unlocked (int category, char *buf, size_t bufsize) #endif } -#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) +#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin */ /* Use a lock, so that no two threads can invoke setlocale_null_unlocked at the same time. */ @@ -125,7 +138,7 @@ setlocale_null_with_lock (int category, char *buf, size_t bufsize) return ret; } -# elif HAVE_PTHREAD_API +# elif HAVE_PTHREAD_API /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin */ extern # if defined _WIN32 || defined __CYGWIN__ @@ -133,19 +146,40 @@ extern # endif pthread_mutex_t *gl_get_setlocale_null_lock (void); +# if HAVE_WEAK_SYMBOLS /* musl libc, FreeBSD, NetBSD, OpenBSD, Haiku */ + + /* Avoid the need to link with '-lpthread'. */ +# pragma weak pthread_mutex_lock +# pragma weak pthread_mutex_unlock + + /* Determine whether libpthread is in use. */ +# pragma weak pthread_mutexattr_gettype + /* See the comments in lock.h. */ +# define pthread_in_use() \ + (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) + +# else +# define pthread_in_use() 1 +# endif + static int setlocale_null_with_lock (int category, char *buf, size_t bufsize) { - pthread_mutex_t *lock = gl_get_setlocale_null_lock (); - int ret; + if (pthread_in_use()) + { + pthread_mutex_t *lock = gl_get_setlocale_null_lock (); + int ret; - if (pthread_mutex_lock (lock)) - abort (); - ret = setlocale_null_unlocked (category, buf, bufsize); - if (pthread_mutex_unlock (lock)) - abort (); + if (pthread_mutex_lock (lock)) + abort (); + ret = setlocale_null_unlocked (category, buf, bufsize); + if (pthread_mutex_unlock (lock)) + abort (); - return ret; + return ret; + } + else + return setlocale_null_unlocked (category, buf, bufsize); } # elif HAVE_THREADS_H diff --git a/m4/duplocale.m4 b/m4/duplocale.m4 index 3900b53..a2ac467 100644 --- a/m4/duplocale.m4 +++ b/m4/duplocale.m4 @@ -115,6 +115,8 @@ int main () else LIB_DUPLOCALE= fi + dnl LIB_DUPLOCALE is expected to be '-pthread' or '-lpthread' on AIX + dnl with gcc or xlc, and empty otherwise. AC_SUBST([LIB_DUPLOCALE]) ]) diff --git a/m4/setlocale_null.m4 b/m4/setlocale_null.m4 index 5c69a3f..eff6e76 100644 --- a/m4/setlocale_null.m4 +++ b/m4/setlocale_null.m4 @@ -1,4 +1,4 @@ -# setlocale_null.m4 serial 1 +# setlocale_null.m4 serial 2 dnl Copyright (C) 2019 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -75,10 +75,18 @@ AC_DEFUN([gl_FUNC_SETLOCALE_NULL], if test $SETLOCALE_NULL_ALL_MTSAFE = 0 || test $SETLOCALE_NULL_ONE_MTSAFE = 0; then case "$host_os" in mingw*) LIB_SETLOCALE_NULL= ;; - *) LIB_SETLOCALE_NULL="$LIBPTHREAD" ;; + *) + gl_WEAK_SYMBOLS + case "$gl_cv_have_weak" in + *yes) LIB_SETLOCALE_NULL= ;; + *) LIB_SETLOCALE_NULL="$LIBPTHREAD" ;; + esac + ;; esac else LIB_SETLOCALE_NULL= fi + dnl LIB_SETLOCALE_NULL is expected to be '-pthread' or '-lpthread' on AIX + dnl with gcc or xlc, and empty otherwise. AC_SUBST([LIB_SETLOCALE_NULL]) ]) diff --git a/m4/threadlib.m4 b/m4/threadlib.m4 index d6e6bf9..96c74c1 100644 --- a/m4/threadlib.m4 +++ b/m4/threadlib.m4 @@ -1,4 +1,4 @@ -# threadlib.m4 serial 23 +# threadlib.m4 serial 24 dnl Copyright (C) 2005-2019 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -142,6 +142,57 @@ changequote([,])dnl fi ]) +dnl Checks whether the compiler and linker support weak declarations of symbols. + +AC_DEFUN([gl_WEAK_SYMBOLS], +[ + AC_CACHE_CHECK([whether imported symbols can be declared weak], + [gl_cv_have_weak], + [gl_cv_have_weak=no + dnl First, test whether the compiler accepts it syntactically. + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[extern void xyzzy (); +#pragma weak xyzzy]], + [[xyzzy();]])], + [gl_cv_have_weak=maybe]) + if test $gl_cv_have_weak = maybe; then + dnl Second, test whether it actually works. On Cygwin 1.7.2, with + dnl gcc 4.3, symbols declared weak always evaluate to the address 0. + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include <stdio.h> +#pragma weak fputs +int main () +{ + return (fputs == NULL); +}]])], + [gl_cv_have_weak=yes], + [gl_cv_have_weak=no], + [dnl When cross-compiling, assume that only ELF platforms support + dnl weak symbols. + AC_EGREP_CPP([Extensible Linking Format], + [#ifdef __ELF__ + Extensible Linking Format + #endif + ], + [gl_cv_have_weak="guessing yes"], + [gl_cv_have_weak="guessing no"]) + ]) + fi + dnl But when linking statically, weak symbols don't work. + case " $LDFLAGS " in + *" -static "*) gl_cv_have_weak=no ;; + esac + ]) + case "$gl_cv_have_weak" in + *yes) + AC_DEFINE([HAVE_WEAK_SYMBOLS], [1], + [Define to 1 if the compiler and linker support weak declarations of symbols.]) + ;; + esac +]) + dnl The guts of gl_PTHREADLIB. Needs to be expanded only once. AC_DEFUN([gl_PTHREADLIB_BODY], @@ -242,45 +293,7 @@ AC_DEFUN([gl_THREADLIB_BODY], LTLIBMULTITHREAD= if test "$gl_use_threads" != no; then dnl Check whether the compiler and linker support weak declarations. - AC_CACHE_CHECK([whether imported symbols can be declared weak], - [gl_cv_have_weak], - [gl_cv_have_weak=no - dnl First, test whether the compiler accepts it syntactically. - AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [[extern void xyzzy (); -#pragma weak xyzzy]], - [[xyzzy();]])], - [gl_cv_have_weak=maybe]) - if test $gl_cv_have_weak = maybe; then - dnl Second, test whether it actually works. On Cygwin 1.7.2, with - dnl gcc 4.3, symbols declared weak always evaluate to the address 0. - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ -#include <stdio.h> -#pragma weak fputs -int main () -{ - return (fputs == NULL); -}]])], - [gl_cv_have_weak=yes], - [gl_cv_have_weak=no], - [dnl When cross-compiling, assume that only ELF platforms support - dnl weak symbols. - AC_EGREP_CPP([Extensible Linking Format], - [#ifdef __ELF__ - Extensible Linking Format - #endif - ], - [gl_cv_have_weak="guessing yes"], - [gl_cv_have_weak="guessing no"]) - ]) - fi - dnl But when linking statically, weak symbols don't work. - case " $LDFLAGS " in - *" -static "*) gl_cv_have_weak=no ;; - esac - ]) + gl_WEAK_SYMBOLS if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then dnl If we use weak symbols to implement pthread_in_use / pth_in_use / dnl thread_in_use, we also need to test whether the ISO C 11 thrd_create