From 803e498e869f88d9daceadf143e3360c17cb7410 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Thu, 6 Feb 2020 21:15:04 -0500 Subject: [PATCH] Improve GLib probe against old GLib versions. The glib_check_version function was not available in older versions of glib2, so this is a bad choice for the link test. Let's use g_get_prgname instead, which is available at least as far back as glib 2.0.0. More importantly, with gcc these old glib versions use 'extern inline' in header files and expect GNU inline semantics. This generally does not work with modern gcc, so add an additional configure test which will detect this problem and work around it. --- .gitignore | 29 +++++++++++++------------- atlocal.in | 1 + configure.ac | 4 +--- m4/glib.m4 | 43 +++++++++++++++++++++++++++++++++++--- t/libdummy.c | 2 ++ tests/libs.at | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ testsuite.at | 2 +- 7 files changed, 117 insertions(+), 21 deletions(-) create mode 100644 atlocal.in diff --git a/.gitignore b/.gitignore index ae53a69..88555f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,22 @@ -/config.* -/configure +*.a +*.lo +*.o +.deps +.dirstamp /aclocal.m4 +/atconfig +/atlocal /autom4te.cache +/compile +/config.* +/configure +/depcomp /install-sh /missing -/depcomp -/compile +/package.m4 +/testsuite +/testsuite.deps /testsuite.dir /testsuite.log -/testsuite.deps -/testsuite -/package.m4 -/atconfig -Makefile.in Makefile -.dirstamp -.deps -*.lo -*.o -*.a +Makefile.in diff --git a/atlocal.in b/atlocal.in new file mode 100644 index 0000000..d15e74d --- /dev/null +++ b/atlocal.in @@ -0,0 +1 @@ +: "${CC=@CC@}" diff --git a/configure.ac b/configure.ac index a74cd71..3501428 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,5 @@ AC_CONFIG_TESTDIR([.]) DX_PROG_AUTOTEST AM_CONDITIONAL([HAVE_AUTOTEST], [test x"$dx_cv_autotest_works" = x"yes"]) -AC_CONFIG_FILES([ - Makefile -]) +AC_CONFIG_FILES([Makefile atlocal]) AC_OUTPUT diff --git a/m4/glib.m4 b/m4/glib.m4 index 32d2784..21676a4 100644 --- a/m4/glib.m4 +++ b/m4/glib.m4 @@ -1,4 +1,4 @@ -dnl Copyright © 2009, 2019 Nick Bowler +dnl Copyright © 2009, 2019-2020 Nick Bowler dnl dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2. dnl This is free software: you are free to do what the fuck you want to. @@ -32,14 +32,15 @@ AC_DEFUN([DX_LIB_GLIB2], m4_define([_DX_LIB_GLIB2_TESTHEAD], [#include ])dnl _DX_LIB_GLIB2_VERSION_TEST(m4_split([$1], [\.]))dnl m4_define([_DX_LIB_GLIB2_TESTMAIN], - [const char *v = glib_check_version(2,0,0);])dnl + [const char *v = g_get_prgname();])dnl m4_define([_DX_GLIB_MODULES], [glib])dnl m4_append_uniq_w([_DX_GLIB_MODULES], [$2])dnl m4_map_args_w(m4_defn([_DX_GLIB_MODULES]), [_DX_LIB_GLIB2_MODULE(], [)]) AC_SUBST([GLIB_CFLAGS])dnl AC_SUBST([GLIB_LIBS])dnl -AS_IF([$_dx_lib_glib_search_ok], [$3], [m4_default([$4], [AC_MSG_FAILURE( +AS_IF([$_dx_lib_glib_search_ok], [DX_LIB_GLIB_BUSTED_GNU_INLINE +$3], [m4_default([$4], [AC_MSG_FAILURE( [GLib[]m4_ifnblank([$1], [ version $1 or newer]) is required. The latest version may be found at . m4_newline([DX_LIB_USERFLAG_BLURB([libglib], [GLib])]) @@ -117,3 +118,39 @@ AC_DEFUN([_DX_LIB_GLIB2_VERSION_TEST], [m4_append([_DX_LIB_GLIB2_TESTHEAD], [ [0])) DX_LIB_COMPILE_ERROR([glib version insufficient]) #endif])]) + +dnl Old glib headers expect gcc to provide GNU inline semantics by default. +dnl This is not the case with modern gcc if the language standard is set to +dnl C99 or later. This results is linker failures due to multiple definitions +dnl when two source files include the GLib headers. +dnl +dnl Pre-#defining G_INLINE_FUNC to 'static inline' works to avoid this problem, +dnl so we have configure first test to see if the problem occurs, then test +dnl if this definition fixes it, then AC_DEFINE that if necessary. +AC_DEFUN([DX_LIB_GLIB_BUSTED_GNU_INLINE], +[AC_CACHE_CHECK([whether GLib needs obsolete GNU inline semantics], +[dx_cv_glib_busted_gnu_inline], +[save_CFLAGS=$CFLAGS save_LIBS=$LIBS CFLAGS="$LIBGLIB_CFLAGS $CFLAGS" +LIBS="conftest_bar.$OBJEXT $LIBGLIB_LIBS $save_LIBS" +dx_cv_glib_busted_gnu_inline=unknown +for dx_attempt in no yes; do +AS_CASE([$dx_attempt], +[yes], [DEFTEST='#define G_INLINE_FUNC static inline' +], [DEFTEST= +]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([$DEFTEST +#include +int bar(void) { return 0; }])], +[mv -f conftest.$OBJEXT conftest_bar.$OBJEXT], +[continue]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([$DEFTEST +#include +extern int bar(void);], [return bar();])], +[dx_cv_glib_busted_gnu_inline=$dx_attempt; break]) +rm -f conftest_bar.$OBJEXT +done +CFLAGS=$save_CFLAGS LIBS=$save_LIBS]) +AS_CASE([$dx_cv_glib_busted_gnu_inline], [yes], +[AC_DEFINE([G_INLINE_FUNC], [static inline], + [Define to static inline to work around multiple definitions in old GLib.]) +])]) diff --git a/t/libdummy.c b/t/libdummy.c index 5404a08..4b92f6f 100644 --- a/t/libdummy.c +++ b/t/libdummy.c @@ -1,3 +1,5 @@ /* Stub function definitions to satisfy link tests, as required. */ void discid_new(void) {} void discid_free(void) {} + +void g_get_prgname(void) {} diff --git a/tests/libs.at b/tests/libs.at index ab348de..cc09cea 100644 --- a/tests/libs.at +++ b/tests/libs.at @@ -85,3 +85,60 @@ AT_CHECK_UNQUOTED([cat test], [0], [no ]) AT_CLEANUP + +AT_SETUP([GLib GNU inline workaround]) + +TEST_DUMMY_PKGCONFIG([-I.], [$builddir/t/libdummy.a]) + +# This test will only work if we have a version of GCC that implements +# C99 inline semantics by default. +AT_DATA([a.c], +[[#if __GNUC__ +extern inline void my_dup_fn(void) { } +#endif +int main(void) { return 0; } +]]) +AT_DATA([b.c], +[[#if __GNUC__ +extern inline void my_dup_fn(void) { } +#endif +]]) + +AT_DATA([test.sh.in], +[[#!/bin/sh +@CC@ @CPPFLAGS@ @CFLAGS@ -c a.c || exit 77 +@CC@ @CPPFLAGS@ @CFLAGS@ -c b.c || exit 77 +@CC@ @CFLAGS@ @LDFLAGS@ a.o b.o || exit 0 +exit 77 +]]) + +AT_DATA([glib.h], +[[#define GLIB_CHECK_VERSION(x, y, z) 1 +const char *g_get_prgname(void); +]]) + +TEST_CONFIGURE_AC([[AC_CONFIG_HEADERS([config.h]) +DX_LIB_GLIB2 +AC_CONFIG_FILES([test.sh], [chmod +x test.sh]) +]]) +TEST_AUTORECONF +TEST_CONFIGURE([PKG_CONFIG=$PWD/pkg-config]) +AT_CHECK([./test.sh], [0], [ignore], [ignore]) + +AT_CHECK([grep G_INLINE_FUNC config.h], [0], +[/* #undef G_INLINE_FUNC */ +]) + +cat >>glib.h <<'EOF' +#ifndef G_INLINE_FUNC +# define G_INLINE_FUNC extern inline +#endif +G_INLINE_FUNC void break_things(void) { } +EOF + +TEST_CONFIGURE([PKG_CONFIG=$PWD/pkg-config]) +AT_CHECK([grep G_INLINE_FUNC config.h], [0], +[#define G_INLINE_FUNC static inline +]) + +AT_CLEANUP diff --git a/testsuite.at b/testsuite.at index 3c5fdac..eff4408 100644 --- a/testsuite.at +++ b/testsuite.at @@ -24,7 +24,7 @@ m4_define([TEST_AUTORECONF], [AT_KEYWORDS([autoconf])dnl AT_CHECK([autoreconf -I "$srcdir/m4"], [0], [], [stderr])]) m4_define([TEST_CONFIGURE], [AT_KEYWORDS([configure])dnl -AT_CHECK([./configure $1], [0], [ignore])]) +AT_CHECK([export CC; ./configure $1], [0], [ignore])]) m4_include([tests/macros.at]) m4_include([tests/functions.at]) -- 2.43.0