裁剪libiconv-1.8

    由於工作需要,在我的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_cn
EUCCN, ei_euc_cn
GB2312, ei_euc_cn
CN-GB, ei_euc_cn
CSGB2312, ei_euc_cn
其他的行全部刪掉了,然後保存,修改後的aliases.gperf文件如下所示:

struct alias { const char* name; unsigned int encoding_index; };
%%
US-ASCII, ei_ascii
ASCII, ei_ascii
ISO646-US, ei_ascii
ISO_646.IRV:1991, ei_ascii
ISO-IR-6, ei_ascii
ANSI_X3.4-1968, ei_ascii
ANSI_X3.4-1986, ei_ascii
CP367, ei_ascii
IBM367, ei_ascii
US, ei_ascii
CSASCII, ei_ascii
UTF-8, ei_utf8
UCS-2, ei_ucs2
ISO-10646-UCS-2, ei_ucs2
CSUNICODE, ei_ucs2
UCS-2BE, ei_ucs2be
UNICODEBIG, ei_ucs2be
UNICODE-1-1, ei_ucs2be
CSUNICODE11, ei_ucs2be
UCS-2LE, ei_ucs2le
UNICODELITTLE, ei_ucs2le
UCS-4, ei_ucs4
ISO-10646-UCS-4, ei_ucs4
CSUCS4, ei_ucs4
UCS-4BE, ei_ucs4be
UCS-4LE, ei_ucs4le
UTF-16, ei_utf16
UTF-16BE, ei_utf16be
UTF-16LE, ei_utf16le
UTF-32, ei_utf32
UTF-32BE, ei_utf32be
UTF-32LE, ei_utf32le
UTF-7, ei_utf7
UNICODE-1-1-UTF-7, ei_utf7
CSUNICODE11UTF7, ei_utf7
UCS-2-INTERNAL, ei_ucs2internal
UCS-2-SWAPPED, ei_ucs2swapped
UCS-4-INTERNAL, ei_ucs4internal
UCS-4-SWAPPED, ei_ucs4swapped
C99, ei_c99
JAVA, ei_java
ISO-8859-1, ei_iso8859_1
ISO_8859-1, ei_iso8859_1
ISO_8859-1:1987, ei_iso8859_1
ISO-IR-100, ei_iso8859_1
CP819, ei_iso8859_1
IBM819, ei_iso8859_1
LATIN1, ei_iso8859_1
L1, ei_iso8859_1
CSISOLATIN1, ei_iso8859_1
EUC-CN, ei_euc_cn
EUCCN, ei_euc_cn
GB2312, ei_euc_cn
CN-GB, ei_euc_cn
CSGB2312, 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.map
CFLAGS      = -Wl,-Map,$(MAPFILE) 
LDLIBS          = -lpthread ./libiconv-1.8/lib/libiconv.a

TGT         = 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 all

all: $(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 $<

發佈了20 篇原創文章 · 獲贊 8 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章