Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.5 channel=1.78.0 だと sqlx-core の推移的依存関係でビルドできない状態 #9

Open
mizchi opened this issue Dec 6, 2024 · 2 comments

Comments

@mizchi
Copy link

mizchi commented Dec 6, 2024

問題

20241207現在、この sqlx-core の内部依存の変更を受け、書籍の手順を 1.78.0 で動かすことは出来ません。

sqlx-core -> url -> idna が 1.81.0 以降を要求します。

再現方法

rust-toolchain.toml で 1.78.0 を指定したまま、Cargo.lock を削除して cargo build し直すと、ビルドに失敗します。

# git clone <repo>
$ git switch chapter3
$ rm -r Cargo.toml target
$ cargo build
....
error[E0658]: use of unstable library feature 'error_in_core'
  --> /home/mizchi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/idna-1.0.3/src/lib.rs:78:6
   |
78 | impl core::error::Error for Errors {}
   |      ^^^^^^^^^^^^^^^^^^
   |
   = note: see issue #103765 <https://github.com/rust-lang/rust/issues/103765> for more information

自分は書籍を読みつつこのリポジトリからコードをコピーして手順を再現しようとしたので、Cargo.lock だけ無視したのでこの状態になりました。

問題の発生理由

sqlx-core が依存する url crate は "version"="^2.2.2" が指定されており、今の状態で更新すると 2.5.2 から 2.5.4 に上がります。その推移的依存関係の idna が 0.5.0 -> 1.0.7 に更新され、これは 1.81 以降でしかビルドできません。

対応案

この本の手順を再現するために 1.78.0 を指定すると、Cargo.lock を移植しない限り、逆に動かない状態になります。

1.78.0 のままで動かすワークアラウンドとして、このリポジトリのCargo.lock をコピーすると問題を回避できるのは確認できています。

じゃあ 1.81.0 にあげるとそのまま解決するかと言うと、次の use が追加で必要になりました。

use axum::extract::State;

