与在Solaris系统上不同,Linux的libc库中包含了libiconv库中函数的定义,因此在Linux上使用libiconv库相关函数,编译时是不需要显式-liconv的。但最近我的一位同事在某redhat enterprise server 5.6机器上编译程序时却遇到了找不到iconv库函数符号的链接问题,到底是怎样一回事呢?这里分享一下问题查找过程。

一、现场重现

这里借用一下这位同事的测试程序以及那台机器,重现一下问题过程:

/test.c/include

int main(void)

{

int r;

char *sin, *sout;

size_t lenin, lenout;

char *src = "你好!";

char dst[256] = {0};

iconv_t c_pt;

sin = src;

lenin = strlen(src)+1;

sout = dst;

lenout = 256;

if ((c_pt = iconv_open("UTF-8", "GB2312")) == (iconv_t)(-1)){

printf("iconv_open error!. errno[%d].\n", errno);

return -1;

}

if ((r = iconv(c_pt, (char **)&sin, &lenin, &sout, &lenout)) != 0){

printf("iconv error!. errno[%d].\n", r);

return -1;

}

iconv_close(c_pt);

printf("SRC[%s], DST[%s].\n", src, dst);

return 0;

}

根据之前的经验,我们按如下命令编译该程序:$> gcc -g -o test test.c

/tmp/ccyQ5blC.o: In function `main':

/home/tonybai/tmp/test.c:28: undefined reference to `libiconv_open'

/home/tonybai/tmp/test.c:33: undefined reference to `libiconv'

/home/tonybai/tmp/test.c:38: undefined reference to `libiconv_close'

咦,这是咋搞的呢?怎么找不到iconv库的符号!!!显式加上iconv的链接指示再试试。$> gcc -g -o test test.c -liconv

这回编译OK了。的确如那位同事所说出现了怪异的情况。

二、现场取证

惯性思维让我首先提出疑问:难道是这台机器上的libc版本有差异,检查一下libc中是否定义了iconv相关符号。$ nm /lib64/libc.so.6 |grep iconv

000000397141e040 T iconv

000000397141e1e0 T iconv_close

000000397141ddc0 T iconv_open

iconv的函数都定义了呀!怎么会链接不到?

我们再来看看已经编译成功的那个test到底连接到哪个iconv库了。$ ldd test

linux-vdso.so.1 => (0x00007fff77d6b000)

libiconv.so.2 => /usr/local/lib/libiconv.so.2 (0x00002abbeb09e000)

libc.so.6 => /lib64/libc.so.6 (0×0000003971400000)

/lib64/ld-linux-x86-64.so.2 (0×0000003971000000)

哦,系统里居然在/usr/local/lib下面单独安装了一份libiconv。gcc显然是链接到这里的libiconv了,但gcc怎么会链接到这里了呢?

三、大侦探的分析^_^

Gcc到底做了什么呢?我们看看其verbose的输出结果。$ gcc -g -o test test.c -liconv -v

使用内建 specs。

目标:x86_64-redhat-linux

配置为:../configure –prefix=/usr –mandir=/usr/share/man –infodir=/usr/share/info –enable-shared –enable-threads=posix –enable- checking=release –with-system-zlib –enable-__cxa_atexit –disable-libunwind-exceptions –enable-libgcj-multifile –enable-languages=c,c++, objc,obj-c++,java,fortran,ada –enable-java-awt=gtk –disable-dssi –disable-plugin –with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre –with-cpu=generic –host=x86_64-redhat-linux

线程模型:posix

gcc 版本 4.1.2 20080704 (Red Hat 4.1.2-50)

/usr/libexec/gcc/x86_64-redhat-linux/4.1.2/cc1 -quiet -v test.c -quiet -dumpbase test.c -mtune=generic -auxbase test -g -version -o /tmp/ ccypZm0v.s

忽略不存在的目录“/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../x86_64-redhat-linux/include”

#include "…" 搜索从这里开始:

#include 搜索从这里开始:

/usr/local/include

/usr/lib/gcc/x86_64-redhat-linux/4.1.2/include

/usr/include

搜索列表结束。

GNU C 版本 4.1.2 20080704 (Red Hat 4.1.2-50) (x86_64-redhat-linux)

由 GNU C 版本 4.1.2 20080704 (Red Hat 4.1.2-50) 编译。

