#icu #unicode #localization #native-bindings

rust_icu_uchar

Unicode ICU4C 库的本地绑定。uchar.h

13 个稳定版本 (4 个主要版本)

5.0.0 2024年2月21日
4.2.3 2023年10月6日
4.0.0 2023年5月2日
3.0.0 2022年11月10日
1.0.3 2021年10月13日

#404 in 国际化(i18n)

Apache-2.0

1.5MB
44K SLoC

rust_icu:ICU 库的底层 Rust 语言绑定

项目 描述
测试 Test status
源代码 https://github.com/google/rust_icu
README https://github.com/google/rust_icu/blob/main/README.md
覆盖率 查看报告
文档 https://docs.rs/crate/rust_icu

这是一个针对 C 语言 ICU(即 ICU4C)库的底层本地 Rust 语言绑定的库。

如果您只想快速了解如何下载和安装,请参阅快速入门指南

有关 ICU 库的详细信息,请参阅ICU 项目主页。库源代码可以在GitHub上查看。

此文件的最新版本可在https://github.com/google/rust_icu找到。

这不是一个官方支持的产品。

为什么使用 ICU 包装(而不是做其他任何事情)?

  • Rust 语言的国际化页面确认,Rust 中的 ICU 支持并不完整,因此拥有一个功能齐全的包装器有助于推动技术的进步。

  • 如 Fuchsia 这样的项目已经依赖于 ICU,而 Rust 绑定提供了一个简单的方法来使用 Unicode 算法,而无需承担更多依赖。

  • 与 ICU4X 等项目在接口上的合作可能允许在未来无缝过渡到全 Rust 实现。

仓库结构

该仓库组织为一个 cargo 工作空间。每个 crate 都对应 ICU4C 库 C API 中的相应头文件。有关头文件中函数覆盖的详细信息,请参阅覆盖率报告

crate 描述
rust_icu 顶级 crate。如果您只想使用所有功能,请包含此 crate。
rust_icu_common 常用的绑定低级包装。
rust_icu_intl 实现 ECMA 402 建议的 API。
rust_icu_sys 低级绑定代码
rust_icu_ubrk 支持文本边界分析。实现了来自ICU库的C API头文件 ubrk.h
rust_icu_ucal ICU日历。实现了来自ICU库的C API头文件 ucal.h
rust_icu_ucol 排序支持。实现了来自ICU库的C API头文件 ucol.h
rust_icu_udat ICU日期和时间。实现了来自ICU库的C API头文件 udat.h
rust_icu_udata ICU二进制数据。实现了来自ICU库的C API头文件 udata.h
rust_icu_uenum ICU枚举。实现了来自ICU库的C API头文件 uenum.h。主要包括 UEnumeration 和相关功能。
rust_icu_uformattable 区域设置敏感的列表格式化支持。实现了来自ICU库的C API头文件 uformattable.h。自0.3.1版起。
rust_icu_ulistformatter 区域设置敏感的列表格式化支持。实现了来自ICU库的C API头文件 ulistformatter.h
rust_icu_uloc 区域设置支持。实现了来自ICU库的C API头文件 uloc.h
rust_icu_umsg MessageFormat支持。实现了来自ICU库的C API头文件 umsg.h
rust_icu_unorm2 Unicode规范化支持。实现了来自ICU库的C API头文件 unorm2.h
rust_icu_unum 数字格式化支持。实现了来自ICU库的C API头文件 unum.h
rust_icu_unumberformatter 数字格式化支持(现代)。实现了来自ICU库的C API头文件 unumberformatter.h
rust_icu_upluralrules 区域设置敏感的复数规则支持。实现了来自ICU库的C API头文件 upluralrules.h
rust_icu_ustring ICU字符串。实现了来自ICU库的C API头文件 ustring.h
rust_icu_utext 文本操作。实现了来自ICU库的C API头文件 utext.h
rust_icu_utrans 转写支持。实现了来自ICU库的C API头文件 utrans.h

限制

今天生成的Rust语言绑定方法将语言绑定的可用性限制在可用的C API上。ICU库的C API(在文档中有时称为ICU4C)与ICU C++ API不同。

本库提供的绑定功能适用范围有限,这意味着在某些情况下可能无法直接使用。如果您遇到此类情况,请随时提交错误报告,以便我们修复。欢迎提交拉取请求

我们目前所知的局限性如下:

  • 无法保证功能完全一致。 在 C++ 中实现的一些算法没有 C 等价版本,反之亦然。如果您使用 C++ 库,这通常不会成问题,因为您可以选择任何适合您的 API 表面。但对于 rust 绑定来说,这是一个问题,因为我们目前只能使用 C API。

  • C++ 新算法的实现不一定总是反映在 C API 中,导致 C 和 C++ API 表面之间的功能差异。例如,请参阅此错误以了解说明。

  • 虽然使用 icu_config 功能可能允许您在一定程度上自由地自动生成适合您自己的库版本的绑定,但我们仍然需要维护一个显式支持 ICU 版本列表,以确保包装器稳定。

