Bother those kernel developers. In the latest rawhide, kernel
and glibc have now been unified so that <netinet/in.h> and
<linux/in6.h> no longer clash; but <linux/if_bridge.h> is still
not self-contained. Because of the latest header change, the
build is failing with:
checking for linux/param.h... no
configure: error: You must install kernel-headers in order to compile libvirt with QEMU or
LXC support
with details:
In file included from conftest.c:561:0:
/usr/include/linux/in6.h:71:18: error: field 'flr_dst' has incomplete type
struct in6_addr flr_dst;
We need a workaround to avoid our workaround :)
* configure.ac (KERNEL_HEADERS_WORKAROUND): New test.
* src/util/virnetdevbridge.c (includes): Use it.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
This qualifies as a build-breaker; but last time I pushed a patch
in this area of code without review, it got reverted, so I'll wait
for the review.
I've tested on RHEL 5, RHEL 6, Fedora 19 (all of which have glibc
and kernel differences, although not the same error messages) and
rawhide (where glibc and kernel finally agree, but where the kernel
headers _still_ assume that the caller already declared ipv6 structs).
configure.ac | 38 ++++++++++++++++++++++++++++----------
src/util/virnetdevbridge.c | 24 ++++++++++++++----------
2 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/configure.ac b/configure.ac
index 8426863..8acccdd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1051,18 +1051,36 @@ dnl check for kernel headers required by src/bridge.c
dnl
if test "$with_linux" = "yes"; then
if test "$with_qemu" = "yes" || test "$with_lxc" =
"yes" ; then
+ # Various kernel versions have headers that are not self-standing, but
+ # yet are incompatible with the corresponding glibc headers. In order
+ # to guarantee compilation across a wide range of versions (from RHEL 5
+ # to rawhide), we first have to probe whether glibc and kernel can be
+ # used in tandem; and if not, provide workarounds that ensure that
+ # ABI-compatible IPv6 types are present for use by the kernel headers.
+ # These probes mirror the usage in virnetdevbridge.c
+ AC_CACHE_CHECK([whether kernel and glibc headers are compatible],
+ [lv_cv_kernel_glibc_compatible],
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <netinet/in.h>
+ #include <linux/in6.h>
+ ]])],
+ [lv_cv_kernel_glibc_compatible=yes],
+ [lv_cv_kernel_glibc_compatible=no])])
+ if test "x$lv_cv_kernel_glibc_compatible" != xyes; then
+ AC_DEFINE([KERNEL_HEADERS_WORKAROUND], [1],
+ [define to 1 if Linux kernel headers require a workaround to avoid
+ compilation errors when mixed with glibc headers])
+ fi
AC_CHECK_HEADERS([linux/param.h linux/sockios.h linux/if_bridge.h linux/if_tun.h],,
[AC_MSG_ERROR([You must install kernel-headers in order to compile libvirt with
QEMU or LXC support])],
- [[/* The kernel folks broke their headers when used with particular
- * glibc versions; although the structs are ABI compatible, the
- * C type system doesn't like struct redefinitions. We work around
- * the problem here in the same manner as in virnetdevbridge.c. */
- #include <netinet/in.h>
- #define in6_addr in6_addr_
- #define sockaddr_in6 sockaddr_in6_
- #define ipv6_mreq ipv6_mreq_
- #define in6addr_any in6addr_any_
- #define in6addr_loopback in6addr_loopback_
+ [[#include <netinet/in.h>
+ #if KERNEL_HEADERS_WORKAROUND
+ # define in6_addr in6_addr_
+ # define sockaddr_in6 sockaddr_in6_
+ # define ipv6_mreq ipv6_mreq_
+ # define in6addr_any in6addr_any_
+ # define in6addr_loopback in6addr_loopback_
+ #endif
#include <linux/in6.h>
]])
fi
diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c
index e4daa27..b78ab07 100644
--- a/src/util/virnetdevbridge.c
+++ b/src/util/virnetdevbridge.c
@@ -39,22 +39,26 @@
#ifdef __linux__
# include <linux/sockios.h>
# include <linux/param.h> /* HZ */
+# if KERNEL_HEADERS_WORKAROUND
/* Depending on the version of kernel vs. glibc, there may be a collision
* between <net/in.h> and kernel IPv6 structures. The different types
* are ABI compatible, but choke the C type system; work around it by
* using temporary redefinitions. */
-# define in6_addr in6_addr_
-# define sockaddr_in6 sockaddr_in6_
-# define ipv6_mreq ipv6_mreq_
-# define in6addr_any in6addr_any_
-# define in6addr_loopback in6addr_loopback_
+# define in6_addr in6_addr_
+# define sockaddr_in6 sockaddr_in6_
+# define ipv6_mreq ipv6_mreq_
+# define in6addr_any in6addr_any_
+# define in6addr_loopback in6addr_loopback_
+# endif
# include <linux/in6.h>
# include <linux/if_bridge.h> /* SYSFS_BRIDGE_ATTR */
-# undef in6_addr
-# undef sockaddr_in6
-# undef ipv6_mreq
-# undef in6addr_any
-# undef in6addr_loopback
+# if KERNEL_HEADERS_WORKAROUND
+# undef in6_addr
+# undef sockaddr_in6
+# undef ipv6_mreq
+# undef in6addr_any
+# undef in6addr_loopback
+# endif
# define JIFFIES_TO_MS(j) (((j)*1000)/HZ)
# define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000)
--
1.8.3.1