裁剪libiconv-1.8

来源:互联网 发布:掉头发怎么办知乎 编辑:程序博客网 时间:2024/06/05 14:55

    由于工作需要,在我的powerpc嵌入式板子上需要用到iconv库函数把UTF-8转化为GB2312,但是可能是因为gcc库中自带的iconv不完善,导致转化结果始终为空(相同的代码在我的linux主机上运行就一切正常)。于是就打算自己下载一个libiconv库交叉编译来使用。

    从网上下载了libiconv-1.14,编译后发现生成的库文件有1.2M之多,感觉太大了,自己认为在库中数据占很大部分,因为iconv支持世界上几乎所有常见语言的编码转换,但是我只需要UTF-8转换为GB2312,所以有必要裁剪一下。

    在对libiconv-1.14裁剪时遇到了很多错误,特别是canonical.h的一大串错误,感觉canonical.h是由其它地方生成的文件,不太好解决,于是决定下载个低版本的libiconv试试,结果还真成功了,下面写一下自己裁剪的过程。

1. 从GNU网站下载libiconv-1.8.tar.gz (http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.8.tar.gz 或者 交大开源镜像http://mirror.bjtu.edu.cn/gnu/libiconv/libiconv-1.8.tar.gz)

2. 下载后解压缩,进入libiconv-1.8目录。

    cd libiconv-1.8

    新建一个目录作为安装路径:    

    mkdir iconv

3.修改源文件。

    需要修改的文件只有两个,都在lib目录下,一个为aliases.gperf,另一个为encodings.def。

    首先打开aliases.gperf,自上到下,直到CSISOLATIN1, ei_iso8859_1这一行,这些是需要保留的,然后剩下的就可以自由裁减了。

    由于我只需要GB2312,所以后面的部分我只保留了下面几行:

EUC-CN, ei_euc_cnEUCCN, ei_euc_cnGB2312, ei_euc_cnCN-GB, ei_euc_cnCSGB2312, ei_euc_cn
其他的行全部删掉了,然后保存,修改后的aliases.gperf文件如下所示:

struct alias { const char* name; unsigned int encoding_index; };%%US-ASCII, ei_asciiASCII, ei_asciiISO646-US, ei_asciiISO_646.IRV:1991, ei_asciiISO-IR-6, ei_asciiANSI_X3.4-1968, ei_asciiANSI_X3.4-1986, ei_asciiCP367, ei_asciiIBM367, ei_asciiUS, ei_asciiCSASCII, ei_asciiUTF-8, ei_utf8UCS-2, ei_ucs2ISO-10646-UCS-2, ei_ucs2CSUNICODE, ei_ucs2UCS-2BE, ei_ucs2beUNICODEBIG, ei_ucs2beUNICODE-1-1, ei_ucs2beCSUNICODE11, ei_ucs2beUCS-2LE, ei_ucs2leUNICODELITTLE, ei_ucs2leUCS-4, ei_ucs4ISO-10646-UCS-4, ei_ucs4CSUCS4, ei_ucs4UCS-4BE, ei_ucs4beUCS-4LE, ei_ucs4leUTF-16, ei_utf16UTF-16BE, ei_utf16beUTF-16LE, ei_utf16leUTF-32, ei_utf32UTF-32BE, ei_utf32beUTF-32LE, ei_utf32leUTF-7, ei_utf7UNICODE-1-1-UTF-7, ei_utf7CSUNICODE11UTF7, ei_utf7UCS-2-INTERNAL, ei_ucs2internalUCS-2-SWAPPED, ei_ucs2swappedUCS-4-INTERNAL, ei_ucs4internalUCS-4-SWAPPED, ei_ucs4swappedC99, ei_c99JAVA, ei_javaISO-8859-1, ei_iso8859_1ISO_8859-1, ei_iso8859_1ISO_8859-1:1987, ei_iso8859_1ISO-IR-100, ei_iso8859_1CP819, ei_iso8859_1IBM819, ei_iso8859_1LATIN1, ei_iso8859_1L1, ei_iso8859_1CSISOLATIN1, ei_iso8859_1EUC-CN, ei_euc_cnEUCCN, ei_euc_cnGB2312, ei_euc_cnCN-GB, ei_euc_cnCSGB2312, ei_euc_cn

    下面修改encodings.def,这个根据刚才修改的aliases.gperf来修改。自上而下,直到  

DEFENCODING(( "ISO-8859-1",             /* IANA */              "ISO_8859-1",             /* IANA */              "ISO_8859-1:1987",        /* IANA */              "ISO-IR-100",             /* IANA */              "CP819",                  /* IANA */              "IBM819",                 /* IANA */              "LATIN1",                 /* IANA */              "L1",                     /* IANA */              "csISOLatin1",            /* IANA */            /*"ISO8859-1",                 X11R6.4, glibc */            /*"ISO8859_1",                 JDK 1.1 */            ),            iso8859_1,            { iso8859_1_mbtowc, NULL },   { iso8859_1_wctomb, NULL })

    这一部分,上面所有的是需要保留的(包括这一部分)。后面再保留:

DEFENCODING(( "EUC-CN",                 /* glibc */              "EUCCN",                  /* glibc */              "GB2312",                 /* IANA */              "CN-GB",                  /* RFC 1922 */              "csGB2312",               /* IANA */            /*"EUC_CN",                    JDK 1.1 */            ),            euc_cn,            { euc_cn_mbtowc, NULL },      { euc_cn_wctomb, NULL })

   这个是关于GB2312编码的。剩余的部分可以全部删除了,这与aliases.gperf对应起来了。

4. 由aliases.gperf重新生成aliases.h。

    aliases.gperf文件的目的是为了生成aliases.h。打开aliases.h,发现前面几行有些注释:

    /* ANSI-C code produced by gperf version 3.0.3 */
    /* Command-line: gperf -t -L ANSI-C -H aliases_hash -N aliases_lookup -G -W aliases -7 -C -k '1,3-11,$' -i 1 aliases.gperf  */

   看到了生成aliases.h的命令行,于是在lib目录下,执行:

    gperf -t -L ANSI-C -H aliases_hash -N aliases_lookup -G -W aliases -7 -C -k '1,3-11,$' -i 1 aliases.gperf > aliases.h

    便可以了。

3. 配置,编译

    进入libiconv-1.81的根目录,执行

    ./configure CC=powerpc-linux-gcc --target=powerpc-linux --host=powerpc-linux --enable-shared=yes --enable-static=yes --prefix=/opt/externel/libiconv-1.8/iconv

    配置完成后,make;make install便可以了。

最后在iconv/lib目录下生成了我所需要的动态库和静态库(libiconv.so.2.1.0和libiconv.a)。

没有精简之前,生成的libiconv.so.2.1.0有1.1M,精简后只有220K。

注:上面配置过程中,--enable-static=yes是为了生成静态库libiconv.a,这样我在编译自己的程序时可以静态链接libiconv.a,把代码编译到自己的可执行程序中,就不再需要在运行时链接libiconv.so.2.1.0库了。

注:在使用时一定要用双引号包含头文件,不要用尖括号,否则编译器可能引用默认的库,导致执行时出问题(因为我的系统库glibc iconv这部分有问题)

#include "libiconv-1.8/include/iconv.h"

附我的转换函数:

#include <stdio.h>#include <string.h>#include <errno.h>#include "libiconv-1.8/include/iconv.h"/* 汉字UTF8编码到GB2312编码的转换函数* 本函数只支持单个汉字的转换* inbuf 汉字的UTF8编码存储区* outbuf 转换完成后存储GB2312编码的缓冲区* out_size outbuf的长度* 返回值:成功则返回outbuf,失败返回NULL** 注意:常用汉字UTF8编码长度为3个字节,本函数只支持3个字节*         转换完成后的GB2312编码长度为2字节,因此outbuf长度至少为3个字节*/static char* hz_utf8_to_gb2312_single(const char *inbuf,char *outbuf, size_t out_size){    char ** __restrict__ src = (char ** )&inbuf;    char *dest = outbuf;    size_t in_size = 3,size;    iconv_t cd;//    printf("%s:0x%X 0x%X 0x%X\n",__func__,//           (unsigned char)inbuf[0], (unsigned char)inbuf[1],(unsigned char)inbuf[2]);    if(out_size < 3)    {        printf("%s: out_size too small\n",__func__,strerror(errno));        return NULL;    }    memset(outbuf,0,3);    cd = iconv_open("GB2312","UTF-8");    if(cd < 0)    {        printf("%s: iconv_open error:%s\n",__func__,strerror(errno));        return NULL;    }    size = iconv(cd,src,&in_size,&dest,&out_size);    if(size < 0)    {        iconv_close(cd);        printf("%s: iconv error:%s\n",__func__,strerror(errno));        return NULL;    }    iconv_close(cd);//    printf("%s: 0x%X 0x%X\n",__func__,(unsigned char)outbuf[0],(unsigned char)outbuf[1]);    return outbuf;}


Makefile:

# ---------------------------------------------------------------------------# platform dependencies# ---------------------------------------------------------------------------CC          = powerpc-linux-gcc CXX         = powerpc-linux-g++# ---------------------------------------------------------------------------# project specifics# ---------------------------------------------------------------------------MAPFILE         = iconv_test.mapCFLAGS      = -Wl,-Map,$(MAPFILE) LDLIBS          = -lpthread ./libiconv-1.8/lib/libiconv.aTGT         = iconv_test CSRC        = iconv_test.c OBJS        = $(CSRC:.c=.o) $(ASRC:.S=.o)DEPS        = $(OBJS:.o=.d) $(NOLINK_OBJS:.o=.d)BIN         = $(TGT).PHONY: clean allall: $(BIN)$(BIN): $(OBJS)        $(CC) $(CFLAGS) $(OBJS) $(LDLIBS) -o $@clean:        rm -f $(DEPS)        rm -f $(OBJS) $(NOLINK_OBJS)        rm -f $(BIN)        rm -f $(MAPFILE)# ---------------------------------------------------------------------------# rules for code generation# ---------------------------------------------------------------------------%.o:    %.c        $(CC) $(CFLAGS) -o $@ -c $<%.o:    %.S        $(CC) $(ASFLAGS) -o $@ -c $<

0 0