兼容性

兼容性保证如下:

  1. 对所有感兴趣的功能组合,对过去三个主要 ICU 库版本的自动测试已执行。
  2. 对 docs.rs 系统使用的 ICU 库版本执行自动测试(因此可以构建文档)。
rust_icu 版本 ICU 63.x ICU 70.1 ICU 71.1 ICU 72.1 ICU 73.1 ICU 74.1
3.0
4.0
5.0

功能

rust_icu 库旨在使用 cargo 编译,并启用以下功能之一。使用 cargo 编译允许我们在 rust_icu_sys 库中的自定义 build.rs 文件中进行库检测,并适应您的构建环境。然而,由于并非每个开发环境都会使用相同的设置,我们选择提供某些功能(如下)作为配置选项。

虽然我们的意图是保持以下功能列表与 实际的 Cargo.toml 列表 保持更新,但该列表可能会偶尔过时。

要使用任何功能,您需要在打算使用的所有 rust_icu_* 钩子中激活该功能。未能这样做将导致编译结果令人困惑。

功能 默认? 描述
use-bindgen 如果设置,cargo 将运行 bindgen 以根据已安装的 ICU 库生成绑定。必须将程序 icu-config 放置在 $PATH 中,以便此功能生效。将来可能会有其他自动检测库的方法,例如通过 pkg-config
renaming 如果设置,将带有版本号附加到 ICU 绑定上生成。这在 ICU 中称为“重命名”,通常只有在需要链接到特定 ICU 版本时才需要,例如,为了绕过必须链接不同 ICU 版本的情况。有关重命名的讨论,请参阅ICU 文档当不使用 bindgen 时,必须使用此功能。
icu_config 如果设置,二进制icu-config将被用于配置库。如果您不希望build.rs尝试自动检测构建环境,请关闭此功能。如果您的构建环境以不同的方式配置ICU,则应跳过此功能。此功能仅在使用bindgen功能时才有意义;否则不起作用。
icu_version_in_env 如果设置,将为环境变量RUST_ICU_MAJOR_VERSION_NUMBER中指定的ICU版本创建ICU绑定,该变量在构建时提供给cargo。有关如何使用此功能的详细信息,请参阅下面的部分。此功能仅在未使用bindgen功能时才有意义;否则不起作用。
静态 如果设置,将静态链接ICU库(以及标准C++的动态库)。如果您在非标准目录中有一个ICU构建,可以使用RUST_ICU_LINK_SEARCH_DIR添加一个额外的搜索路径。

先决条件

必需

  • rust_icu源代码

    使用git克隆

    git clone https://github.com/google/rust_icu.git
    
  • rustup

    https://rustup.rs安装。用于设置工具链默认值。这将安装cargo

  • Clang

    您必须安装Clang以访问正确的头文件。

  • ICU库开发环境

    您将需要访问ICU库以将rust_icu绑定链接到。有关如何构建和安装ICU的详细信息,请参阅ICU简介

    有时,ICU库可能已预安装在您的系统上,或者您可以从包管理程序中拉取库。然而,这不一定是你需要链接到正在开发的程序的那个库。简而言之,您有责任在您的系统上的某个地方准备好ICU的开发版本。

    我们有一个可能能帮助您快速入门的快速入门安装,如果您的情况与我们的配置非常相似并且您想从源代码构建ICU。

可选

  • GNU Make,如果您想使用基于make的构建和测试。

    安装GNU Make超出了此文件的范围。请参阅您操作系统的安装说明。

  • docker,如果您决定使用基于docker的构建和测试。

    安装docker超出了此文件的范围,请参阅docker安装说明以获取详细信息。由于安装docker会干扰主机机器,您的公司可能有自己的内部文档,说明如何正确安装docker

  • icu-config实用工具,如果使用icu_config功能。

    您需要在您的系统上安装ICU库,以便二进制icu-config位于您的$PATH中。构建脚本将使用它来发现库设置并生成正确的链接脚本。如果您使用此功能但未找到icu-config

  • bindgen实用工具,如果使用bindgen功能。

    有关如何安装的说明,请参阅bindgen用户指南

  • rustfmt 工具,如果使用了 bindgen 功能。

    有关安装说明,请参阅 https://github.com/rust-lang/rustfmt

测试

运行 rust_icu 测试有几个选项。

Cargo

使用 cargo 构建和测试是构建和测试 Rust 代码的标准方式。