GGC 准则:–param ggc-min-expand=100 –param ggc-min-heapsize=131072

Compiler executable checksum: ef754737661c9c384f73674bd4e06594

as -V -Qy -o /tmp/ccaqvDgX.o /tmp/ccypZm0v.s

GNU assembler version 2.17.50.0.6-14.el5 (x86_64-redhat-linux) using BFD version 2.17.50.0.6-14.el5 20061020

/usr/libexec/gcc/x86_64-redhat-linux/4.1.2/collect2 –eh-frame-hdr -m elf_x86_64 –hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so. 2 -o test /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o /usr/ lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.1.2 -L/usr/lib/gcc/x86_64-redhat-linux/4.1.2 -L/usr/lib/gcc/ x86_64-redhat-linux/4.1.2/../../../../lib64 -L/lib/../lib64

-L/usr/lib/../lib64 /tmp/ccaqvDgX.o -liconv -lgcc –as-needed -lgcc_s –no-as-needed -lc -lgcc –as-needed -lgcc_s –no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crtn.o

从这个结果来看,gcc在search iconv.h这个头文件时,首先找到的是/usr/local/include/iconv.h,而不是/usr/include/iconv.h。这两个文件有啥不同么?

在/usr/local/include/iconv.h中,我找到如下代码:…

#ifndef LIBICONV_PLUG

#define iconv_open libiconv_open

#endif

extern iconv_t iconv_open (const char* tocode, const char* fromcode);

libiconv_open vs iconv_open,卧槽!!!再对比一下前面编译时输出的错误信息:

/tmp/ccyQ5blC.o: In function `main':

/home/tonybai/tmp/test.c:28: undefined reference to `libiconv_open'

/home/tonybai/tmp/test.c:33: undefined reference to `libiconv'

/home/tonybai/tmp/test.c:38: undefined reference to `libiconv_close'

大侦探醒悟了!大侦探带你还原一下真实情况。

我们在执行gcc -g -o test test.c时, 根据gcc -v中include search dir的顺序,gcc首先search到的是/usr/local/include/iconv.h,而这里iconv_open等函数被预编译器替换成 了libiconv_open等加上了lib前缀的函数,而这些函数符号显然在libc中是无法找到的,libc中只有不带lib前缀的 iconv_open等函数的定义。大侦探也是一时眼拙了,没有细致查看gcc的编译错误信息中的内容,这就是问题所在!

而gcc -g -o test test.c -liconv为何可以顺利编译通过呢?gcc是如何找到/usr/local/lib下的libiconv的呢?大侦探再次为大家还原一下真相。

我们在执行gcc -g -o test test.c -liconv时,gcc同 样首先search到的是/usr/local/include/iconv.h,然后编译test.c源码,ok;接下来启动ld程序进行链接;ld找 到了libiconv,ld是怎么找到iconv的呢,libiconv在/usr/local/lib下,ld显然是到这个目录下search了。我们 通过执行下面命令可以知晓ld的默认搜索路径:$> ld -verbose|grep SEARCH

SEARCH_DIR("/usr/x86_64-redhat-linux/lib64"); SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/x86_64-redhat-linux/lib"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");

ld的默认search路径中有/usr/local/lib(我之前一直是以为/usr/local/lib不是gcc/ld的默认搜索路径的),因此找到libiconv就不足为奇了。方案一:

可以将/usr/local/lib下的那份libiconv卸载掉!

方案二:

gcc 加上 -liconv

方案三:

make编译强制使用libc中的iconv实现了,CCFLAGS = -DLIBICONV_PLUG

