__USE_KERNEL_IPV6_DEFS 定义问题排查
背景:
想编译一下阿里云iot的 sdk4.0(主要是学习目的),下载后,直接执行make命令,报错信息如下:
: Compiling portfiles/aiot_port/posix_port.c ... In file included from portfiles/aiot_port/posix_port.c:13: ./components/das/src/service/compat/netinet/in.h:506:48: error: ‘struct sockaddr_in6’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror] 506 | extern int bindresvport6 (int __sockfd, struct sockaddr_in6 *__sock_in) | ^~~~~~~~~~~~ cc1: all warnings being treated as errors make: *** [Makefile:42: output/./portfiles/aiot_port/posix_port.o] Error 1
环境:
Ubuntu 20.04 LTS
gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
原因:
sdk将部分GNU C Library的源码放在了源文件路径下,但其实又没放全。导致自带的文件和系统的文件不兼容。看下头文件的声明日期。
sdk内的 netinet/in.h:
/* Copyright (C) 1991-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */
系统目录下的 /usr/include/netinet/in.h
/* Copyright (C) 1991-2020 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */
两者其实都包含了文件 #include <bits/in.h>
主要问题在使用宏定义的判断方式差别。
sdk中:
#ifndef __USE_KERNEL_IPV6_DEFS ..... #endif /* !__USE_KERNEL_IPV6_DEFS */
系统文件中:
#if !__USE_KERNEL_IPV6_DEFS ......#endif /* !__USE_KERNEL_IPV6_DEFS */
而在bits/in.h文件中,其实是不管怎样都定义了该变量的
/* If the application has already included linux/in6.h from a linux-based kernel then we will not define the IPv6 IPPROTO_* defines, in6_addr (nor the defines), sockaddr_in6, or ipv6_mreq. Same for in6_ptkinfo or ip6_mtuinfo in linux/ipv6.h. The ABI used by the linux-kernel and glibc match exactly. Neither the linux kernel nor glibc should break this ABI without coordination. In upstream kernel 56c176c9 the _UAPI prefix was stripped so we need to check for _LINUX_IN6_H and _IPV6_H now, and keep checking the old versions for maximum backwards compatibility. */ #if defined _UAPI_LINUX_IN6_H \ || defined _UAPI_IPV6_H \ || defined _LINUX_IN6_H \ || defined _IPV6_H /* This is not quite the same API since the kernel always defines s6_addr16 and s6_addr32. This is not a violation of POSIX since POSIX says "at least the following member" and that holds true. */ # define __USE_KERNEL_IPV6_DEFS 1 #else # define __USE_KERNEL_IPV6_DEFS 0 #endif
这样会导致sdk中的判断永远为否。
这里面涉及到了,#ifndef 和 #if 的差别,简单讲,#ifndef 只管是否有这个定义,而不管这个值是真是假。而#if就不同了。
总结:
部分系统文件(特别是与其他系统文件相关的)还是不要放在源代码中好,指明最低编译器的版本即可。因为绝大部分编译器都是向后兼容的。除非特别老的代码。