Open kuretchi opened 4 years ago
私が知っていることを書いておきます。
まず依存グラフおよび依存先のパッケージの情報はcargo metadata
で簡単に取れます。(この"kind": null
はcargo_metadata::DependencyKind::Normal
にあたります)
❯ cargo metadata --format-version 1 | jq '.resolve.root as $r | .resolve.nodes[] | select(.id == $r) | .deps[0]'
{
"name": "anyhow",
"pkg": "anyhow 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"dep_kinds": [
{
"kind": null,
"target": null
}
]
}
- ライブラリ同士の依存関係を考えるか
少なくとも依存先の方はクレート全体が十分に小さいと考えて、無条件でroot moduleに依存するとみなすという手があると思います。
また展開方法ですが、cargo-equipではこのようにlib
間のextern_crate_name
を解決しています。
+// このような"pseudo extern prelude"を挿入。
+mod __pseudo_extern_prelude {
+ // `extern_crate_name`を翻訳
+ pub(super) use crate::{another_lib1, another_lib2};
+}
+use self::__pseudo_extern_prelude::*;
+
use another_lib1::A;
use another_lib2::B;
ただこれはRust 2015ではコンパイルできない(継ぎ木が無理)ので、ライブラリを2015-compatibleにしたい場合ユーザーがマーカーとしてextern crate
を書くことになります。
mod extern_crates {
- pub(super) extern crate __another_lib as another_lib;
+ pub(super) use crate::another_lib;
}
use self::extern_crates::another_lib::foo::Foo; // Prepend `self::` to make compatible with Rust 2015
ただバージョンが1.31+なのにエディションが2015なサイトに片っぱしから要望を出す方が早いかもしれません。私はこの前Library-CheckerにPRを出し、yukicoderにも昨日要望を出しました。
- ライブラリのソースコードをどのように持ってくるか
cargo metadata
を打った時点で、というより依存グラフが構築された時点で依存クレートはすべてローカルにダウンロードされています。
❯ cargo metadata --format-version 1 | jq '.packages[] | select(.name == "anyhow") | .manifest_path'
"/home/ryo/.cargo/registry/src/github.com-1ecc6299db9ec823/anyhow-1.0.33/Cargo.toml"
ソースコードを編集したやつを保存したいとなればどこかにcp -r
する必要がありますが。(私が考えているやつ。permutohedronとかrustc-hashとかを適切なcopyright notice付きで使えないかなーと)
「このライブラリについては依存関係の解析をスキップ」ができるようにする?
関係あるかわかりませんがAtCoderで使えるクレートについては私はハードコードしてしまいました。ただpermutohedronとか今のままでも普通に展開できそうなんですよね...
ありがとうございます.助かります.
とりあえずの要求として考えていたのは
だったので,(すべての依存先を展開するのではなく) ユーザーが明示的に (依存先のうち) どのクレートを展開するか選択するようにしようというつもりでした.なんですが,これだとクレートを細かく分割するスタイルのライブラリに対応しようとなった場合には困ったことになりますね…
cargo metadataを打った時点で、というより依存グラフが構築された時点で依存クレートはすべてローカルにダウンロードされています。
これは知りませんでした.これなら簡単ですね.
なんですが,これだとクレートを細かく分割するスタイルのライブラリに対応しようとなった場合には困ったことになりますね…
cargo-equip(と今online-judge-tools/verification-helperに出している途中のpr)では私がcollaboratorをやっているcargo-udepsを使って「深さ1」のクレートを絞り込んでます。
なんですがcargo-udeps(1)
に加えてnightlyツールチェインが必要な上に吐くJSONの形式はドキュメント化してないんですよね。
{
"success": false,
"unused_deps": {
"solve 0.0.0 (path+file:///home/ryo/src/local/play-cargo-equip/solve)": {
"manifest_path": "/home/ryo/src/local/play-cargo-equip/solve/Cargo.toml",
"normal": [
"ac-library-rs-parted",
"ac-library-rs-parted-convolution",
"ac-library-rs-parted-dsu",
"ac-library-rs-parted-fenwicktree",
"ac-library-rs-parted-lazysegtree",
"ac-library-rs-parted-math",
"ac-library-rs-parted-maxflow",
"ac-library-rs-parted-mincostflow",
"ac-library-rs-parted-scc",
"ac-library-rs-parted-segtree",
"ac-library-rs-parted-string",
"ac-library-rs-parted-twosat",
"im-rc",
"permutohedron"
],
"development": [],
"build": []
}
},
"note": "Note: These dependencies might be used by other targets.\n To find dependencies that are not used by any target, enable `--all-targets`.\nNote: They might be false-positive.\n For example, `cargo-udeps` cannot detect usage of crates that are only used in doc-tests.\n To ignore some dependencies, write `package.metadata.cargo-udeps.ignore` in Cargo.toml.\n"
}
JSON自体も必要最低限の情報しか詰めてないのでちょっと面倒かも。注意点としてはこのあたり?
「未使用のクレート」は"name in toml"の形でしか含まれてないので、packageとの対応を取るのがほんの少しだけ面倒。取るとしたらこのようにする。
Package::dependencies
のDependency::rename
をHashSet<&str>
で集める (explicit_name_in_toml
s)Resolve::nodes
のNodeDep::name
を見る。
NodeDep::name
は"name in toml"に等しくこれとNodeDep::pkg
が対応する。Package::name
が"name in toml"に等しいとは限らない(リネームされているため)NodeDep::name
は"name in toml"に等しいとは限らない(lib.name
のリネームがあるため)。Package::name
が"name in toml"に等しい[dependencies]
に加えるのは何ら問題はない。ただ我々の場合なら単にエラーにしてもいい)(無いとは思いますが)複数のworkspace memberを扱う場合、unused_deps
のkey部分のpackage idが意図せずして"human readable"表記の方になっちゃっているので、value側のmanifest_path
で区別する(これらは変なsymlinkを張ってない限り一意)。
あとパッケージ/クレートの「名前」については、このように解決されると私は理解しています。Cargoに詳しいわけではないので誤っているかもしれませんが。
Package
→ Package
のname_in_toml
'-'
が含まれているとinvalid)Package
→ Package
のextern_crate_name
== cargo_metadata::NodeDep::name
[*dependencies]
でリネームされているなら、それ(== name_in_toml
) ('-'
が含まれているとinvalid)[*dependencies]
でリネームされてないなら、高々1つあるlib
ターゲットのTarget::name
の.replace('-', "_")
lib.name
が設定されているならそれ。('-'
が含まれているとinvalid)package.name
の.replace('-', "_")
lib
ターゲットが無ければ、存在しない「このライブラリについては依存関係の解析をスキップ」ができるようにする?
関係あるかわかりませんがAtCoderで使えるクレートについては私はハードコードしてしまいました。ただpermutohedronとか今のままでも普通に展開できそうなんですよね...
あと一応これについてですが、明示的に--exclude-atcoder-crates
を付ける形式に先程変えてしまいました。
--exclude <SPEC>... Exclude library crates from bundling
--exclude-atcoder-crates Alias for `--exclude https://github.com/rust-lang/crates.io-index#alga:0.9.3 ..`
--exclude-codingame-crates Alias for `--exclude https://github.com/rust-lang/crates.io-index#chrono:0.4.9 ..`
破壊的変更なのでエラーメッセージも追加した上で。
note: attempted to bundle with the following crate(s), which are available on AtCoder. to exclude them from bundling, run with `--exclude-atcoder-crates`
- `im-rc 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)`
- `rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)`
「CLIオプションで指定するパッケージ」を扱うとしたら krates::PkgSpec
でpackage ID specificationsを取るのがいいと思います。Cargoコマンドらしくなるし。
今までは「ライブラリクレートに対して実行し,必要なコードを抜粋する」コマンドだったのを,「(ライブラリに依存する) バイナリクレートに対して実行し,提出可能なコードを生成する」コマンドにしたい.
Before:
After:
path
(やgit
) のみ対応 /cargo-clone
などを使う