对于 rust_icu 库,您可能会发现您系统上的默认 ICU 开发包非常古老,在这种情况下,您将需要构建自己的 ICU4C 库(下面将介绍)。这将使得需要传递 PKG_CONFIG_PATHLD_LIBRARY_PATH 环境变量来帮助构建代码定位和使用您构建的库,而不是系统默认库。

以下测试都应该构建并通过。请注意,由于所需库位于自定义位置,我们需要在运行测试时设置 LD_LIBRARY_PATH,以及 PKG_CONFIG_PATH

如果您发现您可以使用系统上的默认 ICU 安装,则可以安全地省略这两个库。

env PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig" \
    LD_LIBRARY_PATH="$HOME/local/lib" \
        bash -c 'cargo test'

如果您认为上述方法太过麻烦,可以考虑尝试基于 Docker 的方法。

GNU Make

如果您喜欢使用 GNU 的方式来做事情,您可能会欣赏 GNU Make 方法。

最简单的方法是使用 GNU Make 并运行

make test

如果您正在处理 rust_icu,已经设置了所有开发环境,并希望有一个简短的测试运行方式,则可能想要使用这种方法。

基于 Docker 的

请参阅上面的 可选依赖项部分

要运行 rust_icu 源代码的封闭构建和测试,请发出以下命令

make docker-test

这将运行您本地机器上的基于 Docker 的源代码构建和测试。这是一种测试您的代码是否与特定参考版本的 ICU 一起工作的好方法。

现有技术

已经考虑了许多现有技术。

目前的情况是,我想先自己做一些实验,然后再看看这项工作是否可以整合到上述任何一项努力中。

另请参阅

假设

