Project Setup

Cargo

Add lockjaw to the [dependencies] and [build_dependencies] section of your Cargo.toml:

[dependencies]
lockjaw = "*"

[build-dependencies]
lockjaw = "*"

The proc_macro and runtime library are packaged into the same crate, so this is the only target you need. While the proc_macro library is heavy, Rust should be able to optimize them away in the resulting binary. The runtime is pretty light, and the generated code is supposed to be zero cost abstraction.

Build script

Lockjaw also needs some environment setup, and requires a build script. Add build.rs next to Cargo.toml, and call lockjaw::build_script() in main() inside it:

// https://github.com/azureblaze/lockjaw/tree/main/userguide/projects/setup/build.rs
fn main() {
    lockjaw::build_script();
}

Lockjaw will ask you to do this if this step is missing.

Prologue macro

Before using any Lockjaw attribute macros, the lockjaw prologue!() macro must be called:

// https://github.com/azureblaze/lockjaw/tree/main/userguide/projects/setup/src/main.rs
lockjaw::prologue!("src/main.rs");

The file path of the current source file should be passed to the prologue.

Lockjaw need to perform some static analysis on the current source file to understand type names, which is an integral part of a dependency injection framework. If a type is encountered, what is its fully qualified name? Is it something imported with a use declaration? or if it is a locally declared, what is the mod path to the local scope?

Lockjaw also generates a test to verify the source path is correct. However passing a wrong path often result in weird type resolution errors at compile time. Double-check the source path if there are type resolution issues.

Epilogue macro

You also must call the lockjaw::epilogue!() macro in the root of your crate (lib.rs or main.rs) after all other uses of lockjaw, preferably at the end of the file.

// https://github.com/azureblaze/lockjaw/tree/main/userguide/projects/setup/src/main.rs
lockjaw::epilogue!();

Source of this chapter