Gary V. Vaughan wrote: >> ix86 RHEL 4 gcc 3.4.6 (test-fcntl-h-c++.cc compile failed: >> 133: symbol `mknod' already defined) >> x86_64 RHEL 4i gcc 3.4.6 (test-fcntl-h-c++.cc compile failed: >> 124: symbol `mknod' already defined >> 149: symbol `lstat' already defined >> 172: symbol `fstat' already defined)
The problem is here is a combination of the glibc headers and the name mangling in g++ versions < 4.3. glibc's <sys/stat.h> defines mknod et al. as inline functions. Also, glibc's <fcntl.h> include <sys/stat.h> inside an extern "C" block. This is usually frowned upon, and here leads to the error. It leads to a compilation unit that essentially looks like this: ============================================================================================= extern "C" { extern "C" { extern int mknod (__const char *__path, unsigned int __mode, unsigned long int __dev) throw () __attribute__ ((__nonnull__ (1))); extern int __xmknod (int __ver, __const char *__path, unsigned int __mode, unsigned long int *__dev) throw () __attribute__ ((__nonnull__ (2, 4))); extern __inline__ int mknod (__const char *__path, unsigned int __mode, unsigned long int __dev) throw () { return __xmknod (0, __path, __mode, &__dev); } } namespace gnulib { static int (*mknod) (char const *file, unsigned int mode, unsigned long int dev) = ::mknod; } extern "C" int _gl_cxxalias_dummy; extern __typeof__ (mknod) mknod; } int (*global_mknod) (__const char *__path, unsigned int __mode, unsigned long int __dev) = gnulib::mknod; ============================================================================================= When you compile this with a g++ version < 4.3 and no optimization, you will see that in the .s file the label 'mknod' is defined twice: $ g++ -S bug.cc && grep mknod bug.s .long _GLOBAL__I_global_mknod movl mknod, %eax movl %eax, global_mknod .type _GLOBAL__I_global_mknod, @function _GLOBAL__I_global_mknod: .size _GLOBAL__I_global_mknod, .-_GLOBAL__I_global_mknod .section .text.mknod,"axG",@progbits,mknod,comdat .weak mknod .type mknod, @function mknod: call __xmknod .size mknod, .-mknod .globl global_mknod .type global_mknod, @object .size global_mknod, 4 global_mknod: .type mknod, @object .size mknod, 4 mknod: .long mknod The fix is to remove the extern "C" { ... } bracket around the namespace gnulib { ... } portion of the code. When this is done, the variable 'gnulib::mknod' gets the name mangling _ZN6gnulib5mknodE instead of plain mknod. 2010-11-11 Bruno Haible <br...@clisp.org> fcntl-h: Fix for use of C++ on glibc systems. * lib/fcntl.in.h: Include <sys/stat.h> before include_next <fcntl.h> also on glibc systems in C++ mode. Reported by Gary V. Vaughan <g...@gnu.org>. 2--- lib/fcntl.in.h.orig Fri Nov 12 03:19:39 2010 +++ lib/fcntl.in.h Fri Nov 12 03:18:45 2010 @@ -26,7 +26,13 @@ /* Special invocation convention. */ #include <sys/types.h> -#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */ +/* On some systems other than glibc, <sys/stat.h> is a prerequisite of + <fcntl.h>. On glibc systems, we would like to avoid namespace pollution. + But on glibc systems, <fcntl.h> includes <sys/stat.h> inside an + extern "C" { ... } block, which leads to errors in C++ mode with the + overridden <sys/stat.h> from gnulib. These errors are known to be gone + with g++ version >= 4.3. */ +#if !defined __GLIBC__ || (defined __cplusplus && defined GNULIB_NAMESPACE && !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) # include <sys/stat.h> #endif #...@include_next@ @NEXT_FCNTL_H@