#icu #localization #unicode #native-bindings #build-environment

rust_icu_unum

Unicode ICU4C 库的本地绑定。 - ufmt.h:数字格式化支持

19 个版本 (稳定)

5.0.0 2024 年 2 月 21 日
4.2.3 2023 年 10 月 6 日
4.0.0 2023 年 5 月 2 日
3.0.0 2022 年 11 月 10 日
0.4.1 2020 年 10 月 29 日

#394 in 国际化 (i18n)

Download history 16/week @ 2024-04-02 2/week @ 2024-05-21 9/week @ 2024-05-28 7/week @ 2024-06-04 5/week @ 2024-06-11

173 每月下载量
用于 2 crates

Apache-2.0

1.5MB
46K 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 (即 ICU4C) 的 Unicode 国际组件 (ICU) 库的底层 Rust 语言绑定的库。

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

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

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

这不是官方支持的 Google 产品。

为什么封装 ICU(而不是做其他事情)?

  • Rust 语言的 国际化 页面确认,Rust 中的 ICU 支持参差不齐,因此拥有一个功能性的封装有助于推进技术水平。

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

  • ICU4X 等项目的接口合作将允许在未来无缝过渡到全部 Rust 实现中。

仓库结构

该仓库按照Rust crates的货运工作空间组织。每个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 支持区域敏感的列表格式化。自0.3.1起实现了来自ICU库的C API头文件uformattable.h
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
重命名 如果设置,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。

可选

  • 如果想要使用基于make的构建和测试,则需要GNU 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仓库中的信息,至少在表面上,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镜像有点大,所以需要几个GiB的空间来容纳它们。
  • 您有互联网连接。

从那里,以下命令序列将检出、构建和测试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 方法,只要底层 C API 没有太大变化,就应能够为 ICU 库的新版本生成库包装器。

一种使 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 中名为 lib_XX.rs(其中 XX 是 ICU 版本,例如 67)的静态生成的 bindgen 文件,这些文件在关闭 bindgen 功能时使用。

调用此 make 目标将修改带有较新版本文件的本地签出 lib_XX.rs。创建一个拉取请求并检查它们。

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

依赖关系

~0.5–1.2MB
~25K SLoC