226

I'd like to make a project with a daemon and a client, connecting through a unix socket.

A client and a daemon requires two binaries, so how do I tell Cargo to build two targets from two different sources?

To add a bit of fantasy, I'd like to have a library for the main part of the daemon, and just have a binary to wrap around it and communicate through sockets.

So, we have this kind of tree architecture:

├── Cargo.toml
├── target
|   └── debug
|       ├── daemon
│       └── client
└── src
    ├── daemon
    │   ├── bin
    │   │   └── main.rs
    │   └── lib
    │       └── lib.rs
    └── client
        └── bin
            └── main.rs

I could make one executable which manages both concerns, but that's not what I want to do, unless it's very good practice.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
RallionRl
  • 2,453
  • 2
  • 10
  • 9
  • 4
    Highly relevant: [Rust package with both a library and a binary?](http://stackoverflow.com/q/26946646/155423). – Shepmaster Apr 13 '16 at 17:18
  • In complement of [Dognert's](http://stackoverflow.com/questions/36604010/how-can-i-build-multiple-binaries-with-cargo/36604610#36604610) answer, they answer all the questions I got. Thank you a lot! – RallionRl Apr 13 '16 at 17:45
  • this seems to be the relevant issue: https://github.com/rust-lang/cargo/issues/8294 – Bryan Larsen Sep 30 '22 at 23:49

3 Answers3

318

You can specify multiple binaries using [[bin]], as mentioned in the Cargo Book

[[bin]]
name = "daemon"
path = "src/daemon/bin/main.rs"

[[bin]]
name = "client"
path = "src/client/bin/main.rs"

You can run individual binaries with the cargo run command with the --bin <bin-name> option.

Tip: If you instead put these files in src/bin/daemon.rs and src/bin/client.rs, you'll get two executables named daemon and client as Cargo compiles all files in src/bin into executables with the same name automatically. You need to specify names and paths like in the snippet above only if you don't follow this convention.

BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • @AngelAngel you want to customize the output path? By default it'll be stored in `target/debug/$name` where `$name` is the `name` you specify in Cargo.toml. – Dogbert Apr 14 '16 at 11:48
  • I just wondered if you could say where to install a copy of the binary elsewhere other than the default. A copy in $name and another copy in another path. Not that it is trivial, just curious, thanks for your time. – Angel Angel Apr 14 '16 at 12:01
  • @AngelAngel I think you're looking for the `cargo install` command. Try reading the output of `cargo help install`. – Dogbert Apr 14 '16 at 12:09
  • 1
    This doesn't work if one of the `[[bin]]`s uses `required-features`. For that it seems like `cargo workspace` is the only solution? – Alex Moore-Niemi Jul 14 '21 at 14:37
  • How do you specify the default binary? ie say client should be default – Anatoly Bugakov Sep 09 '22 at 19:13
  • @AnatolyBugakov you mean setting the default for `cargo run`? See https://doc.rust-lang.org/cargo/reference/manifest.html#the-default-run-field. – Dogbert Sep 11 '22 at 09:23
  • It is worth noting that the line 'default-run = "a"' can be added under package in Cargo.toml to specify a default to run when using the form described in this answer. – Cameron Oct 18 '22 at 19:52
  • @Dogbert can these have different dependencies? I'd like to not include all deps of all bins into all bins – Benni May 26 '23 at 19:18
78

Another way is to use the workspace feature. This will provide more flexibility due to the fact that we can have more than one library. Example project structure:

.
├── Cargo.toml
├── cli
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── core
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── daemon
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── gui
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── rpc
    ├── Cargo.toml
    └── src
        └── lib.rs

Contents of the root Cargo.toml:

[workspace]
members = ["cli", "core", "daemon", "gui", "rpc"]
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
UltimaWeapon
  • 2,343
  • 18
  • 19
  • 3
    I could not get this to work. I had to move the binary rust source in the src/ folder and specify another target in `[[bin]]`. Could you give more details about what you did to get this to work? I was getting the following error: `use ::engine::RuleEngine;` `could not find engine in {{root}}` – Kenny Bambridge May 03 '20 at 20:08
  • @KennyBambridge I have not worked on Rust for awhile. IIRC when I have created this answer I tried on my local machine and it work as intended. – UltimaWeapon Jun 22 '20 at 14:57
  • @KennyBambridge You do have to add crates in other workspaces as dependencies in the Cargo.toml where you want to use them. – Caesar Oct 17 '20 at 10:32
  • 1
    I saw filecoin use this code structure: https://github.com/filecoin-project/rust-fil-proofs – Eric Jun 20 '21 at 06:45
  • I got it working, but I ended up referring to different Workspace docs, i.e. the one in the Rust book: https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html – rv.kvetch Feb 17 '22 at 22:55
3

Another format could be to replicate what the Crates.io source code has done, if you have a massive project, something like:

Main Library in src, with a Bin folder with your executables. Then make calls to your main library crate from your executables.

That way you library is centralized so easier to find things as it's cached.