#cli #macro #multicall

pluribus

Small crate providing a macro to create multicall binaries declaratively

1 unstable release

Uses new Rust 2024

new 0.1.0 Apr 28, 2025

#439 in Command-line interface

MIT/Apache

8KB
77 lines

pluribus

Small crate providing a macro to create multicall binaries declaratively.


lib.rs:

pluribus

A small macro crate to make multicall binaries easier!

What is a multicall binary?

Multicall binaries are simply single executables that can behave as many different executables.

Good and famous examples of such a multicall binary would be busybox and uutils.

What is included?

This crate provides a single macro, pluribus!(), with a special, easy to read and write DSL (special syntax) that declaratively turns your modules into separate applications.

Hmm... not quite sure I understood...

Well, no biggie! That's what examples are for!

use pluribus::pluribus;
// Declaring a binary 'greet'.
mod greet {
    // Start is our start symbol!
    pub fn start(args: &[String]) {
        for s in &args[1..] {
            println!("Greetings, {s}!");
        }
    }
}

// Declaring a binary 'bye'
mod bye {
    // Start is our start symbol!
    pub fn start(args: &[String]) {
        for s in &args[1..] {
            println!("Goodbye, {s}!");
        }
    }
}

fn main() -> std::io::Result<()> {
    // symbol: <our function that starts a binary, defaulting to main>;
    // returning: <return type of the binaries>;
    // with: <list of all modules we wish to turn into binaries>
    pluribus!(
        symbol: start;
        returns: ();
        with:
        - greet;
        - bye;
    )
    // skipping first argument because this is an example,
    // which has always "pluribus" as the first argument.
    (&std::env::args().skip(1).collect::<Vec<_>>());
    Ok(())
}

This small program, let's call it 'test', now includes both the greet and bye binaries!

Now, how are they accessed? Like this:

> ./test greet Alice Bob
Greetings, Alice!
Greetings, Bob!

Or, alternatively, we can create a symlink or rename the binary:

> ln -s test greet
> ./greet Alice Bob
Greetings, Alice!
Greetings, Bob!

The syntax

Admittedly, it is a little bit dumb and too strict, but because it is so simple, it should prove easy to use.

There are three directives in the language, and they must be stated in order.

They are as follows:

symbol

symbol specifies the main symbol of the sub-binary, eg. main, _start.

symbol: main;

It defaults to main. If you are using main as the symbol, you may omit this.

returns

returns specifies the return type of the sub-binary, eg (), std::io::Result<()>.

returns: ();

It defaults to (). If you are using () as the return type, you may omit this.

with

with specifies the beginning of the list of modules/sub-binaries. It must be the last (or only) directive.

with:
  - bin1;
  - bin2;
  - bin3;

No runtime deps