[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

glob-h: Avoid conflict with preprocessor macros owned by the system

From: Bruno Haible
Subject: glob-h: Avoid conflict with preprocessor macros owned by the system
Date: Mon, 07 Jun 2021 00:50:59 +0200
User-agent: KMail/5.1.3 (Linux/4.4.0-210-generic; KDE/5.18.0; x86_64; ; )

Building a testdir created with

  ./gnulib-tool --create-testdir --dir=../testdir --with-c++-tests \
                --without-privileged-tests --single-configure \
                dynarray glob scratch_buffer

on DragonFly BSD 6.0, I see this error:

In file included from ../../gltests/../gllib/libc-config.h:158,
                 from ../gllib/glob.h:581,
                 from ../../gltests/test-glob-h-c++.cc:22:
/usr/include/machine/endian.h:152:17: error: duplicate 'inline'
 static __inline __always_inline __uint64_t
/usr/include/machine/endian.h:162:17: error: duplicate 'inline'
 static __inline __always_inline __uint32_t
/usr/include/machine/endian.h:172:17: error: duplicate 'inline'
 static __inline __always_inline __uint16_t

What happens here is a conflict between the definition of
'__always_inline' in gnulib's <cdefs.h> (included from
glob.h -> libc-config.h -> cdefs.h) and the definition of
'__always_inline' in DragonFly's <sys/cdefs.h>.

In C++ it is invalid to write
  static __inline __inline ... some_function (...) { ... }

The DragonFly headers are consistent: They define
  #define __always_inline __attribute__((__always_inline__))
and use it like this in <machine/endian.h>:
  static __inline __always_inline __uint64_t __bswap64 ...

Gnulib's <cdefs.h> definition of __always_inline is tailored for
glibc sources, which do
  static __always_inline bool ...
Therefore it defines it as
  #define __always_inline __inline __attribute__ ((__always_inline__))

But gnulib's <cdefs.h> *overrides* the system's definition. And it
is visible after any of these header files has been included:


After one of these files has been included, the application can
include any system include file, and these system include files will
typically rely on the system's definition of __* macros from <sys/cdefs.h>.

It's a different thing to include <cdefs.h> for the compilation of
a Gnulib .c file than to expose it through a .h file that the application
can include. In the first case, the Gnulib .c file includes a small set
of system's .h files, and therefore we can hope to have resolved the
possible conflicts in a reasonable amount of time. In the second case,
there is an uncountable number of conflicts; so, this problem will
haunt us for years if we don't fix it.

My fix here is to process the glob-libc.h file so that it does not
rely on __* macros (that belong to the system's namespace), only on
Gnulib macros, which we haven't seen conflict with system headers in
17 years.

When glob-libc.h changes (following merges from glibc), the processing
steps in modules/glob-h might need changes, but they will typically
be small and straightforward.

2021-06-06  Bruno Haible  <bruno@clisp.org>

        glob-h: Avoid conflict with preprocessor macros owned by the system.
        This fixes a compilation error on DragonFly BSD 6.0.
        * lib/glob.in.h: Don't include <libc-config.h>. Don't define __USE_GNU.
        Include glob-libc.gl.h instead of glob-libc.h.
        * modules/glob-h (Makefile.am): Arrange to create glob-libc.gl.h from
        * lib/libc-config.h: Add comment.

diff --git a/lib/glob.in.h b/lib/glob.in.h
index 4952666..dbc5b63 100644
--- a/lib/glob.in.h
+++ b/lib/glob.in.h
@@ -70,10 +70,6 @@ typedef int (*_gl_glob_errfunc_fn) (const char *, int);
 /* Preparations for including the standard GNU C Library header.  */
-# ifndef __attribute_maybe_unused__
-#  include <libc-config.h>
-# endif
 # include <stddef.h>
 /* On some systems, such as AIX 5.1, <sys/stat.h> does a "#define stat stat64".
@@ -81,10 +77,6 @@ typedef int (*_gl_glob_errfunc_fn) (const char *, int);
    rely on 'struct stat'.  */
 # include <sys/stat.h>
-# ifndef __USE_GNU
-#  define __USE_GNU    1
-# endif
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define glob rpl_glob
@@ -102,7 +94,7 @@ typedef int (*_gl_glob_errfunc_fn) (const char *, int);
 /* Now the standard GNU C Library header should work.  */
-# include "glob-libc.h"
+# include "glob-libc.gl.h"
diff --git a/lib/libc-config.h b/lib/libc-config.h
index fabca2f..f68749f 100644
--- a/lib/libc-config.h
+++ b/lib/libc-config.h
@@ -28,7 +28,10 @@
    When compiled as part of glibc this is a no-op; when compiled as
    part of Gnulib this includes Gnulib's <config.h> and defines macros
-   that glibc library code would normally assume.  */
+   that glibc library code would normally assume.
+   Note: This header file MUST NOT be included by public header files
+   of Gnulib.  */
 #include <config.h>
diff --git a/modules/glob-h b/modules/glob-h
index 40df48f..0b71fd2 100644
--- a/modules/glob-h
+++ b/modules/glob-h
@@ -51,6 +51,23 @@ glob.h: $(top_builddir)/config.status
 MOSTLYCLEANFILES += glob.h glob.h-t
+BUILT_SOURCES += glob-libc.gl.h
+glob-libc.gl.h: glob-libc.h
+       $(AM_V_GEN)rm -f $@-t $@ && \
+       { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+         sed -e '/__BEGIN_DECLS/{ s/__BEGIN_DECLS/#ifdef __cplusplus%extern 
"C" {%#endif/; y/%/\n/; }' \
+             -e '/__END_DECLS/{ s/__END_DECLS/#ifdef __cplusplus%}%#endif/; 
y/%/\n/; }' \
+             -e 's|__THROW||g' \
+             -e 's|defined __USE_MISC|1|' \
+             -e 's|ifdef __USE_GNU|if 1|' \
+             -e 's|ifdef __USE_LARGEFILE64|if 0|' \
+             < $(srcdir)/glob-libc.h; \
+       } > $@-t && \
+       mv $@-t $@
+MOSTLYCLEANFILES += glob-libc.gl.h glob-libc.gl.h-t

reply via email to

[Prev in Thread] Current Thread [Next in Thread]