GitXplorerGitXplorer
L

cargo-glue

public
0 stars
0 forks
9 issues

Commits

List of commits on branch main.
Verified
9c3df845478550cd4d62fbfc5859dee57d7b4b2b

fix: remove accidentally remained println debug (#22)

LLumaKernel committed a month ago
Verified
81c02546e457229fe96aeac052c7a53f02d56d2b

feat: support recursive (dep of deps, and so on) proc-macro expansion (#18)

LLumaKernel committed a month ago
Verified
b4459c8451cf97c86c185524312148e608d81f21

refactor: minimize usage of krates crate only for krates::PkgSpec and use cargo_metadata for other places (#17)

LLumaKernel committed a month ago
Unverified
f2b94b4d8973480f8cd450a2ea3b247829aa56ee

test: update snapshots for "glue" rename

LLumaKernel committed 2 months ago
Verified
24402de2fe3ed4cf3b1d80917cf2f4bf0103e4d6

feat: Support simple re-exports pattern in lib (#13)

LLumaKernel committed 2 months ago
Verified
7c0776c94a65e2172182c183ee98a84c12920ec8

feat: Convert RAW_IDENTIFIER correctly to path part (#12)

LLumaKernel committed 2 months ago

README

The README file for this repository.

cargo-glue

A Cargo subcommand to bundle your code into one .rs file for competitive programming.

Recent updates

See CHANGELOG.md or Releases for recent updates.

Features

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.

Example

Sqrt Mod - Library-Cheker

[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

Works With

Installation

Install a nightly toolchain and cargo-udeps first.

rustup update nightly
cargo install cargo-udeps

From Crates.io

cargo install cargo-glue

From master branch

cargo install cargo-glue --git https://github.com/LumaKernel/cargo-glue

GitHub Releases

Releases

Usage

Follow these constrants when you writing libraries to bundle.

  1. Set package.edition to "2021".

    Older editions are not supported.

  2. Do not use procedural macros in lib crates.

    You can pub use them, but cannot call.

  3. Use $crate instead of crate in macros.

    cargo-glue replaces $crate in macro_rules! with $crate::extern_crate_name_in_main_crate. crate identifiers in macro_rules! are not modified.

  4. Do not use absolute path as possible.

    cargo-glue replaces crate with crate::extern_crate_name_in_main_crate and pub(crate) with pub(in crate::extern_crate_name_in_main_crate).

    However I cannot ensure this works well. Use self:: and super:: instead of crate::.

    -use crate::foo::Foo;
    +use super::foo::Foo;
  5. If possible, do not use glob import.

    cargo-glue inserts glob imports as substitutes for extern prelude and #[macro_use].

  6. 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 bins/examples are:

  1. 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].

  2. 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"

Resolving #[cfg(…)]

By default, cargo-glue

  1. Removes #[cfg(always_true_predicate)] (e.g. cfg(feature = "enabled-feature")).
  2. Removes items with #[cfg(always_false_preducate)] (e.g. cfg(test), cfg(feature = "disable-feature")).

Predicates are evaluated according to this rule.

#[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;
}

Checking the output

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

Expanding procedural macros

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 compiling proc-macros.
  • procedural macros re-exported with pub use $name::*; are also able to be expanded.

Options

--remove <REMOVE>...

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;
}

--minify <MINIFY>

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.

--no-resolve-cfgs

Do not resolve #[cfg(…)].

--no-rustfmt

Do not format the output.

--no-check

Do not check the output.

History

License

TBD