裁剪 libiconv, 让 OpenWrt 支持 GB2312/GBK

裁剪 libiconv, 让 OpenWrt 支持 GB2312/GBK

iconv库可用于不同字符集之间的转换,比如将 UTF-8 转成 GB2312。在 OpenWrt 中,有libiconv 和 libiconv-full 库,位于:

qca/feeds/packages/libs/libiconv
qca/feeds/packages/libs/libiconv-full

其中 libiconv 是精简版的,libiconv-full 则覆盖了所有的字符集,但是仅仅使用 libiconv-full 库还不能正常的转换中文字符,因为默认情况下 OpenWrt 通过补丁(patch)裁剪掉了很多字符集,其中就包括 GBK/GB2312,所以还需要通过配置才能使用。

在程序中使用iconv,首先,先通过 make menuconfig 打开 libiconv-full,执行:

make menuconfig -> 选择 Libraries -> 选中 libiconv-full

在自己的 Makefile 中引用 libiconv 相关宏,这些宏位于 include/nls.mk 文件中,nls.mk 的内容如下所示:

#
# Copyright (C) 2011-2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

# iconv full
ifeq ($(CONFIG_BUILD_NLS),y)
    ICONV_PREFIX:=$(STAGING_DIR)/usr/lib/libiconv-full
    ICONV_FULL:=1

    INTL_PREFIX:=$(STAGING_DIR)/usr/lib/libintl-full
    INTL_FULL:=1

# iconv stub
else
    ICONV_PREFIX:=$(STAGING_DIR)/usr/lib/libiconv-stub
    ICONV_FULL:=

    INTL_PREFIX:=$(STAGING_DIR)/usr/lib/libintl-stub
    INTL_FULL:=
endif

PKG_CONFIG_DEPENDS += CONFIG_BUILD_NLS
PKG_BUILD_DEPENDS += !BUILD_NLS:libiconv !BUILD_NLS:libintl

ICONV_DEPENDS:=+BUILD_NLS:libiconv-full
ICONV_CFLAGS:=-I$(ICONV_PREFIX)/include
ICONV_CPPFLAGS:=-I$(ICONV_PREFIX)/include
ICONV_LDFLAGS:=-L$(ICONV_PREFIX)/lib

INTL_DEPENDS:=+BUILD_NLS:libintl-full
INTL_CFLAGS:=-I$(INTL_PREFIX)/include
INTL_CPPFLAGS:=-I$(INTL_PREFIX)/include
INTL_LDFLAGS:=-L$(INTL_PREFIX)/lib

TARGET_CFLAGS += $(ICONV_CFLAGS) $(INTL_CFLAGS)
TARGET_CPPFLAGS += $(ICONV_CFLAGS) $(INTL_CPPFLAGS)
TARGET_LDFLAGS += $(ICONV_LDFLAGS) $(INTL_LDFLAGS)

其中需要用到的有 ICONV_DEPENDS, ICONV_LDFLAGS,ICONV_CFLAGS,在自己的Makefile 中添加,如:

...
include $(INCLUDE_DIR)/nls.mk
...
DEPENDS:= $(ICONV_DEPENDS)
...
LDFLAGS += $(ICONV_LDFLAGS) -liconv
CFLAGS  += -I$(ICONV_CFLAGS)

注意到 nls.mk 文件第一条语句

# iconv full
ifeq ($(CONFIG_BUILD_NLS),y)

说明需要先定义 CONFIG_BUILD_NLS 才能使用 iconv-full,该定义需要通过 make menuconfig,执行:

make menuconfig -> 选择 Global build settings -> 选中 Compile with full language support

保存退出后打开 .config 文件,可发现添加了以下配置:

CONFIG_BUILD_NLS=y
...
CONFIG_PACKAGE_libiconv-full=y

此时,在 libiconv-full 默认可以使用的字符集内已经可以进行字符集之间的转换了,比如 UTF-8 -> ASCII,编译并安装:

make package/libiconv-full/{clean,compile,install} 

或全编译安装:

make -j8

编译完成后会新增目录:

package/feeds/packages/libiconv-full

现在 libiconv-full 还不支持 GBK/GB2312,因为被 libiconv-full 的补丁 strip 了,该 patch 位于:

package/feeds/packages/libiconv-full/patch/100-strip_charsets.patch

该 patch 去除了大部分的字符集,除了中文,还包括日文,韩文等,可根据需要裁剪。当然,最直接的就是删除整个 patch(切记先备份),删除后重新编译,会发现已经支持 GB2312/GBK 了:

rm package/feeds/packages/libiconv-full/patch/100-strip_charsets.patch
make package/{clean,compile,install}
make -j8

此时在build_dir/target-*/ 目录下会生成libiconv-1.11.1 目录(版本号不一定相同)。因为它是支持全字符集的,具有一定的参考价值,可以进行备份(下面会用到),这里只需要备份libiconv-1.11.1/lib目录即可。

因为支持所有字符集后,整个库将变得很大,这对小容量 Flash 的系统来说是个大灾难。在这里只让它支持GBK/GB2312即可,即不删除整个 patch,而是对它进行修改。

OpenWrt 使用 quilt 工具管理 patch,所以未安装的先安装 quilt:

sudo apt-get install quilt

关于quilt 的配置和 OpenWrt下使用 quilt 管理 patch 的详情可参考官方文档:

Working with patches

接下来更新补丁 100-strip_charsets.patch:

make package/libiconv-full/{clean,prepare} V=s QUILT=1
cd build_dir/target-*/libiconv-*
quilt series
quilt push 100-strip_charsets.patch