red hat linux没有库文件libiconv.so,libiconv库链接问题一则(备忘)相关推荐

  1. 鸟哥的Linux私房菜(基础篇)- Red Hat 6.x旧文件

    Red Hat 6.x旧文件 最近更新日期:2001/11/04 这里的文章是在 1999~2001 年之间写成的,基本上都是鸟哥不成熟的一些操作经验而已,有问题的地方可能不少啊!有兴趣者,请前往Li ...

  2. red hat linux 7.1 使用手册!,Red Hat Linux 7.1使用手册(中)

    摘要:Red Hat Linux 7.1教程 第3章:Red Hat Linux 7.1使用基础 3.1 登录和退出系统 1. 启动系统 通常LILO是安装在MBR上的,计算机启动后,MBR上的程序被 ...

  3. Red Hat Linux 253 实验部分

    RHCE253实验(服务管理) 试验2 域名系统 估计时间: 2个小时 目标: 安装和配置一个DNS服务器 试验的起点: 标准的Red Hat Linux安装 介绍 本次实验指导您通过使用Berkel ...

  4. SimpleScalar的安装方法(Red Hat Linux 9.0,gcc3.2.2环境)

    SimpleScalar的安装方法(Red Hat Linux 9.0,gcc3.2.2环境) 版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究 ...

  5. 在linux中 系统默认,在Red Hat Linux 9中,系统默认的( )用户对整个系统拥有完全的控制权...

    问题: 在Red Hat Linux 9中,系统默认的( )用户对整个系统拥有完全的控制权 更多相关问题 以下属于基金运作信息披露文件的有(). A.基金份额上市交易公告书B.基金资产净值和 基金营销 ...

  6. Red Hat Linux 9.0软件功能

    Red Hat Linux 9.0软件功能 一:桌面 1:X窗口系统 基本软件包 1.XFree86-用于X工作站的基本字体.程序和文档 2.XFree86-100dpi-fonts-用于X窗口系统的 ...

  7. RHCSA/RHCE Red Hat Linux认证学习指南(第6版):EX200 EX300

    <RHCSA/RHCE Red Hat Linux认证学习指南(第6版):EX200 & EX300> 基本信息 原书名:RHCSA/RHCE Red Hat Linux Cert ...

  8. Red Hat Linux 安装教程

    一.下载链接 链接:https://pan.baidu.com/s/1JShQmOrgGG5_uaqPUuaHLg  提取码:ture 二.安装步骤 1.打开虚拟机,单击"创建新的虚拟机&q ...

  9. 《Red Hat Linux命令速查》—— 带你玩转字符游戏

    命令行管理,一个玩转字符的战场! 忽隐忽现的光标  神秘莫测的符号  闪转腾挪的玄机  直捣黄龙的快意 能领略这一切的人,只有你--深谙命令行管理之道的系统管理员和软件开发人员! 命令行之于优秀的系统 ...

  10. Red Hat Linux、rhel 和 Fedora Core 以及 Centos 区别与联系

    1. Red Hat Linux Linux是GNU/Linux的缩写,通常指各种Linux发行版的通称,Red Hat Linux是redhat最早发行的个人版本的linux, 其1.0版本于199 ...

最新文章

  1. kafka-python 停止消费
  2. leetcode 421. Maximum XOR of Two Numbers in an Array | 421. 数组中两个数的最大异或值(位运算,Trie前缀树)
  3. POI操作Excel常用方法总结
  4. MetaWeblog API中文说明
  5. .NET Core 3.0之深入源码理解ObjectPool(二)
  6. 浅谈C++类(7)--析构函数
  7. 一种类的渐进式开发写法
  8. pytorch中的expand()和expand_as()函数--扩展张量中某维数据的尺寸
  9. 如何把备份的bak还原到新的数据库
  10. grafana的前端技术_Grafana开发环境搭建
  11. 解决 el-autocomplete 不显示及没数据时闪一下的问题
  12. 深度学习中batch-size介绍
  13. 今天向你们分享一个表白代码(I LOVE YOU)
  14. jquery复制粘贴
  15. SAP 月末结账步骤
  16. iOS开发通过微信学习hijack(一)函数劫持
  17. tomcat中的过滤器
  18. BUUCTF Crypto BabyRSA
  19. 东营计算机考试,2018年东营市上半年计算机等级考试报名时间
  20. 2021-04-07千里之行始于足下

热门文章

  1. PADS2007添加过孔
  2. 会计专业与计算机专业结合复合型,对会计专业学生学习计算机的建议
  3. 蓝桥杯官网 试题 PREV-274 历届真题 分果果【第十二届】【省赛】【研究生组】【C++】【Java】两种解法
  4. 计算机操作系统-详细版-王道
  5. 计算机操作系统--思维导图
  6. 泛微OA如何重置管理员密码
  7. 高性能mysql之慎用BLOB与TEXT
  8. go 导出 html 报告(使用 hero 预编译 html 模板引擎)
  9. 【开源系列】三国演义LBS (二)游戏策划案
  10. VBoxGuestAdditions.iso无法在virtualbox中正确安装