编译一个代码有一个函数gethostbyname的静态二进制文件

如何解决编译一个静态二进制代码包括一个函数gethostbyname,如果编译时没有像这样的警告:

警告:在静态链接的应用程序中使用“gethostbyname”需要在运行时从用于链接的glibc版本的共享库

我使用命令在Ubuntu 12.04上编译:

$ gcc -static lookup.c -o lookup 

这是lookup.c的代码:

  /* lookup.c */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> extern int h_errno; int main(int argc,char **argv) { int x, x2; struct hostent *hp; for ( x=1; x<argc; ++x ) { hp = gethostbyname(argv[x]); if ( !hp ) { fprintf(stderr, "%s: host '%s'\n", hstrerror(h_errno), argv[x]); continue; } printf("Host %s : \n" ,argv[x]); printf(" Officially:\t%s\n", hp->h_name); fputs(" Aliases:\t",stdout); for ( x2=0; hp->h_aliases[x2]; ++x2 ) { if ( x2 ) { fputs(", ",stdout); } fputs(hp->h_aliases[x2],stdout); } fputc('\n',stdout); printf(" Type:\t\t%s\n", hp->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6"); if ( hp->h_addrtype == AF_INET ) { for ( x2=0; hp->h_addr_list[x2]; ++x2 ) { printf(" Address:\t%s\n", inet_ntoa( *(struct in_addr *) hp->h_addr_list[x2])); } } putchar('\n'); } return 0; } 

我想如果我通过$ file lookup检查将得到这样的输出:

查找:对于GNU / Linux 2.6.24,BuildID [sha1] = 0x6fcb2684ad8e5e842036936abb50911cdde47c73,静态链接的ELF 32位LSB可执行文件,Intel 80386,版本1(GNU / Linux)

不是这样的:

查找:为GNU / Linux 2.6.24,BuildID [sha1] = 0xf9f18671751927bea80de676d207664abfdcf5dcdynamic链接(使用共享库)ELF 32位LSB可执行文件,英特尔80386,版本1(SYSV)

如果你评论与build议我必须使用没有静态,因为不同的libc我知道它的每一个Linux,我希望你不需要评论。 为什么我坚持静态? 因为在那里我需要做强制使用静态的,二进制文件必须是静态的而不是dynamic的。

我有超过2周的时间寻找这个,但迄今还没有成功。

谢谢你帮我解决我的沉重的问题。

Solutions Collecting From Web of "编译一个代码有一个函数gethostbyname的静态二进制文件"

你所要求的将是非常困难的。

看到这个关于getaddrinfo的StackOverflow问题 。 基本上, getaddrinfo / gethostbyname是glibc的NSS层。 这允许系统管理员说“使用DNS解析主机名到IP地址”,或者“使用LDAP”,或者“不要使用/etc/hosts以外的任何东西”。 这个控件在运行时 系统管理员可以随时改变主机名解析为IP的方式。

由于这种灵活性,glibc中的所有名称解析调用都使用助手库(基本上是插件)来完成解析的繁琐工作。 有一个用于LDAP寻址的共享库,一个用于文件,一个用于DNS,一个用于YP,等等。

如果你想要你的程序100%静态链接,你将不得不去别处(不gethostbyname )将主机名转换为IP地址。 你可以用像uDNS这样的解析器库来做到这一点 (不是一个确切的 – 有类似的工具可用),但是你应该记住, 你的二进制文件不会在配置不使用DNS的系统上做正确的事情

相反,我会建议离开程序(技术上)动态链接。 如果你真的想确保它能在任何平台上运行,你甚至可以用二进制文件发布glibc – 虽然这样做需要LGPL一致性。 留下这一个动态链接只会意味着你不会在glibc版本错误的系统上工作 – 这不是一个巨大的兼容性问题。

谈到许可证合规性,值得注意的是,如果您静态链接glibc ,则很可能必须为整个应用程序提供源代码,以符合glibc的LGPL许可证。 我不是律师,这不是合格的法律建议,但阅读LGPL很清楚,静态链接glibc应用程序必须是开源的。 看到这个主题的StackOverflow问题 。

我得到相同的警告,并修复它我重新编译glibc。 打开开关--enable-static-nss时,配置使其工作。

我有2个答案 –

  1. 保持你的程序的主要部分是静态链接的,分离出一个函数程序来调用gethostbyname()。 允许后者动态链接。 使用fork然后exec执行这个单独的程序来获取一个域名的地址。 而不是叉,然后exec可以使用system(),尽管它需要更长的时间(整个毫秒),不应该担心,因为你在互联网上搜索域名服务器,这需要一段时间。

  2. 编写源代码来完成DNS,就像我所做的一样。 编译成一个档案(.a)并在静态链接中进行搜索。