执行命令 quilt push 会列出该补丁修改了哪些文件,还可以通过以下命令查看:

quilt files

可以看到下列文件被修改了:

lib/aliases.gperf
lib/aliases.h
lib/aliases_dos.h
lib/canonical.h
lib/canonical_dos.h
lib/canonical_local.h
lib/converters.h
lib/encodings.def
lib/encodings_dos.def
lib/loop_unicode.h

再通过命令 quilt diff 查看补丁更新的详情,可根据所需字符集(关键字)过滤结果:

quilt diff | grep -E "GBK|gbk|gb2312|GB2312|EUCCN|EUC-CN"

得到以下输出,前面的符号 “-/+” 表示该语句通过补丁被“删除/添加”:

-GB_2312-80, ei_gb2312
-ISO-IR-58, ei_gb2312
-CSISO58GB231280, ei_gb2312
-CHINESE, ei_gb2312
-EUC-CN, ei_euc_cn
-EUCCN, ei_euc_cn
-GB2312, ei_euc_cn
-CSGB2312, ei_euc_cn
-GBK, ei_ces_gbk
-    char stringpool_str183[sizeof("GB2312")];
-    char stringpool_str426[sizeof("GBK")];
-    char stringpool_str483[sizeof("CSGB2312")];
-    char stringpool_str561[sizeof("CSISO58GB231280")];
-    "GB2312",
-    "EUCCN",
-    "EUC-CN",
-    "GBK",
-    "CSGB2312",
-    "CSISO58GB231280",
-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str91, ei_gb2312},
-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str222, ei_gb2312},
-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str345, ei_gb2312},
-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str426, ei_ces_gbk},
-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str561, ei_gb2312},
-#include "gb2312.h"
-#include "gbk.h"
-#include "ces_gbk.h"
-              "csISO58GB231280",        /* IANA */
-            /*"GB2312.1980-0",             X11R6.4 */
-            gb2312,
-            { gb2312_mbtowc, NULL },      { gb2312_wctomb, NULL })
-DEFENCODING(( "EUC-CN",                 /* glibc */
-              "EUCCN",                  /* glibc */
-              "GB2312",                 /* IANA */
-              "csGB2312",               /* IANA */
-DEFENCODING(( "GBK",                    /* IANA, JDK 1.1 */
-            ces_gbk,
-            { ces_gbk_mbtowc, NULL },     { ces_gbk_wctomb, NULL })

接下来就是要恢复GBK/GB2312被删除的部分,具体删除了哪些内容可以对比之前备份的去掉整个patch后生成的源码。修改patch使用命令quilt edit 'file name'

(1)quilt edit lib/aliases.gperf ,在语句MS-EE, ei_cp1250后添加:

GB_2312-80, ei_gb2312
ISO-IR-58, ei_gb2312
CSISO58GB231280, ei_gb2312
CHINESE, ei_gb2312
EUC-CN, ei_euc_cn
EUCCN, ei_euc_cn
GB2312, ei_euc_cn
CN-GB, ei_euc_cn
CSGB2312, ei_euc_cn
GBK, ei_ces_gbk

(2)修改 lib/aliases.h,该文件是由 gperf 工具根据 lib/aliases.gperf 文件生成的,没有安装的先安装该工具:

sudo apt-get install gperf

至于这里如何使用,lib/aliases.h 文件开头的注释已经说明了,使用命令如下覆盖旧文件:

gperf -m 10 lib/aliases.gperf > lib/aliases.h

更多关于 gperf 工具的使用可参考: 使用 gperf 实现高效的 C/C++ 命令行处理

(3)quilt edit lib/converters.h,在最后添加:

typedef struct {
  unsigned short indx; /* index into big table */
  unsigned short used; /* bitmask of used entries */
} Summary16;

#include "gb2312.h"
#include "gbk.h"
#include "euc_cn.h"
#include "ces_gbk.h"

(4)quilt edit lib/encodings.def,在最后添加:

DEFENCODING(( "GB_2312-80",             /* IANA */
              "ISO-IR-58",              /* IANA */
              "csISO58GB231280",        /* IANA */
              "CHINESE",                /* IANA */
            /*"GB2312.1980-0",             X11R6.4 */
            ),
            gb2312,
            { gb2312_mbtowc, NULL },      { gb2312_wctomb, NULL })

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

DEFENCODING(( "GBK",                    /* IANA, JDK 1.1 */
            ),
            ces_gbk,
            { ces_gbk_mbtowc, NULL },     { ces_gbk_wctomb, NULL })

(5)quilt edit lib/loop_unicode.h,去除对unicode_transliterate()函数体的注释,并将函数体中所有的符号/-**-/恢复成正常注释/**/

(6)由于(5)中的unicode_transliterate()会调用函数johab_hangul_decompose(),该函数位于 lib/converters.h中,再次修改 lib/converters.h 文件,添加:

#include "johab_hangul.h"

至此,修改完成,再次通过quilt diff 命令可以发现被删除的有关GB2312/GBK的部分已经恢复。但是还需要更新补丁修改才能最终完成:

quilt refresh

退回到编译目录, 重新编译:

cd ../../..
make package/libiconv-full/update V=s
make package/libiconv-full/{clean,compile} package/index V=s
make package/libiconv-full/install

在编译过程中,如果出现很多警告,并最终编译错误,请勿慌张,找到编译输出信息的第一个error,一般就知道错在哪了,然后根据上述 patch 的修改方法修改之。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值