A Cargo subcommand to bundle your code into one .rs
file for competitive programming.
See CHANGELOG.md or Releases for recent updates.
cargo-glue can
- bundle multiple crates,
- bundle only used crates,
- exclude certain crates (
--exclude-{atcoder, codingame}-crates
), - expand procedural macros,
- preserve scopes for
#[macro_export]
ed macros, - resolve
#[cfg(..)]
, - remove comments and doc comments (
--remove
), - minify code (
--minify
), - and check the output.
[package]
name = "library-checker"
version = "0.0.0"
edition = "2021"
[dependencies]
ac-library-rs-parted-modint = { git = "https://github.com/qryxip/ac-library-rs-parted" }
proconio = { version = "0.4.3", features = ["derive"] }
qryxip-competitive-tonelli-shanks = { git = "https://github.com/qryxip/competitive-programming-library" }
# ...
use acl_modint::ModInt;
use proconio::{fastout, input};
use tonelli_shanks::ModIntBaseExt as _;
#[fastout]
fn main() {
input! {
yps: [(u32, u32)],
}
for (y, p) in yps {
ModInt::set_modulus(p);
if let Some(x) = ModInt::new(y).sqrt() {
println!("{}", x);
} else {
println!("-1");
}
}
}
mod sub {
// You can also `use` the crate in submodules.
#[allow(unused_imports)]
use proconio::input as _;
}
↓
❯ cargo glue \
> --remove docs `# Remove doc comments` \
> --minify libs `# Minify each library` \
> --bin sqrt_mod `# Specify the bin crate` | xsel -b
Submit Info #59239 - Library-Checker
- [x] fixedbitset 0.4.0
- [x] lazy_static 1.4.0
- [x] maplit 1.0.2
- [x] memoise 0.3.2
- [x] multimap 0.8.3
- [x] permutohedron 0.2.4
- [x] proconio 0.4.3
- [x] rustc-hash 1.1.0
- [x] smallvec 1.6.1
- [x] strsim 0.10.0
- [x] whiteread 0.5.0
Install a nightly
toolchain and cargo-udeps first.
❯ rustup update nightly
❯ cargo install cargo-udeps
❯ cargo install cargo-glue
❯ cargo install cargo-glue --git https://github.com/LumaKernel/cargo-glue
Follow these constrants when you writing libraries to bundle.
-
Set
package.edition
to"2021"
.Older editions are not supported.
-
Do not use procedural macros in
lib
crates.You can
pub use
them, but cannot call. -
Use
$crate
instead ofcrate
in macros.cargo-glue replaces
$crate
inmacro_rules!
with$crate::extern_crate_name_in_main_crate
.crate
identifiers inmacro_rules!
are not modified. -
Do not use absolute path as possible.
cargo-glue replaces
crate
withcrate::extern_crate_name_in_main_crate
andpub(crate)
withpub(in crate::extern_crate_name_in_main_crate)
.However I cannot ensure this works well. Use
self::
andsuper::
instead ofcrate::
.-use crate::foo::Foo; +use super::foo::Foo;
-
If possible, do not use glob import.
cargo-glue inserts glob imports as substitutes for extern prelude and
#[macro_use]
. -
Split into small separate crates as possible.
cargo-glue does not search "dependencies among items".
On a website other except AtCoder, Split your library into small crates to fit in 64KiB.
. ├── a │ ├── Cargo.toml │ └── src │ └── lib.rs ├── b │ ├── Cargo.toml │ └── src │ └── lib.rs ⋮
When you finish preparing your library crates, add them to [dependencies]
of the bin
/example
.
If you generate packages automatically with a tool, add them to its template.
If you want to use rust-lang-ja/ac-library-rs, use qryxip/ac-library-rs-parted instead.
[dependencies]
ac-library-rs-parted = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-convolution = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-dsu = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-fenwicktree = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-lazysegtree = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-math = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-maxflow = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-mincostflow = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-modint = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-scc = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-segtree = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-string = { git = "https://github.com/qryxip/ac-library-rs-parted" }
ac-library-rs-parted-twosat = { git = "https://github.com/qryxip/ac-library-rs-parted" }
The constraints for bin
s/example
s are:
-
If you use
proc-macro
crates, make sure the macro names unique.If you have trouble about procedural macro names, you can import them with
#[macor_use].
-
If possible, do not use glob import.
cargo-glue also inserts glob imports as it does into libraries.
pub use __cargo_glue::prelude::*; // ︙ pub mod __cargo_glue { pub mod crates { // ︙ } // ︙ pub(crate) prelude { pub use crate::__cargo_glue::crates::*; } }
use input::input;
use mic::answer;
use partition_point::RangeBoundsExt as _;
#[answer(join("\n"))]
fn main() -> _ {
input! {
a: [u64],
}
a.into_iter()
.map(|a| (1u64..1_000_000_000).partition_point(|ans| ans.pow(2) < a))
}
Then execute cargo-glue
.
❯ cargo glue --bin "$name"
By default, cargo-glue
- Removes
#[cfg(always_true_predicate)]
(e.g.cfg(feature = "enabled-feature")
). - Removes items with
#[cfg(always_false_preducate)]
(e.g.cfg(test)
,cfg(feature = "disable-feature")
).
Predicates are evaluated according to this rule.
-
test
:false
-
proc_macro
:false
-
cargo_glue
:true
-
feature
:true
for those enabled - Otherwise: unknown
#[allow(dead_code)]
pub mod a {
pub struct A;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
}
↓
#[allow(dead_code)]
pub mod a {
pub struct A;
}
By default, cargo-glue creates a temporary package that shares the current target directory and execute cargo check
before outputting.
Checking cargo-glue-check-output-6j2i3j3tgtugeaqm v0.1.0 (/tmp/cargo-glue-check-output-6j2i3j3tgtugeaqm)
Finished dev [unoptimized + debuginfo] target(s) in 0.11s
cargo-glue can expand procedural macros.
use memoise::memoise;
use proconio_derive::fastout;
#[fastout]
fn main() {
for i in 0..=10 {
println!("{}", fib(i));
}
}
#[memoise(n <= 10)]
fn fib(n: i64) -> i64 {
if n == 0 || n == 1 {
return n;
}
fib(n - 1) + fib(n - 2)
}
-
proc-macro
crates need to be compile with Rust 1.48.0+. If version of the active toolchain is less than 1.48.0, cargo-glue finds an alternative toolchain and uses it for compilingproc-macro
s. - procedural macros re-exported with
pub use $name::*;
are also able to be expanded.
Removes
- doc comments (
//! ..
,/// ..
,/** .. */
,#[doc = ".."]
) with--remove docs
. - comments (
// ..
,/* .. */
) with--remove comments
.
#[allow(dead_code)]
pub mod a {
//! A.
/// A.
pub struct A; // aaaaa
}
↓
#[allow(dead_code)]
pub mod a {
pub struct A;
}
Minifies
- each expaned library with
--minify lib
. - the whole code with
--minify all
.
Not that the minification function is incomplete. Unnecessary spaces may be inserted.
Do not resolve #[cfg(…)]
.
Do not format the output.
Do not check the output.
- cargo-glue is forked from cargo-equip, which is made by Ryo Yamashita and licensed as MIT.
TBD