对于 ICU 绑定,存在几种竞争性方法。然而,根据 Rust 的 RFC 存储库中可用的信息(https://github.com/rust-lang/rfcs/issues/797),Rust 中 ICU 支持的工作似乎仍在进行中。

以下是在创建此库时做出的假设

  • 我们需要一个完整、可重用且易于使用的 ICU 低级库,用于 Rust。

    这意味着我们必须依赖外部 ICU 库,而不是将库本身与绑定代码一起携带。这种模块化允许库的最终用户使用他们选择的 ICU 库,并将其纳入各自的系统中。

  • 不会在库的工作中重新实现 ICU 算法。

    ICU 的重新实现可能需要数千名工程师的年数才能完成。对于像 ICU 这样微妙和复杂的 API,我认为维护单一中央实现可能是更好的投资回报。

    此外,此库的存在并不妨碍重新实现。如果有人想尝试重新实现 ICU,那也很好。

  • 此库应作为 Rust 实现的低级基础。

    低级别的 ICU API 可能不适合最终用户。应该在这些绑定之上构建一个 rust-ful API。将这部分功能细分为 crate 可能是个不错的想法,以符合 Rust 开发者的期望。

    我很乐意重用上述项目中已做出的逻辑分区。

  • 我想探索将现有实现结合起来的方法,以构建一个完整的 Rust ICU 支持。

    希望能够将今天所有可用的 Rust 绑定的优点结合到一个统一的 Rust 库中。我随时可以讨论选项。

    我之所以开始一个独立的项目而不是为“现有艺术”部分中列出的任何项目做出贡献,仅仅是因为我想尝试在 Rust 中生成库会是什么样子。

附加说明

快速入门指南

在开始之前,请确保满足以下先决条件

  • 您已安装 docker 并在您的系统上运行。
  • 您有 GNU Make。
  • 您有 git
  • 您有足够的磁盘空间。构建环境的 Docker 镜像有点大,因此需要几吉字节的空间才能容纳所有这些。
  • 您有互联网连接。

从那里开始,以下命令序列将检出、构建和测试 rust_icu 源代码。

mkdir -p ~/tmp
cd tmp
git clone https://github.com/google/rust_icu
cd rust_icu
make docker-test

您现在可以修改代码和测试。您可以通过运行 make docker-test 重新运行编译和测试循环。

ICU 安装说明

以下说明遵循来自 ICU 仓库 的“树外”构建说明。

假设

以下说明不是自包含的。它们假设

  • 您已经设置好系统,可以有效地遵循 ICU 构建说明。这需要一些前期时间投资。
  • 您可以从源代码构建 ICU,并且您的项目可以访问 ICU 源代码。
  • 您的设置是 Linux,并且有一些非常具体的设置对我来说是有效的。您可能能够将其修改为在您的系统上工作。

编译

mkdir -p $HOME/local
mkdir -p $HOME/tmp
cd $HOME/tmp
git clone https://github.com/unicode-org/icu.git
mkdir icu4c-build
cd icu4c-build
../icu/icu4c/source/runConfigureICU Linux \
  --prefix=$HOME/local \
  --enable-static
make
make install
make doc

如果编译成功完成,目录 $HOME/local/bin 将包含文件 icu-config,这是发现库配置所必需的。

您还可以

make check

来运行单元测试。

如果您将 $HOME/local/bin 添加到 $PATH,或者将 icu-config 移动到您的 $PATH 中列出的目录,您应该已经准备好编译 rust_icu

ICU 重建说明

如果您更改 ICU 库的配置并打算从源代码重新构建库,您可能需要添加一个中间的 make clean 命令。

由于 ICU 构建不是封闭的,这确保了构建目录中没有旧编译过程的残留物。您需要在升级 ICU 库的主要版本时这样做。如果您忘记这样做,您可能会在编译 ICU、链接或运行程序时遇到意外的错误。

针对ICU特定版本的编译

假设

  • 您已选择以下功能集 [重命名,icu_version_in_env]o

或者:

  • 您已手动验证了兼容性矩阵中对于您想要使用的ICU版本和功能集有“是”的标记。

以下是一个测试过的例子。

env PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig" \
    LD_LIBRARY_PATH="$HOME/local/lib" \
    RUST_ICU_MAJOR_VERSION_NUMBER=65 \
        bash -c 'cargo test'

以下是一个尚未测试过的例子,即针对预存的ICU版本66编译rust_icu

env PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig" \
    LD_LIBRARY_PATH="$HOME/local/lib" \
    RUST_ICU_MAJOR_VERSION_NUMBER=66 \
        bash -c 'cargo test'

添加对ICU新版本的支持。

一般来说,只要icu-config方法得到支持,就应能够为ICU库的新版本生成库包装器,前提是底层C API没有太大差异。

支持ICU 65.1的简单方法包括以下步骤。下面,$RUST_ICU_SOURCE_DIR是您提取ICU源代码的目录。

  • 从源代码下载新的ICU版本到$RUST_ICU_SOURCE_DIR
  • 按照例如上面的编译步骤,使用新版本构建ICU库。
  • 从输出目录$RUST_ICU_SOURCE_DIR/target/debug/build/rust_icu_sys-...获取文件lib.rs,将其重命名为lib_66.rs(如果使用ICU版本66,否则添加您使用的版本号)。
  • 将文件保存到目录$RUST_ICU_SOURCE_DIR/rust_icu_sys/bindgen,这是包含预生成源文件的目录。

如果build.rs被修改为包含更多功能,则可能需要重新生成这些文件lib_XX.rs

添加更多绑定

当添加更多ICU包装器时,请确保执行以下操作

  • 检查rust_icu_sys/build.rsrust_icu_sys/bindgen/run_bindgen.sh,将适当的行添加到BINDGEN_SOURCE_MODULES中,然后添加到BINDGEN_ALLOWLIST_FUNCTIONSBINDGEN_ALLOWLIST_TYPES

开启特定功能集进行测试

以下是在ICU 67上运行docker测试的例子,开启了icu_version_in_envrenaming功能,而不是默认功能。请注意,参数主要通过环境变量传递到运行docker-test的容器中。

make DOCKER_TEST_ENV=rust_icu_testenv-67 \
  RUST_ICU_MAJOR_VERSION_NUMBER=67 \
  DOCKER_TEST_CARGO_TEST_ARGS='--no-default-features --features icu_version_in_env,renaming' \
  docker-test

一些说明

  • 环境变量RUST_ICU_MAJOR_VERSION_NUMBER用于功能icu_version_in_env,指示cargo使用文件rust_icu_sys/bindgen/lib_67.rs作为预构建的bindgen源文件,而不是尝试即时生成。
  • 环境变量 DOCKER_TEST_CARGO_TEST_ARGS 用于将命令行参数传递给在 Docker 容器中使用的 cargo test 命令。该环境变量以原始文本形式传递给 cargo test,无需引号,因此环境变量中的单独单词将作为单独的参数传递给 cargo test
  • 环境变量 DOCKER_TEST_ENV 是用于运行测试的 Docker 容器的基名。容器 rust_icu_testenv-67 是一个包含预安装环境,并包含 ICU 67 编译版本的容器镜像。

刷新静态 bindgen 文件

需要 Docker。

定期运行 make static-bindgen,以刷新目录 rust_icu_sys/bindgen 中的静态生成的 bindgen 文件(命名为 lib_XX.rs,其中 XX 是 ICU 版本,例如 67),这些文件在 bindgen 功能关闭时使用。

调用此 make 目标将修改包含较新版本文件 lib_XX.rs 的本地检查。提交一个 pull request 并检查它们。

有关为什么需要此信息,请参阅 bindgen README.md

依赖关系

~0.4–1.1MB
~25K SLoC