これは async fn health_check_db(State(db): State<PgPool>) -> StatusCode { でパターンマッチするための State の参照の解決ですが、マクロ解決か何かの影響を受けて書籍のコードは動きません。

なので、いずれにせよ何らかの対応をしないとこのリポジトリを動かすことができません。

  • 1.78.0 で Cargo.lock を移植する
  • 1.81.0 に use axum::extract::State; を追加する
@mizchi mizchi changed the title 3.5 channel=1.78.0 だと sqlx-core の推移的依存関係で動かない 3.5 channel=1.78.0 だと sqlx-core の推移的依存関係でビルドできない Dec 6, 2024
@mizchi mizchi changed the title 3.5 channel=1.78.0 だと sqlx-core の推移的依存関係でビルドできない 3.5 channel=1.78.0 だと sqlx-core の推移的依存関係でビルドできない状態 Dec 6, 2024
xjr1300 added a commit to xjr1300/rusty-book-manager that referenced this issue Dec 8, 2024
@yuk1ty
Copy link

yuk1ty commented Dec 13, 2024

ありがとうございます!
遅くなってしまいすみません、私の手元でも同様のコンパイルエラーが出ることを再現できました。
著者間で対応を議論させてください🙏🏻
(ちょっと私が多忙すぎて対応がゆっくり目になってしまうと思います…申し訳ないです)

@yuk1ty
Copy link

yuk1ty commented Dec 15, 2024

原因の説明と解決策

書籍で使用しているsqlxのバージョン0.7.4では、内部のクレートであるsqlx-coreがurlクレートをdefault-feature = falseで呼び出しています。これが発端となって、urlクレート側に入った特定のクレートの修正の影響を間接的に受け、コンパイルエラーが発生してしまっています。

解決策としては、次のどれかを推奨します。

  • Rust 1.78.0のまま行きたい場合
    • adapterクレートに所定の依存を加える。
    • ないしは、lockfileに対して所定の編集を加える。
  • ないしは、 rust-toolchain.toml を変更し、Rustのバージョンを1.81.0以上にする。

adapterクレートに所定の依存を加える

著者にとってはこれが一番早いかもしれません。このリポジトリの実装も、後日これに倣って直しておこうと考えています。

adapterクレートのCargo.tomlに次のような記述を追加します。

[dependencies]
kernel.workspace = true
shared.workspace = true
async-trait.workspace = true
bcrypt.workspace = true
chrono.workspace = true
derive-new.workspace = true
secrecy.workspace = true
sqlx.workspace = true
redis.workspace = true

# 追加
url = "~2.2.2"

lockfileに対して所定の編集を加える

今回問題となっているurlとidnaのクレートのバージョンを直接編集して書き換える方法がまず考えられます。あまり推奨された方法ではないかもしれませんが、一応動作させる事はできます。

[[package]]
name = "url"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [
 "form_urlencoded",
 "idna",
 "percent-encoding",
]
[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
 "unicode-bidi",
 "unicode-normalization",
]

rust-toolchain.tomlのバージョンを1.81.0に上げる

読者のみなさんにとってはこれが最もシンプルな解決策になると思います。rust-toolchain.tomlのバージョンを1.81.0に引き上げます。

[toolchain]
channel = "1.81.0"
profile = "default"

報告いただいた方の指摘とは異なり、単にバージョンを上げるのみでよさそうです。そう考えている理由は「補足」を参照してください。

詳細な経緯の説明

エラーの意味するところと、各クレートでのGitHub上での議論を追った結果を残しておきます。詳細な経緯に興味のある方は御覧ください。

エラーの意味するところ

まずエラーの意味するところですが、

error[E0658]: use of unstable library feature 'error_in_core'
  --> /Users/helloyuki/.cargo/registry/src/index.crates.io-6f17d22bba15001f/idna-1.0.3/src/lib.rs:78:6
   |
78 | impl core::error::Error for Errors {}
   |      ^^^^^^^^^^^^^^^^^^
   |
   = note: see issue #103765 <https://github.com/rust-lang/rust/issues/103765> for more information

For more information about this error, try `rustc --explain E0658`.
error: could not compile `idna` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
[cargo-make] ERROR - Error while executing command, exit code: 101
[cargo-make] WARN - Build Failed.

error_in_coreというunstableなfeatureを使用しているとしてエラーが出力されています。Rustには「unstable features」と呼ばれる機能群があり、これらは基本的にnightlyでのみ動かすことができます。日本語圏での解説は、たとえばこの記事などに詳しいです

実は、このerror_in_coreRust 1.81.0で最近安定化されました。この機能は要するに、core::error::Errorというトレイトをstable Rustでも利用できるようにしようというものです。coreは、Rustの標準ライブラリがない環境下(#![no_std])で動かせる機能を提供していて、ここを安定化させたというわけです。ちなみにですが、標準ライブラリ側ではstd::error::Errorというトレイトがあります。

Rust 1.81.0以上にすると、このエラーが検出されなくなるのは、安定化されたためということになります。

sqlx-coreのコンパイラフィーチャーフラグの指定方法が原因なのではないか?

ではなぜ、標準ライブラリしか用いないと想定されるsqlxのようなクレートにおいて、上述したようなcoreにまつわるコンパイルエラーが出てしまうのか?という疑問が浮かびます。

これについては、概ね下記のような経緯があったと推察されます。

  • idnaクレートに、stdフィーチャーでないケースにおいてcore::error::Errorを使用する実装が追加される。
  • urlクレートにて、上記でアップデートされたidnaクレートが参照されるようになる。
  • sqlx-coreクレートにて、上記でアップデートされたurlクレートが参照されるようになる。
  • sqlx-coreクレートでは、もともとdefault-feature = falseが指定されていた。これによりurlクレートのstdフィーチャーが上手にオンにならなかった。idnaクレートも同様にstdフィーチャーがオンにならず、結果的にコンパイルエラーに見られるような食い違いが発生した。

idnaクレートでの変更

直接の原因となったのはidnaクレートに対する変更です。下記のようなPull Requestがマージされており、現在最新バージョンである1.0.3ではこの実装が含まれています。

servo/rust-url#990

この実装では次のようなコードが追加されています。このコードの意味するところは、

  • stdというフィーチャーがオンになっていた場合は、std::error::ErrorErrors型に対して実装する。
  • stdでなかった場合は、core::error::Errorを使用する。

というものです。

#[cfg(feature = "std")]
impl std::error::Error for Errors {}

#[cfg(not(feature = "std"))]
impl core::error::Error for Errors {}

このクレートの修正内容は、urlクレートのバージョン2.5.3以降で利用されるようになります。

sqlx-coreからのurlクレートへの依存

sqlxのバージョン0.7.4では、sqlx-coreにおけるurlクレートへの依存は次のように設定されています

url = { version = "2.2.2", default-features = false }

なお、Cargo.tomlのバージョン指定では、version = 2.2.2という指定方法は、実質的にversion = ^2.2.2を意味します。これにより、mizchiさんが実装された時点では2.5.4が読み込まれることになりました。

default-features = falseとすると、コンパイラフィーチャーフラグで指定されるデフォルトの設定は読み込まれなくなります。

ところで、urlクレートのデフォルトフィーチャーの指定は下記のように、stdとなるよう行われています。この際、idnaクレートに対しても同様に、stdのフィーチャーフラグがオンとなるよう設定されていることがわかります。

[features]
default = ["std"]
std = ["idna/std", "percent-encoding/std", "form_urlencoded/std"]

default-features = falseとすると、stdのフィーチャーフラグも落とされることになります。これにより、idnaクレートのフィーチャーフラグもstdが落とされ、先ほどのErrorトレイトの実装に関する分岐も、std::error::Errorではなく、core::error::Errorが読み込まれるようになったというわけです。これにより、Rust 1.78.0では、core::error::Errorはまだunstable featureであるため、コンパイルエラーとして検出されたと思われます。

書籍執筆時点では影響しなかった理由

単にsqlx-coreがurlの2.5.2を読み込んでいたからです。そして、ロックファイルを削除すると、現時点ではurlの2.5.4を読み込むようになります。これが差分になります。

cargoでは依存関係をツリー上で出力する方法として、cargo-treeというツールを利用できます。これを利用した結果を記しておきます。

書籍執筆時点
│   │   │   ├── sqlx v0.7.4
│   │   │   │   ├── sqlx-core v0.7.4
│   │   │   │   │   ├── ahash v0.8.11
│   │   │   │   │   │   ├── cfg-if v1.0.0
│   │   │   │   │   │   ├── getrandom v0.2.15 (*)
│   │   │   │   │   │   ├── once_cell v1.20.0
│   │   │   │   │   │   └── zerocopy v0.7.35
│   │   │   │   │   │       ├── byteorder v1.5.0
│   │   │   │   │   │       └── zerocopy-derive v0.7.35 (proc-macro)
│   │   │   │   │   │           ├── proc-macro2 v1.0.86 (*)
│   │   │   │   │   │           ├── quote v1.0.37 (*)
│   │   │   │   │   │           └── syn v2.0.77 (*)
│   │   │   │   │   │   [build-dependencies]
│   │   │   │   │   │   └── version_check v0.9.5
│   │   │   │   │   ├── atoi v2.0.0
│   │   │   │   │   │   └── num-traits v0.2.19 (*)
│   │   │   │   │   ├── byteorder v1.5.0
│   │   │   │   │   ├── bytes v1.7.1
│   │   │   │   │   ├── chrono v0.4.38 (*)
│   │   │   │   │   ├── crc v3.2.1
│   │   │   │   │   │   └── crc-catalog v2.4.0
│   │   │   │   │   ├── crossbeam-queue v0.3.11
│   │   │   │   │   │   └── crossbeam-utils v0.8.20
│   │   │   │   │   ├── either v1.13.0 (*)
│   │   │   │   │   ├── event-listener v2.5.3
│   │   │   │   │   ├── futures-channel v0.3.30 (*)
│   │   │   │   │   ├── futures-core v0.3.30
│   │   │   │   │   ├── futures-intrusive v0.5.0
│   │   │   │   │   │   ├── futures-core v0.3.30
│   │   │   │   │   │   ├── lock_api v0.4.12 (*)
│   │   │   │   │   │   └── parking_lot v0.12.3 (*)
│   │   │   │   │   ├── futures-io v0.3.30
│   │   │   │   │   ├── futures-util v0.3.30 (*)
│   │   │   │   │   ├── hashlink v0.8.4
│   │   │   │   │   │   └── hashbrown v0.14.5
│   │   │   │   │   │       ├── ahash v0.8.11 (*)
│   │   │   │   │   │       └── allocator-api2 v0.2.18
│   │   │   │   │   ├── hex v0.4.3
│   │   │   │   │   ├── indexmap v2.5.0
│   │   │   │   │   │   ├── equivalent v1.0.1
│   │   │   │   │   │   ├── hashbrown v0.14.5 (*)
│   │   │   │   │   │   └── serde v1.0.210 (*)
│   │   │   │   │   ├── log v0.4.22
│   │   │   │   │   ├── memchr v2.7.4
│   │   │   │   │   ├── once_cell v1.20.0
│   │   │   │   │   ├── paste v1.0.15 (proc-macro)
│   │   │   │   │   ├── percent-encoding v2.3.1
│   │   │   │   │   ├── serde v1.0.210 (*)
│   │   │   │   │   ├── serde_json v1.0.128 (*)
│   │   │   │   │   ├── sha2 v0.10.8
│   │   │   │   │   │   ├── cfg-if v1.0.0
│   │   │   │   │   │   ├── cpufeatures v0.2.14
│   │   │   │   │   │   │   └── libc v0.2.158
│   │   │   │   │   │   └── digest v0.10.7
│   │   │   │   │   │       ├── block-buffer v0.10.4
│   │   │   │   │   │       │   └── generic-array v0.14.7 (*)
│   │   │   │   │   │       ├── crypto-common v0.1.6 (*)
│   │   │   │   │   │       └── subtle v2.6.1
│   │   │   │   │   ├── smallvec v1.13.2
│   │   │   │   │   ├── sqlformat v0.2.6
│   │   │   │   │   │   ├── nom v7.1.3
│   │   │   │   │   │   │   ├── memchr v2.7.4
│   │   │   │   │   │   │   └── minimal-lexical v0.2.1
│   │   │   │   │   │   └── unicode_categories v0.1.1
│   │   │   │   │   ├── thiserror v1.0.63
│   │   │   │   │   │   └── thiserror-impl v1.0.63 (proc-macro)
│   │   │   │   │   │       ├── proc-macro2 v1.0.86 (*)
│   │   │   │   │   │       ├── quote v1.0.37 (*)
│   │   │   │   │   │       └── syn v2.0.77 (*)
│   │   │   │   │   ├── tokio v1.40.0 (*)
│   │   │   │   │   ├── tokio-stream v0.1.16
│   │   │   │   │   │   ├── futures-core v0.3.30
│   │   │   │   │   │   ├── pin-project-lite v0.2.14
│   │   │   │   │   │   └── tokio v1.40.0 (*)
│   │   │   │   │   ├── tracing v0.1.40 (*)
│   │   │   │   │   ├── url v2.5.2 (*)
│   │   │   │   │   └── uuid v1.10.0
│   │   │   │   │       ├── getrandom v0.2.15 (*)
│   │   │   │   │       └── serde v1.0.210 (*)
現在
│   │   │   ├── sqlx v0.7.4
│   │   │   │   ├── sqlx-core v0.7.4
│   │   │   │   │   ├── ahash v0.8.11
│   │   │   │   │   │   ├── cfg-if v1.0.0
│   │   │   │   │   │   ├── getrandom v0.2.15 (*)
│   │   │   │   │   │   ├── once_cell v1.20.2
│   │   │   │   │   │   └── zerocopy v0.7.35
│   │   │   │   │   │       ├── byteorder v1.5.0
│   │   │   │   │   │       └── zerocopy-derive v0.7.35 (proc-macro)
│   │   │   │   │   │           ├── proc-macro2 v1.0.92 (*)
│   │   │   │   │   │           ├── quote v1.0.37 (*)
│   │   │   │   │   │           └── syn v2.0.90 (*)
│   │   │   │   │   │   [build-dependencies]
│   │   │   │   │   │   └── version_check v0.9.5
│   │   │   │   │   ├── atoi v2.0.0
│   │   │   │   │   │   └── num-traits v0.2.19 (*)
│   │   │   │   │   ├── byteorder v1.5.0
│   │   │   │   │   ├── bytes v1.9.0
│   │   │   │   │   ├── chrono v0.4.39 (*)
│   │   │   │   │   ├── crc v3.2.1
│   │   │   │   │   │   └── crc-catalog v2.4.0
│   │   │   │   │   ├── crossbeam-queue v0.3.11
│   │   │   │   │   │   └── crossbeam-utils v0.8.20
│   │   │   │   │   ├── either v1.13.0 (*)
│   │   │   │   │   ├── event-listener v2.5.3
│   │   │   │   │   ├── futures-channel v0.3.31 (*)
│   │   │   │   │   ├── futures-core v0.3.31
│   │   │   │   │   ├── futures-intrusive v0.5.0
│   │   │   │   │   │   ├── futures-core v0.3.31
│   │   │   │   │   │   ├── lock_api v0.4.12 (*)
│   │   │   │   │   │   └── parking_lot v0.12.3 (*)
│   │   │   │   │   ├── futures-io v0.3.31
│   │   │   │   │   ├── futures-util v0.3.31 (*)
│   │   │   │   │   ├── hashlink v0.8.4
│   │   │   │   │   │   └── hashbrown v0.14.5
│   │   │   │   │   │       ├── ahash v0.8.11 (*)
│   │   │   │   │   │       └── allocator-api2 v0.2.21
│   │   │   │   │   ├── hex v0.4.3
│   │   │   │   │   ├── indexmap v2.7.0
│   │   │   │   │   │   ├── equivalent v1.0.1
│   │   │   │   │   │   ├── hashbrown v0.15.2
│   │   │   │   │   │   └── serde v1.0.216 (*)
│   │   │   │   │   ├── log v0.4.22
│   │   │   │   │   ├── memchr v2.7.4
│   │   │   │   │   ├── once_cell v1.20.2
│   │   │   │   │   ├── paste v1.0.15 (proc-macro)
│   │   │   │   │   ├── percent-encoding v2.3.1
│   │   │   │   │   ├── serde v1.0.216 (*)
│   │   │   │   │   ├── serde_json v1.0.133 (*)
│   │   │   │   │   ├── sha2 v0.10.8
│   │   │   │   │   │   ├── cfg-if v1.0.0
│   │   │   │   │   │   ├── cpufeatures v0.2.16
│   │   │   │   │   │   │   └── libc v0.2.168
│   │   │   │   │   │   └── digest v0.10.7
│   │   │   │   │   │       ├── block-buffer v0.10.4
│   │   │   │   │   │       │   └── generic-array v0.14.7 (*)
│   │   │   │   │   │       ├── crypto-common v0.1.6 (*)
│   │   │   │   │   │       └── subtle v2.6.1
│   │   │   │   │   ├── smallvec v1.13.2
│   │   │   │   │   ├── sqlformat v0.2.6
│   │   │   │   │   │   ├── nom v7.1.3
│   │   │   │   │   │   │   ├── memchr v2.7.4
│   │   │   │   │   │   │   └── minimal-lexical v0.2.1
│   │   │   │   │   │   └── unicode_categories v0.1.1
│   │   │   │   │   ├── thiserror v1.0.69
│   │   │   │   │   │   └── thiserror-impl v1.0.69 (proc-macro)
│   │   │   │   │   │       ├── proc-macro2 v1.0.92 (*)
│   │   │   │   │   │       ├── quote v1.0.37 (*)
│   │   │   │   │   │       └── syn v2.0.90 (*)
│   │   │   │   │   ├── tokio v1.42.0 (*)
│   │   │   │   │   ├── tokio-stream v0.1.17
│   │   │   │   │   │   ├── futures-core v0.3.31
│   │   │   │   │   │   ├── pin-project-lite v0.2.15
│   │   │   │   │   │   └── tokio v1.42.0 (*)
│   │   │   │   │   ├── tracing v0.1.41 (*)
│   │   │   │   │   ├── url v2.5.4 (*)
│   │   │   │   │   └── uuid v1.11.0
│   │   │   │   │       ├── getrandom v0.2.15 (*)
│   │   │   │   │       └── serde v1.0.216 (*)

sqlx側の対応

sqlx側ではこの問題を認識しており、すでにmainブランチの実装では default-features = false は落とされています。これにより、urlクレートのstdフィーチャーをオンにした状態で依存させることができるようになり、上述の問題は起こらなくなりました(手元でもビルドして確認しつつ、わざと落としてみる検証もしました)。この実装が含まれるバージョンがリリースされると、今回Issueとして提出されたコンパイルエラーは何もせずとも起こらなくなる可能性があります(0.7.x系までちゃんと入れてくれればですが…)。

launchbadge/sqlx#3589

確認時点での最新のmainブランチの状況

https://github.com/launchbadge/sqlx/blob/1678b19a4672fd6a18b4891c53bf0b57638b92a4/sqlx-core/Cargo.toml#L79

補足

@mizchi おそらく、1.81.0に上げることと use axum::extract::State; の追加は無関係ではないかと考えています。というのも、このリポジトリのrust-toolchain.tomlを1.81.0に引き上げつつ、Cargo.lockを削除してもう一度ビルドしても私の手元では通ってしまったためです。

このIssueを作成された時点でmizchiさんが取り組まれていたのは、推測するに3章でヘルスチェックを追加する付近だと思いますが、ヘルスチェック用の関数が書かれたページの直前のコードブロックに、 axum::extract::State をインポートに追加する指示が含まれています。これを追加し忘れてらしたのかな?と推察しています。状況違うようでしたらまた教えてください🙏🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants