DEV Community

YJDoc2
YJDoc2

Posted on

Make a Combined Library and Binary Project in Rust

In this article, we will take a look at how to create a combined library-binary project in Rust.

In Rust, Cargo can create two types of projects :

  • library projects which usually contains core logic and functions that together make some kind of library, and is not compiled to a runnable program as it does not have main function, instead it is compiled to some kind of shared library file. These are used by other runnable programs and libraries for internal use. These are created by running
# For creating a new dir
cargo new --lib my_project
# For creating in current dir
cargo init --lib
Enter fullscreen mode Exit fullscreen mode
  • binary projects which can be compiled to runnable program, which can be directly run, and faces users. These are created by running
# For creating a new dir
cargo new my_project
# For creating in current dir
cargo init
Enter fullscreen mode Exit fullscreen mode

Now there are many cases where you might want to create a library along with a binary, where the binary can be installed by user, and run, and the library can be uploaded to crates.io, or just on some git server like github, and can be used by other projects, including that project itself. For example, take a look at

GitHub logo YJDoc2 / 8086-Emulator

An Intel 8086 Emulator created in Rust.

8086 Emulator

Execution GIF

This is an Intel 8086 emulator / vm. It can run most of 8086 instruction set and provides an interactive interpreter to run the program line by line This repository contains the core library which contains the preprocessor, data parser and interpreter ; as well as a command line driver which provides command line interface for running the program For syntax check syntax.md.

This also has be compiled to WASM and available in Web version : https://github.com/YJDoc2/8086-emulator-web

Note

This is a Intel 8086 Emulator, providing a way to run programs written for 8086 assembly instruction set. This internally stores data in the emulated "memory" of 1 MB size, but the code is not compiled to binary or stored in memory. Assembly statements are executed using an interpreter, which operates on the memory and architecture (registers, flags etc.) to emulate execution of the program.

As this does not…


This contains a runnable binary, the 8086 emulator, which can be installed and run as a program, but also contains the core emulator library, which can be used in other projects as well, as it is used here :

GitHub logo YJDoc2 / 8086-emulator-web

Repository for 8086 emulator web implementation

Thus the same code can be reused easily.

Now let us take a look at how to convert a newly created or existing only-binary or only-library project into a combined library-binary project.

From lib project

When we create a lib project using Cargo, we get a src folder, with a lib.rs, and a Cargo.toml. One might then add other files and folder inside src, consisting of the library's modules and functions.
Now to add a binary to this, we need to make the following changes :

  • Add a lib key in Cargo.toml
[lib]
name = "your_library_name"
path = "src/lib.rs"
Enter fullscreen mode Exit fullscreen mode

This will declare the library , as per the things made pub in the lib.rs

  • Create a bin folder, and make a bin.rs (or any other name)
  • Add a bin key in Cargo.toml
[[bin]]
name = "your_program_name"
path = "src/bin/bin.rs" # replace bin.rs with name of your file
Enter fullscreen mode Exit fullscreen mode
  • To use the library in binary, just add following use statement and use that as any other import.
use your_library_name;
...
your_library_name::your_library_function();
...
Enter fullscreen mode Exit fullscreen mode

Now when you will add a main function to bin.rs and run Cargo run , you can see the output of the binary 🎉 🎉

Note that you can make a lib folder and create library files inside it, and keep binary files in src if you are creating a new project. But it can be hard if you are adding binary to existing lib project to shift library files from src to src/lib, maintaining the use statements of each file in other files with correct paths. Thus, we create a bin folder and add binary files to it.

From bin project

A Cargo created binary project comes with a Cargo.toml, and a src folder with main.rs.
Now to add a library, or to port existing parts as a library :

  • Add bin key to Cargo.toml
[[bin]]
name = "your_program_name"
path = "src/bin.rs"
Enter fullscreen mode Exit fullscreen mode
  • Create lib folder, and add a lib.rs to it.
  • Add lib key to Cargo.toml
[lib]
name = "your_library_name"
path = "src/lib/lib.rs"
Enter fullscreen mode Exit fullscreen mode

After this, any pub functions or modules in lib.rs will be available as the library.

Now you can use your library in your binary, just as you use your other dependencies :

use your_library_name;
...
your_library_name::your_library_function();
...
Enter fullscreen mode Exit fullscreen mode

That's how one can create a combined library-binary project 🎉 🎉

Thank you for reading !

If you have any questions, or found any mistakes in this, please write in comments 😄

Top comments (5)

Collapse
 
thawkins profile image
Tim Hawkins

How would you go about creating a project with multiple libraries and binaries that all share the libraries.

Collapse
 
yjdoc2 profile image
YJDoc2

Hey, the exact structure would depend on what is your project, and how it grows, but in starting you can create a single root folder of your main binary and then create subfolders for each library with their own cargo.toml and src files. For example, check out github.com/containers/youki
In its root, it has its main binary , and in folder oci_spec , it has a library. For using that as dependency in root cargo toml, its path is given as part of dependency (check the repo to see what I'm trying to say 😅)

I haven't worked on a project which made multiple binaries in a single project, so can't help you there, but for multiple binaries using multiple local libs, you can create individual folders for each of them and then add them as dependencies as needed.

Hope this helps you 🙂

Collapse
 
nsrcodes profile image
Navdeep Singh Rathore

The project you mentioned now uses workspaces. I don't completely understand how they are used but here is the corresponding chapter from "the book" - doc.rust-lang.org/book/ch14-03-car...

Collapse
 
thawkins profile image
Tim Hawkins

Thanks, I'm still learning rust, but this is useful.

Collapse
 
griffigh profile image
griffi-gh

Cargo workspaces.